[
  {
    "path": ".gitignore",
    "content": "*.o\n*.iso\n*.elf\n*.img\n\ntools/\ngraph.sh\ntags\nmnt/\n\nbuild-tools/*\n!build-tools/build.sh\n!build-tools/aquila/\n!build-tools/patches/\n\nramdisk/sysroot\nramdisk/out\n\nsystem/usr\nsystem/nuklear/nuklear\nsystem/nuklear/libnk.a\nsystem/fbterm/fbterm\nsystem/aqbox/aqbox\n"
  },
  {
    "path": ".gitlab-ci.yml",
    "content": "image: manwar/aquila\n\nbuild:\n  stage: build\n  before_script:\n    - apt update && apt -y install make cpio texinfo grub-pc-bin xorriso wget\n  script:\n    - export PATH=$PATH:/opt/aquila/bin\n    - export TRAVIS_BUILD_DIR=$(pwd)\n    - make aquila.iso -j$(nproc)\n  artifacts:\n    paths:\n      - aquila.iso\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: c\nbefore_install:\n  - sudo apt-get update -qq\n  - sudo apt-get install -qq texinfo grub-pc-bin xorriso\ninstall:\n  - cd build-tools && bash build.sh && cd ..\ncache:\n  directories:\n    # Cache Packages\n  - build-tools/pkgs\n    # And unpacked directories\n  - build-tools/binutils-2.28\n  - build-tools/gcc-7.3.0\n  - build-tools/autoconf-2.69\n  - build-tools/automake-1.12.1\n    # And gcc cross compiler\n  - build-tools/sysroot\nscript:\n  - make aquila.iso\ndeploy:\n  provider: releases\n  api_key:\n    secure: aFJAuaPBhCn7R+4Ymeu12E0WapPSQFDljtCrqFOSsq/vCOJ7QeXuKp0P6XEXEPpZ2mv4V9GVnGHjWflWCH1frWHbCCSZsWkR36Rxlv0sY8ufoMjWeJqkcn1BNUVluGoZSjXyYp9jzFei6kbkk4jsoh3ipfFj8VK/i3qIZuUl7DAz70y8cg9z1Ue3FGgSq010+QI6iH/+hYssn1hJgtyOLmM8Fe4rRADBeAZQ8XFohqj1yTQRCAyVnL96OGes5mBGfYSikwU8n6errx78FI9ei7CkZEqZtqwoBxyX9XKbCo5TcdIITZ/7vXfiEf/3u/G6623M5pPPXRrxZfWcU+Oon20eQU9CKlGnzaMlGXTU6KtqeT53ullkCBC3X6dWwflcFXel/rpSXfyJY5ihllB4CpD/kXWSEZaFm/ip2II+MrkIK+qm469WArMNWvx7NqdC9BujEJ2phrT667qPzoUe+O7XCPxlWrcHJa8veo2GN1f2O8pH1PEvHPMWZfK0Z9N3ZKpLLn3P9BtMh0Chw0Cy+qMEa9Q3joRGBrQAzVUhGcCl9RsSWb89W7v1kvc6C9oiGO1Q+SRcdJtWkFRsjqGGowbzocjakPgJ8NaEztsiZvM0Om7CB0HeJR1fNA2i4NWfLx3GKt81v8/ld4zWjuukIkzxshuXkRqrcYB50cgHXGg=\n  file: aquila.iso\n  skip_cleanup: true\n  on:\n    repo: mohamed-anwar/Aquila\n    tags: true\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    {one line to give the program's name and a brief idea of what it does.}\n    Copyright (C) {year}  {name of author}\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    {project}  Copyright (C) {year}  {fullname}\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "Makefile",
    "content": "# This is the top leve Makefile of AquilaOS\n#\n# Targets:\n#\n#  build-kernel     - build kernel image in kernel/{ARCH}/kernel-{VERSION}.{ARCH}\n#  install-kernel   - install kernel image into {DESTDIR}/boot/kernel\n#  clean-kernel     - clean kernel source tree\n#\n#  build-system     - build system components\n#  install-system   - install system components into {DESTDIR}/\n#  clean-system\t    - clean system source tree\n#\n#  build-initrd     - build ramdisk image in initrd/initrd.img\n#  install-initrd   - install ramdisk image into {DESTDIR}/boot/initrd.img\n#  clean-initrd     - clean ramdisk source tree\n#\n#  build-all        - build everything\n#  install-all      - install everything\n#  clean-all        - clean everything\n#\n\nexport\n\nifeq ($(SRCDIR),)\nSRCDIR := $(TRAVIS_BUILD_DIR)\nendif\n\nifeq ($(SRCDIR),)\nSRCDIR != pwd\nendif\n\nifeq ($(BUILDDIR),)\nBUILDDIR != pwd\nendif\n\nifeq ($(CONFIG),)\nCONFIG := i386-pc\nendif\n\ninclude $(SRCDIR)/configs/$(CONFIG).mk\n\nARCH=i386\nVERSION=0.0.1\nCP=cp\nBASH=bash\nMKDIR=mkdir -p\nECHO=echo\nSTRIP=/opt/aquila/bin/i686-aquila-strip\nLN=ln\n\nMAKEFLAGS += --no-print-directory\n\nGRUB_MKRESCUE = $(shell command -v grub2-mkrescue 2> /dev/null)\nifeq ($(GRUB_MKRESCUE),)\nGRUB_MKRESCUE = grub-mkrescue\nendif\n\nDESTDIR = $(SRCDIR)/sysroot\n\n.PHONY: build-all install-all clean-all\nbuild-all: \\\n\tbuild-kernel \\\n\tbuild-system \\\n\tbuild-initrd\n\ninstall-all: \\\n\tinstall-kernel \\\n\tinstall-system \\\n\tinstall-initrd\n\nclean-all: \\\n\tclean-kernel \\\n\tclean-system \\\n\tclean-initrd\n\n#\n# kernel targets\n#\n\n.PHONY: build-kernel clean-kernel install-kernel\nbuild-kernel:\n\t$(MAKE) -C $(SRCDIR)/kernel/\n\ninstall-kernel:\n\t$(MAKE) -C $(SRCDIR)/kernel/ install\n\nclean-kernel:\n\t$(MAKE) -C $(SRCDIR)/kernel/ clean\n\n#\n# initrd targets\n#\n\n.PHONY: build-initrd install-initrd clean-initrd\nbuild-initrd: build-system\n\t$(MAKE) -C $(SRCDIR)/initrd/\n\ninstall-initrd: build-initrd\n\t$(MAKE) -C $(SRCDIR)/initrd/ install\n\nclean-initrd:\n\t$(MAKE) -C $(SRCDIR)/initrd/ clean\n\n#\n# system targets\n#\n\n.PHONY: build-system install-system clean-system\nbuild-system: \n\t$(MAKE) -C $(SRCDIR)/system/\n\ninstall-system: build-system\n\t$(MAKE) -C $(SRCDIR)/system/ install\n\nclean-system:\n\t$(MAKE) -C $(SRCDIR)/system/ clean\n\n.PHONY: iso/kernel.elf.gz\niso/kernel.elf.gz: build-kernel\n\t$(BASH) -c \"if [[ ! -e iso ]]; then mkdir iso; fi\"\n\t$(CP) kernel/arch/$(ARCH)/kernel-$(VERSION).$(ARCH) iso/kernel.elf\n\tgzip -f iso/kernel.elf\n\n.PHONY: iso/initrd.img.gz\niso/initrd.img.gz: build-initrd\n\t$(BASH) -c \"if [[ ! -e iso ]]; then mkdir iso; fi\"\n\tcp initrd/initrd.img iso/initrd.img\n\tgzip -f iso/initrd.img\n\n.PHONY: try\ntry: aquila.iso\n\tqemu-kvm -cdrom aquila.iso -hda hd.img -serial stdio -m 2G -d cpu_reset -no-reboot -boot d\n\naquila.iso: iso/kernel.elf.gz iso/initrd.img.gz\n\t$(GRUB_MKRESCUE) -d /usr/lib/grub/i386-pc/ -o aquila.iso iso/\n#\t#$(GRUB_MKRESCUE) -d /usr/lib/grub/i386-pc/ --install-modules=\"multiboot normal videoinfo videotest gzio\" --locales=\"en@quot\" --fonts=ascii -o aquila.iso iso/\n"
  },
  {
    "path": "README.md",
    "content": "# Aquila OS ![https://travis-ci.org/mohamed-anwar/Aquila](https://api.travis-ci.org/mohamed-anwar/Aquila.svg?branch=master) [![Gitter chat](https://badges.gitter.im/mohamed-anwar/aquila.png)](https://gitter.im/_aquila)\n![Image of Aquila](http://aquilaos.com/img/screenshot.png)\n\nUNIX-like Operating System, including the kernel and system tools.\nIntended to be fully **POSIX** compliant. Oh, and it compiles with -O3.\n\n#### Build Instructions\nFollow the instructions in this [wiki page.](https://github.com/mohamed-anwar/Aquila/wiki/Build-Instructions)\n\n#### CPU-based Features:\n##### Supported Archetictures:\n> - [X] x86\n> - [ ] x86-64\n\n- [X] Multitasking\n- [X] Multithreading\n- [ ] SMP\n\n#### Kernel Features:\n- [X] Monolitihic kernel\n- [X] Virtual Filesystem\n- [ ] Supports loadable modules\n\n#### Supported Filesystems:\n- [X] initramfs (CPIO Archive filesystem, used for Ramdisk, read only)\n- [X] tmpfs     (Generic temporary filesystem, read/write)\n- [X] devfs     (Virtual filesystem, used for device handlers, statically populated, read/write)\n- [X] devpts    (Virtual filesystem, used for psudo-terminals, dynamically populated, read/write)\n- [X] procfs    (Processes information filesystem, read only)\n- [X] ext2      (Basic Extended 2 filesystem, read/write)\n- [ ] ext3\n- [ ] ext4\n- [ ] sysfs\n\n#### Supported Devices:\n- [X] i8042   (PS/2 Controller)\n- [X] ramdev  (Memory mapped device, generic handler)\n- [X] ps2kbd  (PS/2 Keyboard Controller)\n- [X] console (IBM TGA console)\n- [X] ata     (ATA Harddisk handler, PIO mode)\n- [X] fbdev   (Generic framebuffer device handler)\n- [X] 8250    (UART)\n\n#### Supported video interfaces:\n- [X] VESA 3.0\n\n#### System Feautres:\n- [X] newlib-3.0.0 (latest)\n- [X] aqbox        (Aquila Box, like busybox)\n- [X] fbterm       (Framebuffer based terminal)\n- [X] tcc          (Tiny C Compiler)\n- [X] lua          (Lua programming language)\n- [X] kilo         (Kilo text editor)\n"
  },
  {
    "path": "configs/clang.mk",
    "content": "CC := clang\n\nCFLAGS := $(INCLUDES) \\\n\t\t-nostdlib -ffreestanding -m32 \\\n\t\t-O3 -Wall -Wextra -Werror \\\n\t\t-Wno-unused -Wno-unused-parameter -march=i386\n\nAS := $(CC)\nASFLAGS := $(CFLAGS)\n#LD := ld.gold\nLD := ld.lld\nLDFLAGS := -nostdlib -melf_i386\n"
  },
  {
    "path": "configs/gcc.mk",
    "content": "CC := i686-aquila-gcc\n\nCFLAGS += \\\n\t\t-nostdlib -ffreestanding -m32 \\\n\t\t-O3 -Wall -Wextra -Werror \\\n\t\t-Wno-unused -Wno-unused-parameter -march=i386 \\\n\t\t-funsigned-bitfields -fuse-ld=bfd\n\nAS := $(CC)\nASFLAGS := $(CFLAGS)\nLD := i686-aquila-ld\nLDFLAGS := -nostdlib -melf_i386\n\nSYSCC := i686-aquila-gcc\nSYSLD := i686-aquila-ld\n"
  },
  {
    "path": "configs/i386-pc.mk",
    "content": "include $(SRCDIR)/configs/gcc.mk\n\n#\n# Configurations\n#\n\nARCH=i386\nARCH_DIR=i386\nARCH_I386=y\nARCH_BITS=32\n\n#\n# Boot Definitions\n#\n\nX86_MULTIBOOT=y\n\n#\n# Platform - PC\n#\n\nPLATFORM_X86_PC=y\nPLATFORM_DIR=pc\n# Support 8259 PIC\nPLATFORM_X86_MISC_PIC=y\n# Support 8253/8254 PIT\nPLATFORM_X86_MISC_PIT=y\n# Support i8042 PS/2 Controller\nPLATFORM_X86_MISC_I8042=y\n# Support HPET\nPLATFORM_X86_MISC_HPET=n\n# Support ACPI\nPLATFORM_X86_MISC_ACPI=y\n# Support CMOS\nPLATFORM_X86_MISC_CMOS=y\n\n#\n# Devices\n#\n\n# Generic framebuffer (fbdev) support\nDEV_FRAMEBUFFER=y\n# Generic console (condev) support\nDEV_CONSOLE=y\nDEV_KEYBOARD=y\nDEV_MOUSE=y\nDEV_KEYBOARD_PS2=y\nDEV_UART=y\nDEV_PTY=y\nDEV_MEMDEV=y\nDEV_ATA=y\nDEV_FDC=y\n\n#\n# Framebuffer\n#\n\nFBDEV_VESA=y\n\n# Filesystems\nFS_TMPFS=y\nFS_DEVFS=y\nFS_DEVPTS=y\nFS_EXT2=y\nFS_PROCFS=y\nFS_MINIX=y\n\n# Initramfs\nINITRAMFS_CPIO=y\n\n# Network\nNET_UNIX=y\n"
  },
  {
    "path": "configs/i386-quark.mk",
    "content": "#\n# Compilation flags\n#\n\nCC := $(PDIR)/../build-tools/sys/bin/i686-elf-gcc\nCFLAGS := -std=gnu99 -I. -I$(PDIR)/arch/$$(ARCH_DIR)/chipset/$$(CHIPSET_DIR)/include -I$(PDIR)/arch/$$(ARCH_DIR)/include -I $(PDIR) -I $(PDIR)/include/ -nostdlib -ffreestanding -m32 \\\n\t\t  -O3 -Wall -Wextra -Werror -funsigned-bitfields -fuse-ld=bfd \\\n\t\t  -Wno-unused -march=i586\n\nAS := $(CC)\nASFLAGS := $(CFLAGS)\n\nLD := $(PDIR)/../build-tools/sys/bin/i686-elf-ld.bfd\nLDFLAGS := -nostdlib -melf_i386\n\n#\n# Configurations\n#\n\nARCH=X86\nARCH_DIR=x86\nARCH_X86=y\nARCH_BITS=32\n\n#\n# Boot Definitions\n#\n\nX86_MULTIBOOT=y\n\n#\n# Chipset - generic\n#\n\n#CHIPSET_X86_GENERIC=y\nCHIPSET_X86_QUARK=y\nCHIPSET_DIR=quark\n# Support 8259 PIC\nCHIPSET_X86_MISC_PIC=y\n# Support 8253/8254 PIT\nCHIPSET_X86_MISC_PIT=y\n# Support i8042 PS/2 Controller\n#CHIPSET_X86_MISC_I8042=y\n\n#\n# Devices\n#\n\n# Generic framebuffer (fbdev) support\n#DEV_FRAMEBUFFER=y\n# Generic console (condev) support\nDEV_CONSOLE=y\n#DEV_KEYBOARD=y\n#DEV_MOUSE=y\n#DEV_KEYBOARD_PS2=y\nDEV_UART=y\nDEV_PTY=y\n\n#\n# Framebuffer\n#\n\n#FBDEV_VESA=y\n\n# Filesystems\nFS_TMPFS=y\nFS_DEVFS=y\nFS_DEVPTS=y\n#FS_EXT2=y\nFS_PROCFS=y\n"
  },
  {
    "path": "configs/none.mk",
    "content": "CC := $(PDIR)/../build-tools/sysroot/bin/i686-elf-gcc\nCFLAGS := -std=gnu99 -I. -I$(PDIR)/arch/$$(ARCH_DIR)/chipset/$$(CHIPSET_DIR)/include -I$(PDIR)/arch/$$(ARCH_DIR)/include -I $(PDIR) -I $(PDIR)/include/ -nostdlib -ffreestanding -m32 \\\n\t\t  -O3 -Wall -Wextra -Werror -funsigned-bitfields -fuse-ld=bfd \\\n\t\t  -Wno-unused -march=i386\n\nAS := $(CC)\nASFLAGS := $(CFLAGS)\n\nLD := ld.bfd\nLDFLAGS := -nostdlib -melf_i386 -L /opt/aquila/lib/gcc/i686-aquila/7.3.0/\n\nARCH=none\nARCH_DIR=none\nARCH_NONE=y\nARCH_BITS=32\n\n#DEV_FRAMEBUFFER=y\n#DEV_CONSOLE=y\n#DEV_KEYBOARD=y\n#DEV_MOUSE=y\n#DEV_KEYBOARD_PS2=y\n#DEV_UART=y\n#DEV_PTY=y\n#DEV_MEMDEV=y\n#DEV_ATA=y\n#DEV_FDC=y\n\nFBDEV_VESA=y\n\n# Filesystems\nFS_TMPFS=y\nFS_DEVFS=y\nFS_DEVPTS=y\nFS_EXT2=y\nFS_PROCFS=y\nFS_MINIX=y\n\n# Initramfs\nINITRAMFS_CPIO=y\n"
  },
  {
    "path": "configs/pcc.mk",
    "content": "CC := /opt/aquila/bin/i686-aquila-pcc\n\nCFLAGS += \\\n\t\t-nostdlib -ffreestanding -m32 \\\n\t\t-O3 -Wall -Wextra -Werror \\\n\t\t-Wno-unused -Wno-unused-parameter -march=i386 \\\n\t\t-funsigned-bitfields -fuse-ld=bfd\n\nAS := $(CC)\nASFLAGS := $(CFLAGS)\nLD := /opt/aquila/bin/i686-aquila-ld\nLDFLAGS := -nostdlib -melf_i386\n\nSYSCC := /opt/aquila/bin/i686-aquila-pcc\nSYSLD := /opt/aquila/bin/i686-aquila-ld\n"
  },
  {
    "path": "configs/x86_64-pc.mk",
    "content": "#\n# Compilation flags\n#\n\nCC := gcc\nCFLAGS := -std=gnu99 -I. -I$(PDIR)/arch/$$(ARCH_DIR)/chipset/$$(PLATFORM_DIR)/include -I$(PDIR)/arch/$$(ARCH_DIR)/include -I $(PDIR) -I $(PDIR)/include/ -nostdlib -ffreestanding \\\n\t\t  -O3 -Wall -Wextra -Werror -funsigned-bitfields -fuse-ld=bfd \\\n\t\t  -Wno-unused \\\n\t\t  -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -z max-page-size=0x1000\n\nAS := $(CC)\nASFLAGS := $(CFLAGS)\n\nLD := ld.bfd\nLDFLAGS := -nostdlib -melf_x86_64\n\n#\n# Configurations\n#\n\nARCH=x86_64\nARCH_DIR=x86_64\nARCH_X86_64=y\nARCH_BITS=64\n\n#\n# Boot Definitions\n#\n\nX86_MULTIBOOT=y\n\n#\n# Chipset - generic\n#\n\nPLATFORM_X86_PC=y\nPLATFORM_DIR=pc\n# Support 8259 PIC\nPLATFORM_X86_MISC_PIC=y\n# Support 8253/8254 PIT\nPLATFORM_X86_MISC_PIT=y\n# Support i8042 PS/2 Controller\nPLATFORM_X86_MISC_I8042=y\n\n#\n# Devices\n#\n\n# Generic framebuffer (fbdev) support\nDEV_FRAMEBUFFER=y\n# Generic console (condev) support\nDEV_CONSOLE=y\nDEV_KEYBOARD=y\nDEV_MOUSE=y\nDEV_KEYBOARD_PS2=y\nDEV_UART=y\nDEV_PTY=y\nDEV_MEMDEV=y\nDEV_ATA=y\n\n#\n# Framebuffer\n#\n\nFBDEV_VESA=y\n\n# Filesystems\nFS_TMPFS=y\nFS_DEVFS=y\nFS_DEVPTS=y\n#FS_EXT2=y\nFS_PROCFS=y\n\n# Initramfs\nINITRAMFS_CPIO=y\n"
  },
  {
    "path": "initrd/Makefile",
    "content": "ROOT= initrd\nDIRS= bin sbin dev mnt proc tmp root\nCOPY= etc usr\n\nAQBOX= aqbox\nAQBOX_BIN= cat clear echo env ls mkdir mknod ps pwd sh stat uname unlink touch kill bim date\nAQBOX_SBIN= login mount kbd getty readmbr reboot\n\n# Create initrd CPIO image\ninitrd.img: all\n\tcd $(ROOT); find . | cpio -o > ../initrd.img;\n\nall: $(DIRS) $(COPY) $(ROOT)/init fbterm aqbox $(ROOT)/dev/kmsg #nuklear\n\n$(ROOT):\n\t$(MKDIR) -p $(ROOT)\n\n# Inflate initrd ROOT with required directories\n$(DIRS): $(ROOT)\n\t$(MKDIR) -p $(ROOT)/$@\n\n# Copy some files and directories into initrd ROOT\n$(COPY): $(ROOT)\n\t$(CP) -r $@ $(ROOT)/\n\nfbterm: $(ROOT)/bin/fbterm\n\n$(ROOT)/bin/fbterm: $(ROOT)/bin\n\t$(CP) $(SRCDIR)/system/fbterm/fbterm  $(ROOT)/bin/\n\t$(STRIP) $(ROOT)/bin/fbterm\n\naqbox: $(ROOT)/bin/aqbox $(AQBOX_BIN) $(AQBOX_SBIN)\n\n$(ROOT)/bin/aqbox: $(ROOT)/bin\n\t$(CP) $(SRCDIR)/system/aqbox/aqbox $(ROOT)/bin/\n\t$(STRIP) $(ROOT)/bin/aqbox\n\n$(AQBOX_BIN): $(ROOT)/bin/aqbox\n\t$(LN) -fs /bin/aqbox $(ROOT)/bin/$@\n\n$(AQBOX_SBIN): $(ROOT)/bin/aqbox\n\t$(LN) -fs /bin/aqbox $(ROOT)/sbin/$@\n\n$(ROOT)/init:\n\t$(MAKE) -C init/\n\t$(CP) init/init $@\n\n$(ROOT)/dev/kmsg:\n\t#sudo mknod $(ROOT)/dev/kmsg c 1 11\n\nclean:\n\t$(MAKE) -C init/ clean\n\t$(RM) -rf $(ROOT) initrd.img\n\n.PHONY: all $(DIRS) clean $(COPY) fbterm aqbox $(AQBOX_BIN) $(AQBOX_SBIN) install\ninstall: all\n\t$(MKDIR) -p $(DESTDIR)/boot\n\t$(CP) initrd.img $(DESTDIR)/boot\n"
  },
  {
    "path": "initrd/etc/hostname",
    "content": "aquila\n"
  },
  {
    "path": "initrd/etc/motd",
    "content": "\n                                               _...__..-'\n                                             .'\n                                           .'\n                                         .'\n                                       .'\n            .------._                 ;\n      .-\"\"\"`-.<')    `-._           .'\n     (.--. _   `._       `'---.__.-'\n      `   `;'-.-'         '-    ._\n        .--'``  '._      - '   .\n         `\"\"'-.    `---'    ,\n ''--..__      `\\\n         ``''---'`\\      .'\n                   `'. '\n                     `'.\n   _____               .__.__          ________    _________\n  /  _  \\   ________ __|__|  | _____   \\_____  \\  /   _____/\n /  /_\\  \\ / ____/  |  \\  |  | \\__  \\   /   |   \\ \\_____  \\ \n/    |    < <_|  |  |  /  |  |__/ __ \\_/    |    \\/        \\\n\\____|__  /\\__   |____/|__|____(____  /\\_______  /_______  /\n        \\/    |__|                  \\/         \\/        \\/ \n\nWelcome to AquilaOS!\n\n"
  },
  {
    "path": "initrd/etc/passwd",
    "content": "root:x:0:0:root:/root:/bin/sh\n"
  },
  {
    "path": "initrd/etc/rc.init",
    "content": "#!/bin/sh\n\nset -x\nexport PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/libexec:/usr/local/bin:/usr/local/sbin\n\n# Mount devfs on /dev\necho mounting devfs on /dev\nmount -t devfs /dev\n\n# Populate static devices\necho populating static devices in /dev\nmknod /dev/console c 5 1 \nmknod /dev/ptmx c 5 2 \nmknod /dev/kbd c 11 0 \nmknod /dev/fb0 c 29 0 \nmknod /dev/hda b 3 0 \nmknod /dev/hda1 b 3 1 \nmknod /dev/ttyS0 c 4 64 \nmknod /dev/mouse c 10 1 \nmknod /dev/kmsg c 1 11\nmknod /dev/fd0 b 2 0\n\n# Mount devpts on /dev/pts\necho mounting devpts on /dev/pts\nmkdir /dev/pts\nmount -t devpts /dev/pts\n"
  },
  {
    "path": "initrd/init/Makefile",
    "content": "#ARCH=i686\n#SYSROOT= ../../build-tools/sysroot\n#CC= $(SYSROOT)/bin/$(ARCH)-aquila-gcc\n#CFLAGS= -I$(SYSROOT)/usr/$(ARCH)-aquila/include\n#\n#LD= $(CC)\n#LDFLAGS= -nostdlib -ffreestanding -Wl,-Ttext=0x1000\n#LDLIBS= $(SYSROOT)/usr/$(ARCH)-aquila/lib/crt0.o -L$(SYSROOT)/usr/$(ARCH)-aquila/lib -lc -lpthread -lm -lgcc \n\nall: init\n\ninit: init.c\n\t$(SYSCC) $< -o $@\n\nclean:\n\trm -rf init\n\n.PHONY: all clean\n"
  },
  {
    "path": "initrd/init/init.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <string.h>\n#include <sys/wait.h>\n#include <stdarg.h>\n#include <signal.h>\n#include <errno.h>\n\nint log_fd = -1;\nint log_init()\n{\n    log_fd = open(\"/dev/kmsg\", O_WRONLY);\n}\n\nint _log(int level, const char *fmt, ...)\n{\n    static char buf[512];\n\n    if (log_fd >= 0) {\n        va_list ap;\n        va_start(ap, fmt);\n        int len = vsnprintf(buf, sizeof(buf), fmt, ap);\n        va_end(ap);\n        write(log_fd, buf, len);\n    }\n}\n\nint run(char **argv)\n{\n    int child, status, pid;\n\n    if (child = fork()) {\n        do pid = waitpid(child, &status, 0);\n        while (pid != child);\n    } else {\n        int x = execv(argv[0], argv);\n        _log(1, \"failed to execute %s: %s\\n\", argv[0], strerror(errno));\n        exit(x);\n    }\n\n    return status;\n}\n\nvoid signal_handler(int sig)\n{\n    switch (sig) {\n        case SIGTERM:\n            _log(1, \"init: reached target reboot\\n\");\n            exit(0);\n        default:\n            /* ignore */\n            return;\n    }\n}\n\nint main(int argc, char **argv)\n{\n    signal(SIGKILL, signal_handler);\n    signal(SIGTERM, signal_handler);\n\n    close(0); close(1); close(2);\n    open(\"/dev/kmsg\", O_RDONLY);\n    log_init();\n\n    if (open(\"/dev/kmsg\", O_WRONLY) != 2) {\n        _log(1, \"could not open stderr\\n\");\n    }\n\n    _log(1, \"init: started\\n\");\n\n    /* execute /etc/rc.init script */\n    _log(1, \"init: executing /etc/rc.init script\\n\");\n    char *argp[] = {\"/bin/sh\", \"/etc/rc.init\", NULL};\n    run(argp);\n\n    int use_fbterm = 0, use_serial = 0;\n\n    if (argc > 0) {\n        char *cmdline = argv[0], *token;\n        while ((token = strtok(cmdline, \" \"))) {\n            cmdline = NULL;\n            if (!strcmp(token, \"--serial\"))\n                use_serial = 1;\n            else if (!strcmp(token, \"--fbterm\"))\n                use_fbterm = 1;\n        }\n    }\n\n    if (use_fbterm || !use_serial) {\n        _log(1, \"init: starting fbterm\\n\");\n        char *argp[] = {\"/bin/fbterm\", NULL};\n        if (!fork()) {\n            for (int i = 0; i < 3; ++i)\n                close(i);\n\n            execv(argp[0], argp);\n        }\n    }\n\n    if (use_serial) {\n        if (!fork()) {\n            for (int i = 0; i < 3; ++i)\n                close(i);\n\n            open(\"/dev/ttyS0\", O_RDONLY);\n            open(\"/dev/ttyS0\", O_WRONLY);\n            open(\"/dev/ttyS0\", O_WRONLY);\n\n            char *argp[] = {\"/sbin/login\", NULL};\n            while (1) run(argp);\n            //execv(argp[0], argp);\n        }\n    }\n\n    /* init can't die */\n\tfor (;;);\n}\n"
  },
  {
    "path": "initrd/usr/share/man/man1/ccom.1",
    "content": ".\\\"\t$Id: ccom.1,v 1.33 2018/12/15 09:12:14 plunky Exp $\n.\\\"\n.\\\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net>\n.\\\"\n.\\\" Permission to use, copy, modify, and/or distribute this software for any\n.\\\" purpose with or without fee is hereby granted, provided that the above\n.\\\" copyright notice and this permission notice appear in all copies.\n.\\\"\n.\\\" THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM\n.\\\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND\n.\\\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\n.\\\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\n.\\\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\n.\\\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\n.\\\" THIS SOFTWARE.\n.\\\"\n.Dd March 22, 2012\n.Dt CCOM 1\n.Os\n.Sh NAME\n.Nm ccom\n.Nd C compiler\n.Sh SYNOPSIS\n.Nm\n.Op Fl gkpsv\n.Op Fl f Ar features\n.Op Fl m Ar options\n.Op Fl W Ar warnings\n.Op Fl X Ar flags\n.Op Fl x Ar settings\n.Op Fl Z Ar flags\n.Op infile\n.Op outfile\n.Sh DESCRIPTION\nThe\n.Nm\nutility provides a C compiler.\nThe frontend is usually\n.Xr pcc 1 .\nIt is\n.Em not\nintended to be run directly.\n.Nm\nreads the C source from\n.Ar infile\nor standard input and writes the assembler source\nto\n.Ar outfile\nor to standard output.\n.Pp\nThe options are as follows:\n.Bl -tag -width Ds\n.It Fl f Ar feature\nEnable language features.\nMultiple\n.Fl f\noptions can be given, the following features are supported:\n.Bl -tag -width Ds\n.It Sy stack-protector\nEnable stack smashing protection.\nCurrently the same as\n.Sy stack-protector-all .\n.It Sy stack-protector-all\nEnable stack smashing protection for all functions.\n.It Sy pack-struct Ns Oo = Ns Ar n Oc\nSpecify maximum alignment for structure members, similar to a #pragma pack\nstatement at the start of the file.\nIf no value is given, the default is 1.\n.It Sy freestanding\nEmit code for a freestanding environment.\nCurrently not implemented.\n.El\n.It Fl g\nInclude debugging information in the output code for use by\nsymbolic and source-level debuggers.\nCurrently this uses the\n.Sy stabs\nformat, encoding information in\n.Em s Ns ymbol Em tab Ns le entrie Ns Em s.\n.It Fl k\nGenerate PIC code.\n.It Fl m Ar option\nTarget-specific options, used in machine-dependent code.\nMultiple\n.Fl m\noptions can be given, the following options are supported:\n.Bl -tag -width PowerPC\n.It AMD64\n.It ARM\n.Sy little-endian ,\n.Sy big-endian ,\n.Sy fpe=fpa ,\n.Sy fpe=vpf ,\n.Sy soft-float ,\n.Sy arch=armv1 ,\n.Sy arch=armv2 ,\n.Sy arch=armv2a ,\n.Sy arch=armv3 ,\n.Sy arch=armv4 ,\n.Sy arch=armv4t ,\n.Sy arch=armv4tej ,\n.Sy arch=armv5 ,\n.Sy arch=armv5te ,\n.Sy arch=armv5tej ,\n.Sy arch=armv6 ,\n.Sy arch=armv6t2 ,\n.Sy arch=armv6kz ,\n.Sy arch=armv6k No \\*(Am\n.Sy arch=armv7 .\n.It HPPA\n.It i386\n.It M16C\n.It MIPS\n.Sy little-endian No \\*(Am\n.Sy big-endian .\n.It NOVA\n.It PDP-10\n.It PDP-11\n.It PowerPC\n.Sy little-endian ,\n.Sy big-endian ,\n.Sy soft-float No \\*(Am\n.Sy hard-float .\n.It Sparc64\n.It VAX\n.El\n.It Fl p\nGenerate profiling code.\n.It Fl s\nPrint statistics to standard error when complete.\nThis includes:\nname table entries, name string size, permanent allocated memory,\ntemporary allocated memory, lost memory, argument list unions,\ndimension/function unions, struct/union/enum blocks, inline node count,\ninline control blocks, and permanent symtab entries.\n.\\\" TODO: explain units for above?\n.It Fl v\nDisplay version.\n.It Fl W Ar warning\nDo some basic checks and emit warnings about possible coding problems.\nMultiple\n.Fl W\noptions can be given, the following warnings are supported:\n.Bl -tag -width Ds\n.It Sy error Ns Oo = Ns Ar warning Oc\nEnable\n.Ar warning ,\nand treat it as an error condition.\nIf a specific warning is not given, producing any warning will cause an error.\n.It Sy attributes\nWarn when unsupported attributes are used.\nThis warning is enabled by default.\n.It Sy deprecated-declarations\nReport whenever a symbol marked with the\n.Sq deprecated\nattribute is used.\nThis warning is enabled by default.\n.It Sy implicit-function-declaration\n(TODO) Require explicit prototypes for all called functions.\n.It Sy implicit-int\n(TODO) Warn when a function declaration lacks a type.\n.It Sy missing-prototypes\nRequire explicit prototypes for all global function definitions.\n.It Sy pointer-sign\nWarn when pointer operations are done with mismatched signed and unsigned values.\n.It Sy sign-compare\n(TODO) Warn about comparisons between signed and unsigned values.\n.It Sy strict-prototypes\n(TODO) Require that function prototypes are strictly C99.\n.It Sy shadow\nReport when a local variable shadows something from a higher scope.\n.It Sy truncate\nReport when integer values may be implicitly truncated to fit a smaller type.\n.It Sy uninitialized\nA variable is read before being written.\n.It Sy unknown-pragmas\nReport unhandled pragma statements.\n.It Sy unreachable-code\nReport statements that cannot be executed.\n.El\n.Pp\nAny of the above may be prefixed with\n.Dq no-\nin order to disable the effect.\n.\\\"\n.It Fl X Ar flags\nC specific debugging where\n.Ar flags\nis one or more of the following:\n.Pp\n.Bl -tag -compact -width Ds\n.It Sy b\nBuilding of parse trees\n.It Sy d\nDeclarations (using multiple\n.Sy d\nflags gives more output)\n.It Sy e\nPass1 trees at exit\n.It Sy i\nInitializations\n.It Sy n\nMemory allocations\n.It Sy o\nTurn off optimisations\n.It Sy p\nPrototypes\n.It Sy s\nInlining\n.It Sy t\nType conversions\n.It Sy x\nTarget-specific flag, used in machine-dependent code\n.El\n.\\\"\n.It Fl x Ar setting\nEnable\n.Ar setting\nin the compiler.\nMultiple\n.Fl x\noptions can be given, the following settings are supported:\n.Bl -tag -width Ds\n.It Sy ccp\nApply sparse conditional constant propagation techniques for optimization.\nCurrently not implemented.\n.It Sy dce\nDo dead code elimination.\n.It Sy deljumps\nDelete redundant jumps and dead code.\n.It Sy gnu89\n.It Sy gnu99\nUse GNU C semantics rather than C99 for some things.\nCurrently only inline.\n.It Sy inline\nReplace calls to functions marked with an inline specifier with a copy\nof the actual function.\n.It Sy ssa\nConvert statements into static single assignment form for optimization.\nNot yet finished.\n.It Sy tailcall\nEnable optimization of tail-recursion functions.\nCurrently not implemented.\n.It Sy temps\nLocate automatic variables into registers where possible, for further\noptimization by the register allocator.\n.It Sy uchar\nTreat character constants as unsigned values.\n.El\n.\\\"\n.It Fl Z Ar flags\nCode generator (pass2) specific debugging where\n.Ar flags\nis one or more of the following:\n.Pp\n.Bl -tag -compact -width Ds\n.It Sy b\nBasic block and SSA building\n.It Sy c\nCode printout\n.It Sy e\nTrees when entering pass2\n.It Sy f\nInstruction matcher, may provide much output\n.It Sy g\nPrint flow graphs\n.It Sy n\nMemory allocation\n.It Sy o\nInstruction generator\n.It Sy r\nRegister allocator\n.It Sy s\nShape matching in instruction generator\n.It Sy t\nType matching in instruction generator\n.It Sy u\nSethi-Ullman computations\n.It Sy x\nTarget-specific flag, used in machine-dependent code\n.El\n.El\n.Sh PRAGMAS\nInput lines starting with a\n.Dq #pragma\ndirective can be used to modify behaviour of\n.Nm\nduring compilation.\nAll tokens up to the first unescaped newline are considered part\nof the pragma command, with the following operations being recognized:\n.Bl -tag -width Ds\n.It Sy STDC\nStandard C99 operator follows.\nCurrently no C99 operations are implemented, and any directives starting\nwith this token will be silently ignored.\n.It Sy GCC diagnostic Ar effect Qq Ar option\nGNU C compatibility.\nAlter the effects of compiler diagnostics.\nThe required\n.Ar effect\nshould be stated as\n.Sy warning ,\n.Sy error\nor\n.Sy ignored ,\nfollowed by the compiler diagnostic\n.Ar option\nin double quotes.\nFor example, to force unknown pragmas to always generate an error,\na standard header might include\n.Bd -literal -offset 2n\n#pragma GCC diagnostic error \"-Wunknown-pragmas\"\n.Ed\n.It Sy GCC poison Ar identifier ...\nGNU C compatibility.\nCause an error if any of the following\n.Ar identifier Ns s\nsubsequently appear in the code\n.Pq but not in any macro expansions .\nCurrently not implemented.\n.It Sy GCC system_header\nGNU C compatibility.\nCurrently not implemented.\n.It Sy GCC visibility\nGNU C compatibility.\nCurrently not implemented.\n.It Sy pack Ns Pq Op Ar n\nSet the default maximum alignment for structures and unions, such that\nmembers will have their natural alignment requirements clamped at this\nvalue and may be stored misaligned.\nIf\n.Ar n\nis not given, the alignment is reset to the target default.\n.It Sy pack Ns Pq Sy push Ns Op , Ar n\nPush the current pack setting onto an internal stack then, if\n.Ar n\nis given, change the default alignment for structures and unions.\nCurrently not implemented.\n.It Sy pack Ns Pq Sy pop\nChange the pack setting to the most recently pushed value, and remove\nthat setting from the stack.\nCurrently not implemented.\n.It Sy packed Op Ar n\nSet the maximum alignment for the structure or union defined\nin the current statement.\nIf\n.Ar n\nis not given, the default value of 1 is used.\n.Pq Currently this works except Ar n is not used\n.It Sy aligned Op Ar n\nSet the minimum alignment for the structure or union defined\nin the current statement.\n.It Sy rename Ar name\nProvide an alternative\n.Ar name\nwhich will be used to reference the object declared in the current statement.\n.It Sy weak Ar name Ns Op = Ns Ar alias\nMark\n.Ar name\nas a weak rather than a global symbol, to allow its definition to be\noverridden at link time.\nIf an\n.Ar alias\nis given, this will be used as the default value of\n.Ar name .\n.It Sy ident\nCurrently not implemented.\n.El\n.Lp\nand the following target-specific operations are handled by\nmachine-dependent code:\n.Bl -tag -width Ds\n.It Sy tls\nFor AMD64 and i386 targets, the variable declared in the current statement\nwill be referenced via the\n.Dq thread-local storage\nmechanism.\n.It Sy init\nFor AMD64, ARM, HPPA, i386, MIPS and PowerPC targets, when the current statement is a\nfunction declaration, generate a reference in the\n.Sy .ctors\nsection, enabling library code to call the function prior to entering\n.Fn main .\n.It Sy fini\nFor AMD64, ARM, HPPA, i386, MIPS and PowerPC targets, when the current statement is a\nfunction declaration, generate a reference in the\n.Sy .dtors\nsection, enabling library code to call the function when\n.Fn main\nreturns or the\n.Fn exit\nfunction is called.\n.It Sy section Ar name\nFor AMD64, ARM, HPPA and i386 targets, place the subsequent code in the named\nsection.\n.Pq This is currently broken .\n.It Sy alias Ar name\nFor AMD64, HPPA and i386 targets, emit assembler instructions providing an\nalias for the symbol defined by the current statement.\n.It Sy stdcall\nFor i386 targets, enable\n.Dq stdcall\nsemantics during code generation, where function arguments are passed on\nthe stack in right-to-left order, and the callee is responsible for adjusting\nthe stack pointer before returning.\nAny function result is passed in the EAX register.\nOn win32, the function name is postfixed with an\n.Dq @\nand the size of the stack adjustment.\n.It Sy cdecl\nFor i386 targets, enable\n.Dq cdecl\nsemantics during code generation, where function arguments are passed on\nthe stack in right-to-left order, and the caller is responsible for cleaning\nup the stack after the function returns.\nAny function result is passed in the EAX register.\nThis is the default.\n.It Sy fastcall\nFor i386-win32 targets, enable\n.Dq fastcall\nsemantics during code generation.\n.Po\nCurrently this is equivalent to\n.Sy stdcall ,\nwhich is likely wrong\n.Pc .\n.It Sy dllimport\nFor i386-win32 targets, references to the external symbol defined by\nthe current statement will be made via indirect access through a\nlocation identified by the symbol name prefixed with\n.Dq __imp_ .\n.It Sy dllexport\nFor i386-win32 targets, the external symbol declared by the current\nstatement will be exported as an indirect reference to be\naccessed with\n.Sy dllimport .\nThe global locator will be the symbol name prefixed with\n.Dq __imp_ .\nCurrently this is not completely implemented.\n.El\n.Pp\nAny unknown\n.Dq #pragma\ndirectives will be ignored unless the\n.Fl Wunknown-pragmas\ndiagnostic is in effect.\n.Sh SEE ALSO\n.Xr as 1 ,\n.Xr cpp 1 ,\n.Xr pcc 1\n.Sh HISTORY\nThe\n.Nm\ncompiler is based on the original Portable C Compiler by\n.An \"S. C. Johnson\" ,\nwritten in the late 70's.\nEven though much of the compiler has been rewritten\n.Pq about 50% of the frontend code and 80% of the backend ,\nsome of the basics still remain.\nMost is written by\n.An \"Anders Magnusson\" ,\nwith the exception of the data-flow analysis part and\nthe SSA conversion code which is written by\n.An \"Peter A Jonsson\" ,\nand the Mips port that were written as part of a project\nby undergraduate students at Lulea University of Technology.\n.Pp\nThis product includes software developed or owned by Caldera\nInternational, Inc.\n"
  },
  {
    "path": "initrd/usr/share/man/man1/cpp.1",
    "content": ".\\\"\t$Id: cpp.1,v 1.17 2013/02/26 19:27:38 plunky Exp $\n.\\\"\n.\\\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net>\n.\\\"\n.\\\" Permission to use, copy, modify, and/or distribute this software for any\n.\\\" purpose with or without fee is hereby granted, provided that the above\n.\\\" copyright notice and this permission notice appear in all copies.\n.\\\"\n.\\\" THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM\n.\\\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND\n.\\\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\n.\\\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\n.\\\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\n.\\\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\n.\\\" THIS SOFTWARE.\n.\\\"\n.Dd February 26, 2013\n.Dt CPP 1\n.Os\n.Sh NAME\n.Nm cpp\n.Nd C preprocessor\n.Sh SYNOPSIS\n.Nm\n.Op Fl ACEMPtVv\n.Op Fl D Ar macro Ns Oo = Ns Ar value Oc\n.Op Fl d Ar flags\n.Op Fl I Ar path\n.Op Fl i Ar file\n.Op Fl S Ar path\n.Op Fl U Ar macro\n.Op Ar infile | -\n.Op Ar outfile\n.Sh DESCRIPTION\nThe\n.Nm\nutility is a macro preprocessor used by the\n.Xr pcc 1\ncompiler.\nIt is mainly used to include header files,\nexpand macro definitions,\ndiscard comments,\nand perform conditional compilation.\n.Nm\nis written to comply with the\n.St -isoC-99\nspecification.\n.Pp\nThe\n.Ar infile\ninput file is optional.\nIf not provided or the file name is\n.Qq -\n(dash),\n.Nm\nreads its initial file from standard input.\nThe\n.Ar outfile\noutput file is also optional, with output written to standard\noutput if not provided.\n.Pp\nThe options are as follows:\n.Bl -tag -width Ds\n.It Fl A\nFor assembler-with-cpp input: treat non-directive lines starting\nwith a # as comments.\n.It Fl C\nDo not discard comments.\n.It Fl D Ar macro Ns Oo = Ns Ar value Oc\nCreate a macro definition before processing any input, as if a\n.Lp\n.Dl #define Ar macro Ar value\n.Lp\ndirective had appeared in the source.\nIf\n.Ar value\nis not set on the command-line, then a value of 1 is used.\n.It Fl d Ar flags\nModify output according to\n.Ar flags ,\nwhich can be a list of character flags.\nThe following flags are currently supported:\n.Bl -tag -width \".Sy M\"\n.It Sy M\nDo not process any input, but output a list of\n.Dq #define\nstatements for all defined macros other than builtin macros\n.Pq see below .\n.El\n.Lp\nany unknown flags are ignored.\n.It Fl E\nModify the exit code, if there were any warnings.\n.It Fl I Ar path\nAdd\n.Ar path\nto the list of directories searched by the\n.Dq #include\ndirective.\nThis may be used to override system include directories\n.Pq see Fl S No option .\n.Fl I\nmay be specified multiple times and is cumulative.\n.It Fl i Ar file\nInclude a file before processing any input, as if a\n.Lp\n.Dl #include Qo Ar file Qc\n.Lp\ndirective had appeared in the source.\n.Fl i\nmay be specified multiple times to include several files.\n.It Fl M\nInstead of producing a processed C code file, output a list\nof dependencies for\n.Xr make 1 ,\ndetailing the files that need to be processed when compiling\nthe input.\n.It Fl P\nInhibit generation of line markers.  This is sometimes useful when\nrunning the preprocessor on something other than C code.\n.It Fl S Ar path\nAdd\n.Ar path\nto the list of system directories searched by the\n.Dq #include\ndirective.\nThe\n.Fl S\noption may be specified multiple times and is cumulative.\n.It Fl t\nTraditional cpp syntax.\nDo not define the\n.Dv __TIME__ ,\n.Dv __DATE__ ,\n.Dv __STDC__ ,\nand\n.Dv __STDC_VERSION__\nmacros.\n.It Fl U Ar macro\nUndefine a macro before processing any input, as if a\n.Lp\n.Dl #undef Ar macro\n.Lp\ndirective had appeared in the source.\n.It Fl V\nVerbose debugging output.\n.Fl V\ncan be repeated for greater detail.\n.Po\nThis is only available if the\n.Nm\nprogram was built with\n.Dv PCC_DEBUG\ndefined, which is the default\n.Pc .\n.It Fl v\nDisplay version.\n.El\n.Pp\nThe\n.Fl D ,\n.Fl i\nand\n.Fl U\noptions are processed in the order that they appear on the command\nline, before any input is read but after the command line options\nhave been scanned.\n.Pp\nFiles referenced by the\n.Dq #include\ndirective as\n.Qq ... ,\nare first looked for in the current directory, then as per\n.Aq ...\nfiles, which are first looked for in the list of\ndirectories provided by any\n.Fl I\noptions, then in the list of system directories provided by any\n.Fl S\noptions.\nNote that\n.Nm\ndoes not define any include directories by default; if no\n.Fl I\nor\n.Fl S\noptions are given, then only the current directory will be\nsearched and no system files will be found.\n.Ss Builtin Macros\nA few macros are interpreted inside the\n.Nm cpp\nprogram:\n.Bl -diag\n.It __DATE__\nExpands to a quoted string literal containing the date in the form\n.Qq Mmm dd yyyy ,\nwhere the names of the months are the same as those generated by the\n.Xr asctime 3\nfunction, and the first character of dd is a space character if\nthe value is less than 10.\n.It __FILE__\nExpands to a quoted string literal containing the presumed name of\nthe current source file.\nWhen reading source from standard input, it expands to\n.Qq Aq stdin .\n.It __LINE__\nExpands to an integer constant representing the presumed line number\nof the source line containing the macro.\n.It __STDC__\nExpands to the integer constant\n.Dq 1 ,\nmeaning that the compiler conforms to\n.St -isoC .\n.It __STDC_VERSION__\nExpands to the integer constant\n.Dq 199901L ,\nindicating that\n.Nm\nconforms to\n.St -isoC-99 .\n.It __TIME__\nExpands to a quoted string literal containing the time in the form\n.Qq hh:mm:ss\nas generated by the\n.Xr asctime 3\nfunction.\n.El\n.Pp\nAlso see the\n.Fl t\noption.\n.Sh EXIT STATUS\nThe\n.Nm\nutility exits with one of the following values:\n.Lp\n.Bl -tag -width Ds -offset indent -compact\n.It 0\nSuccessfully finished.\n.It 1\nAn error occurred.\n.It 2\nThe\n.Fl E\noption was given, and warnings were issued.\n.El\n.Sh SEE ALSO\n.Xr as 1 ,\n.Xr ccom 1 ,\n.Xr make 1 ,\n.Xr pcc 1 ,\n.Xr asctime 3\n.Sh HISTORY\nThe\n.Nm\ncommand comes from the original Portable C Compiler by\n.An \"S. C. Johnson\" ,\nwritten in the late 70's.\nThe code originates from the V6 preprocessor with some additions\nfrom V7 cpp and ansi/c99 support.\n.Pp\nA lot of the PCC code was rewritten by\n.An \"Anders Magnusson\" .\n.Pp\nThis product includes software developed or owned by Caldera\nInternational, Inc.\n"
  },
  {
    "path": "initrd/usr/share/man/man1/p++.1",
    "content": ".\\\"\t$Id: cc.1,v 1.45 2016/10/10 11:27:49 ragge Exp $\n.\\\"\n.\\\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net>\n.\\\"\n.\\\" Permission to use, copy, modify, and/or distribute this software for any\n.\\\" purpose with or without fee is hereby granted, provided that the above\n.\\\" copyright notice and this permission notice appear in all copies.\n.\\\"\n.\\\" THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM\n.\\\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND\n.\\\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\n.\\\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\n.\\\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\n.\\\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\n.\\\" THIS SOFTWARE.\n.\\\"\n.Dd June 20, 2014\n.Dt CC 1\n.Os\n.Sh NAME\n.Nm cc\n.Nd front-end to the C compiler\n.Sh SYNOPSIS\n.Nm\n.Op Fl cEgkMPSstvX\n.Op Fl ansi\n.Op Fl B Ns Ar prefix\n.Op Fl D Ar macro Ns Oo = Ns Ar value Oc\n.Op Fl d Ns Ar flags\n.Op Fl f Ns Ar feature\n.Op Fl I Ar path\n.Op Fl include Ar file\n.Op Fl isystem Ar path\n.Op Fl L Ns Ar path\n.Op Fl m Ns Ar option\n.Op Fl nodefaultlibs\n.Op Fl nostartfiles\n.Op Fl nostdinc\n.Op Fl nostdlib\n.Op Fl O Ns Oo Ar level Oc\n.Op Fl o Ar outfile\n.Op Fl pg\n.Op Fl pthread\n.Op Fl shared\n.Op Fl static\n.Op Fl std= Ns Ar standard\n.Op Fl U Ar macro\n.Op Fl Wa Ns , Ns Ar options\n.Op Fl Wc Ns , Ns Ar options\n.Op Fl Wl Ns , Ns Ar options\n.Op Fl Wp Ns , Ns Ar options\n.Op Fl x Ar language\n.Op Fl z Ar keyword\n.Op Ar\n.Sh DESCRIPTION\nThe\n.Nm\nutility provides a front-end to the\n.Dq portable C compiler .\nMultiple files may be given on the command line.\nUnrecognized options are sent directly to\n.Xr ld 1 .\n.Pp\n.\\\" Brief description of its syntax:\nFilenames that end with\n.Sy \\&.c\nare passed via\n.Xr cpp 1\n\\(->\n.Xr ccom 1\n\\(->\n.Xr as 1\n\\(->\n.Xr ld 1 .\n.Pp\nFilenames that end with\n.Sy \\&.i\nare passed via\n.Xr ccom 1\n\\(->\n.Xr as 1\n\\(->\n.Xr ld 1 .\n.Pp\nFilenames that end with\n.Sy \\&.s\nare passed via\n.Xr as 1\n\\(->\n.Xr ld 1 .\n.Pp\nFilenames that end with\n.Sy \\&.S\nare passed via\n.Xr cpp 1\n\\(->\n.Xr as 1\n\\(->\n.Xr ld 1 .\n.Pp\nFilenames that end with\n.Sy \\&.o\nare passed directly to\n.Xr ld 1 .\n.Pp\n.\\\"\nThe options are as follows:\n.Bl -tag -width Ds\n.It Fl ansi\nSynonym for\n.Fl std=c89 .\n.It Fl B Ns Ar prefix\nDefine alternate prefix path for\n.Xr cpp 1 ,\n.Xr ccom 1 ,\n.Xr as 1 ,\nor\n.Xr ld 1\nexecutables.\n.\\\" TODO: provide an example of -B\n.It Fl C\nPassed to the\n.Xr cpp 1\npreprocessor to not discard comments.\n.It Fl c\nStop after generating object code with\n.Xr as 1 .\nDo not link.\nThe resulting object output is saved\nas a filename with a\n.Dq \\&.o\nsuffix unless\n.Fl o\noption is used.\nNote: cannot be combined with\n.Fl o\nif multiple files are given.\n.It Fl D Ar macro Ns Oo = Ns Ar value Oc\nPassed to the\n.Xr cpp 1\npreprocessor to define\n.Ar macro\nwith an optional\n.Ar value .\n.It Fl d Ns Ar flags\nDebug options.\n.Ar flags\nis a string of characters, which signify the following actions.\n.Bl -tag -width \".Sy M\"\n.It Sy M\nCause the preprocessor to output a list of macro definitions.\n.El\n.Lp\nany unknown flags are ignored.\n.It Fl E\nStop after preprocessing with\n.Xr cpp 1 .\nDo not compile, assemble, or link.\nOutput is sent to standard output unless the\n.Fl o\noption is used.\n.It Fl ffreestanding\nAssume a freestanding environment.\n.It Fl fPIC\nGenerate PIC code.\n.\\\" TODO: document about avoiding machine-specific maximum size?\n.It Fl fpic\nTells C compiler to generate PIC code\nand tells assembler that PIC code has been generated.\n.\\\" TODO: document difference between PIC and pic\n.It Fl funsigned-char\nTell the compiler to treat\n.Sq char\ntypes as if they were unsigned unless explicitly defined otherwise.\n.Fl fsigned-char\ncan be used to signify the opposite behaviour.\nThe default for the\n.Sq char\ntype depends on the compiler target architecture.\n.It Fl fstack-protector\nTell the compiler to wrap functions with code which checks at\nruntime that a stack overflow has not occurred.\nWhen stack protection is in effect, the\n.Dv __SSP__\nmacro will be defined.\n.\\\" other -f GCC compatibility flags are ignored for now\n.It Fl g\nSend\n.Fl g\nflag to\n.Xr ccom 1\nto create debug output.\nDebug information output can be disabled with\n.Fl g0 .\n.It Fl I Ar path\nPassed to the\n.Xr cpp 1\npreprocessor to add header search directory to override system defaults.\n.It Fl include Ar file\nTells the\n.Xr cpp 1\npreprocessor to include the\n.Ar file\nduring preprocessing.\n.It Fl isystem Ar path\nDefines\n.Ar path\nas a system header directory for the\n.Xr cpp 1\npreprocessor.\n.It Fl k\nGenerate PIC code.\nSee\n.Fl fpic\noption.\n.It Fl L Ns Ar path\nPassed to the linker, to add\n.Ar path\nto the list of directories searched for shared libraries.\n.It Fl M\nPass\n.Fl M\nflag to\n.Xr cpp 1\nto generate dependencies for\n.Xr make 1 .\n.It Fl m Ns Ar option\nTarget-dependent options.\nMultiple\n.Fl m\noptions can be given, the following are supported:\n.Bl -tag -width PowerPC\n.It ARM\n\\-mlittle-endian \\-mbig-endian \\-mfpe=fpa \\-mfpe=vpf \\-msoft-float \\-march=armv1 \\-march=armv2 \\-march=armv2a \\-march=armv3 \\-march=armv4 \\-march=armv4t \\-march=armv4tej \\-march=armv5 \\-march=armv6 \\-march=armv6t2 \\-march=armv6kz \\-march=armv6k \\-march=armv7\n.It HPPA\n.It i386\n.It MIPS\n\\-mlittle-endian \\-mbig-endian \\-mhard-float \\-msoft-float\n.It PDP-10\n.It PowerPC\n.It Sparc64\n.It VAX\n.El\n.It Fl nodefaultlibs\nDo not link with the system default libraries (libc, etc.)\n.It Fl nostartfiles\nDo not link with the system startup files (crt0.c, etc.)\n.It Fl nostdinc\nDo not use the system include paths (/usr/include, etc.)\n.It Fl nostdlib\nDo not link with the system default libraries or startup files.\n.It Fl O Ns Oo Ar level Oc\nEnable compiler optimizations.\nCurrently, for levels higher than zero,\nthis defines\n.Dv __OPTIMIZE__\nin the\n.Xr cpp 1\npreprocessor, and passes\n.Fl xdce ,\n.Fl xdeljumps ,\n.Fl xtemps\nand\n.Fl xinline\nto\n.Xr ccom 1 .\nIf no level is given the optimization level is\n.Fl O1 .\nOptimizations can be disabled using\n.Fl O0 .\nIn situations where multiple optimization flags are given, the last flag is the\none used.\n.It Fl o Ar outfile\nSave result to\n.Ar outfile .\n.It Fl P\nInhibit generation of line markers in preprocessor output.\nThis is sometimes useful when running the preprocessor on something other than C code.\n.It Fl pg\nEnable profiling on the generated executable.\n.It Fl pthread\nDefines the\n.Dv _PTHREADS\npreprocessor identifier for\n.Xr cpp 1 , and\nadds\n.Fl lpthread\nto the\n.Xr ld 1\nlinker arguments.\n.It Fl S\nStop after compilation by\n.Xr ccom 1 .\nDo not assemble and do not link.\nThe resulting assembler-language output is saved\nas a filename with a\n.Dq \\&.s\nsuffix unless the\n.Fl o\noption is used.\nNote: cannot be combined with\n.Fl o\nif multiple files are given.\n.It Fl s\nPassed to\n.Xr ld 1\nto remove all symbol table and relocation information from the generated\nexecutable.\nThis option is silently ignored if\n.Nm\ndoes not invoke the linker.\n.It Fl shared\nCreate a shared object of the result.\nTells the linker not to generate an executable.\n.It Fl static\nDo not use dynamic linkage.\nBy default, it will link using the dynamic linker options\nand/or shared objects for the platform.\n.It Fl std= Ns Ar standard\nCompile to the specified\n.Ar standard .\nAccepted values for\n.Ar standard\nare\n.Ar c89 ,\n.Ar c99 ,\n.Ar gnu89 ,\n.Ar gnu99 ,\n.Ar gnu9x ,\nand\n.Ar c11 .\n.It Fl t\nPassed to\n.Xr cpp 1\nto suppress some default macro definitions and enable use\nof traditional C preprocessor syntax.\n.It Fl U Ar macro\nPasses to the\n.Xr cpp 1\npreprocessor to remove the initial macro definition.\n.It Fl v\nOutputs the version of\n.Nm\nand shows commands as they are run with their command line arguments.\n.It Fl ###\nAs per\n.Fl v\nexcept that the commands are not run, and the arguments will be quoted\nif they contain unusual characters or spaces.\n.It Fl Wa Ns , Ns Ar options\nComma separated list of options for the assembler.\n.It Fl Wc Ns , Ns Ar options\nComma separated list of options for the compiler.\n.It Fl Wl Ns , Ns Ar options\nComma separated list of options for the linker.\n.It Fl Wp Ns , Ns Ar options\nComma separated list of options for the preprocessor.\n.It Fl X\nDon't remove temporary files on exit.\n.It Fl x Ar language\nGCC compatibility option; specify the language in use rather than\ninterpreting the filename extension.\nCurrently known language values are\n.Sy none ,\n.Sy c ,\n.Sy c++ ,\n.Sy assembler\nand\n.Sy assembler-with-cpp .\nAny unknown\n.Fl x\noptions are passed to\n.Xr ccom 1 .\n.It Fl z Ar keyword\nPassed to\n.Xr ld 1 .\nPlease refer to the documentation of your linker for acceptable values of\n.Ar keyword .\n.El\n.Ss Predefined Macros\nA few\nmacros are predefined by\n.Nm\nwhen sent to\n.Xr cpp 1 .\n.Bl -diag\n.It __PCC__\nSet to the major version of\n.Xr pcc 1 .\nThese macros can be used to select code based on\n.Xr pcc 1\ncompatibility.\nSee the\n.Fl v\noption.\n.It __PCC_MINOR__\nSet to the minor version.\n.It __PCC_MINORMINOR__\nSet to the minor-minor version \\(em the number after the minor version.\n.It _PTHREADS\nDefined when\n.Fl pthread\nswitch is used.\n.It __ASSEMBLER__\nDefined when input files have a .S suffix, or if the\n.Fl x Ns assembler-with-cpp\noption is specified.\n.El\n.Pp\nAlso system- and/or machine-dependent macros may also be predefined;\nfor example:\n.Dv __NetBSD__ ,\n.Dv __ELF__ ,\nand\n.Dv __i386__ .\n.Sh SEE ALSO\n.Xr as 1 ,\n.Xr ccom 1 ,\n.Xr cpp 1 ,\n.Xr ld 1\n.Sh HISTORY\nThe\n.Nm\ncommand comes from the original Portable C Compiler by\n.An \"S. C. Johnson\" ,\nwritten in the late 70's.\n.Pp\nThis product includes software developed or owned by Caldera\nInternational, Inc.\n"
  },
  {
    "path": "initrd/usr/share/man/man1/pcc.1",
    "content": ".\\\"\t$Id: cc.1,v 1.45 2016/10/10 11:27:49 ragge Exp $\n.\\\"\n.\\\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net>\n.\\\"\n.\\\" Permission to use, copy, modify, and/or distribute this software for any\n.\\\" purpose with or without fee is hereby granted, provided that the above\n.\\\" copyright notice and this permission notice appear in all copies.\n.\\\"\n.\\\" THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM\n.\\\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND\n.\\\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\n.\\\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\n.\\\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\n.\\\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\n.\\\" THIS SOFTWARE.\n.\\\"\n.Dd June 20, 2014\n.Dt CC 1\n.Os\n.Sh NAME\n.Nm cc\n.Nd front-end to the C compiler\n.Sh SYNOPSIS\n.Nm\n.Op Fl cEgkMPSstvX\n.Op Fl ansi\n.Op Fl B Ns Ar prefix\n.Op Fl D Ar macro Ns Oo = Ns Ar value Oc\n.Op Fl d Ns Ar flags\n.Op Fl f Ns Ar feature\n.Op Fl I Ar path\n.Op Fl include Ar file\n.Op Fl isystem Ar path\n.Op Fl L Ns Ar path\n.Op Fl m Ns Ar option\n.Op Fl nodefaultlibs\n.Op Fl nostartfiles\n.Op Fl nostdinc\n.Op Fl nostdlib\n.Op Fl O Ns Oo Ar level Oc\n.Op Fl o Ar outfile\n.Op Fl pg\n.Op Fl pthread\n.Op Fl shared\n.Op Fl static\n.Op Fl std= Ns Ar standard\n.Op Fl U Ar macro\n.Op Fl Wa Ns , Ns Ar options\n.Op Fl Wc Ns , Ns Ar options\n.Op Fl Wl Ns , Ns Ar options\n.Op Fl Wp Ns , Ns Ar options\n.Op Fl x Ar language\n.Op Fl z Ar keyword\n.Op Ar\n.Sh DESCRIPTION\nThe\n.Nm\nutility provides a front-end to the\n.Dq portable C compiler .\nMultiple files may be given on the command line.\nUnrecognized options are sent directly to\n.Xr ld 1 .\n.Pp\n.\\\" Brief description of its syntax:\nFilenames that end with\n.Sy \\&.c\nare passed via\n.Xr cpp 1\n\\(->\n.Xr ccom 1\n\\(->\n.Xr as 1\n\\(->\n.Xr ld 1 .\n.Pp\nFilenames that end with\n.Sy \\&.i\nare passed via\n.Xr ccom 1\n\\(->\n.Xr as 1\n\\(->\n.Xr ld 1 .\n.Pp\nFilenames that end with\n.Sy \\&.s\nare passed via\n.Xr as 1\n\\(->\n.Xr ld 1 .\n.Pp\nFilenames that end with\n.Sy \\&.S\nare passed via\n.Xr cpp 1\n\\(->\n.Xr as 1\n\\(->\n.Xr ld 1 .\n.Pp\nFilenames that end with\n.Sy \\&.o\nare passed directly to\n.Xr ld 1 .\n.Pp\n.\\\"\nThe options are as follows:\n.Bl -tag -width Ds\n.It Fl ansi\nSynonym for\n.Fl std=c89 .\n.It Fl B Ns Ar prefix\nDefine alternate prefix path for\n.Xr cpp 1 ,\n.Xr ccom 1 ,\n.Xr as 1 ,\nor\n.Xr ld 1\nexecutables.\n.\\\" TODO: provide an example of -B\n.It Fl C\nPassed to the\n.Xr cpp 1\npreprocessor to not discard comments.\n.It Fl c\nStop after generating object code with\n.Xr as 1 .\nDo not link.\nThe resulting object output is saved\nas a filename with a\n.Dq \\&.o\nsuffix unless\n.Fl o\noption is used.\nNote: cannot be combined with\n.Fl o\nif multiple files are given.\n.It Fl D Ar macro Ns Oo = Ns Ar value Oc\nPassed to the\n.Xr cpp 1\npreprocessor to define\n.Ar macro\nwith an optional\n.Ar value .\n.It Fl d Ns Ar flags\nDebug options.\n.Ar flags\nis a string of characters, which signify the following actions.\n.Bl -tag -width \".Sy M\"\n.It Sy M\nCause the preprocessor to output a list of macro definitions.\n.El\n.Lp\nany unknown flags are ignored.\n.It Fl E\nStop after preprocessing with\n.Xr cpp 1 .\nDo not compile, assemble, or link.\nOutput is sent to standard output unless the\n.Fl o\noption is used.\n.It Fl ffreestanding\nAssume a freestanding environment.\n.It Fl fPIC\nGenerate PIC code.\n.\\\" TODO: document about avoiding machine-specific maximum size?\n.It Fl fpic\nTells C compiler to generate PIC code\nand tells assembler that PIC code has been generated.\n.\\\" TODO: document difference between PIC and pic\n.It Fl funsigned-char\nTell the compiler to treat\n.Sq char\ntypes as if they were unsigned unless explicitly defined otherwise.\n.Fl fsigned-char\ncan be used to signify the opposite behaviour.\nThe default for the\n.Sq char\ntype depends on the compiler target architecture.\n.It Fl fstack-protector\nTell the compiler to wrap functions with code which checks at\nruntime that a stack overflow has not occurred.\nWhen stack protection is in effect, the\n.Dv __SSP__\nmacro will be defined.\n.\\\" other -f GCC compatibility flags are ignored for now\n.It Fl g\nSend\n.Fl g\nflag to\n.Xr ccom 1\nto create debug output.\nDebug information output can be disabled with\n.Fl g0 .\n.It Fl I Ar path\nPassed to the\n.Xr cpp 1\npreprocessor to add header search directory to override system defaults.\n.It Fl include Ar file\nTells the\n.Xr cpp 1\npreprocessor to include the\n.Ar file\nduring preprocessing.\n.It Fl isystem Ar path\nDefines\n.Ar path\nas a system header directory for the\n.Xr cpp 1\npreprocessor.\n.It Fl k\nGenerate PIC code.\nSee\n.Fl fpic\noption.\n.It Fl L Ns Ar path\nPassed to the linker, to add\n.Ar path\nto the list of directories searched for shared libraries.\n.It Fl M\nPass\n.Fl M\nflag to\n.Xr cpp 1\nto generate dependencies for\n.Xr make 1 .\n.It Fl m Ns Ar option\nTarget-dependent options.\nMultiple\n.Fl m\noptions can be given, the following are supported:\n.Bl -tag -width PowerPC\n.It ARM\n\\-mlittle-endian \\-mbig-endian \\-mfpe=fpa \\-mfpe=vpf \\-msoft-float \\-march=armv1 \\-march=armv2 \\-march=armv2a \\-march=armv3 \\-march=armv4 \\-march=armv4t \\-march=armv4tej \\-march=armv5 \\-march=armv6 \\-march=armv6t2 \\-march=armv6kz \\-march=armv6k \\-march=armv7\n.It HPPA\n.It i386\n.It MIPS\n\\-mlittle-endian \\-mbig-endian \\-mhard-float \\-msoft-float\n.It PDP-10\n.It PowerPC\n.It Sparc64\n.It VAX\n.El\n.It Fl nodefaultlibs\nDo not link with the system default libraries (libc, etc.)\n.It Fl nostartfiles\nDo not link with the system startup files (crt0.c, etc.)\n.It Fl nostdinc\nDo not use the system include paths (/usr/include, etc.)\n.It Fl nostdlib\nDo not link with the system default libraries or startup files.\n.It Fl O Ns Oo Ar level Oc\nEnable compiler optimizations.\nCurrently, for levels higher than zero,\nthis defines\n.Dv __OPTIMIZE__\nin the\n.Xr cpp 1\npreprocessor, and passes\n.Fl xdce ,\n.Fl xdeljumps ,\n.Fl xtemps\nand\n.Fl xinline\nto\n.Xr ccom 1 .\nIf no level is given the optimization level is\n.Fl O1 .\nOptimizations can be disabled using\n.Fl O0 .\nIn situations where multiple optimization flags are given, the last flag is the\none used.\n.It Fl o Ar outfile\nSave result to\n.Ar outfile .\n.It Fl P\nInhibit generation of line markers in preprocessor output.\nThis is sometimes useful when running the preprocessor on something other than C code.\n.It Fl pg\nEnable profiling on the generated executable.\n.It Fl pthread\nDefines the\n.Dv _PTHREADS\npreprocessor identifier for\n.Xr cpp 1 , and\nadds\n.Fl lpthread\nto the\n.Xr ld 1\nlinker arguments.\n.It Fl S\nStop after compilation by\n.Xr ccom 1 .\nDo not assemble and do not link.\nThe resulting assembler-language output is saved\nas a filename with a\n.Dq \\&.s\nsuffix unless the\n.Fl o\noption is used.\nNote: cannot be combined with\n.Fl o\nif multiple files are given.\n.It Fl s\nPassed to\n.Xr ld 1\nto remove all symbol table and relocation information from the generated\nexecutable.\nThis option is silently ignored if\n.Nm\ndoes not invoke the linker.\n.It Fl shared\nCreate a shared object of the result.\nTells the linker not to generate an executable.\n.It Fl static\nDo not use dynamic linkage.\nBy default, it will link using the dynamic linker options\nand/or shared objects for the platform.\n.It Fl std= Ns Ar standard\nCompile to the specified\n.Ar standard .\nAccepted values for\n.Ar standard\nare\n.Ar c89 ,\n.Ar c99 ,\n.Ar gnu89 ,\n.Ar gnu99 ,\n.Ar gnu9x ,\nand\n.Ar c11 .\n.It Fl t\nPassed to\n.Xr cpp 1\nto suppress some default macro definitions and enable use\nof traditional C preprocessor syntax.\n.It Fl U Ar macro\nPasses to the\n.Xr cpp 1\npreprocessor to remove the initial macro definition.\n.It Fl v\nOutputs the version of\n.Nm\nand shows commands as they are run with their command line arguments.\n.It Fl ###\nAs per\n.Fl v\nexcept that the commands are not run, and the arguments will be quoted\nif they contain unusual characters or spaces.\n.It Fl Wa Ns , Ns Ar options\nComma separated list of options for the assembler.\n.It Fl Wc Ns , Ns Ar options\nComma separated list of options for the compiler.\n.It Fl Wl Ns , Ns Ar options\nComma separated list of options for the linker.\n.It Fl Wp Ns , Ns Ar options\nComma separated list of options for the preprocessor.\n.It Fl X\nDon't remove temporary files on exit.\n.It Fl x Ar language\nGCC compatibility option; specify the language in use rather than\ninterpreting the filename extension.\nCurrently known language values are\n.Sy none ,\n.Sy c ,\n.Sy c++ ,\n.Sy assembler\nand\n.Sy assembler-with-cpp .\nAny unknown\n.Fl x\noptions are passed to\n.Xr ccom 1 .\n.It Fl z Ar keyword\nPassed to\n.Xr ld 1 .\nPlease refer to the documentation of your linker for acceptable values of\n.Ar keyword .\n.El\n.Ss Predefined Macros\nA few\nmacros are predefined by\n.Nm\nwhen sent to\n.Xr cpp 1 .\n.Bl -diag\n.It __PCC__\nSet to the major version of\n.Xr pcc 1 .\nThese macros can be used to select code based on\n.Xr pcc 1\ncompatibility.\nSee the\n.Fl v\noption.\n.It __PCC_MINOR__\nSet to the minor version.\n.It __PCC_MINORMINOR__\nSet to the minor-minor version \\(em the number after the minor version.\n.It _PTHREADS\nDefined when\n.Fl pthread\nswitch is used.\n.It __ASSEMBLER__\nDefined when input files have a .S suffix, or if the\n.Fl x Ns assembler-with-cpp\noption is specified.\n.El\n.Pp\nAlso system- and/or machine-dependent macros may also be predefined;\nfor example:\n.Dv __NetBSD__ ,\n.Dv __ELF__ ,\nand\n.Dv __i386__ .\n.Sh SEE ALSO\n.Xr as 1 ,\n.Xr ccom 1 ,\n.Xr cpp 1 ,\n.Xr ld 1\n.Sh HISTORY\nThe\n.Nm\ncommand comes from the original Portable C Compiler by\n.An \"S. C. Johnson\" ,\nwritten in the late 70's.\n.Pp\nThis product includes software developed or owned by Caldera\nInternational, Inc.\n"
  },
  {
    "path": "initrd/usr/share/man/man1/pcpp.1",
    "content": ".\\\"\t$Id: cc.1,v 1.45 2016/10/10 11:27:49 ragge Exp $\n.\\\"\n.\\\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net>\n.\\\"\n.\\\" Permission to use, copy, modify, and/or distribute this software for any\n.\\\" purpose with or without fee is hereby granted, provided that the above\n.\\\" copyright notice and this permission notice appear in all copies.\n.\\\"\n.\\\" THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM\n.\\\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED\n.\\\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND\n.\\\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\n.\\\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\n.\\\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\n.\\\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\n.\\\" THIS SOFTWARE.\n.\\\"\n.Dd June 20, 2014\n.Dt CC 1\n.Os\n.Sh NAME\n.Nm cc\n.Nd front-end to the C compiler\n.Sh SYNOPSIS\n.Nm\n.Op Fl cEgkMPSstvX\n.Op Fl ansi\n.Op Fl B Ns Ar prefix\n.Op Fl D Ar macro Ns Oo = Ns Ar value Oc\n.Op Fl d Ns Ar flags\n.Op Fl f Ns Ar feature\n.Op Fl I Ar path\n.Op Fl include Ar file\n.Op Fl isystem Ar path\n.Op Fl L Ns Ar path\n.Op Fl m Ns Ar option\n.Op Fl nodefaultlibs\n.Op Fl nostartfiles\n.Op Fl nostdinc\n.Op Fl nostdlib\n.Op Fl O Ns Oo Ar level Oc\n.Op Fl o Ar outfile\n.Op Fl pg\n.Op Fl pthread\n.Op Fl shared\n.Op Fl static\n.Op Fl std= Ns Ar standard\n.Op Fl U Ar macro\n.Op Fl Wa Ns , Ns Ar options\n.Op Fl Wc Ns , Ns Ar options\n.Op Fl Wl Ns , Ns Ar options\n.Op Fl Wp Ns , Ns Ar options\n.Op Fl x Ar language\n.Op Fl z Ar keyword\n.Op Ar\n.Sh DESCRIPTION\nThe\n.Nm\nutility provides a front-end to the\n.Dq portable C compiler .\nMultiple files may be given on the command line.\nUnrecognized options are sent directly to\n.Xr ld 1 .\n.Pp\n.\\\" Brief description of its syntax:\nFilenames that end with\n.Sy \\&.c\nare passed via\n.Xr cpp 1\n\\(->\n.Xr ccom 1\n\\(->\n.Xr as 1\n\\(->\n.Xr ld 1 .\n.Pp\nFilenames that end with\n.Sy \\&.i\nare passed via\n.Xr ccom 1\n\\(->\n.Xr as 1\n\\(->\n.Xr ld 1 .\n.Pp\nFilenames that end with\n.Sy \\&.s\nare passed via\n.Xr as 1\n\\(->\n.Xr ld 1 .\n.Pp\nFilenames that end with\n.Sy \\&.S\nare passed via\n.Xr cpp 1\n\\(->\n.Xr as 1\n\\(->\n.Xr ld 1 .\n.Pp\nFilenames that end with\n.Sy \\&.o\nare passed directly to\n.Xr ld 1 .\n.Pp\n.\\\"\nThe options are as follows:\n.Bl -tag -width Ds\n.It Fl ansi\nSynonym for\n.Fl std=c89 .\n.It Fl B Ns Ar prefix\nDefine alternate prefix path for\n.Xr cpp 1 ,\n.Xr ccom 1 ,\n.Xr as 1 ,\nor\n.Xr ld 1\nexecutables.\n.\\\" TODO: provide an example of -B\n.It Fl C\nPassed to the\n.Xr cpp 1\npreprocessor to not discard comments.\n.It Fl c\nStop after generating object code with\n.Xr as 1 .\nDo not link.\nThe resulting object output is saved\nas a filename with a\n.Dq \\&.o\nsuffix unless\n.Fl o\noption is used.\nNote: cannot be combined with\n.Fl o\nif multiple files are given.\n.It Fl D Ar macro Ns Oo = Ns Ar value Oc\nPassed to the\n.Xr cpp 1\npreprocessor to define\n.Ar macro\nwith an optional\n.Ar value .\n.It Fl d Ns Ar flags\nDebug options.\n.Ar flags\nis a string of characters, which signify the following actions.\n.Bl -tag -width \".Sy M\"\n.It Sy M\nCause the preprocessor to output a list of macro definitions.\n.El\n.Lp\nany unknown flags are ignored.\n.It Fl E\nStop after preprocessing with\n.Xr cpp 1 .\nDo not compile, assemble, or link.\nOutput is sent to standard output unless the\n.Fl o\noption is used.\n.It Fl ffreestanding\nAssume a freestanding environment.\n.It Fl fPIC\nGenerate PIC code.\n.\\\" TODO: document about avoiding machine-specific maximum size?\n.It Fl fpic\nTells C compiler to generate PIC code\nand tells assembler that PIC code has been generated.\n.\\\" TODO: document difference between PIC and pic\n.It Fl funsigned-char\nTell the compiler to treat\n.Sq char\ntypes as if they were unsigned unless explicitly defined otherwise.\n.Fl fsigned-char\ncan be used to signify the opposite behaviour.\nThe default for the\n.Sq char\ntype depends on the compiler target architecture.\n.It Fl fstack-protector\nTell the compiler to wrap functions with code which checks at\nruntime that a stack overflow has not occurred.\nWhen stack protection is in effect, the\n.Dv __SSP__\nmacro will be defined.\n.\\\" other -f GCC compatibility flags are ignored for now\n.It Fl g\nSend\n.Fl g\nflag to\n.Xr ccom 1\nto create debug output.\nDebug information output can be disabled with\n.Fl g0 .\n.It Fl I Ar path\nPassed to the\n.Xr cpp 1\npreprocessor to add header search directory to override system defaults.\n.It Fl include Ar file\nTells the\n.Xr cpp 1\npreprocessor to include the\n.Ar file\nduring preprocessing.\n.It Fl isystem Ar path\nDefines\n.Ar path\nas a system header directory for the\n.Xr cpp 1\npreprocessor.\n.It Fl k\nGenerate PIC code.\nSee\n.Fl fpic\noption.\n.It Fl L Ns Ar path\nPassed to the linker, to add\n.Ar path\nto the list of directories searched for shared libraries.\n.It Fl M\nPass\n.Fl M\nflag to\n.Xr cpp 1\nto generate dependencies for\n.Xr make 1 .\n.It Fl m Ns Ar option\nTarget-dependent options.\nMultiple\n.Fl m\noptions can be given, the following are supported:\n.Bl -tag -width PowerPC\n.It ARM\n\\-mlittle-endian \\-mbig-endian \\-mfpe=fpa \\-mfpe=vpf \\-msoft-float \\-march=armv1 \\-march=armv2 \\-march=armv2a \\-march=armv3 \\-march=armv4 \\-march=armv4t \\-march=armv4tej \\-march=armv5 \\-march=armv6 \\-march=armv6t2 \\-march=armv6kz \\-march=armv6k \\-march=armv7\n.It HPPA\n.It i386\n.It MIPS\n\\-mlittle-endian \\-mbig-endian \\-mhard-float \\-msoft-float\n.It PDP-10\n.It PowerPC\n.It Sparc64\n.It VAX\n.El\n.It Fl nodefaultlibs\nDo not link with the system default libraries (libc, etc.)\n.It Fl nostartfiles\nDo not link with the system startup files (crt0.c, etc.)\n.It Fl nostdinc\nDo not use the system include paths (/usr/include, etc.)\n.It Fl nostdlib\nDo not link with the system default libraries or startup files.\n.It Fl O Ns Oo Ar level Oc\nEnable compiler optimizations.\nCurrently, for levels higher than zero,\nthis defines\n.Dv __OPTIMIZE__\nin the\n.Xr cpp 1\npreprocessor, and passes\n.Fl xdce ,\n.Fl xdeljumps ,\n.Fl xtemps\nand\n.Fl xinline\nto\n.Xr ccom 1 .\nIf no level is given the optimization level is\n.Fl O1 .\nOptimizations can be disabled using\n.Fl O0 .\nIn situations where multiple optimization flags are given, the last flag is the\none used.\n.It Fl o Ar outfile\nSave result to\n.Ar outfile .\n.It Fl P\nInhibit generation of line markers in preprocessor output.\nThis is sometimes useful when running the preprocessor on something other than C code.\n.It Fl pg\nEnable profiling on the generated executable.\n.It Fl pthread\nDefines the\n.Dv _PTHREADS\npreprocessor identifier for\n.Xr cpp 1 , and\nadds\n.Fl lpthread\nto the\n.Xr ld 1\nlinker arguments.\n.It Fl S\nStop after compilation by\n.Xr ccom 1 .\nDo not assemble and do not link.\nThe resulting assembler-language output is saved\nas a filename with a\n.Dq \\&.s\nsuffix unless the\n.Fl o\noption is used.\nNote: cannot be combined with\n.Fl o\nif multiple files are given.\n.It Fl s\nPassed to\n.Xr ld 1\nto remove all symbol table and relocation information from the generated\nexecutable.\nThis option is silently ignored if\n.Nm\ndoes not invoke the linker.\n.It Fl shared\nCreate a shared object of the result.\nTells the linker not to generate an executable.\n.It Fl static\nDo not use dynamic linkage.\nBy default, it will link using the dynamic linker options\nand/or shared objects for the platform.\n.It Fl std= Ns Ar standard\nCompile to the specified\n.Ar standard .\nAccepted values for\n.Ar standard\nare\n.Ar c89 ,\n.Ar c99 ,\n.Ar gnu89 ,\n.Ar gnu99 ,\n.Ar gnu9x ,\nand\n.Ar c11 .\n.It Fl t\nPassed to\n.Xr cpp 1\nto suppress some default macro definitions and enable use\nof traditional C preprocessor syntax.\n.It Fl U Ar macro\nPasses to the\n.Xr cpp 1\npreprocessor to remove the initial macro definition.\n.It Fl v\nOutputs the version of\n.Nm\nand shows commands as they are run with their command line arguments.\n.It Fl ###\nAs per\n.Fl v\nexcept that the commands are not run, and the arguments will be quoted\nif they contain unusual characters or spaces.\n.It Fl Wa Ns , Ns Ar options\nComma separated list of options for the assembler.\n.It Fl Wc Ns , Ns Ar options\nComma separated list of options for the compiler.\n.It Fl Wl Ns , Ns Ar options\nComma separated list of options for the linker.\n.It Fl Wp Ns , Ns Ar options\nComma separated list of options for the preprocessor.\n.It Fl X\nDon't remove temporary files on exit.\n.It Fl x Ar language\nGCC compatibility option; specify the language in use rather than\ninterpreting the filename extension.\nCurrently known language values are\n.Sy none ,\n.Sy c ,\n.Sy c++ ,\n.Sy assembler\nand\n.Sy assembler-with-cpp .\nAny unknown\n.Fl x\noptions are passed to\n.Xr ccom 1 .\n.It Fl z Ar keyword\nPassed to\n.Xr ld 1 .\nPlease refer to the documentation of your linker for acceptable values of\n.Ar keyword .\n.El\n.Ss Predefined Macros\nA few\nmacros are predefined by\n.Nm\nwhen sent to\n.Xr cpp 1 .\n.Bl -diag\n.It __PCC__\nSet to the major version of\n.Xr pcc 1 .\nThese macros can be used to select code based on\n.Xr pcc 1\ncompatibility.\nSee the\n.Fl v\noption.\n.It __PCC_MINOR__\nSet to the minor version.\n.It __PCC_MINORMINOR__\nSet to the minor-minor version \\(em the number after the minor version.\n.It _PTHREADS\nDefined when\n.Fl pthread\nswitch is used.\n.It __ASSEMBLER__\nDefined when input files have a .S suffix, or if the\n.Fl x Ns assembler-with-cpp\noption is specified.\n.El\n.Pp\nAlso system- and/or machine-dependent macros may also be predefined;\nfor example:\n.Dv __NetBSD__ ,\n.Dv __ELF__ ,\nand\n.Dv __i386__ .\n.Sh SEE ALSO\n.Xr as 1 ,\n.Xr ccom 1 ,\n.Xr cpp 1 ,\n.Xr ld 1\n.Sh HISTORY\nThe\n.Nm\ncommand comes from the original Portable C Compiler by\n.An \"S. C. Johnson\" ,\nwritten in the late 70's.\n.Pp\nThis product includes software developed or owned by Caldera\nInternational, Inc.\n"
  },
  {
    "path": "initrd/usr/test.c",
    "content": "#include <stdio.h>\n\nint main()\n{\n    puts(\"Hello, World!\\n\");\n}\n"
  },
  {
    "path": "iso/boot/grub/grub.cfg",
    "content": "set timeout=5\nset default=0\n\nmenuentry \"Aquila\" {\n\tmultiboot /kernel.elf.gz earlycon=ttyS0\n\tmodule /initrd.img.gz\n\tboot\n}\n"
  },
  {
    "path": "kernel/Makefile",
    "content": "export\n\nPDIR := $(SRCDIR)/kernel\n\n#\n# Add include pathes to CFLAGS & ASFLAGS\n#\n\nCFLAGS += \\\n\t-I. \\\n\t-I$(PDIR)/arch/$(ARCH_DIR)/platform/$(PLATFORM_DIR)/include \\\n\t-I$(PDIR)/arch/$(ARCH_DIR)/include \\\n\t-I$(PDIR)/include \\\n\t-I$(PDIR)\n\nASFLAGS += \\\n\t-I. \\\n\t-I$(PDIR)/arch/$(ARCH_DIR)/platform/$(PLATFORM_DIR)/include \\\n\t-I$(PDIR)/arch/$(ARCH_DIR)/include \\\n\t-I$(PDIR)/include \\\n\t-I$(PDIR)\n\ndirs-y = core/ fs/ dev/ sys/ mm/ net/\n\nall: $(dirs-y) arch/\n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" kernel/$@\n\t@$(MAKE) -C $@ $(param)\n\n.PHONY: arch/\narch/: $(dirs-y) arch/Makefile\n\t@$(ECHO) \"  MK      \" kernel/$@\n\t@$(MAKE) -C $@ $(param)\n\n.PHONY: install\ninstall: all\n\t@$(ECHO) \"Installing kernel-$(VERSION).$(ARCH) into $(DESTDIR)/boot/kernel\"\n\t@$(MKDIR) -p $(DESTDIR)/boot\n\t@$(CP) arch/$(ARCH)/kernel-$(VERSION).$(ARCH) $(DESTDIR)/boot/kernel\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y) arch/\n\n"
  },
  {
    "path": "kernel/README.md",
    "content": "# AquilaOS Kernel\n\n### Source tree structure\n- arch/     - all arch. dependent code\n- configs/  - configurations used during build\n- core/     - system components that do not fit anywhere else\n- dev/      - kdev and supported devices\n- fs/       - vfs and supported filesystems\n- include/  - generic include headers\n- mm/       - arch independent memory management\n- scripts/  - scripts used during build\n- sys/      - core system components (processes, threads, scheduler, etc...)\n\n"
  },
  {
    "path": "kernel/arch/Build.mk",
    "content": "dirs-$(ARCH_NONE)   += none/\ndirs-$(ARCH_I386)   += i386/\ndirs-$(ARCH_X86_64) += x86_64/\ndirs-$(ARCH_ARM)    += arm/\n"
  },
  {
    "path": "kernel/arch/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o $(BUILDDIR)/$(CWD)/builtin.o\n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/arch/arm/Build.mk",
    "content": "obj-y  += none.o\nelf    += kernel-$(VERSION).$(ARCH)\n\nkernel-$(VERSION).$(ARCH): builtin.o\n\t@echo -e \"  ELF     \" $@;\n\t@$(LD) $(LDFLAGS) -Tkernel.$(ARCH).ld -lgcc -o $@\n"
  },
  {
    "path": "kernel/arch/arm/include/core/types.h",
    "content": "#ifndef _NONE_CORE_TYPES_H\n#define _NONE_CORE_TYPES_H\n\ntypedef uintptr_t paddr_t;\ntypedef uintptr_t vaddr_t;\n\n#include_next <core/types.h>\n\n#endif /* _NONE_CORE_TYPES_H */\n"
  },
  {
    "path": "kernel/arch/arm/include/cpu/io.h",
    "content": "#ifndef _NONE_CPU_IO_H\n#define _NONE_CPU_IO_H\n\n#include_next <cpu/io.h>\n\nstatic inline uint8_t io_in8(struct ioaddr *io, uintptr_t off)\n{\n    return 0;\n}\n\nstatic inline uint16_t io_in16(struct ioaddr *io, uintptr_t off)\n{\n    return 0;\n}\n\nstatic inline uint32_t io_in32(struct ioaddr *io, uintptr_t off)\n{\n    return 0;\n}\n\nstatic inline void io_out8(struct ioaddr *io, uintptr_t off, uint8_t val)\n{\n}\n\nstatic inline void io_out16(struct ioaddr *io, uintptr_t off, uint16_t val)\n{\n}\n\nstatic inline void io_out32(struct ioaddr *io, uintptr_t off, uint32_t val)\n{\n}\n\n#endif /* ! _NONE_CPU_IO_H */\n"
  },
  {
    "path": "kernel/arch/arm/include/mm/mm.h",
    "content": "#ifndef _NONE_MM_MM_H\n#define _NONE_MM_MM_H\n\n#define USER_STACK_BASE 0\n#define PAGE_SIZE   (0x1000)\n#define PAGE_MASK   (PAGE_SIZE - 1)\n\n#define ARCH_KVMEM_BASE 100\n#define ARCH_KVMEM_NODES_SIZE   0\n\n#define LMA(n)  (n)\n#define VMA(n)  (n)\n\n#include_next <mm/mm.h>\n\n#endif  /* _NONE_MM_MM_H */\n"
  },
  {
    "path": "kernel/arch/arm/kernel.arm.ld",
    "content": "ENTRY(_start)\nINPUT(builtin.o ../../core/builtin.o ../../fs/builtin.o ../../dev/builtin.o ../../sys/builtin.o ../../mm/builtin.o ../../net/builtin.o)\nOUTPUT(kernel.elf)\n\nSECTIONS {\n\n    LMA = 0x80010000;\n    . = LMA;\n\n    .boot.text : ALIGN(0x1000) {\n        *boot*.o(.text*)\n        *boot*.o(.rodata*)\n    }\n\n    .boot.data : ALIGN(0x1000) {\n        *boot*.o(.data)\n    }\n\n    .boot.bss (NOLOAD) : ALIGN(0x1000) {\n        *boot*.o(*)\n    }\n\n    boot_end = .;\n\n    _VMA = .;\n\n    .text : AT(ADDR(.text) - _VMA) ALIGN(0x1000) {\n        *(.text*)\n        *(.rodata*)\n    }\n\n    .__minit : AT(ADDR(.__minit) - _VMA) ALIGN(0x1000) {\n        __minit = .;\n        *(.__minit*)\n        __minit_end = .;\n    }\n    \n    .data : AT(ADDR(.data) - _VMA) ALIGN(0x1000) {\n        *(.data)\n    }\n    \n    .bss : AT(ADDR(.bss) - _VMA) ALIGN(0x1000) {\n        *(.bss)\n    }\n    \n    /DISCARD/ : {\n        *(.*)\n    }\n    \n    kernel_end = . - _VMA;\n}\n"
  },
  {
    "path": "kernel/arch/arm/none.c",
    "content": ""
  },
  {
    "path": "kernel/arch/i386/Build.mk",
    "content": "dirs-y += boot/\ndirs-y += cpu/\ndirs-y += earlycon/\ndirs-y += mm/\ndirs-y += sys/\ndirs-y += platform/\n\nelf    += kernel-$(VERSION).$(ARCH)\n\nkernel-$(VERSION).$(ARCH): builtin.o\n\t@echo \"  ELF     \" $(CWD)/$@;\n\t@$(LD) $(LDFLAGS) -T kernel.$(ARCH).ld -o $@\n"
  },
  {
    "path": "kernel/arch/i386/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/arch/i386/boot/Build.mk",
    "content": "obj-$(X86_MULTIBOOT) += multiboot.o\nobj-$(ARCH_X86_64)   += x86_64_bootstrap.o\nobj-y += init.o\nobj-y += sys.o\n"
  },
  {
    "path": "kernel/arch/i386/boot/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/arch/i386/boot/init.c",
    "content": "/**********************************************************************\n *                  Early initalization of the kernel\n *                   (Switch to higher half kernel)\n *\n *\n *  This file is part of AquilaOS and is released under the terms of\n *  GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar\n */\n\n#include <core/system.h>\n#include <core/string.h>\n#include <cpu/cpu.h>\n#include <mm/mm.h>\n#include <boot/multiboot.h>\n#include <boot/boot.h>\n\n/* Minimalistic Paging structure for BSP */\n#if ARCH_BITS==32\nvolatile uint32_t _BSP_PD[1024]  __aligned(PAGE_SIZE);\n#else\nvolatile uint64_t _BSP_PD[512]   __aligned(PAGE_SIZE);\nvolatile uint64_t _BSP_PDPT[512] __aligned(PAGE_SIZE);\nvolatile uint64_t _BSP_PML4[512] __aligned(PAGE_SIZE);\n#endif\n\n#define P   _BV(0)\n#define RW  _BV(1)\n#define PCD _BV(4)\n\nextern char kernel_end;\nchar scratch[1024 * 1024] __aligned(PAGE_SIZE); /* 1 MiB scratch area */\n\nstatic inline void enable_paging(uintptr_t page_directory)\n{\n    write_cr3(page_directory);\n#if ARCH_BITS==32\n    uint32_t cr0 = read_cr0();\n    write_cr0(cr0 | CR0_PG);\n#endif\n}\n\nstatic void switch_to_higher_half(void)\n{\n    uint32_t i;\n    uintptr_t entries;\n\n    /* zero out paging structure */\n    memset((void *) _BSP_PD, 0, sizeof(_BSP_PD));\n\n#if ARCH_BITS==64\n    memset((void *) _BSP_PDPT, 0, sizeof(_BSP_PDPT));\n    memset((void *) _BSP_PML4, 0, sizeof(_BSP_PML4));\n#endif\n\n    /* entries count required to map the kernel */\n    entries = ((uintptr_t)(&kernel_end) + KERNEL_HEAP_SIZE + TABLE_MASK) / TABLE_SIZE;\n\n#if ARCH_BITS==32\n    uint32_t *_BSP_PT = (uint32_t *) scratch;\n\n    /* identity map pages */\n    for (i = 0; i < entries * 1024; ++i)\n        _BSP_PT[i] = (i * PAGE_SIZE) | P | RW;\n\n    /* map the lower-half */\n    for (i = 0; i < entries; ++i)\n        _BSP_PD[i] = ((uint32_t) _BSP_PT + i * PAGE_SIZE) | P | RW;\n\n    /* map the upper-half */\n    for (i = 0; i < entries; ++i)\n        _BSP_PD[768 + i] = ((uint32_t) _BSP_PT + i * PAGE_SIZE) | P | RW;\n\n    /* Enable paging using Bootstrap Processor Page Directory */\n    extern void enable_paging(uint32_t);\n    enable_paging((uint32_t) _BSP_PD);\n#else\n    uint64_t *_BSP_PT = (uint64_t *) scratch;\n\n    /* identity map pages */\n    for (i = 0; i < entries * 512; ++i)\n        _BSP_PT[i] = (i * PAGE_SIZE) | P | RW;\n\n    /* map the lower-half */\n    for (i = 0; i < entries; ++i)\n        _BSP_PD[i] = ((uint64_t) _BSP_PT + i * PAGE_SIZE) | P | RW;\n\n    _BSP_PDPT[0] = (uint64_t) _BSP_PD   | P | RW;\n    _BSP_PML4[0] = (uint64_t) _BSP_PDPT | P | RW;\n\n    /* map the upper-half */\n    _BSP_PML4[256] = (uint64_t) _BSP_PDPT | P | RW;\n\n    /* Enable paging using Bootstrap Processor PML4 */\n    enable_paging((uint64_t) _BSP_PML4);\n#endif\n}\n\nvoid x86_bootstrap()\n{\n    /* We assume that GrUB loaded a valid GDT */\n    /* Then we map the kernel to the higher half */\n    switch_to_higher_half();\n\n    /* Now we make SP in the higher half */\n#if ARCH_BITS==32\n    //asm volatile(\"add %0, %%esp\"::\"g\"(VMA((uintptr_t) 0)):\"esp\");\n    extern void early_init_fix_stack(uintptr_t);\n    early_init_fix_stack(VMA((uintptr_t) 0));\n#else\n    asm volatile(\"add %0, %%rsp\"::\"r\"(VMA((uintptr_t) 0)):\"rsp\");\n#endif\n\n    /* Ready to get out of here */\n    extern void x86_cpu_init(void);\n    x86_cpu_init();\n\n    /* Why would we ever get back here? however we should be precautious */\n    for (;;)\n        asm volatile (\"hlt;\");\n}\n"
  },
  {
    "path": "kernel/arch/i386/boot/multiboot.S",
    "content": "/**********************************************************************\n *                      Multiboot support\n *\n *\n *  This file is part of AquilaOS and is released under the terms of\n *  GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar\n */\n\n#include <config.h>\n#define ASM_FILE\n#include <boot/multiboot.h>\n\n/*\n *  Multiboot definitions\n */\n\n#if MULTIBOOT_GFX\n#define MULTIBOOT_GFX_ENABLE    MULTIBOOT_VIDEO_MODE\n#else\n#define MULTIBOOT_GFX_ENABLE    0\n#endif\n\n#define MULTIBOOT_FLAGS  MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_GFX_ENABLE\n#define MULTIBOOT_CHKSUM -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_FLAGS)\n\n/*\n *  Multiboot lookup header\n */\n\n/* struct multiboot_header */\n.align 8\n.long MULTIBOOT_HEADER_MAGIC    /* magic */\n.long MULTIBOOT_FLAGS           /* flags */\n.long MULTIBOOT_CHKSUM          /* checksum */\n.long 0                         /* header_addr */\n.long 0                         /* heload_addr */\n.long 0                         /* heload_end_addr */\n.long 0                         /* hebss_end_addr */\n.long 0                         /* heentry_addr */\n\n.long 0                         /* mode_type */\n.long 1024                      /* mowidth */\n.long 768                       /* moheight */\n.long 32                        /* modepth */\n\n/*\n * Entry point of the bootloader\n */\n\n.global _start\n_start:\n    movl %eax, (multiboot_signature)\n    movl %ebx, (multiboot_info)\n\n    and  $-16, %esp /* Align stack to 16 byte */\n\n    mov  $0, %ebp\n\n    cli\n\n#if ARCH_BITS==32\n    .extern x86_bootstrap\n    call x86_bootstrap\n#else\n    .extern x86_64_bootstrap\n    call x86_64_bootstrap\n#endif\n    jmp .\n\n.global multiboot_signature\n.global multiboot_info\n\nmultiboot_signature: .long 0\nmultiboot_info: .long 0\n\n/* vim: ft=gas:\n*/\n"
  },
  {
    "path": "kernel/arch/i386/boot/sys.S",
    "content": ".global early_init_fix_stack\nearly_init_fix_stack:\n    mov 4(%esp), %eax\n    add %eax, %esp\n    mov $0, %ebp\n    ret\n"
  },
  {
    "path": "kernel/arch/i386/boot/x86_64_bootstrap.S",
    "content": ".code32\n.global x86_64_bootstrap\nx86_64_bootstrap:\n\n    /* Set up basic identity paging\n     * PML4 -> 0x0FF000\n     * PDPT -> 0x0FE000\n     * PD   -> 0x0FD000\n     */\n\n    /* Zero out 0xFE000 -> 0x100000 */\n    mov $0xFE000, %edi\n    mov $0x2000, %ecx\n    xor %eax, %eax\n    rep stosb\n\n    /* Setup PDPT */\n    mov $0x0FD000, %edi\n    mov $0x200, %ecx    /* 512 entries */\n    mov $0x83, %eax\n    \n    .__pdpt:\n        movl %eax, 0(%edi)\n        add $0x4, %edi\n        movl $0, 0(%edi)\n        add $0x4, %edi\n        add $0x200000, %eax\n        dec %ecx\n        jnz .__pdpt\n\n    /* Page Directory */\n    movl $0xFE000, %edi\n    movl $0xFD000 | 3, 0(%edi)\n\n    /* PML4 */\n    movl $0xFF000, %edi\n    movl $0xFE000 | 3, 0(%edi)\n\n    /* Set PAE and PGE */\n    movl $0xA0, %eax\n    mov %eax, %cr4\n\n    /* Point CR3 to PML4 */\n    movl %edi, %cr3\n\n    /* Set LME */\n    mov $0xC0000080, %ecx\n    rdmsr\n    or $0x100, %eax\n    wrmsr\n\n    /* Enable paging and protection */\n    mov %cr0, %eax\n    or $0x80000001, %eax\n    mov %eax, %cr0\n\n    /* Set up basic 64-bit GDT */\n    lgdt __x86_64_bootstrap_gdt_p\n\n    ljmp $0x8, $__x86_64_longmode\n\n.align 4\n__x86_64_bootstrap_gdt:\n    /* NULL segment */\n    .quad 0x0000000000000000\n    /* XR_CODE, DPL0, L segment */\n    .quad 0x00AF9A000000FFFF\n    /* WR_DATA, DPL0, L segment */\n    .quad 0x00AF92000000FFFF\n\n.align 4\n__x86_64_bootstrap_gdt_p:\n    .word . - __x86_64_bootstrap_gdt - 1\n    .long __x86_64_bootstrap_gdt\n\n.code64\n__x86_64_longmode:\n    mov $0x10, %ax\n    mov %ax, %ds\n    mov %ax, %es\n    mov %ax, %fs\n    mov %ax, %gs\n    mov %ax, %ss\n\n    .extern early_init\n    call early_init\n    \n    hlt\n    jmp .\n\n/* vim: ft=gas:\n */\n"
  },
  {
    "path": "kernel/arch/i386/cpu/Build.mk",
    "content": "obj-y += init.o\nobj-y += gdt.o\nobj-y += idt.o\nobj-y += isr.o\n#obj-y += smp.o\nobj-y += fpu.o\nobj-y += cpu.o\nobj-y += arith.o\nobj-y += trace.o\n"
  },
  {
    "path": "kernel/arch/i386/cpu/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/arch/i386/cpu/arith.c",
    "content": "/*\n * https://www.ida.liu.se/~TDIU25/pintos/src/lib/arithmetic.c\n */\n\n#include <stdint.h>\n\n/* Uses x86 DIVL instruction to divide 64-bit N by 32-bit D to\n     yield a 32-bit quotient.  Returns the quotient.\n     Traps with a divide error (#DE) if the quotient does not fit\n     in 32 bits. */\nstatic inline uint32_t divl(uint64_t n, uint32_t d)\n{\n    uint32_t n1 = n >> 32;\n    uint32_t n0 = n;\n    uint32_t q, r;\n\n    asm (\"divl %4\"\n             : \"=d\" (r), \"=a\" (q)\n             : \"0\" (n1), \"1\" (n0), \"rm\" (d));\n\n    return q;\n}\n\n/* Returns the number of leading zero bits in X,\n     which must be nonzero. */\nstatic int nlz(uint32_t x) \n{\n    int n = 0;\n    if (x <= 0x0000FFFF) {\n        n += 16;\n        x <<= 16; \n    }\n\n    if (x <= 0x00FFFFFF) {\n        n += 8;\n        x <<= 8; \n    }\n\n    if (x <= 0x0FFFFFFF) {\n        n += 4;\n        x <<= 4;\n    }\n\n    if (x <= 0x3FFFFFFF) {\n        n += 2;\n        x <<= 2; \n    }\n\n    if (x <= 0x7FFFFFFF)\n        n++;\n\n    return n;\n}\n\n/* Divides unsigned 64-bit N by unsigned 64-bit D and returns the\n     quotient. */\nstatic uint64_t udiv64(uint64_t n, uint64_t d)\n{\n    if ((d >> 32) == 0) {\n        /* Proof of correctness:\n         * Let n, d, b, n1, and n0 be defined as in this function.\n         * Let [x] be the \"floor\" of x.  Let T = b[n1/d].  Assume d\n         * nonzero.  Then:\n         *   [n/d] = [n/d] - T + T\n         *         = [n/d - T] + T                      by (1) below\n         *         = [(b*n1 + n0)/d - T] + T            by definition of n\n         *         = [(b*n1 + n0)/d - dT/d] + T\n         *         = [(b(n1 - d[n1/d]) + n0)/d] + T\n         *         = [(b[n1 % d] + n0)/d] + T,          by definition of %\n         * which is the expression calculated below.\n         *\n         * (1) Note that for any real x, integer i: [x] + i = [x + i].\n         *\n         * To prevent divl() from trapping, [(b[n1 % d] + n0)/d] must\n         * be less than b.    Assume that [n1 % d] and n0 take their\n         * respective maximum values of d - 1 and b - 1:\n         *   [(b(d - 1) + (b - 1))/d] < b\n         *   <=> [(bd - 1)/d] < b\n         *   <=> [b - 1/d] < b\n         * which is a tautology.\n         *\n         * Therefore, this code is correct and will not trap.\n         */\n\n        uint64_t b = 1ULL << 32;\n        uint32_t n1 = n >> 32;\n        uint32_t n0 = n; \n        uint32_t d0 = d;\n\n        return divl(b * (n1 % d0) + n0, d0) + b * (n1 / d0); \n    } else {\n        /* Based on the algorithm and proof available from\n         * http://www.hackersdelight.org/revisions.pdf.\n         */\n        if (n < d) {\n            return 0;\n        } else {\n            uint32_t d1 = d >> 32;\n            int s = nlz(d1);\n            uint64_t q = divl(n >> 1, (d << s) >> 32) >> (31 - s);\n            return n - (q - 1) * d < d ? q - 1 : q; \n        }\n    }\n}\n\n/* Divides unsigned 64-bit N by unsigned 64-bit D and returns the\n     remainder. */\nstatic uint32_t umod64(uint64_t n, uint64_t d)\n{\n    return n - d * udiv64(n, d);\n}\n\n/* Divides signed 64-bit N by signed 64-bit D and returns the\n     quotient. */\nstatic int64_t sdiv64(int64_t n, int64_t d)\n{\n    uint64_t n_abs = n >= 0 ? (uint64_t) n : -(uint64_t) n;\n    uint64_t d_abs = d >= 0 ? (uint64_t) d : -(uint64_t) d;\n    uint64_t q_abs = udiv64 (n_abs, d_abs);\n    return (n < 0) == (d < 0) ? (int64_t) q_abs : -(int64_t) q_abs;\n}\n\n/* Divides signed 64-bit N by signed 64-bit D and returns the\n     remainder. */\nstatic int32_t smod64(int64_t n, int64_t d)\n{\n    return n - d * sdiv64(n, d);\n}\n\n/* These are the routines that GCC calls. */\n\nlong long __divdi3(long long n, long long d);\nlong long __moddi3(long long n, long long d);\nunsigned long long __udivdi3(unsigned long long n, unsigned long long d);\nunsigned long long __umoddi3(unsigned long long n, unsigned long long d);\n\n/* Signed 64-bit division. */\nlong long __divdi3(long long n, long long d) \n{\n    return sdiv64(n, d);\n}\n\n/* Signed 64-bit remainder. */\nlong long __moddi3(long long n, long long d) \n{\n    return smod64 (n, d);\n}\n\n/* Unsigned 64-bit division. */\nunsigned long long __udivdi3(unsigned long long n, unsigned long long d) \n{\n    return udiv64 (n, d);\n}\n\n/* Unsigned 64-bit remainder. */\nunsigned long long __umoddi3(unsigned long long n, unsigned long long d) \n{\n    return umod64 (n, d);\n}\n"
  },
  {
    "path": "kernel/arch/i386/cpu/cpu.S",
    "content": "#include <config.h>\n\n.global x86_cpuid_check\nx86_cpuid_check:\n#if ARCH_BITS==32\n    pushf\n    pushf\n    xorl $1 << 21, (%esp)\n    popf\n    pushf\n    pop %eax\n    xorl (%esp), %eax\n    andl $1 << 21, %eax\n    popf\n    ret\n#else\n    /* TODO */\n#endif\n\n/*\n * ISRs -- Interrupt Service Routines\n */\n\n.global __x86_isr_int_num, __x86_isr_err_num\n__x86_isr_int_num: .long 0\n__x86_isr_err_num: .long 0\n\n.macro ISR_NOERR v\n.global __x86_isr\\v\n__x86_isr\\v:\n    cli\n#if ARCH_BITS==32\n    movl $0,  (__x86_isr_err_num)\n    movl $\\v, (__x86_isr_int_num)\n#else\n    movl $0,  __x86_isr_err_num(%rip)\n    movl $\\v, __x86_isr_int_num(%rip)\n#endif\n    jmp isr_handler\n.endm\n\n.macro ISR_ERR v\n.global __x86_isr\\v\n__x86_isr\\v:\n    cli\n#if ARCH_BITS==32\n    popl (__x86_isr_err_num)\n    movl $\\v, (__x86_isr_int_num)\n    jmp isr_handler\n#else\n    push %rbx\n    movq 8(%rsp), %rbx\n    movl %ebx, __x86_isr_err_num(%rip)\n    pop  %rbx\n    add  $8, %rsp\n    movl $\\v, __x86_isr_int_num(%rip)\n    jmp isr_handler\n#endif\n.endm\n\n.macro push_context\n#if ARCH_BITS==32\n    push %eax\n    push %edx\n    push %ecx\n    push %ebx\n    push %ebp\n    push %esi\n    push %edi\n#else\n    push %rax\n    push %rdx\n    push %rcx\n    push %rbx\n    push %rbp\n    push %rsi\n    push %rdi\n    push %r8\n    push %r9\n    push %r10\n    push %r11\n    push %r12\n    push %r13\n    push %r14\n    push %r15\n#endif\n.endm\n    \n.macro pop_context\n#if ARCH_BITS==32\n    pop %edi\n    pop %esi\n    pop %ebp\n    pop %ebx\n    pop %ecx\n    pop %edx\n    pop %eax\n#else\n    pop %r15\n    pop %r14\n    pop %r13\n    pop %r12\n    pop %r11\n    pop %r10\n    pop %r9\n    pop %r8\n    pop %rdi\n    pop %rsi\n    pop %rbp\n    pop %rbx\n    pop %rcx\n    pop %rdx\n    pop %rax\n#endif\n.endm\n\n/* Refer to \n * - Intel 64 and IA-32 Architectures Software Developer’s Manual\n * - Volume 3: System Programming Guide\n * - Table 6-1. Protected-Mode Exceptions and Interrupts\n */\n\nISR_NOERR 0\nISR_NOERR 1\nISR_NOERR 2\nISR_NOERR 3\nISR_NOERR 4\nISR_NOERR 5\nISR_NOERR 6\nISR_NOERR 7\nISR_ERR   8\nISR_NOERR 9\nISR_ERR   10\nISR_ERR   11\nISR_ERR   12\nISR_ERR   13\nISR_ERR   14\nISR_NOERR 15\nISR_NOERR 16\nISR_ERR   17\nISR_NOERR 18\nISR_NOERR 19\nISR_NOERR 20\nISR_NOERR 21\nISR_NOERR 22\nISR_NOERR 23\nISR_NOERR 24\nISR_NOERR 25\nISR_NOERR 26\nISR_NOERR 27\nISR_NOERR 28\nISR_NOERR 29\nISR_NOERR 30\nISR_NOERR 31\nISR_NOERR 128\n\n.extern __x86_isr\nisr_handler:\n#if ARCH_BITS==32\n    push_context\n    push %esp\n    mov $0, %ebp\n    call __x86_isr\n    pop %eax\n    pop_context\n    iret\n#else\n    push_context\n    mov %rsp, %rdi\n    call __x86_isr\n    pop_context\n    iretq\n#endif\n\n/*\n * IRQs -- external interrupt requists (from PIC)\n */\n.macro IRQ n, i\n.global __x86_irq\\n\n__x86_irq\\n:\n#if ARCH_BITS==32\n    cli\n    movl $\\i, (__x86_isr_int_num)\n    jmp irq_stub\n#else\n    cli\n    movl $\\i, __x86_isr_int_num(%rip)\n    jmp irq_stub\n#endif\n.endm\n\nIRQ 0, 32\nIRQ 1, 33\nIRQ 2, 34\nIRQ 3, 35\nIRQ 4, 36\nIRQ 5, 37\nIRQ 6, 38\nIRQ 7, 39\nIRQ 8, 40\nIRQ 9, 41\nIRQ 10, 42\nIRQ 11, 43\nIRQ 12, 44\nIRQ 13, 45\nIRQ 14, 46\nIRQ 15, 47\n\n\n.extern __x86_irq_handler\nirq_stub:\n#if ARCH_BITS==32\n    push_context\n    push %esp\n    call __x86_irq_handler\n    pop %eax\n    pop_context\n    iret\n#else\n    push_context\n    mov %rsp, %rdi\n    call __x86_irq_handler\n    pop_context\n    iretq\n#endif\n\n.global x86_jump_user\nx86_jump_user:  /* eax, eip, cs, eflags, esp, ss */\n#if ARCH_BITS==32\n    pop  %eax   /* Caller return address */\n    mov  $0x20 | 0x3, %ax\n    movw %ax, %ds\n    movw %ax, %es\n    movw %ax, %fs\n    movw %ax, %gs\n    pop  %eax   /* eax for sys_fork return */\n    iret\n#else\n    pop  %rax   /* Caller return address */\n    /* set segments */\n    mov  $0x20 | 0x3, %ax\n    movw %ax, %ds\n    movw %ax, %es\n    movw %ax, %fs\n    movw %ax, %gs\n    mov  %rdi, %rax   /* rax for sys_fork return */\n    /* push registers */\n    pushq %r9    /* ss */\n    pushq %r8    /* rsp */\n    pushq %rcx   /* rflags */\n    pushq %rdx   /* cs */\n    pushq %rsi   /* rip */\n    iretq\n#endif\n\n.global x86_read_ip\nx86_read_ip:\n#if ARCH_BITS==32\n    mov (%esp), %eax\n#else\n    mov (%rsp), %rax\n#endif\n    ret\n\n.global x86_goto\nx86_goto:\n#if ARCH_BITS==32\n    pop %ebx    /* Caller return address */\n    pop %ebx    /* eip */\n    pop %ebp\n    pop %esp\n    mov $-1, %eax /* Return -1 -> Done switching */\n    jmp *%ebx\n#else\n    pop %rbx        /* Caller return address */\n    mov %rdi, %rbx  /* rip */\n    mov %rsi, %rbp\n    mov %rdx, %rsp\n    mov $-1, %rax /* Return -1 -> Done switching */\n    jmp *%rbx\n#endif\n\n\n.extern internal_arch_sleep\n.global x86_sleep\nx86_sleep:\n    push_context\n    call internal_arch_sleep\n    pop_context\n    ret\n\n.global x86_fork_return\nx86_fork_return:\n#if ARCH_BITS==32\n    pop_context\n    iret\n#else\n    pop_context\n    iretq\n#endif\n\n.global return_from_signal\nreturn_from_signal:\n    mov 4(%esp), %edi\n    mov %edi, %esp    /* Fix stack pointer */\n    pop_context\n    iret\n\n.align 8\ngdt_pointer:\n    .word 0\n#if ARCH_BITS==32\n    .long 0\n#else\n    .quad 0\n#endif\n\n.global x86_lgdt\nx86_lgdt:\n#if ARCH_BITS==32\n    movw 4(%esp), %ax\n    movl 8(%esp), %ebx\n    movw %ax, (gdt_pointer)\n    movl %ebx, (gdt_pointer + 2)\n    lgdt (gdt_pointer)\n    ljmp $0x8, $1f\n#else\n    movw %di, gdt_pointer(%rip)\n    movq %rsi, (gdt_pointer + 2)(%rip)\n    lgdt gdt_pointer(%rip)\n#endif\n1:\n    movl $0x10, %eax\n    movl %eax, %ds\n    movl %eax, %es\n    movl %eax, %fs\n    movl %eax, %gs\n    movl %eax, %ss\n    ret\n\n.global x86_lidt\nx86_lidt:\n#if ARCH_BITS==32\n    movl 4(%esp), %eax\n    lidt (%eax)\n#else\n    lidt (%rdi)\n#endif\n    ret\n\n.global x86_ltr\nx86_ltr:\n#if ARCH_BITS==32\n    movl 4(%esp), %eax\n    ltr %ax\n#else\n    ltr %di\n#endif\n    ret\n\n/* vim: ft=gas:\n */\n"
  },
  {
    "path": "kernel/arch/i386/cpu/cpu.h",
    "content": "#ifndef _CPU_SYS_H\n#define _CPU_SYS_H\n\n#include <core/system.h>\n\nvoid x86_lgdt(uint16_t, uintptr_t);\nvoid x86_lidt(uintptr_t);\nvoid x86_ltr(uintptr_t);\n\n#endif /* ! _CPU_SYS_H */\n"
  },
  {
    "path": "kernel/arch/i386/cpu/fpu.c",
    "content": "#include <core/system.h>\n#include <core/panic.h>\n#include <core/assert.h>\n#include <core/arch.h>\n#include <cpu/cpu.h>\n#include <sys/proc.h>\n#include <sys/sched.h>\n\nMALLOC_DEFINE(M_X86_FPU, \"x86-fpu\", \"x86 FPU context\");\n\nstatic char fpu_context[512] __aligned(16);\nstruct thread *last_fpu_thread = NULL;\n\nvoid x86_fpu_enable(void)\n{\n    asm volatile(\"clts\");\n    write_cr0((read_cr0() & ~CR0_EM) | CR0_MP);\n}\n\nvoid x86_fpu_disable(void)\n{\n    write_cr0(read_cr0() | CR0_EM);\n}\n\nvoid x86_fpu_init(void)\n{\n    assert_alignof(fpu_context, 16);\n    asm volatile(\"fninit\");\n}\n\nstatic inline void fpu_save(void)\n{\n    asm volatile(\"fxsave (%0)\"::\"r\"(fpu_context):\"memory\");\n}\n\nstatic inline void fpu_restore(void)\n{\n    asm volatile(\"fxrstor (%0)\"::\"r\"(fpu_context):\"memory\");\n}\n\nvoid x86_fpu_trap(void)\n{\n    x86_fpu_enable();\n\n    struct x86_thread *arch = curthread->arch;\n\n    if (!last_fpu_thread) {   /* Initialize */\n        x86_fpu_init();\n        arch->fpu_enabled = 1;\n    } else if (curthread != last_fpu_thread) {\n        struct x86_thread *_arch = last_fpu_thread->arch;\n\n        if (!_arch->fpu_context) {  /* Lazy allocate */\n            _arch->fpu_context = kmalloc(512, &M_X86_FPU, 0);\n\n            if (!_arch->fpu_context) {\n                /* TODO */\n            }\n        }\n\n        fpu_save();\n        memcpy(_arch->fpu_context, fpu_context, 512);\n\n        if (arch->fpu_enabled) {    /* Restore context */\n            memcpy(fpu_context, arch->fpu_context, 512);\n            fpu_restore();\n        } else {\n            x86_fpu_init();\n            arch->fpu_enabled = 1;\n        }\n    }\n\n    last_fpu_thread = curthread;\n}\n"
  },
  {
    "path": "kernel/arch/i386/cpu/gdt.c",
    "content": "/**********************************************************************\n *              Global Descriptor Table (GDT)\n *\n *\n *  This file is part of Aquila OS and is released under the terms of\n *  GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar\n */\n\n\n#include <core/system.h>\n#include <core/panic.h>\n#include <core/assert.h>\n#include <core/string.h>\n\n#include \"cpu.h\"\n\n#if ARCH_BITS==32\nstatic struct {\n    uint32_t link;\n    uint32_t sp;\n    uint32_t ss;\n    uint32_t _[23]; /* To know the actuall fields, consult Intel Manuals */\n} __packed tss_entry __aligned(8);\n#else\nstatic struct {\n    uint32_t _;\n    uint64_t sp;\n    uint32_t __[23]; /* To know the actuall fields, consult Intel Manuals */\n} __packed tss_entry __aligned(8);\n#endif\n\n#define TSS_BASE    ((uintptr_t) &tss_entry)\n#define TSS_LIMIT   (sizeof(tss_entry) - 1)\n\n#define RW_DATA 0x2\n#define XR_CODE 0xA\n#define TSS_AVL 0x9\n\n#define BASE  0\n#define LIMIT -1\n\n#define DPL0 0\n#define DPL3 3\n\n#if ARCH_BITS==32\n#define L   0\n#define D   1\n#else\n#define L   1\n#define D   0\n#endif\n\nstatic struct gdt_entry {\n    uint32_t limit_lo : 16; /* Segment Limit 15:00 */\n    uint32_t base_lo  : 16; /* Base Address 15:00 */\n\n    uint32_t base_mid : 8;  /* Base Address 23:16 */\n    uint32_t type     : 4;  /* Segment Type */\n    uint32_t s        : 1;  /* Descriptor type (0=system, 1=code) */\n    uint32_t dpl      : 2;  /* Descriptor Privellage Level */\n    uint32_t p        : 1;  /* Segment present */\n\n    uint32_t limit_hi : 4;  /* Segment Limit 19:16 */\n    uint32_t avl      : 1;  /* Avilable for use by system software */\n    uint32_t l        : 1;  /* Long mode segment (64-bit only) */\n    uint32_t db       : 1;  /* Default operation size / upper Bound */\n    uint32_t g        : 1;  /* Granularity */\n    uint32_t base_hi  : 8;  /* Base Address 31:24 */\n} __aligned(8) gdt[256] = {\n    /* Null Segment */\n    {0},\n\n    /* Code Segment - Kernel */\n    {LIMIT, BASE, BASE, XR_CODE, 1, DPL0, 1, LIMIT, 0, L, D, 1, BASE},\n\n    /* Data Segment - Kernel */\n    {LIMIT, BASE, BASE, RW_DATA, 1, DPL0, 1, LIMIT, 0, L, D, 1, BASE},\n\n    /* Code Segment - User */\n    {LIMIT, BASE, BASE, XR_CODE, 1, DPL3, 1, LIMIT, 0, L, D, 1, BASE},\n\n    /* Data Segment - User */\n    {LIMIT, BASE, BASE, RW_DATA, 1, DPL3, 1, LIMIT, 0, L, D, 1, BASE},\n};\n\nvoid x86_gdt_setup(void)\n{\n    assert_sizeof(gdt, 8*256);\n    assert_alignof(&gdt, 8);\n    x86_lgdt(sizeof(gdt) - 1, (uintptr_t) &gdt);\n}\n\nvoid x86_tss_setup(uintptr_t sp)\n{\n    assert_sizeof(tss_entry, 104);\n    assert_alignof(&tss_entry, 8);\n\n#if ARCH_BITS==32\n    tss_entry.ss = 0x10;\n#endif\n    tss_entry.sp = sp;\n\n    /* TSS Segment */\n#if 0\n    gdt[5] = (struct gdt_entry){TSS_LIMIT & 0xFFFF, TSS_BASE & 0xFFFF,\n        (TSS_BASE >> 16) & 0xFF, TSS_AVL, 0, DPL3, 1,\n        (TSS_LIMIT >> 16) & 0xF, 0, 0, 0, 0, (TSS_BASE >> 24 & 0xFF)};\n#endif\n    gdt[5].limit_lo = TSS_LIMIT & 0xFFFF;\n    gdt[5].base_lo  = TSS_BASE & 0xFFFF;\n    gdt[5].base_mid = (TSS_BASE >> 16) & 0xFF;\n    gdt[5].type     = TSS_AVL;\n    gdt[5].s        = 0;\n    gdt[5].dpl      = DPL3;\n    gdt[5].p        = 1;\n    gdt[5].limit_hi = (TSS_LIMIT >> 16) & 0xF;\n    gdt[5].avl      = 0;\n    gdt[5].l        = 0;\n    gdt[5].db       = 0;\n    gdt[5].g        = 0;\n    gdt[5].base_hi  = (TSS_BASE >> 24 & 0xFF);\n\n#if ARCH_BITS==64\n    uint32_t *base_high = (uint32_t *) &gdt[6];\n    *base_high = TSS_BASE >> 32;\n#endif\n\n    x86_ltr(0x28 | DPL3);\n}\n\nvoid x86_kernel_stack_set(uintptr_t sp)\n{\n    tss_entry.sp = sp;\n}\n"
  },
  {
    "path": "kernel/arch/i386/cpu/idt.c",
    "content": "/**********************************************************************\n *              Interrupt Descriptor Table (IDT)\n *\n *\n *  This file is part of Aquila OS and is released under the terms of\n *  GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar \n */\n\n#include <core/system.h>\n#include \"cpu.h\"\n\n#if __pragma_pack\n#pragma pack(1)\n#endif\nstatic struct idt_entry {\n    uint32_t offset_lo : 16;    /* offset 0:15 */\n    uint32_t selector  : 16;    /* Code segment selector */\n    uint32_t _unused   : 8;     /* Unused, should be set to 0 */\n    uint32_t flags     : 5;     /* Always set to 01110 */\n    uint32_t dpl       : 2;     /* Descriptor privellage level */\n    uint32_t p         : 1;     /* Present */\n    uint16_t offset_hi : 16;    /* offset 16:31 */\n#if ARCH_BITS==64\n    uint32_t offset_ext: 32;    /* offset 32:63 */\n    uint32_t           : 32;    /* reserved */\n#endif\n} __packed idt[256];\n\nstruct idt_ptr {\n    uint16_t limit;\n    uintptr_t base;\n} __packed idt_pointer;\n#if __pragma_pack\n#pragma pack()\n#endif\n\n#define DPL0 0\n#define DPL3 3\n\n/* Sets Interrupt gates in Kernel Code Segment */\nvoid x86_idt_gate_set(uint32_t id, uintptr_t offset)\n{\n    idt[id].offset_lo  = (offset >> 0x00) & 0xFFFF;\n    idt[id].offset_hi  = (offset >> 0x10) & 0xFFFF;\n#if ARCH_BITS==64\n    idt[id].offset_ext = (offset >> 0x20) & 0xFFFFFFFF;\n#endif\n\n    idt[id].selector   = 0x8;\n    idt[id].p          = 1;\n    idt[id].dpl        = DPL0;\n    idt[id].flags      = 0x0E;\n}\n\n/* Sets Interrupt gates in User Code Segment */\nvoid x86_idt_gate_user_set(uint32_t id, uintptr_t offset)\n{\n    idt[id].offset_lo  = (offset >> 0x00) & 0xFFFF;\n    idt[id].offset_hi  = (offset >> 0x10) & 0xFFFF;\n#if ARCH_BITS==64\n    idt[id].offset_ext = (offset >> 0x20) & 0xFFFFFFFF;\n#endif\n\n    idt[id].selector   = 0x8;\n    idt[id].p          = 1;\n    idt[id].dpl        = DPL3;\n    idt[id].flags      = 0x0E;\n}\n\nvoid x86_idt_setup()\n{\n    idt_pointer.limit = sizeof(idt) - 1;\n    idt_pointer.base  = (uintptr_t) &idt;\n    x86_lidt((uintptr_t) &idt_pointer);\n}\n"
  },
  {
    "path": "kernel/arch/i386/cpu/init.c",
    "content": "/**********************************************************************\n *                  Initalization of the kernel\n *           (Setup CPU structures and memory managment)\n *\n *\n *  This file is part of AquilaOS and is released under the terms of\n *  GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar\n */\n\n#include <boot/boot.h>\n#include <boot/multiboot.h>\n#include <console/earlycon.h>\n#include <core/kargs.h>\n#include <core/platform.h>\n#include <core/printk.h>\n#include <core/string.h>\n#include <cpu/cpu.h>\n#include <ds/bitmap.h>\n#include <mm/mm.h>\n#include <mm/vm.h>\n#include <video/vbe.h>\n\nstruct x86_cpu cpus[32];\nint cpus_count;\nstruct boot *__kboot;\n\nvoid x86_cpu_init(void)\n{\n    earlycon_init();\n    printk(\"x86: Welcome to AquilaOS!\\n\");\n\n    printk(\"x86: installing GDT\\n\");\n    x86_gdt_setup();\n    x86_tss_setup(VMA(0x100000ULL));\n\n    printk(\"x86: installing IDT\\n\");\n    x86_idt_setup();\n\n    printk(\"x86: installing ISRs\\n\");\n    x86_isr_setup();\n\n    printk(\"x86: processing multiboot info block at %p\\n\", (uintptr_t) multiboot_info);\n    struct boot *boot = process_multiboot_info((multiboot_info_t *)(uintptr_t) multiboot_info);\n    __kboot = boot;\n\n    mm_setup(boot);\n    kvmem_setup();\n\n    /* parse command line */\n    kargs_parse(boot->cmdline);\n\n    /* reinit early console */\n    earlycon_reinit();\n\n    platform_init();\n\n    extern void kmain(struct boot *);\n    kmain(boot);\n}\n"
  },
  {
    "path": "kernel/arch/i386/cpu/isr.c",
    "content": "/**********************************************************************\n *              Interrupt Service Routines (ISRs)\n *\n *\n *  This file is part of AquilaOS and is released under the terms of\n *  GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar\n */\n\n#include <core/system.h>\n#include <core/arch.h>\n\n#include <core/panic.h>\n#include <core/string.h>\n#include <cpu/cpu.h>\n#include <sys/sched.h>\n#include <mm/mm.h>\n\nextern void __x86_isr0 (void);\nextern void __x86_isr1 (void);\nextern void __x86_isr2 (void);\nextern void __x86_isr3 (void);\nextern void __x86_isr4 (void);\nextern void __x86_isr5 (void);\nextern void __x86_isr6 (void);\nextern void __x86_isr7 (void);\nextern void __x86_isr8 (void);\nextern void __x86_isr9 (void);\nextern void __x86_isr10(void);\nextern void __x86_isr11(void);\nextern void __x86_isr12(void);\nextern void __x86_isr13(void);\nextern void __x86_isr14(void);\nextern void __x86_isr15(void);\nextern void __x86_isr16(void);\nextern void __x86_isr17(void);\nextern void __x86_isr18(void);\nextern void __x86_isr19(void);\nextern void __x86_isr20(void);\nextern void __x86_isr21(void);\nextern void __x86_isr22(void);\nextern void __x86_isr23(void);\nextern void __x86_isr24(void);\nextern void __x86_isr25(void);\nextern void __x86_isr26(void);\nextern void __x86_isr27(void);\nextern void __x86_isr28(void);\nextern void __x86_isr29(void);\nextern void __x86_isr30(void);\nextern void __x86_isr31(void);\nextern void __x86_isr128(void);\n\n/* Refer to \n * - Intel 64 and IA-32 Architectures Software Developer’s Manual\n * - Volume 3: System Programming Guide\n * - Table 6-1. Protected-Mode Exceptions and Interrupts\n */\n\nstatic const char *int_msg[32] = {\n    /* 0x00 */ \"#DE: Divide Error\",\n    /* 0x01 */ \"#DB: Debug Exception\",\n    /* 0x02 */ \"NMI Interrupt\",\n    /* 0x03 */ \"#BP: Breakpoint\",\n    /* 0x04 */ \"#OF: Overflow\",\n    /* 0x05 */ \"#BR: BOUND Range Exceeded\",\n    /* 0x06 */ \"#UD: Invalid Opcode (Undefined Opcode)\",\n    /* 0x07 */ \"#NM: Device Not Available (No Math Coprocessor)\",\n    /* 0x08 */ \"#DF: Double Fault\",\n    /* 0x09 */ \"Coprocessor Segment Overrun (reserved)\",\n    /* 0x0a */ \"#TS: Invalid TSS\",\n    /* 0x0b */ \"#NP: Segment Not Present\",\n    /* 0x0C */ \"#SS: Stack-Segment Fault\",\n    /* 0x0D */ \"#GP: General Protection\",\n    /* 0x0E */ \"#PF: Page Fault\",\n    /* 0x0F */ \"Reserved\",\n    /* 0x10 */ \"#MF: x87 FPU Floating-Point Error (Math Fault)\",\n    /* 0x11 */ \"#AC: Alignment Check\",\n    /* 0x12 */ \"#MC: Machine Check\",\n    /* 0x13 */ \"#XM: SIMD Floating-Point Exception\",\n    /* 0x14 */ \"#VE: Virtualization Exception\",\n    /* 0x15 */ \"Reserved\",\n    /* 0x16 */ \"Reserved\",\n    /* 0x17 */ \"Reserved\",\n    /* 0x18 */ \"Reserved\",\n    /* 0x19 */ \"Reserved\",\n    /* 0x1A */ \"Reserved\",\n    /* 0x1B */ \"Reserved\",\n    /* 0x1C */ \"Reserved\",\n    /* 0x1D */ \"Reserved\",\n    /* 0x1E */ \"Reserved\",\n    /* 0x1F */ \"Reserved\"\n};\n\nvoid __x86_isr(struct x86_regs *regs)\n{\n    extern uint32_t __x86_isr_int_num;\n    extern uint32_t __x86_isr_err_num;\n\n    if (__x86_isr_int_num == 0xE && curthread) { /* Page Fault */\n        struct x86_thread *arch = curthread->arch;\n        //arch->regs = regs;\n\n#if ARCH_BITS==32\n        if (regs->eip == 0x0FFF) {  /* Signal return */\n#else\n        if (regs->rip == 0x0FFF) {  /* Signal return */\n#endif\n            /* Fix kstack and regs pointers*/\n            arch->regs = (struct x86_regs *) arch->kstack;\n            arch->kstack += sizeof(struct x86_regs); \n            x86_kernel_stack_set(arch->kstack);\n\n            extern void return_from_signal(uintptr_t) __attribute__((noreturn));\n            return_from_signal((uintptr_t) arch->regs);\n        }\n\n#if 0\n        const char *name = curthread->owner->name;\n        if (name && !strcmp(name, \"/bin/fbterm\")) {\n            x86_dump_registers(regs);\n            printk(\"page = %p\\n\", read_cr2());\n            for (;;);\n        }\n#endif\n\n        //x86_dump_registers(regs);\n        uintptr_t addr = read_cr2();\n\n        arch_mm_page_fault(addr, __x86_isr_err_num);\n        return;\n    }\n\n    if (__x86_isr_int_num == 0x07) {  /* FPU Trap */\n        x86_fpu_trap();\n        return;\n    }\n    \n    if (__x86_isr_int_num == 0x80) {  /* syscall */\n        struct x86_thread *arch = curthread->arch;\n        arch->regs = regs;\n        //asm volatile (\"sti\");\n        arch_syscall(regs);\n        return;\n    }\n\n\n    if (__x86_isr_int_num < 32) {\n        const char *msg = int_msg[__x86_isr_int_num];\n        printk(\"Recieved interrupt %d [err=%d]: %s\\n\", __x86_isr_int_num, __x86_isr_err_num, msg);\n\n        if (__x86_isr_int_num == 0x0E) { /* Page Fault */\n            printk(\"CR2 = %p\\n\", read_cr2());\n        }\n        x86_dump_registers(regs);\n        panic(\"Kernel Exception\");\n    } else {\n        printk(\"Unhandled interrupt %d\\n\", __x86_isr_int_num);\n        panic(\"Kernel Exception\");\n    }\n}\n\nvoid x86_isr_setup(void)\n{   \n    x86_idt_gate_set(0x00, (uintptr_t) __x86_isr0);\n    x86_idt_gate_set(0x01, (uintptr_t) __x86_isr1);\n    x86_idt_gate_set(0x02, (uintptr_t) __x86_isr2);\n    x86_idt_gate_set(0x03, (uintptr_t) __x86_isr3);\n    x86_idt_gate_set(0x04, (uintptr_t) __x86_isr4);\n    x86_idt_gate_set(0x05, (uintptr_t) __x86_isr5);\n    x86_idt_gate_set(0x06, (uintptr_t) __x86_isr6);\n    x86_idt_gate_set(0x07, (uintptr_t) __x86_isr7);\n    x86_idt_gate_set(0x08, (uintptr_t) __x86_isr8);\n    x86_idt_gate_set(0x09, (uintptr_t) __x86_isr9);\n    x86_idt_gate_set(0x0A, (uintptr_t) __x86_isr10);\n    x86_idt_gate_set(0x0B, (uintptr_t) __x86_isr11);\n    x86_idt_gate_set(0x0C, (uintptr_t) __x86_isr12);\n    x86_idt_gate_set(0x0D, (uintptr_t) __x86_isr13);\n    x86_idt_gate_set(0x0E, (uintptr_t) __x86_isr14);\n    x86_idt_gate_set(0x0F, (uintptr_t) __x86_isr15);\n    x86_idt_gate_set(0x10, (uintptr_t) __x86_isr16);\n    x86_idt_gate_set(0x11, (uintptr_t) __x86_isr17);\n    x86_idt_gate_set(0x12, (uintptr_t) __x86_isr18);\n    x86_idt_gate_set(0x13, (uintptr_t) __x86_isr19);\n    x86_idt_gate_set(0x14, (uintptr_t) __x86_isr20);\n    x86_idt_gate_set(0x15, (uintptr_t) __x86_isr21);\n    x86_idt_gate_set(0x16, (uintptr_t) __x86_isr22);\n    x86_idt_gate_set(0x17, (uintptr_t) __x86_isr23);\n    x86_idt_gate_set(0x18, (uintptr_t) __x86_isr24);\n    x86_idt_gate_set(0x19, (uintptr_t) __x86_isr25);\n    x86_idt_gate_set(0x1A, (uintptr_t) __x86_isr26);\n    x86_idt_gate_set(0x1B, (uintptr_t) __x86_isr27);\n    x86_idt_gate_set(0x1C, (uintptr_t) __x86_isr28);\n    x86_idt_gate_set(0x1D, (uintptr_t) __x86_isr29);\n    x86_idt_gate_set(0x1E, (uintptr_t) __x86_isr30);\n    x86_idt_gate_set(0x1F, (uintptr_t) __x86_isr31);\n    x86_idt_gate_user_set(0x80, (uintptr_t) __x86_isr128);\n}\n"
  },
  {
    "path": "kernel/arch/i386/cpu/smp.S",
    "content": ".code16\n\n.global trampoline\ntrampoline:\n    movw $0x1400, %ax\n    movw %ax, %ds\n    lgdt %ds:(0x00)\n    movl %cr0, %eax\n    orl $1, %eax\n    movl %eax, %cr0\n    ljmp $0x8,$pmode_trampoline - trampoline\n\n.code32\n\n\n.extern gdt_pointer\n.extern x86_ap_init\n.global pmode_trampoline\npmode_trampoline:\n    movw $0x10, %ax\n    movw %ax, %ds\n    movw %ax, %ss\n    movw %ax, %es\n    incl (ap_done)\n    movl $0x8000, %esp\n    lgdtl (gdt_pointer)\n    //ljmp $0x8,$x86_ap_init\n\n.global trampoline_end\ntrampoline_end:\n\n.global ap_done\nap_done: .long 0\n"
  },
  {
    "path": "kernel/arch/i386/cpu/trace.c",
    "content": "#include <core/system.h>\n#include <core/printk.h>\n#include <boot/boot.h>\n\nstruct stack_frame {\n    struct stack_frame *bp;\n    uintptr_t ip;\n};\n\nextern struct boot *__kboot;\n\nint __printing_trace = 0;\n\nvoid arch_stack_trace()\n{\n#if 1\n    __printing_trace = 1;\n\n    struct stack_frame *stk = NULL;\n\n    asm volatile (\"movl %%ebp, %0\":\"=r\"(stk));\n\n    printk(\"stack trace:\\n\");\n\n    const char *strs = (const char *) __kboot->strtab->sh_addr;\n\n    for (int frame = 0; stk && frame < 20; ++frame) {\n\n        /* find symbol */\n        struct elf32_sym *sym = (struct elf32_sym *) __kboot->symtab->sh_addr;\n\n        int found = 0;\n\n        for (size_t i = 0; i < __kboot->symnum; ++i) {\n            if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC) {\n                if (stk->ip > sym->st_value && stk->ip < sym->st_value + sym->st_size) {\n                    found = 1;\n                    break;\n                }\n            }\n            ++sym;\n        }\n\n        if (found) {\n            off_t off = stk->ip - sym->st_value;\n            printk(\"  [%p] %s+0x%x\\n\", stk->ip, strs + sym->st_name, off);\n        } else {\n            printk(\"  [%p]\\n\", stk->ip);\n        }\n\n        stk = stk->bp;\n    }\n#endif\n}\n"
  },
  {
    "path": "kernel/arch/i386/earlycon/Build.mk",
    "content": "obj-y += uart.o\nobj-y += vga.o\nobj-y += earlycon.o\nobj-y += fb.o\n"
  },
  {
    "path": "kernel/arch/i386/earlycon/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/arch/i386/earlycon/earlycon.c",
    "content": "#include <core/kargs.h>\n#include <core/string.h>\n#include <console/earlycon.h>\n\nstatic struct earlycon *earlycon;\n\nextern struct earlycon earlycon_uart;\nextern struct earlycon earlycon_vga;\nextern struct earlycon earlycon_fb;\n\nint earlycon_puts(char *s)\n{\n    return earlycon->puts(s);\n}\n\nint earlycon_putc(char c)\n{\n    return earlycon->putc(c);\n}\n\nvoid earlycon_init()\n{\n    earlycon = &earlycon_uart;\n    earlycon->init();\n}\n\nvoid earlycon_reinit()\n{\n    const char *arg_earlycon;\n    earlycon = &earlycon_fb; /* default */\n\n    if (!kargs_get(\"earlycon\", &arg_earlycon)) {\n        if (!strcmp(arg_earlycon, \"ttyS0\"))\n            earlycon = &earlycon_uart;\n        else if (!strcmp(arg_earlycon, \"vga\"))\n            earlycon = &earlycon_vga;\n        else if (!strcmp(arg_earlycon, \"fb\"))\n            earlycon = &earlycon_fb;\n    }\n\n    earlycon->init();\n}\n"
  },
  {
    "path": "kernel/arch/i386/earlycon/fb.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n#include <console/earlycon.h>\n#include <cpu/io.h>\n#include <mm/vm.h>\n\n#include \"font.h\"\n\nstatic uintptr_t fb_paddr, fb_init = 0;\nstatic uint32_t fb_xres, fb_yres, fb_depth,\n                fb_scanline, fb_row = 0, fb_col = 0,\n                fb_rows = 25, fb_cols = 80, fb_size;\n\nstatic struct vm_entry fb_vmr = {\n    .base = 0xE8000000,\n};\n\nstatic char *vmem   = (char *) 0xE8000000;\nstatic char *cursor = (char *) 0xE8000000;\n\nvoid earlycon_fb_register(uintptr_t paddr, uint32_t scanline, uint32_t yres, uint32_t xres, uint32_t depth)\n{\n    //printk(\"earlycon_fb_register(paddr=%p, scanline=%d, yres=%d, xres=%d, depth=%d)\\n\",\n    //        paddr, scanline, yres, xres, depth);\n    fb_paddr    = paddr;\n    fb_scanline = scanline;\n    fb_yres     = yres;\n    fb_xres     = xres;\n    fb_depth    = depth;\n    fb_size     = yres * scanline * depth / 8;\n}\n\nstatic void earlycon_fb_scroll(int n)\n{\n    size_t size = n * 16 * fb_scanline;\n    memcpy(vmem, vmem + size, fb_size - size);\n    memset(vmem + fb_size - size, 0, size);\n}\n\nstatic void fb_putc(int row, int col, char c)\n{\n    cursor = vmem + row * 16 * fb_scanline + col * 8 * fb_depth / 8;\n\n    char *base = cursor;\n\n    for (int i = 0; i < 16; ++i) {\n        for (int j = 0; j < 8; ++j) {\n            char b = 0;\n\n            if (vga_font[(unsigned) c * 16 + i] & (1 << (7 - j)))\n                b = 0xA0;\n\n            cursor[0] = b;\n            cursor[1] = b;\n            cursor[2] = b;\n            cursor[3] = b;\n\n            cursor += 4;\n        }\n\n        cursor += fb_scanline - 8 * 4;\n    }\n}\n\nstatic int earlycon_fb_putc(char c)\n{\n    if (!fb_init)\n        return -1;\n\n    if ((unsigned) c < 128) {\n        if (c == '\\n') {\n            fb_col = 0;\n            fb_row++;\n\n            if (fb_row >= fb_rows) {\n                earlycon_fb_scroll(1);\n                fb_row = fb_rows - 1;\n            }\n            return 1;\n        }\n\n        fb_putc(fb_row, fb_col, c);\n        ++fb_col;\n\n        if (fb_col >= fb_cols) {\n            fb_col = 0;\n            fb_row++;\n\n            if (fb_row >= fb_rows) {\n                earlycon_fb_scroll(1);\n                fb_row = fb_rows - 1;\n            }\n        }\n\n        return 1;\n    }\n\n    return 0;\n}\n\nstatic int earlycon_fb_puts(char *s)\n{\n    while (*s)\n        earlycon_fb_putc(*s++);\n\n    return 0;\n}\n\nstatic void earlycon_fb_init()\n{\n    fb_vmr.paddr = fb_paddr;\n    fb_vmr.size  = fb_size;\n    fb_vmr.flags = VM_KRW | VM_NOCACHE;\n\n    vm_map(&kvm_space, &fb_vmr);\n    fb_init = 1;\n\n    fb_cols = fb_xres / 8;\n    fb_rows = fb_yres / 16;\n}\n\nstruct earlycon earlycon_fb = {\n    .init = earlycon_fb_init,\n    .putc = earlycon_fb_putc,\n    .puts = earlycon_fb_puts,\n};\n"
  },
  {
    "path": "kernel/arch/i386/earlycon/font.h",
    "content": "/* from linux/drivers/video/font-8x16.c */\n\n/**********************************************/\n/*                                            */\n/*       Font file generated by cpi2fnt       */\n/*                                            */\n/**********************************************/\n\nunsigned char vga_font[] = {\n\t/* 0 0x00 '^@' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 1 0x01 '^A' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0x81, /* 10000001 */\n\t0xa5, /* 10100101 */\n\t0x81, /* 10000001 */\n\t0x81, /* 10000001 */\n\t0xbd, /* 10111101 */\n\t0x99, /* 10011001 */\n\t0x81, /* 10000001 */\n\t0x81, /* 10000001 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 2 0x02 '^B' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0xff, /* 11111111 */\n\t0xdb, /* 11011011 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xc3, /* 11000011 */\n\t0xe7, /* 11100111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 3 0x03 '^C' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x6c, /* 01101100 */\n\t0xfe, /* 11111110 */\n\t0xfe, /* 11111110 */\n\t0xfe, /* 11111110 */\n\t0xfe, /* 11111110 */\n\t0x7c, /* 01111100 */\n\t0x38, /* 00111000 */\n\t0x10, /* 00010000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 4 0x04 '^D' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x10, /* 00010000 */\n\t0x38, /* 00111000 */\n\t0x7c, /* 01111100 */\n\t0xfe, /* 11111110 */\n\t0x7c, /* 01111100 */\n\t0x38, /* 00111000 */\n\t0x10, /* 00010000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 5 0x05 '^E' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x3c, /* 00111100 */\n\t0xe7, /* 11100111 */\n\t0xe7, /* 11100111 */\n\t0xe7, /* 11100111 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 6 0x06 '^F' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x7e, /* 01111110 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0x7e, /* 01111110 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 7 0x07 '^G' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x3c, /* 00111100 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 8 0x08 '^H' */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xe7, /* 11100111 */\n\t0xc3, /* 11000011 */\n\t0xc3, /* 11000011 */\n\t0xe7, /* 11100111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\n\t/* 9 0x09 '^I' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3c, /* 00111100 */\n\t0x66, /* 01100110 */\n\t0x42, /* 01000010 */\n\t0x42, /* 01000010 */\n\t0x66, /* 01100110 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 10 0x0a '^J' */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xc3, /* 11000011 */\n\t0x99, /* 10011001 */\n\t0xbd, /* 10111101 */\n\t0xbd, /* 10111101 */\n\t0x99, /* 10011001 */\n\t0xc3, /* 11000011 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\n\t/* 11 0x0b '^K' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x1e, /* 00011110 */\n\t0x0e, /* 00001110 */\n\t0x1a, /* 00011010 */\n\t0x32, /* 00110010 */\n\t0x78, /* 01111000 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x78, /* 01111000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 12 0x0c '^L' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3c, /* 00111100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x3c, /* 00111100 */\n\t0x18, /* 00011000 */\n\t0x7e, /* 01111110 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 13 0x0d '^M' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3f, /* 00111111 */\n\t0x33, /* 00110011 */\n\t0x3f, /* 00111111 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x70, /* 01110000 */\n\t0xf0, /* 11110000 */\n\t0xe0, /* 11100000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 14 0x0e '^N' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7f, /* 01111111 */\n\t0x63, /* 01100011 */\n\t0x7f, /* 01111111 */\n\t0x63, /* 01100011 */\n\t0x63, /* 01100011 */\n\t0x63, /* 01100011 */\n\t0x63, /* 01100011 */\n\t0x67, /* 01100111 */\n\t0xe7, /* 11100111 */\n\t0xe6, /* 11100110 */\n\t0xc0, /* 11000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 15 0x0f '^O' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0xdb, /* 11011011 */\n\t0x3c, /* 00111100 */\n\t0xe7, /* 11100111 */\n\t0x3c, /* 00111100 */\n\t0xdb, /* 11011011 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 16 0x10 '^P' */\n\t0x00, /* 00000000 */\n\t0x80, /* 10000000 */\n\t0xc0, /* 11000000 */\n\t0xe0, /* 11100000 */\n\t0xf0, /* 11110000 */\n\t0xf8, /* 11111000 */\n\t0xfe, /* 11111110 */\n\t0xf8, /* 11111000 */\n\t0xf0, /* 11110000 */\n\t0xe0, /* 11100000 */\n\t0xc0, /* 11000000 */\n\t0x80, /* 10000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 17 0x11 '^Q' */\n\t0x00, /* 00000000 */\n\t0x02, /* 00000010 */\n\t0x06, /* 00000110 */\n\t0x0e, /* 00001110 */\n\t0x1e, /* 00011110 */\n\t0x3e, /* 00111110 */\n\t0xfe, /* 11111110 */\n\t0x3e, /* 00111110 */\n\t0x1e, /* 00011110 */\n\t0x0e, /* 00001110 */\n\t0x06, /* 00000110 */\n\t0x02, /* 00000010 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 18 0x12 '^R' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x7e, /* 01111110 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x7e, /* 01111110 */\n\t0x3c, /* 00111100 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 19 0x13 '^S' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x00, /* 00000000 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 20 0x14 '^T' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7f, /* 01111111 */\n\t0xdb, /* 11011011 */\n\t0xdb, /* 11011011 */\n\t0xdb, /* 11011011 */\n\t0x7b, /* 01111011 */\n\t0x1b, /* 00011011 */\n\t0x1b, /* 00011011 */\n\t0x1b, /* 00011011 */\n\t0x1b, /* 00011011 */\n\t0x1b, /* 00011011 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 21 0x15 '^U' */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0x60, /* 01100000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x6c, /* 01101100 */\n\t0x38, /* 00111000 */\n\t0x0c, /* 00001100 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 22 0x16 '^V' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0xfe, /* 11111110 */\n\t0xfe, /* 11111110 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 23 0x17 '^W' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x7e, /* 01111110 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x7e, /* 01111110 */\n\t0x3c, /* 00111100 */\n\t0x18, /* 00011000 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 24 0x18 '^X' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x7e, /* 01111110 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 25 0x19 '^Y' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x7e, /* 01111110 */\n\t0x3c, /* 00111100 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 26 0x1a '^Z' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x0c, /* 00001100 */\n\t0xfe, /* 11111110 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 27 0x1b '^[' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0xfe, /* 11111110 */\n\t0x60, /* 01100000 */\n\t0x30, /* 00110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 28 0x1c '^\\' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 29 0x1d '^]' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x28, /* 00101000 */\n\t0x6c, /* 01101100 */\n\t0xfe, /* 11111110 */\n\t0x6c, /* 01101100 */\n\t0x28, /* 00101000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 30 0x1e '^^' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x10, /* 00010000 */\n\t0x38, /* 00111000 */\n\t0x38, /* 00111000 */\n\t0x7c, /* 01111100 */\n\t0x7c, /* 01111100 */\n\t0xfe, /* 11111110 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 31 0x1f '^_' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0xfe, /* 11111110 */\n\t0x7c, /* 01111100 */\n\t0x7c, /* 01111100 */\n\t0x38, /* 00111000 */\n\t0x38, /* 00111000 */\n\t0x10, /* 00010000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 32 0x20 ' ' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 33 0x21 '!' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x3c, /* 00111100 */\n\t0x3c, /* 00111100 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 34 0x22 '\"' */\n\t0x00, /* 00000000 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x24, /* 00100100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 35 0x23 '#' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0xfe, /* 11111110 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0xfe, /* 11111110 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 36 0x24 '$' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc2, /* 11000010 */\n\t0xc0, /* 11000000 */\n\t0x7c, /* 01111100 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x86, /* 10000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 37 0x25 '%' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc2, /* 11000010 */\n\t0xc6, /* 11000110 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0xc6, /* 11000110 */\n\t0x86, /* 10000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 38 0x26 '&' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x38, /* 00111000 */\n\t0x76, /* 01110110 */\n\t0xdc, /* 11011100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 39 0x27 ''' */\n\t0x00, /* 00000000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 40 0x28 '(' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x0c, /* 00001100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 41 0x29 ')' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 42 0x2a '*' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x66, /* 01100110 */\n\t0x3c, /* 00111100 */\n\t0xff, /* 11111111 */\n\t0x3c, /* 00111100 */\n\t0x66, /* 01100110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 43 0x2b '+' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x7e, /* 01111110 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 44 0x2c ',' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 45 0x2d '-' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 46 0x2e '.' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 47 0x2f '/' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x02, /* 00000010 */\n\t0x06, /* 00000110 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0xc0, /* 11000000 */\n\t0x80, /* 10000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 48 0x30 '0' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xd6, /* 11010110 */\n\t0xd6, /* 11010110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x6c, /* 01101100 */\n\t0x38, /* 00111000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 49 0x31 '1' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x38, /* 00111000 */\n\t0x78, /* 01111000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 50 0x32 '2' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0x06, /* 00000110 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0xc0, /* 11000000 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 51 0x33 '3' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x3c, /* 00111100 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 52 0x34 '4' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x0c, /* 00001100 */\n\t0x1c, /* 00011100 */\n\t0x3c, /* 00111100 */\n\t0x6c, /* 01101100 */\n\t0xcc, /* 11001100 */\n\t0xfe, /* 11111110 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x1e, /* 00011110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 53 0x35 '5' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xfc, /* 11111100 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 54 0x36 '6' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x60, /* 01100000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xfc, /* 11111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 55 0x37 '7' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0xc6, /* 11000110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 56 0x38 '8' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 57 0x39 '9' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7e, /* 01111110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x0c, /* 00001100 */\n\t0x78, /* 01111000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 58 0x3a ':' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 59 0x3b ';' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 60 0x3c '<' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x06, /* 00000110 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x0c, /* 00001100 */\n\t0x06, /* 00000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 61 0x3d '=' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 62 0x3e '>' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x60, /* 01100000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x0c, /* 00001100 */\n\t0x06, /* 00000110 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 63 0x3f '?' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 64 0x40 '@' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xde, /* 11011110 */\n\t0xde, /* 11011110 */\n\t0xde, /* 11011110 */\n\t0xdc, /* 11011100 */\n\t0xc0, /* 11000000 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 65 0x41 'A' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x10, /* 00010000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 66 0x42 'B' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfc, /* 11111100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x7c, /* 01111100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0xfc, /* 11111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 67 0x43 'C' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3c, /* 00111100 */\n\t0x66, /* 01100110 */\n\t0xc2, /* 11000010 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc2, /* 11000010 */\n\t0x66, /* 01100110 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 68 0x44 'D' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xf8, /* 11111000 */\n\t0x6c, /* 01101100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x6c, /* 01101100 */\n\t0xf8, /* 11111000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 69 0x45 'E' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0x66, /* 01100110 */\n\t0x62, /* 01100010 */\n\t0x68, /* 01101000 */\n\t0x78, /* 01111000 */\n\t0x68, /* 01101000 */\n\t0x60, /* 01100000 */\n\t0x62, /* 01100010 */\n\t0x66, /* 01100110 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 70 0x46 'F' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0x66, /* 01100110 */\n\t0x62, /* 01100010 */\n\t0x68, /* 01101000 */\n\t0x78, /* 01111000 */\n\t0x68, /* 01101000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0xf0, /* 11110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 71 0x47 'G' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3c, /* 00111100 */\n\t0x66, /* 01100110 */\n\t0xc2, /* 11000010 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xde, /* 11011110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x66, /* 01100110 */\n\t0x3a, /* 00111010 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 72 0x48 'H' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 73 0x49 'I' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3c, /* 00111100 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 74 0x4a 'J' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x1e, /* 00011110 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x78, /* 01111000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 75 0x4b 'K' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xe6, /* 11100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x6c, /* 01101100 */\n\t0x78, /* 01111000 */\n\t0x78, /* 01111000 */\n\t0x6c, /* 01101100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0xe6, /* 11100110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 76 0x4c 'L' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xf0, /* 11110000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x62, /* 01100010 */\n\t0x66, /* 01100110 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 77 0x4d 'M' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xee, /* 11101110 */\n\t0xfe, /* 11111110 */\n\t0xfe, /* 11111110 */\n\t0xd6, /* 11010110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 78 0x4e 'N' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xe6, /* 11100110 */\n\t0xf6, /* 11110110 */\n\t0xfe, /* 11111110 */\n\t0xde, /* 11011110 */\n\t0xce, /* 11001110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 79 0x4f 'O' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 80 0x50 'P' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfc, /* 11111100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x7c, /* 01111100 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0xf0, /* 11110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 81 0x51 'Q' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xd6, /* 11010110 */\n\t0xde, /* 11011110 */\n\t0x7c, /* 01111100 */\n\t0x0c, /* 00001100 */\n\t0x0e, /* 00001110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 82 0x52 'R' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfc, /* 11111100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x7c, /* 01111100 */\n\t0x6c, /* 01101100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0xe6, /* 11100110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 83 0x53 'S' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x60, /* 01100000 */\n\t0x38, /* 00111000 */\n\t0x0c, /* 00001100 */\n\t0x06, /* 00000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 84 0x54 'T' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0x7e, /* 01111110 */\n\t0x5a, /* 01011010 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 85 0x55 'U' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 86 0x56 'V' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x6c, /* 01101100 */\n\t0x38, /* 00111000 */\n\t0x10, /* 00010000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 87 0x57 'W' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xd6, /* 11010110 */\n\t0xd6, /* 11010110 */\n\t0xd6, /* 11010110 */\n\t0xfe, /* 11111110 */\n\t0xee, /* 11101110 */\n\t0x6c, /* 01101100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 88 0x58 'X' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x6c, /* 01101100 */\n\t0x7c, /* 01111100 */\n\t0x38, /* 00111000 */\n\t0x38, /* 00111000 */\n\t0x7c, /* 01111100 */\n\t0x6c, /* 01101100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 89 0x59 'Y' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x3c, /* 00111100 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 90 0x5a 'Z' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0xc6, /* 11000110 */\n\t0x86, /* 10000110 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0xc2, /* 11000010 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 91 0x5b '[' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3c, /* 00111100 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 92 0x5c '\\' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x80, /* 10000000 */\n\t0xc0, /* 11000000 */\n\t0xe0, /* 11100000 */\n\t0x70, /* 01110000 */\n\t0x38, /* 00111000 */\n\t0x1c, /* 00011100 */\n\t0x0e, /* 00001110 */\n\t0x06, /* 00000110 */\n\t0x02, /* 00000010 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 93 0x5d ']' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3c, /* 00111100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 94 0x5e '^' */\n\t0x10, /* 00010000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 95 0x5f '_' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xff, /* 11111111 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 96 0x60 '`' */\n\t0x00, /* 00000000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x0c, /* 00001100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 97 0x61 'a' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x78, /* 01111000 */\n\t0x0c, /* 00001100 */\n\t0x7c, /* 01111100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 98 0x62 'b' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xe0, /* 11100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x78, /* 01111000 */\n\t0x6c, /* 01101100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 99 0x63 'c' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 100 0x64 'd' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x1c, /* 00011100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x3c, /* 00111100 */\n\t0x6c, /* 01101100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 101 0x65 'e' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 102 0x66 'f' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x1c, /* 00011100 */\n\t0x36, /* 00110110 */\n\t0x32, /* 00110010 */\n\t0x30, /* 00110000 */\n\t0x78, /* 01111000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x78, /* 01111000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 103 0x67 'g' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x76, /* 01110110 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x7c, /* 01111100 */\n\t0x0c, /* 00001100 */\n\t0xcc, /* 11001100 */\n\t0x78, /* 01111000 */\n\t0x00, /* 00000000 */\n\n\t/* 104 0x68 'h' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xe0, /* 11100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x6c, /* 01101100 */\n\t0x76, /* 01110110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0xe6, /* 11100110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 105 0x69 'i' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 106 0x6a 'j' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x00, /* 00000000 */\n\t0x0e, /* 00001110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\n\t/* 107 0x6b 'k' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xe0, /* 11100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x66, /* 01100110 */\n\t0x6c, /* 01101100 */\n\t0x78, /* 01111000 */\n\t0x78, /* 01111000 */\n\t0x6c, /* 01101100 */\n\t0x66, /* 01100110 */\n\t0xe6, /* 11100110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 108 0x6c 'l' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 109 0x6d 'm' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xec, /* 11101100 */\n\t0xfe, /* 11111110 */\n\t0xd6, /* 11010110 */\n\t0xd6, /* 11010110 */\n\t0xd6, /* 11010110 */\n\t0xd6, /* 11010110 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 110 0x6e 'n' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xdc, /* 11011100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 111 0x6f 'o' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 112 0x70 'p' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xdc, /* 11011100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x7c, /* 01111100 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0xf0, /* 11110000 */\n\t0x00, /* 00000000 */\n\n\t/* 113 0x71 'q' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x76, /* 01110110 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x7c, /* 01111100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x1e, /* 00011110 */\n\t0x00, /* 00000000 */\n\n\t/* 114 0x72 'r' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xdc, /* 11011100 */\n\t0x76, /* 01110110 */\n\t0x66, /* 01100110 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0xf0, /* 11110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 115 0x73 's' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0x60, /* 01100000 */\n\t0x38, /* 00111000 */\n\t0x0c, /* 00001100 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 116 0x74 't' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x10, /* 00010000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0xfc, /* 11111100 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x36, /* 00110110 */\n\t0x1c, /* 00011100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 117 0x75 'u' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 118 0x76 'v' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x6c, /* 01101100 */\n\t0x38, /* 00111000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 119 0x77 'w' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xd6, /* 11010110 */\n\t0xd6, /* 11010110 */\n\t0xd6, /* 11010110 */\n\t0xfe, /* 11111110 */\n\t0x6c, /* 01101100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 120 0x78 'x' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0x6c, /* 01101100 */\n\t0x38, /* 00111000 */\n\t0x38, /* 00111000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 121 0x79 'y' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7e, /* 01111110 */\n\t0x06, /* 00000110 */\n\t0x0c, /* 00001100 */\n\t0xf8, /* 11111000 */\n\t0x00, /* 00000000 */\n\n\t/* 122 0x7a 'z' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0xcc, /* 11001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 123 0x7b '{' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x0e, /* 00001110 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x70, /* 01110000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x0e, /* 00001110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 124 0x7c '|' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 125 0x7d '}' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x70, /* 01110000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x0e, /* 00001110 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x70, /* 01110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 126 0x7e '~' */\n\t0x00, /* 00000000 */\n\t0x76, /* 01110110 */\n\t0xdc, /* 11011100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 127 0x7f '' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x10, /* 00010000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 128 0x80 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3c, /* 00111100 */\n\t0x66, /* 01100110 */\n\t0xc2, /* 11000010 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc2, /* 11000010 */\n\t0x66, /* 01100110 */\n\t0x3c, /* 00111100 */\n\t0x18, /* 00011000 */\n\t0x70, /* 01110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 129 0x81 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xcc, /* 11001100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 130 0x82 '�' */\n\t0x00, /* 00000000 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 131 0x83 '�' */\n\t0x00, /* 00000000 */\n\t0x10, /* 00010000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0x00, /* 00000000 */\n\t0x78, /* 01111000 */\n\t0x0c, /* 00001100 */\n\t0x7c, /* 01111100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 132 0x84 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xcc, /* 11001100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x78, /* 01111000 */\n\t0x0c, /* 00001100 */\n\t0x7c, /* 01111100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 133 0x85 '�' */\n\t0x00, /* 00000000 */\n\t0x60, /* 01100000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x78, /* 01111000 */\n\t0x0c, /* 00001100 */\n\t0x7c, /* 01111100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 134 0x86 '�' */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0x38, /* 00111000 */\n\t0x00, /* 00000000 */\n\t0x78, /* 01111000 */\n\t0x0c, /* 00001100 */\n\t0x7c, /* 01111100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 135 0x87 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x18, /* 00011000 */\n\t0x70, /* 01110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 136 0x88 '�' */\n\t0x00, /* 00000000 */\n\t0x10, /* 00010000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 137 0x89 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 138 0x8a '�' */\n\t0x00, /* 00000000 */\n\t0x60, /* 01100000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 139 0x8b '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x66, /* 01100110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 140 0x8c '�' */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x66, /* 01100110 */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 141 0x8d '�' */\n\t0x00, /* 00000000 */\n\t0x60, /* 01100000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 142 0x8e '�' */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x10, /* 00010000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 143 0x8f '�' */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0x38, /* 00111000 */\n\t0x10, /* 00010000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 144 0x90 '�' */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0x66, /* 01100110 */\n\t0x62, /* 01100010 */\n\t0x68, /* 01101000 */\n\t0x78, /* 01111000 */\n\t0x68, /* 01101000 */\n\t0x62, /* 01100010 */\n\t0x66, /* 01100110 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 145 0x91 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xec, /* 11101100 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x7e, /* 01111110 */\n\t0xd8, /* 11011000 */\n\t0xd8, /* 11011000 */\n\t0x6e, /* 01101110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 146 0x92 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3e, /* 00111110 */\n\t0x6c, /* 01101100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xfe, /* 11111110 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xce, /* 11001110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 147 0x93 '�' */\n\t0x00, /* 00000000 */\n\t0x10, /* 00010000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 148 0x94 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 149 0x95 '�' */\n\t0x00, /* 00000000 */\n\t0x60, /* 01100000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 150 0x96 '�' */\n\t0x00, /* 00000000 */\n\t0x30, /* 00110000 */\n\t0x78, /* 01111000 */\n\t0xcc, /* 11001100 */\n\t0x00, /* 00000000 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 151 0x97 '�' */\n\t0x00, /* 00000000 */\n\t0x60, /* 01100000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 152 0x98 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7e, /* 01111110 */\n\t0x06, /* 00000110 */\n\t0x0c, /* 00001100 */\n\t0x78, /* 01111000 */\n\t0x00, /* 00000000 */\n\n\t/* 153 0x99 '�' */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 154 0x9a '�' */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 155 0x9b '�' */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 156 0x9c '�' */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0x64, /* 01100100 */\n\t0x60, /* 01100000 */\n\t0xf0, /* 11110000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0xe6, /* 11100110 */\n\t0xfc, /* 11111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 157 0x9d '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x3c, /* 00111100 */\n\t0x18, /* 00011000 */\n\t0x7e, /* 01111110 */\n\t0x18, /* 00011000 */\n\t0x7e, /* 01111110 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 158 0x9e '�' */\n\t0x00, /* 00000000 */\n\t0xf8, /* 11111000 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xf8, /* 11111000 */\n\t0xc4, /* 11000100 */\n\t0xcc, /* 11001100 */\n\t0xde, /* 11011110 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 159 0x9f '�' */\n\t0x00, /* 00000000 */\n\t0x0e, /* 00001110 */\n\t0x1b, /* 00011011 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x7e, /* 01111110 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0xd8, /* 11011000 */\n\t0x70, /* 01110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 160 0xa0 '�' */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0x00, /* 00000000 */\n\t0x78, /* 01111000 */\n\t0x0c, /* 00001100 */\n\t0x7c, /* 01111100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 161 0xa1 '�' */\n\t0x00, /* 00000000 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 162 0xa2 '�' */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 163 0xa3 '�' */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0x00, /* 00000000 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 164 0xa4 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x76, /* 01110110 */\n\t0xdc, /* 11011100 */\n\t0x00, /* 00000000 */\n\t0xdc, /* 11011100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 165 0xa5 '�' */\n\t0x76, /* 01110110 */\n\t0xdc, /* 11011100 */\n\t0x00, /* 00000000 */\n\t0xc6, /* 11000110 */\n\t0xe6, /* 11100110 */\n\t0xf6, /* 11110110 */\n\t0xfe, /* 11111110 */\n\t0xde, /* 11011110 */\n\t0xce, /* 11001110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 166 0xa6 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3c, /* 00111100 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x3e, /* 00111110 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 167 0xa7 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x38, /* 00111000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 168 0xa8 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x00, /* 00000000 */\n\t0x30, /* 00110000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0xc0, /* 11000000 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x7c, /* 01111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 169 0xa9 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 170 0xaa '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 171 0xab '�' */\n\t0x00, /* 00000000 */\n\t0x60, /* 01100000 */\n\t0xe0, /* 11100000 */\n\t0x62, /* 01100010 */\n\t0x66, /* 01100110 */\n\t0x6c, /* 01101100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0xdc, /* 11011100 */\n\t0x86, /* 10000110 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x3e, /* 00111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 172 0xac '�' */\n\t0x00, /* 00000000 */\n\t0x60, /* 01100000 */\n\t0xe0, /* 11100000 */\n\t0x62, /* 01100010 */\n\t0x66, /* 01100110 */\n\t0x6c, /* 01101100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x66, /* 01100110 */\n\t0xce, /* 11001110 */\n\t0x9a, /* 10011010 */\n\t0x3f, /* 00111111 */\n\t0x06, /* 00000110 */\n\t0x06, /* 00000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 173 0xad '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x3c, /* 00111100 */\n\t0x3c, /* 00111100 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 174 0xae '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x36, /* 00110110 */\n\t0x6c, /* 01101100 */\n\t0xd8, /* 11011000 */\n\t0x6c, /* 01101100 */\n\t0x36, /* 00110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 175 0xaf '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xd8, /* 11011000 */\n\t0x6c, /* 01101100 */\n\t0x36, /* 00110110 */\n\t0x6c, /* 01101100 */\n\t0xd8, /* 11011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 176 0xb0 '�' */\n\t0x11, /* 00010001 */\n\t0x44, /* 01000100 */\n\t0x11, /* 00010001 */\n\t0x44, /* 01000100 */\n\t0x11, /* 00010001 */\n\t0x44, /* 01000100 */\n\t0x11, /* 00010001 */\n\t0x44, /* 01000100 */\n\t0x11, /* 00010001 */\n\t0x44, /* 01000100 */\n\t0x11, /* 00010001 */\n\t0x44, /* 01000100 */\n\t0x11, /* 00010001 */\n\t0x44, /* 01000100 */\n\t0x11, /* 00010001 */\n\t0x44, /* 01000100 */\n\n\t/* 177 0xb1 '�' */\n\t0x55, /* 01010101 */\n\t0xaa, /* 10101010 */\n\t0x55, /* 01010101 */\n\t0xaa, /* 10101010 */\n\t0x55, /* 01010101 */\n\t0xaa, /* 10101010 */\n\t0x55, /* 01010101 */\n\t0xaa, /* 10101010 */\n\t0x55, /* 01010101 */\n\t0xaa, /* 10101010 */\n\t0x55, /* 01010101 */\n\t0xaa, /* 10101010 */\n\t0x55, /* 01010101 */\n\t0xaa, /* 10101010 */\n\t0x55, /* 01010101 */\n\t0xaa, /* 10101010 */\n\n\t/* 178 0xb2 '�' */\n\t0xdd, /* 11011101 */\n\t0x77, /* 01110111 */\n\t0xdd, /* 11011101 */\n\t0x77, /* 01110111 */\n\t0xdd, /* 11011101 */\n\t0x77, /* 01110111 */\n\t0xdd, /* 11011101 */\n\t0x77, /* 01110111 */\n\t0xdd, /* 11011101 */\n\t0x77, /* 01110111 */\n\t0xdd, /* 11011101 */\n\t0x77, /* 01110111 */\n\t0xdd, /* 11011101 */\n\t0x77, /* 01110111 */\n\t0xdd, /* 11011101 */\n\t0x77, /* 01110111 */\n\n\t/* 179 0xb3 '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 180 0xb4 '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0xf8, /* 11111000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 181 0xb5 '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0xf8, /* 11111000 */\n\t0x18, /* 00011000 */\n\t0xf8, /* 11111000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 182 0xb6 '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0xf6, /* 11110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 183 0xb7 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 184 0xb8 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xf8, /* 11111000 */\n\t0x18, /* 00011000 */\n\t0xf8, /* 11111000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 185 0xb9 '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0xf6, /* 11110110 */\n\t0x06, /* 00000110 */\n\t0xf6, /* 11110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 186 0xba '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 187 0xbb '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0x06, /* 00000110 */\n\t0xf6, /* 11110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 188 0xbc '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0xf6, /* 11110110 */\n\t0x06, /* 00000110 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 189 0xbd '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 190 0xbe '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0xf8, /* 11111000 */\n\t0x18, /* 00011000 */\n\t0xf8, /* 11111000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 191 0xbf '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xf8, /* 11111000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 192 0xc0 '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x1f, /* 00011111 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 193 0xc1 '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0xff, /* 11111111 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 194 0xc2 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xff, /* 11111111 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 195 0xc3 '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x1f, /* 00011111 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 196 0xc4 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xff, /* 11111111 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 197 0xc5 '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0xff, /* 11111111 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 198 0xc6 '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x1f, /* 00011111 */\n\t0x18, /* 00011000 */\n\t0x1f, /* 00011111 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 199 0xc7 '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x37, /* 00110111 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 200 0xc8 '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x37, /* 00110111 */\n\t0x30, /* 00110000 */\n\t0x3f, /* 00111111 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 201 0xc9 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3f, /* 00111111 */\n\t0x30, /* 00110000 */\n\t0x37, /* 00110111 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 202 0xca '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0xf7, /* 11110111 */\n\t0x00, /* 00000000 */\n\t0xff, /* 11111111 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 203 0xcb '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xff, /* 11111111 */\n\t0x00, /* 00000000 */\n\t0xf7, /* 11110111 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 204 0xcc '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x37, /* 00110111 */\n\t0x30, /* 00110000 */\n\t0x37, /* 00110111 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 205 0xcd '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xff, /* 11111111 */\n\t0x00, /* 00000000 */\n\t0xff, /* 11111111 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 206 0xce '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0xf7, /* 11110111 */\n\t0x00, /* 00000000 */\n\t0xf7, /* 11110111 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 207 0xcf '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0xff, /* 11111111 */\n\t0x00, /* 00000000 */\n\t0xff, /* 11111111 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 208 0xd0 '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0xff, /* 11111111 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 209 0xd1 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xff, /* 11111111 */\n\t0x00, /* 00000000 */\n\t0xff, /* 11111111 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 210 0xd2 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xff, /* 11111111 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 211 0xd3 '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x3f, /* 00111111 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 212 0xd4 '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x1f, /* 00011111 */\n\t0x18, /* 00011000 */\n\t0x1f, /* 00011111 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 213 0xd5 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x1f, /* 00011111 */\n\t0x18, /* 00011000 */\n\t0x1f, /* 00011111 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 214 0xd6 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x3f, /* 00111111 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 215 0xd7 '�' */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0xff, /* 11111111 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\n\t/* 216 0xd8 '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0xff, /* 11111111 */\n\t0x18, /* 00011000 */\n\t0xff, /* 11111111 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 217 0xd9 '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0xf8, /* 11111000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 218 0xda '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x1f, /* 00011111 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 219 0xdb '�' */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\n\t/* 220 0xdc '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\n\t/* 221 0xdd '�' */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\t0xf0, /* 11110000 */\n\n\t/* 222 0xde '�' */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\t0x0f, /* 00001111 */\n\n\t/* 223 0xdf '�' */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0xff, /* 11111111 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 224 0xe0 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x76, /* 01110110 */\n\t0xdc, /* 11011100 */\n\t0xd8, /* 11011000 */\n\t0xd8, /* 11011000 */\n\t0xd8, /* 11011000 */\n\t0xdc, /* 11011100 */\n\t0x76, /* 01110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 225 0xe1 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x78, /* 01111000 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xcc, /* 11001100 */\n\t0xd8, /* 11011000 */\n\t0xcc, /* 11001100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xcc, /* 11001100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 226 0xe2 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0xc0, /* 11000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 227 0xe3 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 228 0xe4 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0xc6, /* 11000110 */\n\t0x60, /* 01100000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 229 0xe5 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0xd8, /* 11011000 */\n\t0xd8, /* 11011000 */\n\t0xd8, /* 11011000 */\n\t0xd8, /* 11011000 */\n\t0xd8, /* 11011000 */\n\t0x70, /* 01110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 230 0xe6 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x7c, /* 01111100 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0xc0, /* 11000000 */\n\t0x00, /* 00000000 */\n\n\t/* 231 0xe7 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x76, /* 01110110 */\n\t0xdc, /* 11011100 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 232 0xe8 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0x18, /* 00011000 */\n\t0x3c, /* 00111100 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x3c, /* 00111100 */\n\t0x18, /* 00011000 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 233 0xe9 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xfe, /* 11111110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x6c, /* 01101100 */\n\t0x38, /* 00111000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 234 0xea '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0xee, /* 11101110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 235 0xeb '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x1e, /* 00011110 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x0c, /* 00001100 */\n\t0x3e, /* 00111110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x66, /* 01100110 */\n\t0x3c, /* 00111100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 236 0xec '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0xdb, /* 11011011 */\n\t0xdb, /* 11011011 */\n\t0xdb, /* 11011011 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 237 0xed '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x03, /* 00000011 */\n\t0x06, /* 00000110 */\n\t0x7e, /* 01111110 */\n\t0xdb, /* 11011011 */\n\t0xdb, /* 11011011 */\n\t0xf3, /* 11110011 */\n\t0x7e, /* 01111110 */\n\t0x60, /* 01100000 */\n\t0xc0, /* 11000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 238 0xee '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x1c, /* 00011100 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x7c, /* 01111100 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x60, /* 01100000 */\n\t0x30, /* 00110000 */\n\t0x1c, /* 00011100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 239 0xef '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7c, /* 01111100 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0xc6, /* 11000110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 240 0xf0 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0xfe, /* 11111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 241 0xf1 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x7e, /* 01111110 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 242 0xf2 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x0c, /* 00001100 */\n\t0x06, /* 00000110 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 243 0xf3 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x30, /* 00110000 */\n\t0x60, /* 01100000 */\n\t0x30, /* 00110000 */\n\t0x18, /* 00011000 */\n\t0x0c, /* 00001100 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 244 0xf4 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x0e, /* 00001110 */\n\t0x1b, /* 00011011 */\n\t0x1b, /* 00011011 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\n\t/* 245 0xf5 '�' */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0xd8, /* 11011000 */\n\t0xd8, /* 11011000 */\n\t0xd8, /* 11011000 */\n\t0x70, /* 01110000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 246 0xf6 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 247 0xf7 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x76, /* 01110110 */\n\t0xdc, /* 11011100 */\n\t0x00, /* 00000000 */\n\t0x76, /* 01110110 */\n\t0xdc, /* 11011100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 248 0xf8 '�' */\n\t0x00, /* 00000000 */\n\t0x38, /* 00111000 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x38, /* 00111000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 249 0xf9 '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 250 0xfa '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x18, /* 00011000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 251 0xfb '�' */\n\t0x00, /* 00000000 */\n\t0x0f, /* 00001111 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0x0c, /* 00001100 */\n\t0xec, /* 11101100 */\n\t0x6c, /* 01101100 */\n\t0x6c, /* 01101100 */\n\t0x3c, /* 00111100 */\n\t0x1c, /* 00011100 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 252 0xfc '�' */\n\t0x00, /* 00000000 */\n\t0x6c, /* 01101100 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x36, /* 00110110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 253 0xfd '�' */\n\t0x00, /* 00000000 */\n\t0x3c, /* 00111100 */\n\t0x66, /* 01100110 */\n\t0x0c, /* 00001100 */\n\t0x18, /* 00011000 */\n\t0x32, /* 00110010 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 254 0xfe '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x7e, /* 01111110 */\n\t0x7e, /* 01111110 */\n\t0x7e, /* 01111110 */\n\t0x7e, /* 01111110 */\n\t0x7e, /* 01111110 */\n\t0x7e, /* 01111110 */\n\t0x7e, /* 01111110 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\n\t/* 255 0xff '�' */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n\t0x00, /* 00000000 */\n};\n"
  },
  {
    "path": "kernel/arch/i386/earlycon/uart.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n#include <console/earlycon.h>\n#include <cpu/io.h>\n#include <mm/mm.h>\n\n#define SERIAL_MMIO 0\n\n#if SERIAL_MMIO\nstatic struct ioaddr earlycon_uart_ioaddr = {\n    .addr = 0xCF00B000,\n    .type = IOADDR_MMIO32,\n};\n#else\nstatic struct ioaddr earlycon_uart_ioaddr = {\n    .addr = 0x3F8,\n    .type = IOADDR_PORT,\n};\n#endif\n\n#define UART_IER    1\n#define UART_FCR    2\n#define UART_LCR    3\n#define UART_MCR    4\n#define UART_DLL    0\n#define UART_DLH    1\n#define UART_LCR_DLAB    0x80\n\nstatic void serial_init(void)\n{\n    io_out8(&earlycon_uart_ioaddr, UART_IER, 0x00);    /* Disable all interrupts */\n    io_out8(&earlycon_uart_ioaddr, UART_FCR, 0x00);    /* Disable FIFO */\n    io_out8(&earlycon_uart_ioaddr, UART_LCR, 0x03);    /* 8 bits, no parity, one stop bit */\n    io_out8(&earlycon_uart_ioaddr, UART_MCR, 0x03);    /* RTS + DTR */\n\n    uint8_t lcr = io_in8(&earlycon_uart_ioaddr, UART_LCR);\n    io_out8(&earlycon_uart_ioaddr, UART_LCR, lcr | UART_LCR_DLAB);  /* Enable DLAB */\n    io_out8(&earlycon_uart_ioaddr, UART_DLL, 0x18);    /* Set divisor to 1 (lo byte) 115200 baud */\n    io_out8(&earlycon_uart_ioaddr, UART_DLH, 0x00);    /*                  (hi byte)            */\n    io_out8(&earlycon_uart_ioaddr, UART_LCR, lcr & ~UART_LCR_DLAB); /* Disable DLAB */\n}\n\nstatic int serial_tx_empty(void)\n{\n    return io_in8(&earlycon_uart_ioaddr, 5) & 0x20;\n}\n\nstatic int serial_chr(char chr)\n{\n    if (chr == '\\n')\n        serial_chr('\\r');\n\n    while (!serial_tx_empty());\n\n    io_out8(&earlycon_uart_ioaddr, 0, chr);\n\n    return 1;\n}\n\nstatic int serial_str(char *str)\n{\n    int ret = 0;\n\n    while (*str) {\n        ++ret;\n        ret += serial_chr(*str++);\n    }\n\n    return ret;\n}\n\nstatic int earlycon_uart_puts(char *s)\n{\n    return serial_str(s);\n}\n\nstatic int earlycon_uart_putc(char c)\n{\n    return serial_chr(c);\n}\n\nstatic void earlycon_uart_init(void)\n{\n#if SERIAL_MMIO\n    pmman.map_to(0x9000B000, 0xCF00B000, PAGE_SIZE, VM_KRW);\n#endif\n    serial_init();\n\n    /* Assume a terminal, clear formatting */\n    serial_str(\"\\033[0m\");\n}\n\nstruct earlycon earlycon_uart = {\n    .init = earlycon_uart_init,\n    .putc = earlycon_uart_putc,\n    .puts = earlycon_uart_puts,\n};\n"
  },
  {
    "path": "kernel/arch/i386/earlycon/vga.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n#include <console/earlycon.h>\n#include <cpu/io.h>\n\nstatic char *vga_start = (char*) 0xC00B8000;\nstatic char *vga = (char*) 0xC00B8000;\n\nstruct ioaddr vga_ioaddr = {\n    .addr = 0x3D4,\n    .type = IOADDR_PORT,\n};\n\nstatic void earlycon_vga_scroll(int n)\n{\n    memcpy(vga_start, vga_start + 160 * n, 160 * (25 - n));\n    vga = vga_start + 160 * (25 - n);\n\n    int i;\n    for (i = 0; i < 80 * n; ++i) {\n        vga[2 * i + 0] = '\\0';\n        vga[2 * i + 1] = 0x07;\n    }\n}\n\nstatic int earlycon_vga_putc(char c)\n{\n    if (c) {\n        if (c == '\\n') {\n            vga = vga_start + (vga - vga_start) / 160 * 160 + 160;\n            if (vga - vga_start >= 160 * 25)\n                earlycon_vga_scroll(1);\n            return 1;\n        }\n\n        *vga = c;\n        vga += 2;\n        return 1;\n    }\n\n    return 0;\n}\n\nstatic int earlycon_vga_puts(char *s)\n{\n    char *_s = s;\n    while (*s) {\n        *vga = *s++;\n        vga += 2;\n    }\n\n    return (int)(s - _s);\n}\n\nstatic void earlycon_vga_init()\n{\n    io_out8(&vga_ioaddr, 0x00, 0x0F);\n    io_out8(&vga_ioaddr, 0x01, 0xFF);\n    io_out8(&vga_ioaddr, 0x00, 0x0E);\n    io_out8(&vga_ioaddr, 0x01, 0xFF);\n\n    unsigned i;\n    for (i = 0; i < 80*25; ++i)\n        vga_start[2*i] = 0;\n}\n\nstruct earlycon earlycon_vga = {\n    .init = earlycon_vga_init,\n    .putc = earlycon_vga_putc,\n    .puts = earlycon_vga_puts,\n};\n"
  },
  {
    "path": "kernel/arch/i386/include/boot/boot.h",
    "content": "#ifndef _X86_BOOT_H\n#define _X86_BOOT_H\n\n#include_next <boot/boot.h>\n#include <boot/multiboot.h>\n\n#ifdef MULTIBOOT_GFX\n#include <dev/fbdev.h>\n#include <video/vbe.h>\n#include <video/vesa.h>\n#endif\n\nstatic inline int get_multiboot_mmap_count(multiboot_info_t *info)\n{\n    int count = 0;\n    uint32_t _mmap = info->mmap_addr;\n    multiboot_mmap_t *mmap = (multiboot_mmap_t *)(uintptr_t)_mmap;\n    uint32_t mmap_end = _mmap + info->mmap_length;\n\n    while (_mmap < mmap_end) {\n        //if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE)\n        ++count;\n        _mmap += mmap->size + sizeof(uint32_t);\n        mmap   = (multiboot_mmap_t *)(uintptr_t) _mmap;\n    }\n    return count;\n}\n\nstatic inline void \nbuild_multiboot_mmap(multiboot_info_t *info, mmap_t *boot_mmap)\n{\n    uint32_t _mmap = info->mmap_addr;\n    multiboot_mmap_t *mmap = (multiboot_mmap_t *)(uintptr_t) _mmap;\n    uint32_t mmap_end = _mmap + info->mmap_length;\n\n    while (_mmap < mmap_end) {\n\n        *boot_mmap = (mmap_t) {\n            .type  = mmap->type,\n            .start = mmap->addr,\n            .end = mmap->addr + mmap->len\n        };\n\n        ++boot_mmap;\n        _mmap += mmap->size + sizeof(uint32_t);\n        mmap   = (multiboot_mmap_t *)(uintptr_t) _mmap;\n    }\n}\n\nstatic inline void \nbuild_multiboot_modules(multiboot_info_t *info, module_t *modules)\n{\n    multiboot_module_t *mods = (multiboot_module_t *)(uintptr_t) info->mods_addr;\n\n    for (unsigned i = 0; i < info->mods_count; ++i) {\n        modules[i] = (module_t) {\n            .addr = (void *) VMA((uintptr_t) mods[i].mod_start),\n            .size = mods[i].mod_end - mods[i].mod_start,\n            .cmdline = (char *) VMA((uintptr_t) mods[i].cmdline)\n        };\n    }\n}\n\nstatic inline struct boot *process_multiboot_info(multiboot_info_t *info)\n{\n    static struct boot boot;\n\n    boot.cmdline = (char *) VMA((uintptr_t) info->cmdline);\n    boot.total_mem = info->mem_lower + info->mem_upper;\n\n    if (info->flags & MULTIBOOT_INFO_ELF_SHDR) {\n        boot.shdr = (struct elf32_shdr *) VMA((uintptr_t) info->u.elf_sec.addr);\n        boot.shdr_num = info->u.elf_sec.num;\n\n        struct elf32_shdr *symtab = NULL;\n        struct elf32_shdr *strtab = NULL;\n\n        for (size_t i = 0; i < boot.shdr_num; ++i) {\n            struct elf32_shdr *shdr = &boot.shdr[i];\n\n            if (shdr->sh_type == SHT_SYMTAB) {\n                symtab = shdr;\n                symtab->sh_addr = VMA((uintptr_t) symtab->sh_addr);\n                boot.symtab = symtab;\n                boot.symnum = shdr->sh_size / sizeof(struct elf32_sym);\n            }\n\n            if (shdr->sh_type == SHT_STRTAB && !strtab) {\n                strtab = shdr;\n                strtab->sh_addr = VMA((uintptr_t) strtab->sh_addr);\n                boot.strtab = strtab;\n            }\n        }\n    }\n\n    boot.mmap_count = get_multiboot_mmap_count(info);\n    static mmap_t mmap[32];\n    boot.mmap = mmap;\n    build_multiboot_mmap(info, boot.mmap);\n\n#ifdef MULTIBOOT_GFX\n    /* We report video memory as mmap region */\n    boot.mmap[boot.mmap_count].type = MMAP_RESERVED;\n\n    struct vbe_info_block  *vinfo = (struct vbe_info_block *)(uintptr_t)  info->vbe_control_info;\n    struct mode_info_block *minfo = (struct mode_info_block *)(uintptr_t) info->vbe_mode_info;\n\n    boot.mmap[boot.mmap_count].start = minfo->phys_base_ptr;\n    boot.mmap[boot.mmap_count].end   = minfo->phys_base_ptr + minfo->y_resolution * minfo->lin_bytes_per_scanline;\n\n    boot.mmap_count++;\n\n    extern void earlycon_fb_register(uintptr_t, uint32_t, uint32_t, uint32_t, uint32_t);\n\n    uintptr_t vaddr    = minfo->phys_base_ptr;\n    uint32_t  scanline = minfo->lin_bytes_per_scanline;\n    uint32_t  yres     = minfo->y_resolution;\n    uint32_t  xres     = minfo->x_resolution;\n    uint32_t  depth    = minfo->bits_per_pixel;\n\n    earlycon_fb_register(vaddr, scanline, yres, xres, depth);\n\n    static struct fbdev_vesa data;\n    data.vbe_info  = (struct vbe_info_block *) VMA(vinfo);\n    data.mode_info = (struct mode_info_block *) VMA(minfo);\n\n    /* And register fbdev of type `vesa' */\n    fbdev_register(FBDEV_TYPE_VESA, &data);\n#endif\n\n    boot.modules_count = info->mods_count;\n    static module_t modules[32];\n    boot.modules = modules;\n    build_multiboot_modules(info, boot.modules);\n\n    return &boot;\n}\n\n#endif /* _X86_BOOT_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/boot/multiboot.h",
    "content": "/* multiboot.h - Multiboot header file. */\n/* Copyright (C) 1999,2003,2007,2008,2009  Free Software Foundation, Inc.\n *\n *  Permission is hereby granted, free of charge, to any person obtaining a copy\n *  of this software and associated documentation files (the \"Software\"), to\n *  deal in the Software without restriction, including without limitation the\n *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n *  sell copies of the Software, and to permit persons to whom the Software is\n *  furnished to do so, subject to the following conditions:\n *\n *  The above copyright notice and this permission notice shall be included in\n *  all copies or substantial portions of the Software.\n *\n *  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n *  DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n *  IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef MULTIBOOT_HEADER\n#define MULTIBOOT_HEADER 1\n\n/* How many bytes from the start of the file we search for the header. */\n#define MULTIBOOT_SEARCH                        8192\n\n/* The magic field should contain this. */\n#define MULTIBOOT_HEADER_MAGIC                  0x1BADB002\n\n/* This should be in %eax. */\n#define MULTIBOOT_BOOTLOADER_MAGIC              0x2BADB002\n\n/* The bits in the required part of flags field we don't support. */\n#define MULTIBOOT_UNSUPPORTED                   0x0000fffc\n\n/* Alignment of multiboot modules. */\n#define MULTIBOOT_MOD_ALIGN                     0x00001000\n\n/* Alignment of the multiboot info structure. */\n#define MULTIBOOT_INFO_ALIGN                    0x00000004\n\n/* Flags set in the 'flags' member of the multiboot header. */\n\n/* Align all boot modules on i386 page (4KB) boundaries. */\n#define MULTIBOOT_PAGE_ALIGN                    0x00000001\n\n/* Must pass memory information to OS. */\n#define MULTIBOOT_MEMORY_INFO                   0x00000002\n\n/* Must pass video information to OS. */\n#define MULTIBOOT_VIDEO_MODE                    0x00000004\n\n/* This flag indicates the use of the address fields in the header. */\n#define MULTIBOOT_AOUT_KLUDGE                   0x00010000\n\n/* Flags to be set in the 'flags' member of the multiboot info structure. */\n\n/* is there basic lower/upper memory information? */\n#define MULTIBOOT_INFO_MEMORY                   0x00000001\n/* is there a boot device set? */\n#define MULTIBOOT_INFO_BOOTDEV                  0x00000002\n/* is the command-line defined? */\n#define MULTIBOOT_INFO_CMDLINE                  0x00000004\n/* are there modules to do something with? */\n#define MULTIBOOT_INFO_MODS                     0x00000008\n\n/* These next two are mutually exclusive */\n\n/* is there a symbol table loaded? */\n#define MULTIBOOT_INFO_AOUT_SYMS                0x00000010\n/* is there an ELF section header table? */\n#define MULTIBOOT_INFO_ELF_SHDR                 0X00000020\n\n/* is there a full memory map? */\n#define MULTIBOOT_INFO_MEM_MAP                  0x00000040\n\n/* Is there drive info? */\n#define MULTIBOOT_INFO_DRIVE_INFO               0x00000080\n\n/* Is there a config table? */\n#define MULTIBOOT_INFO_CONFIG_TABLE             0x00000100\n\n/* Is there a boot loader name? */\n#define MULTIBOOT_INFO_BOOT_LOADER_NAME         0x00000200\n\n/* Is there a APM table? */\n#define MULTIBOOT_INFO_APM_TABLE                0x00000400\n\n/* Is there video information? */\n#define MULTIBOOT_INFO_VIDEO_INFO               0x00000800\n\n#ifndef ASM_FILE\n\n#include <stdint.h>\n\nstruct multiboot_header\n{\n  /* Must be MULTIBOOT_MAGIC - see above. */\n  uint32_t magic;\n\n  /* Feature flags. */\n  uint32_t flags;\n\n  /* The above fields plus this one must equal 0 mod 2^32. */\n  uint32_t checksum;\n\n  /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */\n  uint32_t header_addr;\n  uint32_t load_addr;\n  uint32_t load_end_addr;\n  uint32_t bss_end_addr;\n  uint32_t entry_addr;\n\n  /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */\n  uint32_t mode_type;\n  uint32_t width;\n  uint32_t height;\n  uint32_t depth;\n};\n\n/* The symbol table for a.out. */\nstruct multiboot_aout_symbol_table\n{\n  uint32_t tabsize;\n  uint32_t strsize;\n  uint32_t addr;\n  uint32_t reserved;\n};\ntypedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;\n\n/* The section header table for ELF. */\nstruct multiboot_elf_section_header_table\n{\n  uint32_t num;\n  uint32_t size;\n  uint32_t addr;\n  uint32_t shndx;\n};\ntypedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;\n\nstruct multiboot_info\n{\n  /* Multiboot info version number */\n  uint32_t flags;\n\n  /* Available memory from BIOS */\n  uint32_t mem_lower;\n  uint32_t mem_upper;\n\n  /* \"root\" partition */\n  uint32_t boot_device;\n\n  /* Kernel command line */\n  uint32_t cmdline;\n\n  /* Boot-Module list */\n  uint32_t mods_count;\n  uint32_t mods_addr;\n\n  union\n  {\n    multiboot_aout_symbol_table_t aout_sym;\n    multiboot_elf_section_header_table_t elf_sec;\n  } u;\n\n  /* Memory Mapping buffer */\n  uint32_t mmap_length;\n  uint32_t mmap_addr;\n\n  /* Drive Info buffer */\n  uint32_t drives_length;\n  uint32_t drives_addr;\n\n  /* ROM configuration table */\n  uint32_t config_table;\n\n  /* Boot Loader Name */\n  uint32_t boot_loader_name;\n\n  /* APM table */\n  uint32_t apm_table;\n\n  /* Video */\n  uint32_t vbe_control_info;\n  uint32_t vbe_mode_info;\n  uint16_t vbe_mode;\n  uint16_t vbe_interface_seg;\n  uint16_t vbe_interface_off;\n  uint16_t vbe_interface_len;\n};\ntypedef struct multiboot_info multiboot_info_t;\n\nstruct multiboot_mmap_entry\n{\n  uint32_t size;\n  uint64_t addr;\n  uint64_t len;\n#define MULTIBOOT_MEMORY_AVAILABLE              1\n#define MULTIBOOT_MEMORY_RESERVED               2\n  uint32_t type;\n} __attribute__((packed));\ntypedef struct multiboot_mmap_entry multiboot_mmap_t;\n\nstruct multiboot_mod_list\n{\n  /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */\n  uint32_t mod_start;\n  uint32_t mod_end;\n\n  /* Module command line */\n  uint32_t cmdline;\n\n  /* padding to take it to 16 bytes (must be zero) */\n  uint32_t pad;\n};\ntypedef struct multiboot_mod_list multiboot_module_t;\n\nextern uint32_t multiboot_signature;\nextern uint32_t multiboot_info;\n\n#endif /* ! ASM_FILE */\n\n#endif /* ! MULTIBOOT_HEADER */\n"
  },
  {
    "path": "kernel/arch/i386/include/config.h",
    "content": "#ifndef _X86_CONFIG_H\n#define _X86_CONFIG_H\n\n#if 1\n#define ARCH X86\n#define ARCH_X86\n#define ARCH_BITS 32\n#define MULTIBOOT_GFX   1\n\n#define UTSNAME_MACHINE  \"i386\"\n#else\n#define ARCH X86_64\n#define ARCH_X86_64\n#define ARCH_BITS 64\n#define MULTIBOOT_GFX   1\n\n#define UTSNAME_MACHINE  \"x86_64\"\n#endif\n\n#include_next <config.h>\n\n#endif /* ! _X86_CONFIG_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/core/_string.h",
    "content": "#ifndef _X86_STRING_H\n#define _X86_STRING_H\n\n#include <core/system.h>\n#include <mm/mm.h>\n\nstatic inline void *memcpy(void *dst, const void *src, size_t n)\n{\n    asm volatile (\n        \"cld;\"\n        \"rep movsd;\"\n#if ARCH_BITS==32\n        \"mov %3, %%ecx;\"\n#else\n        \"movq %3, %%rcx;\"\n#endif\n        \"rep movsb;\"\n        :\"=S\"((int){0}), \"=D\"((int){0}), \"=c\"((int){0})\n        :\"g\"(n & 3), \"S\"(src), \"D\"(dst), \"c\"(n >> 2)\n        :\"memory\");\n    return dst;\n}\n\nstatic inline void *memset(void *s, int _c, size_t n)\n{\n    uint8_t c = _c & 0xFF;\n    uint32_t f = (c << 0x00) | (c << 0x08) | (c << 0x10) | (c << 0x18);\n    asm volatile (\n        \"cld;\"\n        \"rep stosl;\"\n#if ARCH_BITS==32\n        \"mov %2, %%ecx;\"\n#else\n        \"movq %2, %%rcx;\"\n#endif\n        \"rep stosb;\"\n        :\"=D\"((int){0}), \"=c\"((int){0})\n        :\"g\"(n & 3), \"D\"(s), \"a\"(f), \"c\"(n >> 2)\n        :\"memory\");\n\n    return s;\n}\n\n\nstatic inline int strncmp(const char *s1, const char *s2, size_t n)\n{\n    char ret = 0;\n    asm volatile(\n        \"cld;\"\n        \"repe cmpsd;\"\n        \"jnz 1f;\"\n        \"mov %4, %%ecx;\"\n        \"repe cmpsb;\"\n        \"jnz 2f;\"\n        \"1:\"\n            /* Before you start blaming me for this awful solution, I tried\n             * setting direction flag and scanning the string backwards but\n             * for some reason it does not work, if you know why please elaborate!\n             */\n            \"mov $4, %%ecx;\"\n            \"sub $4, %%esi;\"\n            \"sub $4, %%edi;\"\n            \"repe cmpsb;\"\n        \"2:\"\n            \"dec %%esi;\"\n            \"dec %%edi;\"\n            \"mov (%%esi), %%cl;\"\n            \"subb (%%edi), %%cl;\"\n            \"mov %%cl, %0;\"\n        :\"=g\"(ret), \"=S\"((int){0}), \"=D\"((int){0}), \"=c\"((int){0})\n        :\"g\"(n & 3), \"S\"(s1),\"D\"(s2), \"c\"(n >> 2));\n\n    return ret;\n}\n\nint snprintf(char *s, size_t n, const char *fmt, ...);\n\nstatic inline int strcmp(const char *s1, const char *s2)\n{\n    while (*s1 && *s2 && *s1 == *s2) {s1++; s2++;}\n    return *s1 - *s2;\n}\n\nstatic inline int strlen(const char *s)\n{\n    const char *_s = s;\n    while (*_s) _s++;\n    return _s - s;\n}\n\nstatic inline char *strdup(const char *s)\n{\n    int len = strlen(s);\n    char *ret = kmalloc(len + 1);\n    memcpy(ret, s, len + 1);\n    return ret;\n}\n\nstatic inline char *strcpy(char *dst, const char *src)\n{\n    char *retval = dst;\n    \n    while (*src)\n        *dst++ = *src++;\n    *dst = *src;    /* NULL terminator */\n\n    return retval;\n}\n\nstatic inline char **tokenize(const char *s, char c)\n{\n    if (!s || !*s) return NULL;\n\n    while (*s == c)\n        ++s;\n\n    char *tokens = strdup(s);\n    int len = strlen(s);\n\n    if (!len) {\n        char **ret = kmalloc(sizeof(char *));\n        *ret = NULL;\n        return ret;\n    }\n\n    int i, count = 0;\n    for (i = 0; i < len; ++i) {\n        if (tokens[i] == c) {\n            tokens[i] = 0;\n            ++count;\n        }\n    }\n\n    if (s[len-1] != c)\n        ++count;\n    \n    char **ret = kmalloc(sizeof(char *) * (count + 1));\n\n    int j = 0;\n    ret[j++] = tokens;\n\n    for (i = 0; i < strlen(s) - 1; ++i)\n        if (tokens[i] == 0)\n            ret[j++] = &tokens[i+1];\n\n    ret[j] = NULL;\n\n    return ret;\n}\n\nstatic inline void free_tokens(char **ptr)\n{\n    if (!ptr) return;\n    if (*ptr)\n        kfree(*ptr);\n    kfree(ptr);\n}\n\n#endif /* !_X86_STRING_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/core/arch.h",
    "content": "#ifndef _X86_ARCH_H\n#define _X86_ARCH_H\n\n#include <cpu/cpu.h>\n\n#define X86_SS      (0x20 | 3)\n#define X86_EFLAGS  (0x200)\n#define X86_CS      (0x18 | 3)\n\nstruct x86_thread {\n    uintptr_t   kstack; /* Kernel stack */\n\n#if ARCH_BITS==32\n    uintptr_t   eip;\n    uintptr_t   esp;\n    uintptr_t   ebp;\n    uintptr_t   eflags;\n    uintptr_t   eax;    /* For syscall return if thread is not spawned */\n#else\n    uintptr_t   rip;\n    uintptr_t   rsp;\n    uintptr_t   rbp;\n    uintptr_t   rflags;\n    uintptr_t   rax;    /* For syscall return if thread is not spawned */\n#endif\n\n    struct x86_regs *regs;  /* Pointer to registers on the stack */\n    void *fpu_context;\n\n    /* Flags */\n    int fpu_enabled;\n    //int isr;\n};\n\nMALLOC_DECLARE(M_X86_THREAD);\nMALLOC_DECLARE(M_KERN_STACK);\n\nvoid arch_syscall(struct x86_regs *r);\n\n#define USER_STACK      (0xC0000000UL)\n#define USER_STACK_BASE (USER_STACK - USER_STACK_SIZE)\n\n#define KERN_STACK_SIZE (8192U)  /* 8 KiB */\n\nstatic inline void arch_interrupts_enable(void)\n{\n    asm volatile (\"sti\");\n}\n\nstatic inline void arch_interrupts_disable(void)\n{\n    asm volatile (\"cli\");\n}\n\nvoid x86_jump_user(uintptr_t eax, uintptr_t eip, uintptr_t cs, uintptr_t eflags, uintptr_t esp, uintptr_t ss) __attribute__((noreturn));\nvoid x86_goto(uintptr_t eip, uintptr_t ebp, uintptr_t esp) __attribute__((noreturn));\n\n#include_next <core/arch.h>\n\n#endif /* ! _X86_ARCH_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/core/panic.h",
    "content": "#ifndef _PANIC_H\n#define _PANIC_H\n\n#include <core/system.h>\n#include <core/arch.h>\n#include <core/printk.h>\n\n#define __PANIC_MSG \"Bailing out. You are on your own. Good luck.\"\n\nextern int __printing_trace;\n\n#define panic(s) \\\n{\\\n    printk(\"KERNEL PANIC: %s\\n%s[%d]: %s\\n\", \\\n        s, __FILE__, __LINE__, __func__);\\\n    if (__printing_trace) {\\\n        printk(\"Panicked while panicking :)\\n\"); \\\n    } else {\\\n        arch_stack_trace(); \\\n        printk(\"%s\\n\", __PANIC_MSG); \\\n    } \\\n    asm(\"cli\"); \\\n    for(;;); \\\n}\\\n\n#endif /* ! _PANIC_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/core/platform.h",
    "content": "#ifndef _X86_CORE_PLATFORM_H\n#define _X86_CORE_PLATFORM_H\n\nint platform_init(void);\nuint32_t platform_timer_setup(size_t period_ns, void (*handler)());\n\n#endif /* ! _X86_CORE_PLATFORM_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/core/system.h",
    "content": "#ifndef _X86_SYSTEM_H\n#define _X86_SYSTEM_H\n\n#include <config.h>\n\n#define PAGE_SIZE   (0x1000)\n#define PAGE_MASK   (PAGE_SIZE - 1)\n#define PAGE_SHIFT  (12)\n\n#if ARCH_BITS==32\n#define TABLE_SIZE  (0x400 * PAGE_SIZE)\n#define TABLE_MASK  (TABLE_SIZE - 1)\n#else\n#define TABLE_SIZE  (0x200 * PAGE_SIZE)\n#define TABLE_MASK  (TABLE_SIZE - 1)\n#endif\n\n#define KERNEL_BREAK 0xC0000000\n\n#include_next <core/system.h>\n\n#endif /* ! _X86_SYSTEM_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/cpu/cpu.h",
    "content": "#ifndef _X86_CPU_H\n#define _X86_CPU_H\n\n#include <core/system.h>\n#include <cpu/cpuid.h>\n\nstruct x86_regs {\n#if ARCH_BITS==32\n    uint32_t\n    edi, esi, ebp, ebx, ecx, edx, eax,\n    eip, cs, eflags, esp, ss;\n#else\n    uint64_t\n    r15, r14, r13, r12, r11, r10, r9, r8,\n    rdi, rsi, rbp, rbx, rcx, rdx, rax,\n    rip, cs, rflags, rsp, ss;\n#endif\n};\n\nstatic inline void x86_dump_registers(struct x86_regs *regs)\n{\n    printk(\"Registers dump:\\n\");\n#if ARCH_BITS==32\n    printk(\"edi = %p\\n\", regs->edi);\n    printk(\"esi = %p\\n\", regs->esi);\n    printk(\"ebp = %p\\n\", regs->ebp);\n    printk(\"ebx = %p\\n\", regs->ebx);\n    printk(\"ecx = %p\\n\", regs->ecx);\n    printk(\"edx = %p\\n\", regs->edx);\n    printk(\"eax = %p\\n\", regs->eax);\n    printk(\"eip = %p\\n\", regs->eip);\n    printk(\"cs  = %p\\n\", regs->cs );\n    printk(\"eflags = %p\\n\", regs->eflags);\n    printk(\"esp = %p\\n\", regs->esp);\n    printk(\"ss  = %p\\n\", regs->ss);\n#else\n    printk(\"r15 = %p\\n\", regs->r15);\n    printk(\"r14 = %p\\n\", regs->r14);\n    printk(\"r13 = %p\\n\", regs->r13);\n    printk(\"r12 = %p\\n\", regs->r12);\n    printk(\"r11 = %p\\n\", regs->r11);\n    printk(\"r10 = %p\\n\", regs->r10);\n    printk(\"r9  = %p\\n\", regs->r9);\n    printk(\"r8  = %p\\n\", regs->r8);\n    printk(\"rdi = %p\\n\", regs->rdi);\n    printk(\"rsi = %p\\n\", regs->rsi);\n    printk(\"rbp = %p\\n\", regs->rbp);\n    printk(\"rbx = %p\\n\", regs->rbx);\n    printk(\"rcx = %p\\n\", regs->rcx);\n    printk(\"rdx = %p\\n\", regs->rdx);\n    printk(\"rax = %p\\n\", regs->rax);\n    printk(\"rip = %p\\n\", regs->rip);\n    printk(\"cs  = %p\\n\", regs->cs );\n    printk(\"rflags = %p\\n\", regs->rflags);\n    printk(\"rsp = %p\\n\", regs->rsp);\n    printk(\"ss  = %p\\n\", regs->ss);\n#endif\n}\n\nstruct x86_cpu {\n    int id;\n    union  x86_cpuid_vendor   vendor;\n    //struct x86_cpuid_features features;\n};\n\n/* CR0 */\n#define CR0_PG  _BV(31)\n#define CR0_MP  _BV(1)\n#define CR0_EM  _BV(2)\n#define CR0_NE  _BV(5)\n\n/* CR4 */\n#define CR4_PSE _BV(4)\n\n/* CPU function */\nstatic inline uintptr_t read_cr0(void)\n{\n    uint32_t retval = 0;\n#if ARCH_BITS==32\n    asm volatile(\"mov %%cr0, %%eax\":\"=a\"(retval));\n#else\n    asm volatile(\"movq %%cr0, %%rax\":\"=a\"(retval));\n#endif\n    return retval;\n}\n\nstatic inline uintptr_t read_cr1(void)\n{\n    uintptr_t retval = 0;\n#if ARCH_BITS==32\n    asm volatile(\"mov %%cr1, %%eax\":\"=a\"(retval));\n#else\n    asm volatile(\"movq %%cr1, %%rax\":\"=a\"(retval));\n#endif\n    return retval;\n}\n\nstatic inline uintptr_t read_cr2(void)\n{\n    uintptr_t retval = 0;\n#if ARCH_BITS==32\n    asm volatile(\"mov %%cr2, %%eax\":\"=a\"(retval));\n#else\n    asm volatile(\"movq %%cr2, %%rax\":\"=a\"(retval));\n#endif\n    return retval;\n}\n\nstatic inline uintptr_t read_cr3(void)\n{\n    uintptr_t retval = 0;\n#if ARCH_BITS==32\n    asm volatile(\"mov %%cr3, %%eax\":\"=a\"(retval));\n#else\n    asm volatile(\"movq %%cr3, %%rax\":\"=a\"(retval));\n#endif\n    return retval;\n}\n\nstatic inline uintptr_t read_cr4(void)\n{\n    uintptr_t retval = 0;\n#if ARCH_BITS==32\n    asm volatile(\"mov %%cr4, %%eax\":\"=a\"(retval));\n#else\n    asm volatile(\"movq %%cr4, %%rax\":\"=a\"(retval));\n#endif\n    return retval;\n}\n\nstatic inline void write_cr0(uintptr_t val)\n{\n#if ARCH_BITS==32\n    asm volatile(\"mov %%eax, %%cr0\"::\"a\"(val));\n#else\n    asm volatile(\"movq %%rax, %%cr0\"::\"a\"(val));\n#endif\n}\n\nstatic inline void write_cr1(uintptr_t val)\n{\n#if ARCH_BITS==32\n    asm volatile(\"mov %%eax, %%cr1\"::\"a\"(val));\n#else\n    asm volatile(\"movq %%rax, %%cr1\"::\"a\"(val));\n#endif\n}\n\nstatic inline void write_cr2(uintptr_t val)\n{\n#if ARCH_BITS==32\n    asm volatile(\"mov %%eax, %%cr2\"::\"a\"(val));\n#else\n    asm volatile(\"movq %%rax, %%cr2\"::\"a\"(val));\n#endif\n}\n\nstatic inline void write_cr3(uintptr_t val)\n{\n#if ARCH_BITS==32\n    asm volatile(\"mov %%eax, %%cr3\"::\"a\"(val));\n#else\n    asm volatile(\"movq %%rax, %%cr3\"::\"a\"(val));\n#endif\n}\n\nstatic inline void write_cr4(uintptr_t val)\n{\n#if ARCH_BITS==32\n    asm volatile(\"mov %%eax, %%cr4\"::\"a\"(val));\n#else\n    asm volatile(\"movq %%rax, %%cr4\"::\"a\"(val));\n#endif\n}\n\n/* cpu/gdt.c */\nvoid x86_gdt_setup(void);\nvoid x86_tss_setup(uintptr_t sp);\nvoid x86_kernel_stack_set(uintptr_t sp);\n\n/* cpu/idt.c */\nvoid x86_idt_setup(void);\nvoid x86_idt_gate_set(uint32_t id, uintptr_t offset);\nvoid x86_idt_gate_user_set(uint32_t id, uintptr_t offset);\n\n/* cpu/isr.c */\nvoid x86_isr_setup(void);\n\n/* cpu/fpu.c */\nvoid x86_fpu_enable(void);\nvoid x86_fpu_disable(void);\nvoid x86_fpu_trap(void);\n\n//void pic_setup(void);\n//void pic_disable(void);\n//void pit_setup(uint32_t);\n//void acpi_setup(void);\n//uintptr_t acpi_rsdt_find(char signature[4]);\n//void hpet_setup(void);\n//int hpet_timer_setup(size_t period_ns, void (*handler)());\n\n//#include \"msr.h\"\n//#include \"sdt.h\"\n//#include \"pit.h\"\n\n#include_next <cpu/cpu.h>\n\n#endif /* ! _X86_CPU_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/cpu/cpuid.h",
    "content": "#ifndef _X86_CPUID_H\n#define _X86_CPUID_H\n\n#include <core/system.h>\n\nunion x86_cpuid_vendor {\n    char string[13];\n    uint32_t array[3];\n} __packed;\n\n#if 0\nstruct x86_cpuid_features {\n    int fpu   : 1;  /* onboard x87 FPU */\n    int vme   : 1;  /* Virtual 8086 Mode Extensions */\n    int de    : 1;  /* Debugging Extensions */\n    int pse   : 1;  /* Page Size Extensions */\n    int tsc   : 1;  /* Time Stamp Counter */\n    int msr   : 1;  /* Mode Specific Regisgers */\n    int pae   : 1;  /* Physical Address Extensions */\n    int mce   : 1;  /* Machine Check Exceptions */\n    int cx8   : 1;  /* CMPXCHG8 (compare and swap) instruction support */\n    int apic  : 1;  /* onboard Advanced Programmable Interrupt Controller */\n    int       : 1;  /* reserved */\n    int sep   : 1;  /* SYSENTER and SYSEXIT instructions */\n    int mtrr  : 1;  /* Memory Type Range Registers */\n    int pge   : 1;  /* Page Global Enable bit in CR4 support */\n    int mca   : 1;  /* Machine Check Architecture */\n    int cmov  : 1;  /* Conditional MOV and FCMOV instructions support */\n    int pat   : 1;  /* Page Attribute Table */\n    int pse36 : 1;  /* 36-bit Page Size Extension */\n    int psn   : 1;  /* Processor Serial Number */\n    int clfsh : 1;  /* CLFluSH instruction (SSE2) support */\n    int       : 1;  /* reserved */\n    int ds    : 1;  /* Debug Store: save trace of executed jumps */\n    int acpi  : 1;  /* onboard thermal contorl MSRs for ACPI */\n    int mmx   : 1;  /* MMX instructions support */\n    int fxsr  : 1;  /* FXSAVE, FXRESTOR instruction support */\n    int sse   : 1;  /* SSE instruction support */\n    int sse2  : 1;  /* SSE2 instruction support */\n    int ss    : 1;  /* CPU cache Self-Snoop support */\n    int htt   : 1;  /* Hyper-Threading Technology support */\n    int tm    : 1;  /* Thermal Monitor support */\n    int ia64  : 1;  /* IA64 processor emulating x86 */\n    int pbe   : 1;  /* Pending Break Enable */\n} __packed;\n\nint x86_cpuid_check(void);\n\nstatic inline int x86_cpuid_features(struct x86_cpuid_features *features)\n{\n    if (x86_cpuid_check()) {\n        asm volatile (\"cpuid\":\"=b\"((int){0}), \"=c\"((int){0}), \"=d\"(*features):\"a\"(1):\"memory\");\n    } else {\n        /* CPUID is not supported -- fall back to i386 */\n        /* TODO */\n        printk(\"i386 Support not implemented\");\n        for (;;);\n    }\n\n    return 0;\n}\n#endif\n\nstatic inline int x86_cpuid_vendor(union x86_cpuid_vendor *vendor)\n{\n    asm volatile(\"cpuid\":\n        \"=b\"(vendor->array[0]),\n        \"=d\"(vendor->array[1]),\n        \"=c\"(vendor->array[2])\n        :\"a\"(0));\n    vendor->string[12] = 0;\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "kernel/arch/i386/include/cpu/io.h",
    "content": "#ifndef _X86_IO_H\n#define _X86_IO_H\n\n#include <stdint.h>\n\n#define __inb(port) \\\n({ \\\n    uint8_t ret; \\\n    asm volatile (\"inb %%dx, %%al\":\"=a\"(ret):\"d\"(port)); \\\n    ret; \\\n})\n\n#define __inw(port) \\\n({ \\\n    uint16_t ret; \\\n    asm volatile (\"inw %%dx, %%ax\":\"=a\"(ret):\"dN\"(port)); \\\n    ret; \\\n})\n\n#define __inl(port) \\\n({ \\\n    uint32_t ret; \\\n    asm volatile (\"inl %%dx, %%eax\":\"=a\"(ret):\"d\"(port)); \\\n    ret; \\\n})\n\n#define __insw(port, count, buf) \\\n({ \\\n    asm volatile (\"rep insw\"::\"D\"(buf), \"c\"(count), \"d\"(port):\"memory\"); \\\n})\n\n#define __outb(port, value) \\\n({ \\\n    asm volatile (\"outb %%al, %%dx\"::\"d\"((port)),\"a\"((value))); \\\n})\n\n#define __outw(port, value) \\\n({ \\\n    asm volatile (\"outw %%ax, %%dx\"::\"d\"(port),\"a\"(value)); \\\n})\n\n#define __outl(port, value) \\\n({ \\\n    asm volatile (\"outl %%eax, %%dx\"::\"d\"(port),\"a\"(value)); \\\n})\n\n#define __io_wait() \\\n({ \\\n    asm volatile ( \"jmp 1f\\n\\t\" \\\n                   \"1:jmp 2f\\n\\t\" \\\n                   \"2:\" ); \\\n})\n\n#define __mmio_inb(addr) (*((volatile uint8_t *)(addr)))\n#define __mmio_inw(addr) (*((volatile uint16_t *)(addr)))\n#define __mmio_inl(addr) (*((volatile uint32_t *)(addr)))\n#define __mmio_inq(addr) (*((volatile uint64_t *)(addr)))\n\n#define __mmio_outb(addr, v) (*((volatile uint8_t  *)(addr)) = v)\n#define __mmio_outw(addr, v) (*((volatile uint16_t *)(addr)) = v)\n#define __mmio_outl(addr, v) (*((volatile uint32_t *)(addr)) = v)\n#define __mmio_outq(addr, v) (*((volatile uint64_t *)(addr)) = v)\n\n#define IOADDR_PORT    1\n#define IOADDR_MMIO8   2\n#define IOADDR_MMIO16  3\n#define IOADDR_MMIO32  4\n\nstruct ioaddr {\n    char type;\n    uintptr_t addr;\n};\n\nstatic inline char *ioaddr_type_str(struct ioaddr *io)\n{\n    switch (io->type) {\n        case IOADDR_PORT:\n            return \"pio\";\n        case IOADDR_MMIO8:\n            return \"mmio8\";\n        case IOADDR_MMIO16:\n            return \"mmio16\";\n        case IOADDR_MMIO32:\n            return \"mmio32\";\n    }\n\n    return NULL;\n}\n\nstatic inline uint8_t io_in8(struct ioaddr *io, uintptr_t off)\n{\n    switch (io->type) {\n        case IOADDR_PORT:\n            return __inb(io->addr + off);\n        case IOADDR_MMIO8:\n            return __mmio_inb(io->addr + off);\n        case IOADDR_MMIO16:\n            return __mmio_inb(io->addr + (off << 1));\n        case IOADDR_MMIO32:\n            return __mmio_inb(io->addr + (off << 2));\n    }\n\n    return 0;\n}\n\nstatic inline uint16_t io_in16(struct ioaddr *io, uintptr_t off)\n{\n    switch (io->type) {\n        case IOADDR_PORT:\n            return __inw(io->addr + off);\n        case IOADDR_MMIO8:\n            return __mmio_inw(io->addr + off);\n        case IOADDR_MMIO16:\n            return __mmio_inw(io->addr + (off << 1));\n        case IOADDR_MMIO32:\n            return __mmio_inw(io->addr + (off << 2));\n    }\n\n    return 0;\n}\n\nstatic inline uint32_t io_in32(struct ioaddr *io, uintptr_t off)\n{\n    switch (io->type) {\n        case IOADDR_PORT:\n            return __inl(io->addr + off);\n        case IOADDR_MMIO8:\n            return __mmio_inl(io->addr + off);\n        case IOADDR_MMIO16:\n            return __mmio_inl(io->addr + (off << 1));\n        case IOADDR_MMIO32:\n            return __mmio_inl(io->addr + (off << 2));\n    }\n\n    return 0;\n}\n\nstatic inline void io_out8(struct ioaddr *io, uintptr_t off, uint8_t val)\n{\n    switch (io->type) {\n        case IOADDR_PORT:\n            __outb(io->addr + off, val); return;\n        case IOADDR_MMIO8:\n            __mmio_outb(io->addr + off, val); return;\n        case IOADDR_MMIO16:\n            __mmio_outb(io->addr + (off << 1), val); return;\n        case IOADDR_MMIO32:\n            __mmio_outb(io->addr + (off << 2), val); return;\n    }\n}\n\nstatic inline void io_out16(struct ioaddr *io, uintptr_t off, uint16_t val)\n{\n    switch (io->type) {\n        case IOADDR_PORT:\n            __outw(io->addr + off, val); return;\n        case IOADDR_MMIO8:\n            __mmio_outw(io->addr + off, val); return;\n        case IOADDR_MMIO16:\n            __mmio_outw(io->addr + (off << 1), val); return;\n        case IOADDR_MMIO32:\n            __mmio_outw(io->addr + (off << 2), val); return;\n    }\n}\n\nstatic inline void io_out32(struct ioaddr *io, uintptr_t off, uint32_t val)\n{\n    switch (io->type) {\n        case IOADDR_PORT:\n            __outl(io->addr + off, val); return;\n        case IOADDR_MMIO8:\n            __mmio_outl(io->addr + off, val); return;\n        case IOADDR_MMIO16:\n            __mmio_outl(io->addr + (off << 1), val); return;\n        case IOADDR_MMIO32:\n            __mmio_outl(io->addr + (off << 2), val); return;\n    }\n}\n\n#endif /* ! _X86_IO_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/cpu/msr.h",
    "content": "#ifndef _X86_MSR_H\n#define _X86_MSR_H\n\n#include <core/system.h>\n\nstatic inline uint64_t msr_read(uint32_t msr)\n{\n    uint32_t lo, hi;\n    asm volatile(\"rdmsr\" : \"=a\"(lo), \"=d\"(hi) : \"c\"(msr));\n    return ((uint64_t)hi << 32) | lo;\n}\n \nstatic inline void msr_write(uint32_t msr, uint64_t val)\n{\n    uint32_t lo = val & 0xFFFFFFFF;\n    uint32_t hi = val >> 32;\n    asm volatile(\"wrmsr\" : : \"a\"(lo), \"d\"(hi), \"c\"(msr));\n}\n\n#define APIC_BASE   0x1B\n\n#endif /* ! _X86_MSR_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/cpu/pit.h",
    "content": "#ifndef _X86_PIT_H\n#define _X86_PIT_H\n\n#include <core/system.h>\n\nvoid pit_setup(uint32_t freq);\n\n#endif /* ! _X86_PIT_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/cpu/sdt.h",
    "content": "#ifndef _X86_SDT_H\n#define _X86_SDT_H\n\n#include <core/system.h>\n\nstruct acpi_rsdp {\n    char     signature[8];\n    uint8_t  checksum;\n    char     oem_id[6];\n    uint8_t  rev;\n    uint32_t rsdt;\n} __packed;\n\nstruct acpi_sdt_header {\n    char     signature[4];\n    uint32_t length;\n    uint8_t  rev;\n    uint8_t  checksum;\n    char     oemid[6];\n    char     oem_table_id[8];\n    uint32_t oem_rev;\n    uint32_t creator_id;\n    uint32_t creator_rev;\n} __packed;\n\nstruct acpi_rsdt {\n    struct acpi_sdt_header header;\n    uint32_t sdt[0];\n} __packed;\n\n#define ACPI_MADT_LOCAL_APIC    0\n#define ACPI_MADT_IO_APIC       2\n#define ACPI_MADT_INT_SRC_OVERRIDE      3\n\nstruct acpi_madt_entry {\n    uint8_t type;\n    uint8_t length;\n    union {\n        struct { /* LOCAL APIC */\n            uint8_t processor_id;\n            uint8_t apic_id;\n            uint32_t flags;\n        } __packed local_apic;\n        struct { /* IO APIC */\n            uint8_t ioapic_id;\n            uint8_t __reserved;\n            uint32_t ioapic_address;\n            uint32_t global_system_interrupt_base;\n        } __packed ioapic;\n        struct { /* INTERRUPT SOURCE OVERRIDE */\n            uint8_t bus_source;\n            uint8_t irq_source;\n            uint32_t global_system_interrupt;\n        } __packed interrupt_source_override;\n    } __packed data;\n}__packed;\n\nstruct acpi_madt {\n    struct acpi_sdt_header header;\n    uint32_t local_controller_address;\n    uint32_t flags;\n    struct acpi_madt_entry entry[0];\n}__packed;\n\n#endif /* ! _X86_SDT_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/mm/mm.h",
    "content": "#ifndef _I386_MM_H\n#define _I386_MM_H\n\n#include <core/system.h>\n#include <cpu/cpu.h>\n\n#define NR_PAGE_SIZE           2\n#define KERNEL_HEAP_SIZE       (8ULL * 1024 * 1024)  /* 8 MiB */\n\n#if ARCH_BITS==32\n#define ARCH_KVMEM_BASE        (0xD0000000UL)\n#define ARCH_KVMEM_NODES_SIZE  (0x00100000UL)\n#else\n#define ARCH_KVMEM_BASE        (0xFFFFD00000000000ULL)\n#define ARCH_KVMEM_NODES_SIZE  (0x00100000ULL)\n#endif\n\nextern char _VMA; /* Must be defined in linker script */\n#define VMA(obj)  ((typeof((obj)))((uintptr_t)(void*)&_VMA + (uintptr_t)(void*)(obj)))\n#define LMA(obj)  ((typeof((obj)))((uintptr_t)(void*)(obj)) - (uintptr_t)(void*)&_VMA)\n\nstatic inline void tlb_flush(void)\n{\n    write_cr3(read_cr3());\n}\n\n#if ARCH_BITS==32\ntypedef uint32_t paddr_t;\ntypedef uint32_t vaddr_t;\n#else\ntypedef uint64_t paddr_t;\ntypedef uint64_t vaddr_t;\n#endif\n\nvoid arch_mm_page_fault(vaddr_t vaddr, int err);\n\n#include_next <mm/mm.h>\n\n#endif /* ! _I386_MM_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/mm/pmap.h",
    "content": "#ifndef _I386_MM_PMAP_H\n#define _I386_MM_PMAP_H\n\nstruct pmap {\n    paddr_t map;\n    size_t  ref;\n};\n\n#include_next <mm/pmap.h>\n\n#endif /* ! _I386_MM_PMAP_H */\n"
  },
  {
    "path": "kernel/arch/i386/include/platform/misc.h",
    "content": "#ifndef _PLATFORM_MISC_H\n#define _PLATFORM_MISC_H\n\n#include <cpu/cpu.h>\n#include <cpu/io.h>\n\ntypedef void (*x86_irq_handler_t)(struct x86_regs *r);\n\nint  x86_pic_setup(struct ioaddr *master, struct ioaddr *slave);\nvoid x86_pic_disable(void);\nvoid x86_irq_handler_install(unsigned irq, x86_irq_handler_t handler);\nvoid x86_irq_handler_uninstall(unsigned irq);\n\nint x86_i8042_setup(struct ioaddr *io);\nvoid x86_i8042_handler_register(int channel, void (*fun)(int));\nvoid x86_i8042_reboot(void);\n\nint x86_pit_setup(struct ioaddr *io);\nuint32_t x86_pit_period_set(uint32_t period_ns);\n\nint x86_cmos_setup(struct ioaddr *ioaddr);\n\n#endif /* ! _PLATFORM_MISC_H */\n"
  },
  {
    "path": "kernel/arch/i386/kernel.i386.ld",
    "content": "OUTPUT_FORMAT(elf32-i386)\nENTRY(_start)\nINPUT(boot/builtin.o cpu/builtin.o earlycon/builtin.o mm/builtin.o sys/builtin.o platform/builtin.o ../../core/builtin.o\n../../fs/builtin.o ../../dev/builtin.o ../../sys/builtin.o ../../mm/builtin.o ../../net/builtin.o)\nOUTPUT(kernel.elf)\n\nSECTIONS {\n    LMA = 0x100000;\n    . = LMA;\n\n    kernel_start = .;\n\n    .boot.text : ALIGN(0x1000) {\n        *boot*.o(.text*)\n        *boot*.o(.rodata*)\n    }\n\n    .boot.data : ALIGN(0x1000) {\n        *boot*.o(.data)\n    }\n\n    .boot.bss (NOLOAD) : ALIGN(0x1000) {\n        *boot*.o(*)\n    }\n\n    boot_end = .;\n\n    _VMA = 0xC0000000;\n    . += _VMA;\n\n    .text : AT(ADDR(.text) - _VMA) ALIGN(0x1000) {\n        *(.text*)\n        *(.rodata*)\n    }\n\n    .__minit : AT(ADDR(.__minit) - _VMA) ALIGN(0x1000) {\n        __minit = .;\n        *(.__minit*)\n        __minit_end = .;\n    }\n    \n    .data : AT(ADDR(.data) - _VMA) ALIGN(0x1000) {\n        *(.data)\n    }\n    \n    .bss : AT(ADDR(.bss) - _VMA) ALIGN(0x1000) {\n        *(.bss)\n    }\n\n    .rel.plt : AT(ADDR(.rel.plt) - _VMA) ALIGN(0x1000) {\n        *(.rel.plt)\n    }\n\n    .strtab : AT(ADDR(.strtab) - _VMA) ALIGN(0x1000) {\n        *(.strtab)\n    }\n\n    .shstrtab : AT(ADDR(.shstrtab) - _VMA) ALIGN(0x1000) {\n        *(.shstrtab)\n    }\n    \n    /DISCARD/ : {\n        *(.*)\n    }\n    \n    kernel_end = . - _VMA;\n}\n"
  },
  {
    "path": "kernel/arch/i386/kernel.x86_64.ld",
    "content": "OUTPUT_FORMAT(elf64-x86-64)\nENTRY(_start)\nINPUT(boot/builtin.o cpu/builtin.o earlycon/builtin.o mm/builtin.o sys/builtin.o platform/builtin.o ../../core/builtin.o\n../../fs/builtin.o ../../dev/builtin.o ../../sys/builtin.o ../../mm/builtin.o ../../net/builtin.o)\nOUTPUT(kernel.elf)\n\nSECTIONS {\n\n    LMA = 0x100000;\n    . = LMA;\n\n    .boot.text : ALIGN(0x1000) {\n        *boot*.o(.text*)\n        *boot*.o(.rodata*)\n    }\n\n    .boot.data : ALIGN(0x1000) {\n        *boot*.o(.data)\n    }\n\n    .boot.bss (NOLOAD) : ALIGN(0x1000) {\n        *boot*.o(*)\n    }\n\n    boot_end = .;\n\n    _VMA = 0xFFFF800000000000;\n    . += _VMA;\n\n    .text : AT(ADDR(.text) - _VMA) ALIGN(0x1000) {\n        *(.text*)\n        *(.rodata*)\n    }\n\n    .__minit : AT(ADDR(.__minit) - _VMA) ALIGN(0x1000) {\n        __minit = .;\n        *(.__minit*)\n        __minit_end = .;\n    }\n    \n    .data : AT(ADDR(.data) - _VMA) ALIGN(0x1000) {\n        *(.data)\n    }\n    \n    .bss : AT(ADDR(.bss) - _VMA) ALIGN(0x1000) {\n        *(.bss)\n    }\n    \n    /DISCARD/ : {\n        *(.*)\n    }\n    \n    kernel_end = . - _VMA;\n}\n"
  },
  {
    "path": "kernel/arch/i386/mm/Build.mk",
    "content": "obj-y  \t\t\t   += mm.o\nobj-$(ARCH_I386)   += i386.o\nobj-$(ARCH_X86_64) += x86_64.o\n"
  },
  {
    "path": "kernel/arch/i386/mm/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/arch/i386/mm/frame_utils.h",
    "content": "#ifndef _FRAME_UTILS_H\n#define _FRAME_UTILS_H\n\nstatic inline uintptr_t frame_get()\n{\n    uintptr_t frame = buddy_alloc(BUDDY_ZONE_NORMAL, PAGE_SIZE);\n\n    if (!frame) {\n        panic(\"Could not allocate frame\");\n    }\n\n    uintptr_t old = frame_mount(frame);\n    volatile void *p = MOUNT_ADDR;\n    memset((void *) p, 0, PAGE_SIZE);\n    frame_mount(old);\n\n    return frame;\n}\n\nstatic inline uintptr_t frame_get_no_clr()\n{\n    uintptr_t frame = buddy_alloc(BUDDY_ZONE_NORMAL, PAGE_SIZE);\n\n    if (!frame) {\n        panic(\"Could not allocate frame\");\n    }\n\n    return frame;\n}\n\nstatic void frame_release(uintptr_t i)\n{\n    buddy_free(BUDDY_ZONE_NORMAL, i, PAGE_SIZE);\n}\n\n#endif\n"
  },
  {
    "path": "kernel/arch/i386/mm/i386.c",
    "content": "/*\n *                 Intel 32-Bit Paging Mode Handler\n *\n *  References:\n *      [1] - Intel(R) 64 and IA-32 Architectures Software Developers Manual\n *          - Volume 3, System Programming Guide\n *          - Chapter 4, Paging\n *\n */\n\n#include <core/arch.h>\n#include <core/panic.h>\n#include <core/printk.h>\n#include <core/system.h>\n#include <cpu/cpu.h>\n#include <ds/queue.h>\n\n#include <mm/pmap.h>\n#include <mm/buddy.h>\n#include <mm/vm.h>\n\n#include <sys/sched.h>\n\n#include \"i386.h\"\n\nMALLOC_DEFINE(M_PMAP, \"pmap\", \"physical memory map structure\");\n\nstatic struct pmap *cur_pmap = NULL;\n\nstatic volatile uint32_t *bootstrap_processor_table = NULL;\nstatic volatile uint32_t last_page_table[1024] __aligned(PAGE_SIZE) = {0};\n\nstatic inline void tlb_invalidate_page(uintptr_t virt)\n{\n    asm volatile(\"invlpg (%%eax)\"::\"a\"(virt));\n}\n\n#define MOUNT_ADDR  ((void *) 0xFFBFF000)\n#define PAGE_DIR    ((uint32_t *) 0xFFFFF000)\n#define PAGE_TBL(i) ((uint32_t *) (0xFFC00000 + 0x1000 * (i)))\n\n/* ================== Frame Helpers ================== */\n\nstatic inline uintptr_t frame_mount(uintptr_t paddr)\n{\n    uintptr_t prev = (uintptr_t) last_page_table[1023] & ~PAGE_MASK;\n\n    if (!paddr)\n        return prev; //(uintptr_t) last_page_table[1023] & ~PAGE_MASK;\n\n    if (paddr & PAGE_MASK)\n        panic(\"Mount must be on page (4K) boundary\");\n\n    uint32_t page = paddr | PG_PRESENT | PG_WRITE;\n\n    last_page_table[1023] = page;\n    tlb_invalidate_page((uintptr_t) MOUNT_ADDR);\n\n    return prev;\n}\n\nstatic inline uintptr_t frame_get(void)\n{\n    struct vm_page *vm_page = mm_page_alloc();\n    uintptr_t frame = vm_page->paddr; //buddy_alloc(BUDDY_ZONE_NORMAL, PAGE_SIZE);\n\n    if (!frame) {\n        panic(\"Could not allocate frame\");\n    }\n\n    uintptr_t old = frame_mount(frame);\n    memset(MOUNT_ADDR, 0, PAGE_SIZE);\n    frame_mount(old);\n\n    return frame;\n}\n\nstatic inline uintptr_t frame_get_no_clr(void)\n{\n    struct vm_page *vm_page = mm_page_alloc();\n    uintptr_t frame = vm_page->paddr; //buddy_alloc(BUDDY_ZONE_NORMAL, PAGE_SIZE);\n\n    if (!frame) {\n        panic(\"Could not allocate frame\");\n    }\n\n    return frame;\n}\n\nstatic void frame_release(uintptr_t i)\n{\n    buddy_free(BUDDY_ZONE_NORMAL, i, PAGE_SIZE);\n}\n\n/* ================== Table Helpers ================== */\n\nstatic inline paddr_t table_alloc(void)\n{\n    uintptr_t paddr = frame_get();\n\n    struct vm_page *vm_page = mm_page(paddr);\n    memset(vm_page, 0, sizeof(struct vm_page));\n    vm_page->paddr = paddr;\n\n    return paddr;\n}\n\nstatic inline void table_dealloc(paddr_t paddr)\n{\n    frame_release(paddr);\n}\n\nstatic inline int table_map(paddr_t paddr, size_t pdidx, int flags)\n{\n    if (pdidx > 1023)\n        return -EINVAL;\n\n    uint32_t table;\n    table  = paddr | (PG_PRESENT|PG_WRITE|PG_USER);\n    PAGE_DIR[pdidx] = table;\n\n    tlb_flush();\n\n    return 0;\n}\n\nstatic inline void table_unmap(size_t pdidx)\n{\n    if (pdidx > 1023)\n        return;\n\n    if (PAGE_DIR[pdidx] & PG_PRESENT) {\n        PAGE_DIR[pdidx] &= ~PG_PRESENT;\n        table_dealloc(PAGE_DIR[pdidx] & ~PAGE_MASK);\n    }\n\n    tlb_flush();\n}\n\n/* ================== Page Helpers ================== */\nstatic inline int page_map(paddr_t paddr, size_t pdidx, size_t ptidx, int flags)\n{\n    /* Sanity checking */\n    if (pdidx > 1023 || ptidx > 1023) {\n        return -EINVAL;\n    }\n\n    uint32_t page;\n\n    page  = paddr | PG_PRESENT;\n    page |= flags & (VM_KW | VM_UW)? PG_WRITE : 0;\n    page |= flags & (VM_URWX)? PG_USER : 0;\n\n    /* Check if table is present */\n    if (!(PAGE_DIR[pdidx] & PG_PRESENT)) {\n        //struct vm_page *vm_page = mm_page_alloc();\n        //paddr_t table = vm_page->paddr; //table_alloc();\n        paddr_t table = table_alloc();\n\n        table_map(table, pdidx, flags);\n    }\n\n    PAGE_TBL(pdidx)[ptidx] = page;\n\n    /* Increment references to table */\n    paddr_t table = PHYSADDR(PAGE_DIR[pdidx]);\n    mm_page_incref(table);\n\n    return 0;\n}\n\nstatic inline int page_protect(size_t pdidx, size_t ptidx, uint32_t flags)\n{\n    /* Sanity checking */\n    if (pdidx > 1023 || ptidx > 1023) {\n        return -EINVAL;\n    }\n\n    uint32_t page;\n\n    /* Check if table is present */\n    if (!(PAGE_DIR[pdidx] & PG_PRESENT)) {\n        return -EINVAL;\n    }\n\n    page = PAGE_TBL(pdidx)[ptidx];\n\n    if (page & PG_PRESENT) {\n        page &= ~(PG_WRITE|PG_USER);\n        page |= (flags & (VM_KW | VM_UW))? PG_WRITE : 0;\n        page |= (flags & VM_URWX)? PG_USER : 0;\n\n        PAGE_TBL(pdidx)[ptidx] = page;\n    }\n\n    return 0;\n}\n\nstatic inline void page_unmap(vaddr_t vaddr)\n{\n    if (vaddr & PAGE_MASK)\n        return;\n\n    size_t pdidx = VDIR(vaddr);\n    size_t ptidx = VTBL(vaddr);\n\n    if (PAGE_DIR[pdidx] & PG_PRESENT) {\n        if (PAGE_TBL(pdidx)[ptidx] & PG_PRESENT) {\n            uintptr_t old_page = PAGE_ALIGN(PAGE_TBL(pdidx)[ptidx]);\n            //printk(\"old_page %p (ref=%d)\\n\", old_page, mm_page_ref(old_page));\n\n            PAGE_TBL(pdidx)[ptidx] = 0;\n\n            /* Decrement references to table */\n            paddr_t table = PHYSADDR(PAGE_DIR[pdidx]);\n            //printk(\"mm_page_ref(table) = %d\\n\", mm_page_ref(table));\n\n            mm_page_decref(table);\n\n            if (mm_page_ref(table) == 0)\n                table_unmap(pdidx);\n\n            tlb_invalidate_page(vaddr);\n        }\n    }\n}\n\nstatic inline uint32_t __page_get_mapping(vaddr_t vaddr)\n{\n    if (PAGE_DIR[VDIR(vaddr)] & PG_PRESENT) {\n        uint32_t page = PAGE_TBL(VDIR(vaddr))[VTBL(vaddr)];\n\n        if (page & PG_PRESENT)\n            return page;\n    }\n\n    return 0;\n}\n\nstatic void table_dump(paddr_t table)\n{\n    uintptr_t mnt = frame_mount(table);\n    uint32_t *_pages = MOUNT_ADDR;\n\n    printk(\"Table: %p\\n\", table);\n\n    for (int i = 0; i < 1024; ++i) {\n        if (_pages[i] & PG_PRESENT) {\n            paddr_t page = PHYSADDR(_pages[i]);\n            size_t ref = mm_page_ref(table);\n            printk(\"  %p: %d\\n\", page, ref);\n        }\n    }\n\n    frame_mount(mnt);\n}\n\n#include \"page_utils.h\"\n\nstruct pmap *pmap_switch(struct pmap *pmap)\n{\n    if (!pmap)\n        panic(\"pmap?\");\n\n    struct pmap *ret = cur_pmap;\n\n    if (cur_pmap && cur_pmap->map == pmap->map) {\n        cur_pmap == pmap;\n        return ret;\n    }\n\n    if (cur_pmap) { /* Store current directory mapping in old_dir */\n        copy_virtual_to_physical((void *) cur_pmap->map, (void *) bootstrap_processor_table, 768 * 4);\n    }\n\n    copy_physical_to_virtual((void *) bootstrap_processor_table, (void *) pmap->map, 768 * 4);\n    cur_pmap = pmap;\n    tlb_flush();\n\n    return ret;\n}\n\nstatic struct pmap k_pmap;\n\nstatic void setup_i386_paging(void)\n{\n    printk(\"x86: setting up 32-bit paging\\n\");\n    uintptr_t __cur_pd = read_cr3() & ~PAGE_MASK;\n\n    bootstrap_processor_table = (uint32_t *) VMA(__cur_pd);\n    bootstrap_processor_table[1023] = LMA((uint32_t) bootstrap_processor_table) | PG_WRITE | PG_PRESENT;\n    bootstrap_processor_table[1022] = LMA((uint32_t) last_page_table) | PG_PRESENT | PG_WRITE;\n\n    /* Unmap lower half */\n    for (int i = 0; bootstrap_processor_table[i]; ++i)\n        bootstrap_processor_table[i] = 0;\n\n    tlb_flush();\n\n    k_pmap.map = __cur_pd;\n    kvm_space.pmap = &k_pmap;\n}\n\n/*\n *  Archeticture Interface\n */\n\nint arch_page_unmap(vaddr_t vaddr)\n{\n    if (vaddr & PAGE_MASK)\n        return -EINVAL;\n\n    page_unmap(vaddr);\n    return 0;\n}\n\nvoid arch_mm_page_fault(vaddr_t vaddr, int err)\n{\n    int flags = 0;\n\n    flags |= err & 0x01? PF_PRESENT : 0;\n    flags |= err & 0x02? PF_WRITE   : PF_READ;\n    flags |= err & 0x04? PF_USER    : 0;\n    flags |= err & 0x10? PF_EXEC    : 0;\n\n    mm_page_fault(vaddr, flags);\n\n    return;\n}\n\nstatic struct pmap *pmap_alloc(void)\n{\n    return kmalloc(sizeof(struct pmap), &M_PMAP, 0);\n}\n\nstatic void pmap_release(struct pmap *pmap)\n{\n    if (pmap == cur_pmap) {\n        pmap_switch(&k_pmap);\n        //cur_pmap = NULL;\n    }\n\n    if (pmap->map)\n        frame_release(pmap->map);\n\n    kfree(pmap);\n}\n\nvoid pmap_init(void)\n{\n    setup_i386_paging();\n    cur_pmap = &k_pmap;\n}\n\nstruct pmap *pmap_create(void)\n{\n    struct pmap *pmap = pmap_alloc();\n\n    if (pmap == NULL)\n        return NULL;\n\n    memset(pmap, 0, sizeof(struct pmap));\n\n    pmap->map = frame_get();\n    pmap->ref = 1;\n\n    return pmap;\n}\n\nvoid pmap_incref(struct pmap *pmap)\n{\n    /* XXX Handle overflow */\n    pmap->ref++;\n}\n\nvoid pmap_decref(struct pmap *pmap)\n{\n    pmap->ref--;\n\n    if (pmap->ref == 0) {\n        //printk(\"should release pmap %p\\n\", pmap);\n        pmap_release(pmap);\n    }\n}\n\nint pmap_add(struct pmap *pmap, vaddr_t va, paddr_t pa, uint32_t flags)\n{\n    //printk(\"pmap_add(pmap=%p, va=%p, pa=%p, flags=0x%x)\\n\", pmap, va, pa, flags);\n\n    if ((va & PAGE_MASK) || (pa & PAGE_MASK))\n        return -EINVAL;\n\n    struct pmap *old_map = pmap_switch(pmap);\n\n    size_t pdidx = VDIR(va);\n    size_t ptidx = VTBL(va);\n\n    page_map(pa, pdidx, ptidx, flags);\n    tlb_invalidate_page(va);\n\n    pmap_switch(old_map);\n\n    return 0;\n}\n\nvoid pmap_remove(struct pmap *pmap, vaddr_t sva, vaddr_t eva)\n{\n    if ((sva & PAGE_MASK) || (eva & PAGE_MASK))\n        return;\n\n    struct pmap *old_map = pmap_switch(pmap);\n\n    while (sva < eva) {\n        page_unmap(sva);\n        sva += PAGE_SIZE;\n    }\n\n    pmap_switch(old_map);\n}\n\nstatic void table_remove_all(paddr_t table)\n{\n    uintptr_t mnt = frame_mount(table);\n    uint32_t *_pages = MOUNT_ADDR;\n\n    for (int i = 0; i < 1024; ++i) {\n        if (_pages[i] & PG_PRESENT) {\n            paddr_t page = PHYSADDR(_pages[i]);\n            _pages[i] = 0;\n\n            mm_page_decref(page);\n            size_t ref = mm_page_ref(table);\n            mm_page_decref(table);\n        }\n    }\n\n    frame_mount(mnt);\n}\n\nvoid pmap_remove_all(struct pmap *pmap)\n{\n    //printk(\"pmap_remove_all(pmap=%p)\\n\", pmap);\n\n    struct pmap *old_map = pmap_switch(&k_pmap);\n\n    paddr_t base = pmap->map;\n\n    uintptr_t old_mount = frame_mount(base);\n    uint32_t *tbl = (uint32_t *) MOUNT_ADDR;\n\n    for (int i = 0; i < 768; ++i) {\n        if (tbl[i] & PG_PRESENT) {\n            paddr_t table = PHYSADDR(tbl[i]);\n            table_remove_all(table);\n            tbl[i] = 0;\n            table_dealloc(table);\n        }\n    }\n\n    tlb_flush();\n\n    frame_mount(old_mount);\n\n    pmap_switch(old_map);\n\n\n\n    return;\n}\n\nvoid pmap_protect(struct pmap *pmap, vaddr_t sva, vaddr_t eva, uint32_t prot)\n{\n    if (sva & PAGE_MASK)\n        return;\n\n    struct pmap *old_map = pmap_switch(pmap);\n\n    while (sva < eva) {\n        size_t pdidx = VDIR(sva);\n        size_t ptidx = VTBL(sva);\n\n        page_protect(pdidx, ptidx, prot);\n        tlb_invalidate_page(sva);\n\n        sva += PAGE_SIZE;\n    }\n\n    pmap_switch(old_map);\n}\n\nvoid pmap_copy(struct pmap *dst_map, struct pmap *src_map, vaddr_t dst_addr, size_t len,\n vaddr_t src_addr)\n{\n    return;\n}\n\nvoid pmap_update(struct pmap *pmap)\n{\n    return;\n}\n\nstatic char __copy_buf[PAGE_SIZE] __aligned(PAGE_SIZE);\nvoid pmap_page_copy(paddr_t src, paddr_t dst)\n{\n    copy_physical_to_virtual(__copy_buf, (char *) src, PAGE_SIZE);\n    copy_virtual_to_physical((char *) dst, __copy_buf, PAGE_SIZE);\n    return;\n}\n\nvoid pmap_page_protect(struct vm_page *pg, uint32_t flags)\n{\n    return;\n}\n\nint pmap_clear_modify(struct vm_page *pg)\n{\n    return -1;\n}\n\nint pmap_clear_reference(struct vm_page *pg)\n{\n    return -1;\n}\n\nint pmap_is_modified(struct vm_page *pg)\n{\n    return -1;\n}\n\nint pmap_is_referenced(struct vm_page *pg)\n{\n    return -1;\n}\n\npaddr_t arch_page_get_mapping(struct pmap *pmap, vaddr_t vaddr)\n{\n    struct pmap *old_map = pmap_switch(pmap);\n\n    //printk(\"arch_page_get_mapping(vaddr=%p)\\n\", vaddr);\n    uint32_t page = __page_get_mapping(vaddr);\n\n    if (page) {\n        pmap_switch(old_map);\n\n        return PHYSADDR(page);\n    }\n\n    pmap_switch(old_map);\n\n    return 0;\n}\n\nint pmap_page_read(paddr_t paddr, off_t off, size_t size, void *buf)\n{\n    size_t sz = MAX(PAGE_SIZE, size - off);\n    uintptr_t old = frame_mount(paddr);\n    char *page = (char *) MOUNT_ADDR;\n    memcpy(buf, page + off, sz);\n    frame_mount(old);\n    return 0;\n}\n\nint pmap_page_write(paddr_t paddr, off_t off, size_t size, void *buf)\n{\n    size_t sz = MAX(PAGE_SIZE, size - off);\n    uintptr_t old = frame_mount(paddr);\n    char *page = (char *) MOUNT_ADDR;\n    memcpy(page + off, buf, sz);\n    frame_mount(old);\n    return 0;\n}\n"
  },
  {
    "path": "kernel/arch/i386/mm/i386.h",
    "content": "#ifndef _PAGING_I386_H\n#define _PAGING_I386_H\n\n#include <core/system.h>\n\n#define PG_PRESENT  1\n#define PG_WRITE    2\n#define PG_USER     4\n\n#define VTBL(n) (((n) >> 12) & 0x3ff)\n#define VDIR(n) (((n) >> 22) & 0x3ff)\n\n#define PHYSADDR(s) ((s) & ~0xfff)\n\n#endif /* ! _PAGING_I386_H */\n"
  },
  {
    "path": "kernel/arch/i386/mm/mm.c",
    "content": "/**********************************************************************\n *                  Physical Memory Manager\n *\n *\n *  This file is part of AquilaOS and is released under the terms of\n *  GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar\n */\n\n#include <core/system.h>\n#include <core/string.h>\n#include <core/panic.h>\n#include <core/arch.h>\n\n#include <cpu/cpu.h>\n\n#include <boot/multiboot.h>\n#include <boot/boot.h>\n\n#include <mm/pmap.h>\n#include <mm/mm.h>\n\nvoid arch_mm_setup(void)\n{\n    pmap_init();\n}\n"
  },
  {
    "path": "kernel/arch/i386/mm/page_utils.h",
    "content": "#ifndef _PAGE_UTILS_H\n#define _PAGE_UTILS_H\n\nstatic void *copy_physical_to_virtual(void *_virt_dest, void *_phys_src, size_t n)\n{\n    //printk(\"copy_physical_to_virtual(v=%p, p=%p, n=%d)\\n\", _virt_dest, _phys_src, n);\n    char *virt_dest = (char *) _virt_dest;\n    char *phys_src  = (char *) _phys_src;\n\n    void *ret = virt_dest;\n\n    /* Copy up to page boundary */\n    size_t offset = (uintptr_t) phys_src % PAGE_SIZE;\n    size_t size = MIN(n, PAGE_SIZE - offset);\n    \n    if (size) {\n        uintptr_t prev_mount = frame_mount((uintptr_t) phys_src);\n        volatile char *p = MOUNT_ADDR;\n        memcpy(virt_dest, (char *) (p + offset), size);\n        \n        phys_src  += size;\n        virt_dest += size;\n\n        /* Copy complete pages */\n        n -= size;\n        size = n / PAGE_SIZE;\n        while (size--) {\n            frame_mount((uintptr_t) phys_src);\n            memcpy(virt_dest, (char *) p, PAGE_SIZE);\n            phys_src += PAGE_SIZE;\n            virt_dest += PAGE_SIZE;\n        }\n\n        /* Copy what is remainig */\n        size = n % PAGE_SIZE;\n        if (size) {\n            frame_mount((uintptr_t) phys_src);\n            memcpy(virt_dest, (char *) p, size);\n        }\n\n        frame_mount(prev_mount);\n    }\n\n    return ret;\n}\n\nstatic void *copy_virtual_to_physical(void *_phys_dest, void *_virt_src, size_t n)\n{\n    char *phys_dest = (char *) _phys_dest;\n    char *virt_src  = (char *) _virt_src;\n    void *ret = phys_dest;\n\n    size_t s = n / PAGE_SIZE;\n    \n    uintptr_t prev_mount = frame_mount(0);\n\n    while (s--) {\n        frame_mount((uintptr_t) phys_dest);\n        void *p = MOUNT_ADDR;\n        memcpy(p, virt_src, PAGE_SIZE);\n        phys_dest += PAGE_SIZE;\n        virt_src  += PAGE_SIZE;\n    }\n\n    s = n % PAGE_SIZE;\n\n    if (s) {\n        frame_mount((uintptr_t) phys_dest);\n        void *p = MOUNT_ADDR;\n        memcpy(p, virt_src, s);\n    }\n\n    frame_mount((uintptr_t) prev_mount);\n    return ret;\n}\n\n#endif\n"
  },
  {
    "path": "kernel/arch/i386/mm/x86_64.c",
    "content": "#include <core/arch.h>\n#include <core/panic.h>\n#include <core/printk.h>\n#include <core/system.h>\n#include <cpu/cpu.h>\n#include <ds/queue.h>\n#include <mm/buddy.h>\n#include <mm/vm.h>\n\n#include \"x86_64.h\"\n\nMALLOC_DEFINE(M_PMAP, \"pmap\", \"physical memory map structure\");\n\nstatic volatile __dirtbl_t    *bsp_lvl4 = NULL;\nstatic volatile __directory_t *bsp_lvl3 = NULL;\nstatic volatile __table_t     *bsp_lvl2 = NULL;\n\nstatic volatile __page_t last_page_table[512] __aligned(PAGE_SIZE) = {0};\n\n#define MOUNT_ADDR  ((void *) 0xFFFF80003FFFF000)\n\n#define LVL4            ((__dirtbl_t *)   (0xFFFFFFFFFFFFF000ULL))\n#define LVL3(i)         ((__directory_t *)(0xFFFFFFFFFFE00000ULL + 0x1000ULL * (i)))\n#define LVL2(i, j)      ((__table_t *)    (0xFFFFFFFFC0000000ULL + 512ULL * 0x1000 * (i) + 0x1000ULL * (j)))\n#define LVL1(i, j, k)   ((__page_t *)     (0xFFFFFF8000000000ULL + 512ULL * 512ULL * 0x1000 * (i) + 512ULL * 0x1000 * (j) + 0x1000ULL * (k)))\n\n#define VADDR(i, j, k, l)    ((uintptr_t)      ((512UL * 512UL * 512UL * (i) + 512UL * 512UL * (j) + 512UL * (k) + (l)) * 0x1000UL))\n\nstatic inline void tlb_invalidate_page(uintptr_t virt)\n{\n    asm volatile (\"invlpg (%%rax)\"::\"a\"(virt));\n}\n\n/* ================== Frame Helpers ================== */\n\nstatic inline uintptr_t frame_mount(uintptr_t paddr)\n{\n    if (!paddr)\n        return (uintptr_t) last_page_table[511].raw & ~PAGE_MASK;\n\n    if (paddr & PAGE_MASK)\n        panic(\"Mount must be on page (4K) boundary\");\n\n    uintptr_t prev = (uintptr_t) last_page_table[511].raw & ~PAGE_MASK;\n\n    __page_t page;\n    page.raw = paddr;\n\n    page.present = 1;\n    page.write = 1;\n\n    last_page_table[511] = page;\n    tlb_invalidate_page((uintptr_t) MOUNT_ADDR);\n\n    return prev;\n} \n\n#include \"frame_utils.h\"\n\n/* ================== PDPT Helpers ================== */\n\nstatic inline int pdpt_map(paddr_t paddr, size_t idx, int flags)\n{\n    if (idx > 511)\n        return -EINVAL;\n\n    __dirtbl_t dirtbl = {.raw = paddr};\n\n    dirtbl.present = 1;\n    dirtbl.write   = !!(flags & (VM_KW | VM_UW));\n    dirtbl.user    = !!(flags & (VM_URWX));\n\n    LVL4[idx] = dirtbl;\n\n    //tlb_flush();\n\n    return 0;\n}\n\n/* ================== PD Helpers ================== */\n\nstatic inline int pd_map(paddr_t paddr, size_t pdpt_idx, size_t pd_idx, int flags)\n{\n    if (pdpt_idx > 511 || pd_idx > 511)\n        return -EINVAL;\n\n    __directory_t dir = {.raw = paddr};\n\n    dir.present = 1;\n    dir.write   = !!(flags & (VM_KW | VM_UW));\n    dir.user    = !!(flags & (VM_URWX));\n\n    LVL3(pdpt_idx)[pd_idx] = dir;\n\n    //tlb_flush();\n\n    return 0;\n}\n\n/* ================== Table Helpers ================== */\n\nstatic inline int table_map(paddr_t paddr, size_t pdpt_idx, size_t pd_idx, size_t dir_idx, int flags)\n{\n    if (pdpt_idx > 511 || pd_idx > 511 || dir_idx > 511)\n        return -EINVAL;\n\n    __table_t table = {.raw = paddr};\n\n    table.present = 1;\n    table.write   = !!(flags & (VM_KW | VM_UW));\n    table.user    = !!(flags & (VM_URWX));\n\n    LVL2(pdpt_idx, pd_idx)[dir_idx] = table;\n\n    //tlb_flush();\n\n    return 0;\n}\n\n/* ================== Page Helpers ================== */\n\nstatic inline int __page_map(paddr_t paddr, size_t pml4, size_t dirtbl, size_t dir, size_t table, int flags)\n{\n    /* Sanity checking */\n    if (pml4 > 511 || dirtbl > 511 || dir > 511 || table > 511) {\n        return -EINVAL;\n    }\n\n    __page_t page = {.raw = paddr};\n\n    page.present = 1;\n    page.write   = !!(flags & (VM_KW | VM_UW));\n    page.user    = !!(flags & (VM_URWX));\n\n    /* Check if PDPT is present */\n    if (!LVL4[pml4].present) {\n        paddr_t paddr = frame_get();\n        pdpt_map(paddr, pml4, flags);\n    }\n\n    //pages[GET_PHYS_ADDR(&LVL4[pml4])/PAGE_SIZE].refs++;\n    mm_page_incref(GET_PHYS_ADDR(&LVL4[pml4]));\n\n    /* Check if PD is present */\n    if (!LVL3(pml4)[dirtbl].present) {\n        paddr_t paddr = frame_get();\n        pd_map(paddr, pml4, dirtbl, flags);\n    }\n\n    //pages[GET_PHYS_ADDR(&LVL3(pml4)[dirtbl])/PAGE_SIZE].refs++;\n    mm_page_incref(GET_PHYS_ADDR(&LVL3(pml4)[dirtbl]));\n\n    /* Check if table is present */\n    if (!LVL2(pml4, dirtbl)[dir].present) {\n        paddr_t paddr = frame_get();\n        table_map(paddr, pml4, dirtbl, dir, flags);\n    }\n\n    //pages[GET_PHYS_ADDR(&LVL2(pml4, dirtbl)[dir])/PAGE_SIZE].refs++;\n    mm_page_incref(GET_PHYS_ADDR(&LVL2(pml4, dirtbl)[dir]));\n\n    LVL1(pml4, dirtbl, dir)[table] = page;\n\n    return 0;\n}\n\nstatic inline void __page_unmap(vaddr_t vaddr)\n{\n    if (vaddr & PAGE_MASK)\n        return;\n\n    __virtaddr_t virtaddr = {.raw = vaddr};\n    size_t pml4      = virtaddr.pml4;\n    size_t dirtbl    = virtaddr.dirtbl;\n    size_t directory = virtaddr.directory;\n    size_t table     = virtaddr.table;\n\n    if (LVL4[pml4].present &&\n        LVL3(pml4)[dirtbl].present &&\n        LVL2(pml4, dirtbl)[directory].present) {\n\n        /* Dereference page */\n        LVL1(pml4, dirtbl, directory)[table].raw = 0;\n\n#if 0\n        /* Decrement references */\n        paddr_t table_phy = GET_PHYS_ADDR(&LVL2(pml4, dirtbl)[directory]);\n        pages[table_phy/PAGE_SIZE].refs--;\n        if (!pages[table_phy/PAGE_SIZE].refs) {\n            frame_release(table_phy);\n            LVL2(pml4, dirtbl)[directory].present = 0;\n        }\n\n        paddr_t directory_phy = GET_PHYS_ADDR(&LVL3(pml4)[dirtbl]);\n        pages[directory_phy/PAGE_SIZE].refs--;\n        if (!pages[directory_phy/PAGE_SIZE].refs) {\n            frame_release(directory_phy);\n            LVL3(pml4)[dirtbl].present = 0;\n        }\n\n        paddr_t dirtbl_phy = GET_PHYS_ADDR(&LVL4[pml4]);\n        pages[directory_phy/PAGE_SIZE].refs--;\n        if (!pages[directory_phy/PAGE_SIZE].refs) {\n            frame_release(directory_phy);\n            LVL4[pml4].present = 0;\n        }\n#endif\n\n        tlb_invalidate_page(vaddr);\n    }\n}\n\n\n/* =================== XXX =============== */\n#include \"page_utils.h\"\n\n\n/* =================== Arch MM Interface =============== */\n\nint arch_page_map(paddr_t paddr, vaddr_t vaddr, int flags)\n{\n    if (vaddr & PAGE_MASK)\n        return -EINVAL;\n\n    __virtaddr_t virtaddr = {.raw = vaddr};\n\n    size_t pml4   = virtaddr.pml4;\n    size_t dirtbl = virtaddr.dirtbl;\n    size_t dir    = virtaddr.directory;\n    size_t table  = virtaddr.table;\n\n    __page_map(paddr, pml4, dirtbl, dir, table, flags);\n    tlb_invalidate_page(vaddr);\n\n    return 0;\n}\n\nint arch_page_unmap(vaddr_t vaddr)\n{\n    /* XXX */\n    if (vaddr >= 0xFFFFD00000000000)\n        printk(\"arch_page_unmap(vaddr=%p)\\n\", vaddr);\n\n    if (vaddr & PAGE_MASK)\n        return -EINVAL;\n\n    __page_unmap(vaddr);\n\n    return 0;\n}\n\nstatic inline __page_t *__page_get_mapping(uintptr_t addr)\n{\n    __virtaddr_t virt = (__virtaddr_t){.raw = addr};\n\n    if (LVL4[virt.pml4].present &&\n        LVL3(virt.pml4)[virt.dirtbl].present &&\n        LVL2(virt.pml4, virt.dirtbl)[virt.directory].present &&\n        LVL1(virt.pml4, virt.dirtbl, virt.directory)[virt.table].present) {\n\n        __page_t *page = &LVL1(virt.pml4, virt.dirtbl, virt.directory)[virt.table];\n\n        if (page->present)\n            return page;\n    }\n\n    return NULL;\n}\n\npaddr_t arch_page_get_mapping(struct pmap *pmap, vaddr_t vaddr)\n{\n    __page_t *page = __page_get_mapping(vaddr);\n\n    if (page)\n        return GET_PHYS_ADDR(page);\n\n    return 0;\n}\n\nvoid arch_mm_page_fault(vaddr_t vaddr, int err)\n{\n    //printk(\"arch_mm_page_fault(vaddr=%p)\\n\", vaddr);\n    int flags = 0;\n\n    flags |= err & 0x01? PF_PRESENT : 0;\n    flags |= err & 0x02? PF_WRITE   : PF_READ;\n    flags |= err & 0x04? PF_USER    : 0;\n    flags |= err & 0x10? PF_EXEC    : 0;\n\n    mm_page_fault(vaddr, flags);\n}\n\npaddr_t arch_get_frame()\n{\n    return frame_get();\n}\n\nvoid arch_release_frame(paddr_t paddr)\n{\n    frame_release(paddr);\n}\n\nstatic struct pmap *cur_pmap = NULL;\nstruct pmap *arch_pmap_switch(struct pmap *pmap)\n{\n    if (!pmap)\n        panic(\"pmap?\");\n\n    struct pmap *ret = cur_pmap;\n\n    if (cur_pmap && cur_pmap->map == pmap->map) {\n        cur_pmap == pmap;\n        return ret;\n    }\n\n    if (cur_pmap) { /* Store current directory mapping in old_dir */\n        copy_virtual_to_physical((void *) cur_pmap->map, (void *) bsp_lvl4, 255 * 8);\n    }\n\n    copy_physical_to_virtual((void *) bsp_lvl4, (void *) pmap->map, 255 * 8);\n\n    cur_pmap = pmap;\n    tlb_flush();\n\n    return ret;\n}\n\nstatic struct pmap k_pmap;\n\nvoid setup_64_bit_paging()\n{\n    printk(\"x86: Setting up 64-bit paging\\n\");\n\n    uintptr_t __cur_pml4 = read_cr3() & ~PAGE_MASK;\n    bsp_lvl4 = (__dirtbl_t *)    VMA(__cur_pml4);\n    bsp_lvl3 = (__directory_t *) VMA((uintptr_t) GET_PHYS_ADDR(&bsp_lvl4[0]));\n    bsp_lvl2 = (__table_t *)     VMA((uintptr_t) GET_PHYS_ADDR(&bsp_lvl3[0]));\n\n    /* Recursive map paging structure */\n    bsp_lvl4[511].raw     = __cur_pml4; //LMA((uintptr_t) bsp_lvl4);\n    bsp_lvl4[511].write   = 1;\n    bsp_lvl4[511].present = 1;\n\n    /* Map last page table */\n    bsp_lvl2[511].raw     = LMA((uintptr_t) last_page_table);\n    bsp_lvl2[511].write   = 1;\n    bsp_lvl2[511].present = 1;\n\n    /* Unmap lower half */\n    bsp_lvl4[0].raw = 0;\n\n    tlb_flush();\n}\n\nstatic struct pmap *pmap_alloc(void)\n{\n    return kmalloc(sizeof(struct pmap), &M_PMAP, 0);\n}\n\nstatic void pmap_release(struct pmap *pmap)\n{\n    if (pmap == cur_pmap) {\n        arch_pmap_switch(&k_pmap);\n        //cur_pmap = NULL;\n    }\n\n    if (pmap->map)\n        arch_release_frame(pmap->map);\n\n    kfree(pmap);\n}\n\nvoid arch_pmap_init(void)\n{\n    setup_64_bit_paging();\n    cur_pmap = &k_pmap;\n}\n\nstruct pmap *arch_pmap_create(void)\n{\n    struct pmap *pmap = pmap_alloc();\n\n    if (pmap == NULL)\n        return NULL;\n\n    memset(pmap, 0, sizeof(struct pmap));\n\n    pmap->map = arch_get_frame();\n    pmap->ref = 1;\n\n    return pmap;\n}\n\n#if 0\nvoid arch_pmap_incref(struct pmap *pmap)\n{\n    /* XXX Handle overflow */\n    pmap->ref++;\n}\n#endif\n\nvoid arch_pmap_decref(struct pmap *pmap)\n{\n    pmap->ref--;\n\n    if (pmap->ref == 0)\n        pmap_release(pmap);\n}\n\nint arch_pmap_add(struct pmap *pmap, vaddr_t va, paddr_t pa, uint32_t flags)\n{\n    //printk(\"arch_pmap_add(pmap=%p, va=%p, pa=%p, flags=0x%x)\\n\", pmap, va, pa, flags);\n\n    struct pmap *old_map = arch_pmap_switch(pmap);\n\n    if (va & PAGE_MASK) {\n        struct pmap *old_map = arch_pmap_switch(pmap);\n        return -EINVAL;\n    }\n\n    __virtaddr_t virtaddr = {.raw = va};\n\n    size_t pml4   = virtaddr.pml4;\n    size_t dirtbl = virtaddr.dirtbl;\n    size_t dir    = virtaddr.directory;\n    size_t table  = virtaddr.table;\n\n    __page_map(pa, pml4, dirtbl, dir, table, flags);\n\n    tlb_invalidate_page(va);\n\n    arch_pmap_switch(old_map);\n\n    return 0;\n}\n\nvoid arch_pmap_remove(struct pmap *pmap, vaddr_t sva, vaddr_t eva)\n{\n    struct pmap *old_map = arch_pmap_switch(pmap);\n\n    if (sva & PAGE_MASK || eva & PAGE_MASK) {\n        arch_pmap_switch(old_map);\n        return;\n    }\n\n    while (sva < eva) {\n        page_unmap(sva);\n        sva += PAGE_SIZE;\n    }\n\n    arch_pmap_switch(old_map);\n}\n\nvoid arch_pmap_remove_all(struct pmap *pmap)\n{\n    struct pmap *old_map = arch_pmap_switch(pmap);\n\n    paddr_t base = pmap->map;\n\n    uintptr_t old_mount = frame_mount(base);\n    uint32_t *tbl = (uint32_t *) MOUNT_ADDR;\n\n    for (int i = 0; i < 768; ++i) {\n        if (tbl[i] & PG_PRESENT) {\n            paddr_t table = GET_PHYS_ADDR(tbl[i]);\n\n            uintptr_t _mnt = frame_mount(table);\n            uint32_t  *pg  = MOUNT_ADDR;\n\n            for (int j = 0; j < 1024; ++j) {\n                if (pg[j] & PG_PRESENT) {\n                    paddr_t page = GET_PHYS_ADDR(pg[j]);\n                    pg[j] = 0;\n                    mm_page_decref(page);\n                    mm_page_decref(table);\n                }\n            }\n\n            tbl[i] = 0;\n\n            frame_mount(_mnt);\n        }\n    }\n\n    tlb_flush();\n\n    frame_mount(old_mount);\n\n    arch_pmap_switch(old_map);\n    return;\n}\n\nvoid arch_pmap_protect(struct pmap *pmap, vaddr_t sva, vaddr_t eva, uint32_t prot)\n{\n    struct pmap *old_map = arch_pmap_switch(pmap);\n\n    //printk(\"arch_pmap_protect(pmap=%p, sva=%p, eva=%p, prot=0x%x)\\n\", pmap, sva, eva, prot);\n\n    if (sva & PAGE_MASK) {\n        arch_pmap_switch(old_map);\n        return;\n    }\n\n    while (sva < eva) {\n        size_t pdidx = VDIR(sva);\n        size_t ptidx = VTBL(sva);\n\n        page_protect(pdidx, ptidx, prot);\n        tlb_invalidate_page(sva);\n\n        sva += PAGE_SIZE;\n    }\n\n    arch_pmap_switch(old_map);\n}\n\nvoid arch_pmap_copy(struct pmap *dst_map, struct pmap *src_map, vaddr_t dst_addr, size_t len,\n vaddr_t src_addr)\n{\n    return;\n}\n\nvoid arch_pmap_update(struct pmap *pmap)\n{\n    return;\n}\n\nstatic char __copy_buf[PAGE_SIZE] __aligned(PAGE_SIZE);\nvoid arch_pmap_page_copy(paddr_t src, paddr_t dst)\n{\n    copy_physical_to_virtual(__copy_buf, (char *) src, PAGE_SIZE);\n    copy_virtual_to_physical((char *) dst, __copy_buf, PAGE_SIZE);\n    return;\n}\n\nvoid arch_pmap_page_protect(struct vm_page *pg, uint32_t flags)\n{\n    return;\n}\n\nint arch_pmap_clear_modify(struct vm_page *pg)\n{\n    return -1;\n}\n\nint arch_pmap_clear_reference(struct vm_page *pg)\n{\n    return -1;\n}\n\nint arch_pmap_is_modified(struct vm_page *pg)\n{\n    return -1;\n}\n\nint arch_pmap_is_referenced(struct vm_page *pg)\n{\n    return -1;\n}\n\npaddr_t arch_page_get_mapping(struct pmap *pmap, vaddr_t vaddr)\n{\n    struct pmap *old_map = arch_pmap_switch(pmap);\n\n    //printk(\"arch_page_get_mapping(vaddr=%p)\\n\", vaddr);\n    uint32_t page = __page_get_mapping(vaddr);\n\n    if (page) {\n        arch_pmap_switch(old_map);\n\n        return GET_PHYS_ADDR(page);\n    }\n\n    arch_pmap_switch(old_map);\n\n    return 0;\n}\n"
  },
  {
    "path": "kernel/arch/i386/mm/x86_64.h",
    "content": "#ifndef _PAGING_X86_64_H\n#define _PAGING_X86_64_H\n\n#include <core/system.h>\n\n/* \n * Page Management Level 4 (PML4)\n * Table 4-12. Use of CR3 with IA-32e Paging and CR4.PCIDE = 0\n */\n\ntypedef union __pml4 {\n    struct {\n        size_t : 3;\n        size_t page_level_write_through : 1;\n        size_t page_level_cache_disable : 1;\n        size_t : 7;\n        uintptr_t phys_addr : 52;\n    } __packed;\n    uint64_t raw;\n} __packed __pml4_t;\n\n/* \n * PML4 Entry (Directory Table)\n * Table 4-14. Format of an IA-32e PML4 Entry (PML4E) \n *  that References a Page-Directory-Pointer Table\n */\n\ntypedef union __dirtbl {\n    struct {\n        size_t present : 1;\n        size_t write : 1;\n        size_t user : 1;\n        size_t page_level_write_through : 1;\n        size_t page_level_cache_disable : 1;\n        size_t accessed : 1;\n        size_t : 1;\n        size_t page_size : 1;\n        size_t : 4;\n        uintptr_t phys_addr : 52;\n    } __packed;\n    uint64_t raw;\n} __packed __dirtbl_t;\n\n/*\n * Page Directory (Directory) Structure\n * Table 4-16. Format of an IA-32e Page-Directory-Pointer-Table\n *  Entry (PDPTE) that References a Page Directory\n */\n\ntypedef union __directory {\n    struct {\n        size_t present : 1;\n        size_t write : 1;\n        size_t user : 1;\n        size_t page_level_write_through : 1;\n        size_t page_level_cache_disable : 1;\n        size_t : 7;\n        uintptr_t phys_addr : 52;\n    } __packed;\n    uint64_t raw;\n} __packed __directory_t;\n\n/*\n * Page Directory Entry (Table) Structure\n * Table 4-18. Format of an IA-32e Page-Directory Entry \n *  that References a Page Table\n */\n\ntypedef union __table {\n    struct {\n        size_t present : 1;\n        size_t write : 1;\n        size_t user : 1;\n        size_t page_level_write_through : 1;\n        size_t page_level_cache_disable : 1;\n        size_t accessed : 1;\n        size_t : 1;\n        size_t page_size : 1;\n        size_t : 4;\n        uintptr_t phys_addr : 52;\n    } __packed;\n    uint64_t raw;\n} __packed __table_t;\n\n\n/*\n * Page Table Entry (Page) Structure\n * Table 4-19. Format of an IA-32e Page-Table Entry\n *  that Maps a 4-KByte Page\n */\n\ntypedef union __page {\n    struct {\n        size_t present : 1;\n        size_t write : 1;\n        size_t user : 1;\n        size_t page_level_write_through : 1;\n        size_t page_level_cache_disable : 1;\n        size_t accessed : 1;\n        size_t dirty : 1;\n        size_t memory_type: 1;\n        size_t global : 1;\n        size_t : 3;\n        uintptr_t phys_addr : 52;\n    } __packed;\n    uint64_t raw;\n} __packed __page_t;\n\n#define LOWER_TABLE_BOUNDARY(ptr) ((ptr) & ~TABLE_MASK)\n#define UPPER_TABLE_BOUNDARY(ptr) (((ptr) + TABLE_MASK) & ~TABLE_MASK)\n\n#define GET_PHYS_ADDR(s) (((s)->phys_addr) << 12U)\n\ntypedef union {\n    struct {\n        size_t offset    : 12;\n        size_t table     : 9;\n        size_t directory : 9;\n        size_t dirtbl    : 9;\n        size_t pml4      : 9;\n        size_t           : 16;\n    } __packed;\n    uint64_t raw;\n} __packed __virtaddr_t;\n\n#endif /* ! _PAGING_X86_64_H */\n"
  },
  {
    "path": "kernel/arch/i386/platform/Build.mk",
    "content": "dirs-y += misc/\ndirs-$(PLATFORM_X86_PC)    += pc/\ndirs-$(PLATFORM_X86_QUARK) += quark/\n"
  },
  {
    "path": "kernel/arch/i386/platform/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/arch/i386/platform/misc/Build.mk",
    "content": "obj-$(PLATFORM_X86_MISC_PIC)   += pic.o\nobj-$(PLATFORM_X86_MISC_I8042) += i8042.o\nobj-$(PLATFORM_X86_MISC_PIT)   += pit.o\nobj-$(PLATFORM_X86_MISC_CMOS)  += cmos.o\n#obj-$(PLATFORM_X86_MISC_HPET)  += hpet.o\n#obj-$(PLATFORM_X86_MISC_ACPI)  += acpi.o\n"
  },
  {
    "path": "kernel/arch/i386/platform/misc/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/arch/i386/platform/misc/acpi.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n\n#include <cpu/cpu.h>\n\n#include <mm/vm.h>\n\nstatic inline int byte_checksum(const char *p, size_t s)\n{\n    int8_t ret = 0;\n    while (s--) ret += (int8_t) *p++;\n    return ret;\n}\n\nstruct acpi_rsdp *acpi_rsdp_detect(void)\n{\n    uint16_t ebda_p = * VMA((uint16_t *) 0x40E);\n    char *ebda = VMA((char *) (uintptr_t) ebda_p);\n    \n    char *p = ebda;\n\n    while (p <= ebda + 0x400) {\n        if (!strncmp(p, \"RSD PTR \", 8))\n            if (!byte_checksum(p, sizeof(struct acpi_rsdp)))\n                return (struct acpi_rsdp *) p;\n\n        p += 0x10;\n    }\n\n    while (p < VMA((char *) 0x000FFFFF)) {\n        if (!strncmp(p, \"RSD PTR \", 8))\n            if (!byte_checksum(p, sizeof(struct acpi_rsdp)))\n                return (struct acpi_rsdp *) p;\n        \n        p += 0x10;\n    }\n\n    return NULL;\n}\n\n/* Dummy page used for mapping ACPI SDT -- XXX */\nstatic char acpi_data[PAGE_SIZE] __aligned(PAGE_SIZE);\nstatic uintptr_t acpi_rsdt = 0;\nstatic struct vmr acpi_vmr;\n\n#define ACPI_ADDR(phy) ((uintptr_t) acpi_data + (((uintptr_t)(phy)) & PAGE_MASK))\n\nvoid acpi_setup()\n{\n    printk(\"acpi: Locating RSDP...\\n\");\n    struct acpi_rsdp *rsdp = acpi_rsdp_detect();\n\n    if (rsdp) {\n        printk(\"acpi: RSDP found at %p\\n\", rsdp);\n    } else {\n        printk(\"acpi: RSDP not found\\n\");\n        return;\n    }\n\n    /* Map to VM */\n    uintptr_t rsdt_phy  = rsdp->rsdt;\n    uintptr_t rsdt_page = rsdp->rsdt & ~PAGE_MASK;\n    uintptr_t rsdt_vir  = ACPI_ADDR(rsdt_phy);\n\n    printk(\"acpi: RSDT is located at %p\\n\", rsdt_phy);\n    printk(\"acpi: Remapping RSDT to %p\\n\", rsdt_vir);\n\n    acpi_vmr.base  = (uintptr_t) acpi_data;\n    acpi_vmr.paddr = rsdt_page;\n    acpi_vmr.size  = PAGE_SIZE;\n    acpi_vmr.flags = VM_KRW;\n\n    vm_map(&acpi_vmr);\n    acpi_rsdt = rsdt_vir;\n}\n\nuintptr_t acpi_rsdt_find(char signature[4])\n{\n    struct acpi_rsdt *rsdt = (struct acpi_rsdt *) acpi_rsdt;\n\n    /* ACPI not initalized */\n    if (!rsdt)\n        return 0;\n\n    int entries = (rsdt->header.length - sizeof(rsdt->header))/sizeof(uint32_t);\n    printk(\"entries %d\\n\", entries);\n\n    for (int i = 0; i < entries; ++i) {\n        struct acpi_sdt_header *hdr = (struct acpi_sdt_header *) ACPI_ADDR(rsdt->sdt[i]);\n\n        if (!strncmp(hdr->signature, signature, 4))\n            return (uintptr_t) hdr;\n    }\n\n    /* Not found */\n    return 0;\n}\n"
  },
  {
    "path": "kernel/arch/i386/platform/misc/cmos.c",
    "content": "#include <core/system.h>\n#include <core/types.h>\n#include <cpu/io.h>\n\n#define RTC_SEC    0x00      /* Seconds */\n#define RTC_MIN    0x02      /* Minutes */\n#define RTC_HRS    0x04      /* Hours */\n#define RTC_WD     0x06      /* Weekday */\n#define RTC_DOM    0x07      /* Day of Month */\n#define RTC_MON    0x08      /* Month */\n#define RTC_YR     0x09      /* Year */\n#define RTC_SA     0x0A      /* Status Register A */\n#define RTC_SB     0x0B      /* Status Register B */\n\n#define RTC_BIN    0x04      /* Binary mode */\n\nstatic struct ioaddr cmos;\n\nstatic uint8_t cmos_reg_read(uint8_t reg)\n{\n    io_out8(&cmos, 0, (1 << 7) | (reg));\n    return io_in8(&cmos, 1);\n}\n\nstruct cmos_rtc {\n    uint8_t yr;\n    uint8_t mon;\n    uint8_t mday;\n    uint8_t hrs;\n    uint8_t min;\n    uint8_t sec;\n    uint8_t wday;\n};\n\nstatic inline uint8_t bcd_to_bin(uint8_t bcd)\n{\n    return ((bcd >> 4) & 0xF) * 10 + (bcd & 0xF);\n}\n\nstatic int cmos_time(struct cmos_rtc *rtc)\n{\n    uint8_t  fmt = cmos_reg_read(RTC_SB);\n\n    rtc->yr   = cmos_reg_read(RTC_YR);\n    rtc->mon  = cmos_reg_read(RTC_MON);\n    rtc->mday = cmos_reg_read(RTC_DOM);\n    rtc->hrs  = cmos_reg_read(RTC_HRS);\n    rtc->min  = cmos_reg_read(RTC_MIN);\n    rtc->sec  = cmos_reg_read(RTC_SEC);\n    rtc->wday = cmos_reg_read(RTC_WD);\n\n    if (!(fmt & RTC_BIN)) {\n        /* convert all values to binary */\n        rtc->yr   = bcd_to_bin(rtc->yr);\n        rtc->mon  = bcd_to_bin(rtc->mon);\n        rtc->mday = bcd_to_bin(rtc->mday);\n        rtc->hrs  = bcd_to_bin(rtc->hrs);\n        rtc->min  = bcd_to_bin(rtc->min);\n        rtc->sec  = bcd_to_bin(rtc->sec);\n        rtc->wday = bcd_to_bin(rtc->wday);\n    }\n\n    return 0;\n}\n\n/* FIXME: Should be elsewhere */\nint arch_time_get(struct timespec *ts)\n{\n    struct cmos_rtc rtc;\n    cmos_time(&rtc);\n\n    time_t time = 0;\n    uint32_t yr = rtc.yr + 2000;\n\n    /* Convert years to days */\n    time = (365 * yr) + (yr / 4) - (yr / 100) + (yr / 400);\n    /* Convert months to days */\n    time += (30 * rtc.mon) + (3 * (rtc.mon + 1) / 5) + rtc.mday;\n    /* UNIX time starts on January 1st, 1970 */\n    time -= 719561;\n    /* Convert days to seconds */\n    time *= 86400;\n    /* Add hours, minutes and seconds */\n    time += (3600 * rtc.hrs) + (60 * rtc.min) + rtc.sec;\n\n    ts->tv_sec = time;\n    ts->tv_nsec = 0;\n\n    return 0;\n}\n\nint x86_cmos_setup(struct ioaddr *ioaddr)\n{\n    cmos = *ioaddr;\n    printk(\"cmos: initializing [%p (%s)]\\n\", cmos.addr, ioaddr_type_str(&cmos));\n\n    return 0;\n}\n"
  },
  {
    "path": "kernel/arch/i386/platform/misc/hpet.c",
    "content": "#include <core/system.h>\n#include <mm/mm.h>\n#include <cpu/cpu.h>\n#include <cpu/io.h>\n\n#define HPET_MEM_IO     0\n#define HPET_PORT_IO    1\n\n#define HPET_REG_CAP           (0x000)\n#define HPET_REG_CNF           (0x010)\n#define HPET_REG_INT           (0x020)\n#define HPET_REG_CNT           (0x0F0)\n#define HPET_REG_TMR_CNF(n)    (0x100 + 0x20 * (n))\n#define HPET_REG_TMR_CMP(n)    (0x108 + 0x20 * (n))\n#define HPET_REG_TMR_INT(n)    (0x110 + 0x20 * (n))\n\nstruct hpet_reg_cap {\n    union {\n        struct {\n            uint32_t rev_id: 8;\n            uint32_t num_tim: 5;\n            uint32_t count_size: 1;\n            uint32_t : 1;\n            uint32_t legacy: 1;\n            uint32_t vendor_id: 16;\n            uint32_t counter_clk_period: 32;\n        } __packed;\n        uint64_t value;\n    } __packed;\n} __packed;\n\nstruct hpet_reg_cnf {\n    union {\n        struct {\n            uint32_t enable: 1;\n            uint32_t legacy: 1;\n            uint64_t : 62;\n        } __packed;\n        uint64_t value;\n    } __packed;\n} __packed;\n\n#define _TMR_ENB _BV(0)\n#define _LEGACY  _BV(1)\n\nstruct hpet_reg_tmr_cnf {\n    union {\n        struct {\n            uint32_t : 1;\n            uint32_t cnf_int_type: 1;\n            uint32_t cnf_int_enb: 1;\n            uint32_t cnf_type: 1;\n            uint32_t cap_per: 1;\n            uint32_t cap_size: 1;\n            uint32_t cnf_val_set: 1;\n            uint32_t : 1;\n            uint32_t cnf_32mode: 1;\n            uint32_t cnf_route: 5;\n            uint32_t cnf_fsb_en: 1;\n            uint32_t cap_fsb_del: 1;\n            uint32_t : 16;\n            uint32_t cap_route: 32;\n        } __packed;\n        uint64_t value;\n    } __packed;\n} __packed;\n\n#define _INT_ENB  _BV(2)\n#define _PERIODIC _BV(3)\n#define _SET_VAL  _BV(6)\n\nstruct hpet {\n    struct acpi_sdt_header header;\n    uint8_t  hardware_rev_id;\n    uint8_t  comparator_count: 5;\n    uint8_t  counter_size: 1;\n    uint8_t  reserved: 1;\n    uint8_t  legacy_replacement: 1;\n    uint16_t pci_vendor_id;\n\n    struct {\n        uint8_t  type;\n        uint8_t  register_bit_width;\n        uint8_t  register_bit_offset;\n        uint8_t  reserved;\n        uint64_t address;\n    } address __packed;\n\n    uint8_t  hpet_number;\n    uint16_t minimum_tick;\n    uint8_t  page_protection;\n} __packed;\n\nstatic char hpet_data[PAGE_SIZE] __aligned(PAGE_SIZE);\nstatic uint32_t hpet_timer_period = 0;\nstatic size_t   hpet_timer_id = 0;\nstatic struct   hpet *hpet = NULL;\nstatic void (*hpet_handler)(void);\n\n#define HPET_ADDR(off) ((uintptr_t)hpet_data + (off))\n#define HPET_REG(off) ((uint32_t) hpet->address.address + (off))\n\nstatic uint64_t hpet_reg_read(uint16_t off)\n{\n    if (hpet->address.type == HPET_PORT_IO)\n        //return inq(HPET_REG(off));\n        return 0;\n    else\n        return __mmio_inq(HPET_ADDR(off));\n}\n\nstatic void hpet_reg_write(uint16_t off, uint64_t val)\n{\n    if (hpet->address.type == HPET_PORT_IO)\n        //return inq(HPET_REG(off));\n        return;\n    else\n        __mmio_outq(HPET_ADDR(off), val);\n}\n\nvoid hpet_irq_handler(void)\n{\n    if (hpet_handler)\n        hpet_handler();\n}\n\nint hpet_timer_setup(size_t period_ns, void (*handler)())\n{\n    hpet_handler = handler;\n\n    /* Initialize timer */\n    uint64_t period_fs = period_ns * 1000000ULL;\n    size_t n = hpet_timer_id;\n\n    printk(\"HPET: Setting timer %d with period %ld fs\\n\", n, period_fs);\n\n    hpet_reg_write(HPET_REG_TMR_CNF(n), _INT_ENB | _PERIODIC | _SET_VAL);\n    hpet_reg_write(HPET_REG_TMR_CMP(n), hpet_reg_read(HPET_REG_CNT) + period_fs);\n    hpet_reg_write(HPET_REG_TMR_CMP(n), period_fs);\n\n    //irq_install_handler(0, hpet_irq_handler);\n\n    hpet_reg_write(HPET_REG_CNF, _TMR_ENB | _LEGACY);\n    return 0;\n}\n\nvoid hpet_setup()\n{\n    uintptr_t hpet_addr = acpi_rsdt_find(\"HPET\");\n\n    printk(\"HPET: Found at %p\\n\", hpet_addr);\n    hpet = (struct hpet *) hpet_addr;\n\n    if (hpet->address.type == HPET_MEM_IO) {\n        printk(\"HPET: Mem I/O\\n\");\n        printk(\"HPET: Addr %p\\n\", hpet->address.address);\n        printk(\"HPET: Remappng addr to %p\\n\", hpet_data);\n        //pmman.map_to(__hpet->address.address, (uintptr_t) hpet_data, PAGE_SIZE, KRW);\n    }\n\n    struct hpet_reg_cap cap;\n    cap.value = hpet_reg_read(HPET_REG_CAP);\n    hpet_timer_period = cap.counter_clk_period;\n\n    size_t tmrs_cnt = cap.num_tim;\n    for (size_t i = 0; i < tmrs_cnt; ++i) {\n        struct hpet_reg_tmr_cnf tcnf;\n        tcnf.value = hpet_reg_read(HPET_REG_TMR_CNF(i));\n        if (tcnf.cap_per) {\n            hpet_timer_id = i;\n            printk(\"HPET: Using timer %d\\n\", i);\n            break;\n        }\n    }\n\n    //hpet_timer_setup(500ULL * 1000 * 1000, NULL);\n}\n"
  },
  {
    "path": "kernel/arch/i386/platform/misc/i8042.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n#include <core/kargs.h>\n#include <cpu/cpu.h>\n#include <cpu/io.h>\n#include <platform/misc.h>\n\nstatic struct ioaddr i8042_ioaddr;\n\nstatic void (*channel1_handler)(int) = NULL;\nstatic void (*channel2_handler)(int) = NULL;\n\n#define FIRST_IRQ        1\n#define SECOND_IRQ       12\n\n#define DATA_PORT        0x00\n#define STATUS_PORT      0x04\n#define COMMAND_PORT     0x04\n\n#define STATUS_OBUF_FULL 0x01\n#define STATUS_IBUF_FULL 0x02\n#define STATUS_SYSTEM    0x04\n#define STATUS_COMMAND   0x08\n#define STATUS_TOUT      0x40\n#define STATUS_PARITY    0x80\n\nstatic uint8_t read_status(void)\n{\n    return io_in8(&i8042_ioaddr, STATUS_PORT);\n}\n\nstatic void x86_i8042_read_wait(void)\n{\n    /* TODO -- timeout */\n    while (read_status() & STATUS_IBUF_FULL);\n}\n\nstatic int x86_i8042_check(void)\n{\n    io_out8(&i8042_ioaddr, COMMAND_PORT, 0xAA);\n    while (!(read_status() & STATUS_OBUF_FULL));\n    uint8_t r = io_in8(&i8042_ioaddr, DATA_PORT);\n    return r == 0x55;\n}\n\nstatic void x86_i8042_first_handler(struct x86_regs *r)\n{\n    (void) r;\n\n    x86_i8042_read_wait();\n    int scancode = io_in8(&i8042_ioaddr, DATA_PORT);\n\n    if (channel1_handler)\n        channel1_handler(scancode);\n}\n\nstatic void x86_i8042_second_handler(struct x86_regs *r)\n{\n    (void) r;\n\n    x86_i8042_read_wait();\n    int scancode = io_in8(&i8042_ioaddr, DATA_PORT);\n    if (channel2_handler)\n        channel2_handler(scancode); \n}\n\nstatic void x86_i8042_handler_install(void)\n{\n    printk(\"i8042: installing IRQ %d\\n\", FIRST_IRQ);\n    x86_irq_handler_install(FIRST_IRQ, x86_i8042_first_handler);\n\n    printk(\"i8042: installing IRQ %d\\n\", SECOND_IRQ);\n    x86_irq_handler_install(SECOND_IRQ, x86_i8042_second_handler);\n\n    /* flush any pending data */\n    for (int i = 0; i < 10; ++i)\n        io_in8(&i8042_ioaddr, DATA_PORT);\n}\n\nvoid x86_i8042_handler_register(int channel, void (*fun)(int))\n{\n    switch (channel) {\n        case 1:\n            channel1_handler = fun;\n            break;\n        case 2:\n            channel2_handler = fun;\n            break;\n    }\n}\n\nvoid x86_i8042_reboot(void)\n{\n    io_out8(&i8042_ioaddr, COMMAND_PORT, 0xFE);\n}\n\nint x86_i8042_setup(struct ioaddr *io)\n{\n    i8042_ioaddr = *io;\n\n    int check = kargs_get(\"i8042.nocheck\", NULL);\n\n    if (check && !(read_status() & STATUS_SYSTEM)) {\n        printk(\"i8042: controller not found\\n\");\n        return -1;\n    } else {\n        printk(\"i8042: skipping check\\n\");\n    }\n\n    //x86_i8042_check();\n\n    printk(\"i8042: initializing controller [%p (%s)]\\n\", io->addr, ioaddr_type_str(io));\n    x86_i8042_handler_install();\n    return 0;\n}\n"
  },
  {
    "path": "kernel/arch/i386/platform/misc/pic.c",
    "content": "/**********************************************************************\n *              Programmable Interrupt Controller (PIC)\n *                   (Legacy PIC (8259) support)\n *\n *  -- Should only be used when no APIC is avilable or APIC support \n *  isn't built into the kernel.\n *\n *  This file is part of AquilaOS and is released under the terms of\n *  GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar\n */\n\n#include <core/system.h>\n#include <core/panic.h>\n\n#include <core/arch.h>\n#include <platform/misc.h>\n#include <cpu/cpu.h>\n\n#define PIC_CMD   0x00\n#define PIC_DATA  0x01\n\nstatic struct ioaddr master;\nstatic struct ioaddr slave;\n\n/**\n * \\file pic.c\n * ```\n * ICW1 (Sent on COMMAND port of each PIC)\n *\n * | A7 | A6 | A5 | 1 | LTIM | ADI | SINGL | IC4 |\n *   |____|____|          |     |     |       |______ 1=ICW4 REQUIRED\n *        |               |     |   1=SINGEL          0=ICW4 NOT REQUIRED\n *  A7:5 OF INTERRUPT     |     |   0=CASCADED\n *   VECTOR ADDRESS       |     |\n * (MCS-80/85 MODE ONLY!) | CALL ADDRESS INTERVAL (IGNORED IN 8086 MODE)\n *                        | 1=INTERVAL OF 4\n *                        | 0=INTERVAL OF 8\n *                        |\n *              1=LEVEL TRIGERED MODE\n *              0= EDGE TRIGERED MODE\n *\n *******************************************************************************\n * ICW2 (Sent on DATA port of each PIC)\n *\n * | A15 | A14 | A13 | A12 | A11 | A10 | A9 | A8 |\n *   |_____|_____|_____|_____|_____|_____|____|\n *                        |\n *     A15:8 OF INTERRUPT VECTOR ADDRESS (MCS-80/85 MODE)\n *     T7:3  OF INTERRUPT VECTOR ADDRESS (8086 MODE)\n *\n *******************************************************************************\n * ICW3 (Sent on DATA port of each PIC)\n *\n * --FOR MASTER:\n * | S7 | S6 | S5 | S4 | S3 | S2 | S1 | S0 |\n *   |____|____|____|____|____|____|____|\n *                  |\n *       1=IR LINE HAS SLAVE (CASCADED)\n *       0=IR LINE DOES NOT HAVE SLAVE (SINGLE)\n *\n * --FOR SLAVE:\n * | 0 | 0 | 0 | 0 | 0 | ID2 | ID1 | ID0 |\n *                       |_____|_____|\n *                             |\n *                         SLAVE ID\n *\n *******************************************************************************\n * ICW4 (Sent on DATA port of each PIC)\n * Well, I am too lazy to write this one XD so I will just tell you that setting\n * the least-significant bit sets the PIC to 8086 MODE\n *```\n */\n\n#define ICW1        0x11 /* Both Master and Slave use the same ICW1 */\n#define ICW2_MASTER 0x20 /* Interrupts (from Master) start from offset 32 */\n#define ICW2_SLAVE  0x28 /* Interrupts (from Slave)  start from offset 40 */\n#define ICW3_MASTER 0x04 /* Master has a Slave attached to IR 2 */\n#define ICW3_SLAVE  0x02 /* Slave ID is 2 */\n#define ICW4        0x01 /* Sets PIC to 8086 MODE */\n\n/* The mask value currently on slave:master */\nstatic uint16_t pic_mask = 0xFFFF;\n\nvoid x86_irq_mask(int irq)\n{\n    if (irq < 8) {  /* Master */\n        pic_mask |= 1 << irq;\n        io_out8(&master,  PIC_DATA, pic_mask & 0xFF);\n    } else if (irq < 16) {  /* Slave */\n        pic_mask |= 1 << irq;\n        io_out8(&slave,  PIC_DATA, (pic_mask >> 8) & 0xFF);\n    } else {\n        panic(\"Invalid IRQ number\\n\");\n    }\n}\n\nvoid x86_irq_unmask(int irq)\n{\n    if (irq < 8) {  /* Master */\n        pic_mask &= ~(1 << irq);\n        io_out8(&master,  PIC_DATA, pic_mask & 0xFF);\n    } else if (irq < 16) {  /* Slave */\n        pic_mask &= ~(1 << irq);\n        pic_mask &= ~(1 << 2);  /* Unmask slave */\n        io_out8(&slave,  PIC_DATA, (pic_mask >> 8) & 0xFF);\n    } else {\n        panic(\"Invalid IRQ number\\n\");\n    }\n}\n\nstatic void x86_irq_remap(void)\n{\n    /*\n     * Initializes PIC & remaps PIC interrupts to different interrupt\n     * numbers so as not to conflict with CPU exceptions\n     */\n\n    io_out8(&master, PIC_CMD,  ICW1);\n    io_out8(&slave,  PIC_CMD,  ICW1);\n    io_out8(&master, PIC_DATA, ICW2_MASTER);\n    io_out8(&slave,  PIC_DATA, ICW2_SLAVE);\n    io_out8(&master, PIC_DATA, ICW3_MASTER);\n    io_out8(&slave,  PIC_DATA, ICW3_SLAVE);\n    io_out8(&master, PIC_DATA, ICW4);\n    io_out8(&slave,  PIC_DATA, ICW4);\n}\n\nextern void __x86_irq0 (void);\nextern void __x86_irq1 (void);\nextern void __x86_irq2 (void);\nextern void __x86_irq3 (void);\nextern void __x86_irq4 (void);\nextern void __x86_irq5 (void);\nextern void __x86_irq6 (void);\nextern void __x86_irq7 (void);\nextern void __x86_irq8 (void);\nextern void __x86_irq9 (void);\nextern void __x86_irq10(void);\nextern void __x86_irq11(void);\nextern void __x86_irq12(void);\nextern void __x86_irq13(void);\nextern void __x86_irq14(void);\nextern void __x86_irq15(void);\n\nstatic x86_irq_handler_t irq_handlers[16];\n\nvoid x86_irq_handler_install(unsigned irq, x86_irq_handler_t handler)\n{\n    if (irq < 16) {\n        x86_irq_unmask(irq);\n        irq_handlers[irq] = handler;\n    }\n}\n\nvoid x86_irq_handler_uninstall(unsigned irq)\n{\n    if (irq < 16) {\n        x86_irq_mask(irq);\n        irq_handlers[irq] = (x86_irq_handler_t) NULL;\n    }\n}\n\n#define IRQ_ACK 0x20\nstatic void x86_irq_ack(uint32_t irq_no)\n{\n    if (irq_no > 7) /* IRQ fired from the Slave PIC */\n        io_out8(&slave, PIC_CMD, IRQ_ACK);\n\n    io_out8(&master, PIC_CMD, IRQ_ACK);\n}\n\nvoid __x86_irq_handler(struct x86_regs *r)\n{\n    extern uint32_t __x86_isr_int_num;\n\n    x86_irq_handler_t handler = NULL;\n\n    if (__x86_isr_int_num > 47 || __x86_isr_int_num < 32) /* Out of range */\n        handler = NULL;\n    else\n        handler = irq_handlers[__x86_isr_int_num - 32];\n\n    x86_irq_ack(__x86_isr_int_num - 32);\n\n    if (handler)\n        handler(r);\n}\n\nstatic void x86_irq_gates_setup(void)\n{\n    x86_idt_gate_set(32, (uintptr_t) __x86_irq0);\n    x86_idt_gate_set(33, (uintptr_t) __x86_irq1);\n    x86_idt_gate_set(34, (uintptr_t) __x86_irq2);\n    x86_idt_gate_set(35, (uintptr_t) __x86_irq3);\n    x86_idt_gate_set(36, (uintptr_t) __x86_irq4);\n    x86_idt_gate_set(37, (uintptr_t) __x86_irq5);\n    x86_idt_gate_set(38, (uintptr_t) __x86_irq6);\n    x86_idt_gate_set(39, (uintptr_t) __x86_irq7);\n    x86_idt_gate_set(40, (uintptr_t) __x86_irq8);\n    x86_idt_gate_set(41, (uintptr_t) __x86_irq9);\n    x86_idt_gate_set(42, (uintptr_t) __x86_irq10);\n    x86_idt_gate_set(43, (uintptr_t) __x86_irq11);\n    x86_idt_gate_set(44, (uintptr_t) __x86_irq12);\n    x86_idt_gate_set(45, (uintptr_t) __x86_irq13);\n    x86_idt_gate_set(46, (uintptr_t) __x86_irq14);\n    x86_idt_gate_set(47, (uintptr_t) __x86_irq15);\n}\n\nstatic int x86_pic_probe(void)\n{\n    /* Mask all slave IRQs */\n    io_out8(&slave, PIC_DATA, 0xFF);\n\n    /* Mask all master IRQs -- except slave cascade */\n    io_out8(&master, PIC_DATA, 0xDF);\n\n    /* Check if there is a devices listening to port */\n    if (io_in8(&master, PIC_DATA) != 0xDF)\n        return -1;\n\n    return 0;\n}\n\nvoid x86_pic_disable(void)\n{\n    /* Done by masking all IRQs */\n    io_out8(&slave,  PIC_DATA, 0xFF);\n    io_out8(&master, PIC_DATA, 0xFF);\n}\n\nint x86_pic_setup(struct ioaddr *_master, struct ioaddr *_slave)\n{\n    master = *_master;\n    slave  = *_slave;\n\n    if (x86_pic_probe()) {\n        printk(\"i8259: Controller not found\\n\");\n        return -1;\n    }\n\n    printk(\"i8259: initializing [Master: %p (%s), Salve: %p (%s)]\\n\",\n            master.addr, ioaddr_type_str(&master),\n            slave.addr, ioaddr_type_str(&slave));\n\n    /* Initialize */\n    x86_irq_remap();\n\n    /* Mask all interrupts */\n    x86_pic_disable();\n\n    /* Setup call gates */\n    x86_irq_gates_setup();\n    return 0;\n}\n"
  },
  {
    "path": "kernel/arch/i386/platform/misc/pit.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n#include <core/kargs.h>\n#include <cpu/io.h>\n#include <platform/misc.h>\n\nstatic struct ioaddr pit_ioaddr;\n\n#define PIT_CHANNEL0    0x00\n#define PIT_CMD         0x03\n\nstruct pit_cmd_register {\n    union {\n        struct {\n            uint32_t bcd    : 1;\n            uint32_t mode   : 3;\n            uint32_t access : 2;\n            uint32_t channel: 2;\n        } __packed;\n        uint8_t raw;\n    } __packed;\n} __packed;\n\n#define PIT_MODE_RATE_GENERATOR 0x2\n#define PIT_MODE_SQUARE_WAVE    0x3\n#define PIT_ACCESS_LOHIBYTE     0x3\n\nint x86_pit_setup(struct ioaddr *io)\n{\n    printk(\"i8254: Initializing [%p (%s)]\\n\", io->addr, ioaddr_type_str(io));\n    pit_ioaddr = *io;\n    return 0;\n}\n\n#define FBASE   1193182ULL  /* PIT Oscillator operates at 1.193182 MHz */\n\nstatic uint32_t atou32(const char *s)\n{\n    uint32_t ret = 0;\n\n    while (*s) {\n        ret = ret * 10 + (*s - '0');\n        ++s;\n    }\n\n    return ret;\n}\n\nuint32_t x86_pit_period_set(uint32_t period_ns)\n{\n    printk(\"i8254: requested period %d ns\\n\", period_ns);\n\n    uint32_t div;\n    const char *arg_div = NULL;\n\n    if (!kargs_get(\"i8254.div\", &arg_div)) {\n        div = atou32(arg_div);\n    } else {\n        div = period_ns/838UL;\n    }\n\n    if (div == 0) div = 1;\n\n    period_ns = 1000000000UL/(FBASE/div);\n\n    printk(\"i8254: Setting period to %d ns (div = %d)\\n\", period_ns, div);\n\n    struct pit_cmd_register cmd = {\n        .bcd = 0,\n        .mode = PIT_MODE_SQUARE_WAVE,\n        .access = PIT_ACCESS_LOHIBYTE,\n        .channel = 0,\n    };\n\n    io_out8(&pit_ioaddr, PIT_CMD, cmd.raw);\n    io_out8(&pit_ioaddr, PIT_CHANNEL0, (div >> 0) & 0xFF);\n    io_out8(&pit_ioaddr, PIT_CHANNEL0, (div >> 8) & 0xFF);\n\n    return period_ns;\n}\n"
  },
  {
    "path": "kernel/arch/i386/platform/pc/Build.mk",
    "content": "obj-y += init.o\nobj-y += reboot.o\n"
  },
  {
    "path": "kernel/arch/i386/platform/pc/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/arch/i386/platform/pc/init.c",
    "content": "#include <core/kargs.h>\n#include <core/system.h>\n#include <cpu/io.h>\n#include <dev/pci.h>\n#include <platform/misc.h>\n\n\n/* PCI bus */\n#define PCI_ADDR    0xCF8\n#define PCI_TYPE    IOADDR_PORT\n\n/* i8042 PS/2 controller */\n#define I8042_ADDR  0x60\n#define I8042_TYPE  IOADDR_PORT\n\n/* i8254 PIT controller */\n#define I8254_ADDR  0x40\n#define I8254_TYPE  IOADDR_PORT\n\n#define PIC_MASTER  0x20\n#define PIC_SLAVE   0xA0\n\nstatic int x86_pc_pic_init(void)\n{\n    struct ioaddr pic_master;\n    struct ioaddr pic_slave;\n\n    pic_master.addr = PIC_MASTER;\n    pic_master.type = IOADDR_PORT;\n    pic_slave.addr  = PIC_SLAVE;\n    pic_slave.type  = IOADDR_PORT;\n\n    return x86_pic_setup(&pic_master, &pic_slave);\n}\n\nstatic void x86_pc_pci_init(void)\n{\n    printk(\"x86: Initializing PCI\\n\");\n\n    struct ioaddr pci;\n\n    pci.addr = PCI_ADDR;\n    pci.type = PCI_TYPE;\n\n    pci_ioaddr_set(&pci);\n}\n\nstatic int x86_pc_i8042_init(void)\n{\n    struct ioaddr i8042;\n\n    i8042.addr = I8042_ADDR;\n    i8042.type = I8042_TYPE;\n\n    return x86_i8042_setup(&i8042);\n}\n\nstatic int x86_pc_pit_init(void)\n{\n    struct ioaddr pit;\n\n    pit.addr = I8254_ADDR;\n    pit.type = I8254_TYPE;\n\n    return x86_pit_setup(&pit);\n}\n\nstatic int x86_pc_cmos_init(void)\n{\n    struct ioaddr cmos;\n    cmos.addr = 0x70;\n    cmos.type = IOADDR_PORT;\n\n    return x86_cmos_setup(&cmos);\n}\n\n#define PIT_IRQ 0\nuint32_t platform_timer_setup(size_t period_ns, void (*handler)())\n{\n    uint32_t period = x86_pit_period_set(period_ns);\n    x86_irq_handler_install(PIT_IRQ, handler);\n    return period;\n}\n\nint platform_init(void)\n{\n    x86_pc_pci_init();\n    x86_pc_pic_init();\n    x86_pc_i8042_init();\n    x86_pc_pit_init();\n    x86_pc_cmos_init();\n    \n    return 0;\n}\n"
  },
  {
    "path": "kernel/arch/i386/platform/pc/reboot.c",
    "content": "#include <core/system.h>\n#include <core/arch.h>\n#include <platform/misc.h>\n\nvoid platform_reboot(void)\n{\n    x86_i8042_reboot();\n}\n\nvoid arch_reboot(void)\n{\n    platform_reboot();\n} \n"
  },
  {
    "path": "kernel/arch/i386/platform/quark/Build.mk",
    "content": "dirs-y += legacy/\nobj-y += init.o\n"
  },
  {
    "path": "kernel/arch/i386/platform/quark/include/chipset/legacy_bridge.h",
    "content": "#ifndef _QUARK_LEGACY_BRIDGE_H\n#define _QUARK_LEGACY_BRIDGE_H\n\n#include <dev/pci.h>\n\nextern struct pci_dev qrk_leg_brdg;\nvoid quark_legacy_bridge_setup();\n\n#endif /* ! _QUARK_LEGACY_BRIDGE_H */\n"
  },
  {
    "path": "kernel/arch/i386/platform/quark/include/chipset/root_complex.h",
    "content": "#ifndef _QUARK_ROOT_COMPLEX_H\n#define _QUARK_ROOT_COMPLEX_H\n\nvoid quark_root_complex_io_fabric_route(int intr_pin, int irq);\nvoid quark_root_complex_init();\n\n#endif /* ! _QUARK_ROOT_COMPLEX_H */\n"
  },
  {
    "path": "kernel/arch/i386/platform/quark/include/chipset/system.h",
    "content": "#ifndef _QUARK_CHIPSET\n#define _QUARK_CHIPSET\n\nvoid quark_legacy_bridge_setup();\n\n#endif /* ! _QUARK_CHIPSET */\n"
  },
  {
    "path": "kernel/arch/i386/platform/quark/init.c",
    "content": "#include <core/system.h>\n#include <chipset/system.h>\n#include <chipset/misc.h>\n#include <cpu/io.h>\n#include <console/earlycon.h>\n#include <dev/pci.h>\n\n#include <chipset/legacy_bridge.h>\n#include <chipset/root_complex.h>\n\n#define PIC_MASTER  0x20\n#define PIC_SLAVE   0xA0\n\nint quark_pic_setup()\n{\n    struct ioaddr pic_master;\n    struct ioaddr pic_slave;\n\n    pic_master.addr = PIC_MASTER;\n    pic_master.type = IOADDR_PORT;\n    pic_slave.addr  = PIC_SLAVE;\n    pic_slave.type  = IOADDR_PORT;\n\n    return x86_pic_setup(&pic_master, &pic_slave);\n}\n\nvoid quark_pci_init()\n{\n    printk(\"Quark SoC: Initializing PCI\\n\");\n    struct ioaddr pci;\n    pci.addr = 0xCF8;\n    pci.type = IOADDR_PORT;\n    pci_ioaddr_set(&pci);\n}\n\n#define QRK_HSUART_VENDOR_ID  0x8086\n#define QRK_HSUART_DEVICE_ID  0x0936\n\n#define QRK_HSUART_REG_INTR_PIN 0x3D\n#define UART_IER    1\n#define UART_FCR    2\n#define UART_LCR    3\n#define UART_MCR    4\n#define UART_DLL    0\n#define UART_DLH    1\n#define UART_LCR_DLAB    0x80\n\nstatic struct pci_dev hsuart;\nstatic struct ioaddr __hsuart_ioaddr = {\n    .addr = 0xCF00B000,\n    .type = IOADDR_MMIO32,\n};\n\nvoid quark_hsuart_setup()\n{\n    printk(\"Quark SoC: Initalizing HSUART\\n\");\n\n    if (pci_device_scan(QRK_HSUART_VENDOR_ID, QRK_HSUART_DEVICE_ID, &hsuart)) {\n        panic(\"Quark SoC: HSUART not found!\\n\");\n    }\n\n    printk(\"Quark SoC: HSUART [Bus: %d, Device: %d, Function: %d]\\n\", hsuart.bus, hsuart.dev, hsuart.func);\n\n    uint8_t intr_pin = pci_reg8_read(&hsuart, QRK_HSUART_REG_INTR_PIN);\n    printk(\"Quark SoC: HSUART: Interrupt Pin INT%c#\\n\", 'A' + intr_pin - 1);\n    //quark_root_complex_iofabric_route(intr_pin, 4);\n    \n    quark_root_complex_io_fabric_route(1, 4);\n    quark_root_complex_io_fabric_route(2, 4);\n    quark_root_complex_io_fabric_route(3, 4);\n    quark_root_complex_io_fabric_route(4, 4);\n\n    /* Switch HSUART to Interrup mode */\n\n    printk(\"Quark SoC: HSUART: Switching to FIFO Interrupt-Mode Operation\\n\");\n\n    /* Wait until all transmission ends */\n    while (!(io_in8(&__hsuart_ioaddr, 5) & 0x20));\n\n    io_out8(&__hsuart_ioaddr, UART_FCR, 0x07);    /* Enable FIFO, Rx trigger when 1 character in */\n    io_out8(&__hsuart_ioaddr, UART_IER, 0x01);    /* Enable Rx interrupt */\n}\n\n\n#define PIT_IRQ 0\nvoid chipset_timer_setup(size_t period_ns, void (*handler)())\n{\n    //pit_setup(timer_freq);\n    x86_irq_handler_install(PIT_IRQ, handler);\n    //hpet_timer_setup(1, x86_sched_handler);\n}\n\nint chipset_init()\n{\n    earlycon_init();\n    printk(\"Quark SoC: Welcome to AquilaOS!\\n\");\n\n    quark_pci_init();\n    quark_legacy_bridge_setup();\n    quark_pic_setup();\n    quark_hsuart_setup();\n\n    printk(\"Try it!\\n\");\n\n    for (;;)\n        asm volatile (\"sti; hlt; cli;\");\n\n    for (;;);\n\n    return 0;\n}\n"
  },
  {
    "path": "kernel/arch/i386/platform/quark/legacy/Build.mk",
    "content": "obj-y += bridge.o\nobj-y += root_complex.o\n"
  },
  {
    "path": "kernel/arch/i386/platform/quark/legacy/bridge.c",
    "content": "#include <core/system.h>\n#include <dev/pci.h>\n\n#include <chipset/root_complex.h>\n\n#define QRK_LEG_BRDG_VENDOR_ID  0x8086\n#define QRK_LEG_BRDG_DEVICE_ID  0x095E\n\nstruct pci_dev qrk_leg_brdg;\n\nvoid quark_legacy_bridge_setup()\n{\n    printk(\"Quark SoC: Initalizing Legacy Bridge\\n\");\n\n    if (pci_device_scan(QRK_LEG_BRDG_VENDOR_ID, QRK_LEG_BRDG_DEVICE_ID, &qrk_leg_brdg)) {\n        panic(\"Quark SoC: Legacy Bridge is not found!\\n\");\n    }\n\n    printk(\"Quark SoC: Legacy Bridge [Bus: %d, Device: %d, Function: %d]\\n\", qrk_leg_brdg.bus, qrk_leg_brdg.dev, qrk_leg_brdg.func);\n\n    quark_root_complex_init();\n}\n"
  },
  {
    "path": "kernel/arch/i386/platform/quark/legacy/interrupt.c",
    "content": "#include <core/system.h>\n\nvoid quark_interrupt_decoder_setup()\n{\n\n}\n"
  },
  {
    "path": "kernel/arch/i386/platform/quark/legacy/root_complex.c",
    "content": "#include <core/system.h>\n#include <chipset/legacy_bridge.h>\n#include <chipset/root_complex.h>\n\n#define QRK_LEG_BRDG_REG_RCBA   0xF0\n#define QRK_LEG_BRDG_REG_PIRQx  0x60\n\n#define QRK_LEG_BRDG_RC_IRQAGENT0  0x3140\n#define QRK_LEG_BRDG_RC_IRQAGENT1  0x3142\n#define QRK_LEG_BRDG_RC_IRQAGENT2  0x3144\n#define QRK_LEG_BRDG_RC_IRQAGENT3  0x3146\n\nstatic char __rcrb[4 * PAGE_SIZE] __aligned(PAGE_SIZE);\nstatic struct ioaddr __rcrb_ioaddr = {\n    .addr = (uintptr_t) __rcrb,\n    .type = IOADDR_MMIO8, /* Direct offset */\n};\n\n#define PIC_ELCR   0x4D0\nvoid quark_root_complex_io_fabric_route(int intr_pin, int irq)\n{\n    if (intr_pin < 1 || intr_pin > 4)\n        panic(\"Invalid INTR_PIN\");\n\n    uint32_t irqagent3 = io_in16(&__rcrb_ioaddr, QRK_LEG_BRDG_RC_IRQAGENT3);\n    printk(\"irqagent3 %x\\n\", irqagent3);\n\n    uint32_t pirq = ((irqagent3) >> (intr_pin - 1) * 4) & 0x7;\n\n    printk(\"Quark SoC: Root Complex: IO Fabric INT%c# is mapped to PIRQ%c\\n\", 'A' + intr_pin - 1, 'A' + pirq);\n    printk(\"Quark SoC: Root Complex: Routing PIRQ%c to IRQ%d\\n\", 'A' + pirq, irq);\n\n    uint8_t pirq_val = irq | (1 << 7);\n    pci_reg8_write(&qrk_leg_brdg, QRK_LEG_BRDG_REG_PIRQx + pirq, pirq_val);\n\n#if 0\n    printk(\"Quark SoC: Root Complex: Setting PIC IRQ %d to level sensetive\\n\", irq);\n    struct __ioaddr io = {\n        .addr = 0x4D0,\n        .type = __IOADDR_PORT,\n    };\n\n    if (irq >= 3 && irq <= 7) {\n        uint8_t elc = __io_in8(&io, 0); /* ELCR1 */\n        printk(\"ELCR1 %x\\n\", elc);\n        elc |= 1 << irq;\n        __io_out8(&io, 0, elc);\n    } else if ((irq >= 9 && irq <= 12) || irq == 14 || irq == 15) {\n        uint8_t elc = __io_in8(&io, 1); /* ELCR2 */\n        printk(\"ELCR2 %x\\n\", elc);\n        elc |= 1 << (irq - 8);\n        __io_out8(&io, 1, elc);\n    } else {\n        panic(\"Invalid IRQ\\n\");\n    }\n#endif\n}\n\nvoid quark_root_complex_init()\n{\n    uint32_t rcba = pci_reg32_read(&qrk_leg_brdg, QRK_LEG_BRDG_REG_RCBA);\n\n    if (!(rcba & 1)) {\n        /* Enable Root Complex */\n        rcba |= 1;\n        pci_reg32_write(&qrk_leg_brdg, QRK_LEG_BRDG_REG_RCBA, rcba);\n    }\n\n    rcba &= ~1;\n\n    printk(\"Quark SoC: Legacy Bridge: Root Complex Base Address %x\\n\", rcba);\n    printk(\"Quark SoC: Legacy Bridge: Mapping RCRB to %p\\n\", __rcrb);\n    pmman.map_to(rcba, (uintptr_t) __rcrb, 4 * PAGE_SIZE, VM_KRW);\n}\n"
  },
  {
    "path": "kernel/arch/i386/sys/Build.mk",
    "content": "obj-y += fork.o\nobj-y += proc.o\nobj-y += thread.o\nobj-y += syscall.o\nobj-y += sched.o\nobj-y += execve.o\nobj-y += signal.o\n"
  },
  {
    "path": "kernel/arch/i386/sys/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/arch/i386/sys/execve.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n#include <core/arch.h>\n#include <sys/proc.h>\n\nvoid arch_sys_execve(struct proc *proc, int argc, char * const _argp[], int envc, char * const _envp[])\n{\n    struct thread *thread = (struct thread *) proc->threads.head->value;\n    struct x86_thread *arch = thread->arch;\n\n#if ARCH_BITS==32\n    arch->eip = proc->entry;\n    arch->eflags = X86_EFLAGS;\n#else\n    arch->rip = proc->entry;\n    arch->rflags = X86_EFLAGS;\n#endif\n\n    char **argp = (char **) _argp;\n    char **u_argp = kmalloc(argc * sizeof(char *), &M_BUFFER, 0);\n\n    char **envp = (char **) _envp;\n    char **u_envp = kmalloc(envc * sizeof(char *), &M_BUFFER, 0);\n\n    /* Start at the top of user stack */\n    volatile char *stack = (volatile char *) USER_STACK;\n    tlb_flush();\n\n    /* Push envp strings */\n    int tmp_envc = envc;\n    u_envp[--tmp_envc] = NULL;\n\n    for (int i = envc - 2; i >= 0; --i) {\n        stack -= strlen(envp[i]) + 1;\n        strcpy((char *) stack, envp[i]);\n        u_envp[--tmp_envc] = (char *) stack;\n    }\n\n    /* Push argp strings */\n    int tmp_argc = argc;\n    u_argp[--tmp_argc] = NULL;\n\n    for (int i = argc - 2; i >= 0; --i) {\n        stack -= strlen(argp[i]) + 1;\n        strcpy((char *) stack, argp[i]);\n        u_argp[--tmp_argc] = (char *) stack;\n    }\n\n    stack -= envc * sizeof(char *);\n    memcpy((void *) stack, u_envp, envc * sizeof(char *));\n\n    uintptr_t env_ptr = (uintptr_t) stack;\n\n    stack -= argc * sizeof(char *);\n    memcpy((void *) stack, u_argp, argc * sizeof(char *));\n\n    uintptr_t arg_ptr = (uintptr_t) stack;\n\n    /* main(int argc, char **argv, char **envp) */\n    stack -= sizeof(uintptr_t);\n    *(volatile uintptr_t *) stack = env_ptr;\n\n    stack -= sizeof(uintptr_t);\n    *(volatile uintptr_t *) stack = arg_ptr;\n\n#if ARCH_BITS==32\n    stack -= sizeof(int32_t);\n    *(volatile int32_t *) stack = argc - 1;\n#else\n    stack -= sizeof(int64_t);\n    *(volatile int64_t *) stack = argc - 1;\n#endif\n\n    kfree(u_envp);\n    kfree(u_argp);\n\n#if ARCH_BITS==32\n    arch->esp = (uintptr_t) stack;\n#else\n    arch->rsp = (uintptr_t) stack;\n#endif\n}\n"
  },
  {
    "path": "kernel/arch/i386/sys/fork.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n#include <core/arch.h>\n\n#include <sys/proc.h>\n#include <sys/sched.h>\n\n#include <bits/errno.h>\n\nint arch_proc_fork(struct thread *thread, struct proc *fork)\n{\n    int err = 0;\n\n    struct x86_thread *ptarch = thread->arch;\n    struct x86_thread *ftarch = NULL;\n\n    ftarch = kmalloc(sizeof(struct x86_thread), &M_X86_THREAD, 0);\n\n    if (ftarch == NULL) {\n        /* Failed to allocate fork thread arch structure */\n        err = -ENOMEM;\n        goto free_resources;\n    }\n\n    /* Setup kstack */\n    uintptr_t fkstack_base = (uintptr_t) kmalloc(KERN_STACK_SIZE, &M_KERN_STACK, 0);\n    ftarch->kstack = fkstack_base + KERN_STACK_SIZE;\n\n    /* Copy registers */\n    struct x86_regs *fork_regs = (void *) (ftarch->kstack - (ptarch->kstack - (uintptr_t) ptarch->regs));\n    ftarch->regs = fork_regs;\n\n    /* Copy kstack */\n    memcpy((void *) fkstack_base, (void *) (ptarch->kstack - KERN_STACK_SIZE), KERN_STACK_SIZE);\n\n    extern void x86_fork_return();\n#if ARCH_BITS==32\n    ftarch->eip = (uintptr_t) x86_fork_return;\n    ftarch->esp = (uintptr_t) fork_regs;\n#else\n    ftarch->rip = (uintptr_t) x86_fork_return;\n    ftarch->rsp = (uintptr_t) fork_regs;\n#endif\n\n    struct thread *fthread = (struct thread *) fork->threads.head->value;\n    fthread->arch = ftarch;\n\n    ftarch->fpu_enabled = 0;\n    ftarch->fpu_context = NULL;\n\n    return 0;\n\nfree_resources:\n    if (ftarch)\n        kfree(ftarch);\n    return err;\n}\n"
  },
  {
    "path": "kernel/arch/i386/sys/proc.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n#include <core/arch.h>\n#include <sys/proc.h>\n#include <sys/sched.h>\n#include <sys/signal.h>\n#include <ds/queue.h>\n#include <mm/pmap.h>\n\nvoid arch_proc_init(struct proc *proc)\n{\n    struct x86_thread *arch = kmalloc(sizeof(struct x86_thread), &M_X86_THREAD, M_ZERO);\n    if (!arch) {\n        /* TODO */\n    }\n\n    //struct arch_binfmt *s = d;\n    //pmap->map = s->new_map;\n\n    uintptr_t kstack_base = (uintptr_t) kmalloc(KERN_STACK_SIZE, &M_KERN_STACK, 0);\n\n    arch->kstack = kstack_base + KERN_STACK_SIZE;   /* Kernel stack */\n#if ARCH_BITS==32\n    arch->eip    = proc->entry;\n    arch->esp    = USER_STACK;\n    arch->eflags = X86_EFLAGS;\n#else\n    arch->rip    = proc->entry;\n    arch->rsp    = USER_STACK;\n    arch->rflags = X86_EFLAGS;\n#endif\n\n    //p->vm_space.pmap = pmap;\n\n    struct thread *thread = (struct thread *) proc->threads.head->value;\n    thread->arch = arch;\n}\n\nvoid arch_init_execve(struct proc *proc, int argc, char * const _argp[], int envc, char * const _envp[])\n{\n    //printk(\"arch_init_execve(proc=%p, argc=%d, _argp=%p, envc=%d, _envp=%p)\\n\", proc, argc, _argp, envc, _argp);\n\n    struct pmap *pmap = proc->vm_space.pmap;\n    struct thread *thread = (struct thread *) proc->threads.head->value;\n\n    curthread = thread;\n    pmap_switch(pmap);\n\n    arch_sys_execve(proc, argc, _argp, envc, _envp);\n    curthread = NULL;\n}\n"
  },
  {
    "path": "kernel/arch/i386/sys/sched.c",
    "content": "#include <core/arch.h>\n#include <core/platform.h>\n#include <core/time.h>\n#include <mm/mm.h>\n#include <sys/proc.h>\n#include <sys/sched.h>\n\n#include \"sys.h\"\n\nstatic uint32_t timer_period = 0;\nstatic uint64_t timer_ticks = 0;\n\nuint64_t arch_rtime_ns(void)\n{\n    return timer_ticks * timer_period;\n}\n\nuint64_t arch_rtime_us(void)\n{\n    return timer_ticks * timer_period / 1000ULL;\n}\n\nuint64_t arch_rtime_ms(void)\n{\n    return timer_ticks * timer_period / 1000000ULL;\n}\n\nstatic uint64_t first_measured_time = 0;\n\nstatic void x86_sched_handler(struct x86_regs *r) \n{\n    /* we check time every 2^16 ticks */\n    if (!(timer_ticks & 0xFFFF)) {\n        if (!timer_ticks) {\n            struct timespec ts = {0};\n            gettime(&ts);\n            first_measured_time = ts.tv_sec;\n        } else {\n            struct timespec ts = {0};\n            gettime(&ts);\n\n            uint64_t measured_time = ts.tv_sec - first_measured_time;\n            uint64_t calculated_time = arch_rtime_ms() / 1000;\n\n            int32_t delta = calculated_time - measured_time;\n\n            if (ABS(delta) > 1) {\n                printk(\"warning: calculated time differs from measured time by %c%d seconds\\n\", delta < 0? '-' : '+', ABS(delta));\n                printk(\"calculated time: %d seconds\\n\", calculated_time);\n                printk(\"measured time: %d seconds\\n\", measured_time);\n\n                /* TODO: attempt to correct time */\n            }\n        }\n    }\n\n    ++timer_ticks;\n\n    if (!kidle) {\n        struct x86_thread *arch = (struct x86_thread *) curthread->arch;\n\n        extern uintptr_t x86_read_ip(void);\n\n        volatile uintptr_t ip = 0, sp = 0, bp = 0;    \n#if ARCH_BITS==32\n        asm volatile(\"mov %%esp, %0\":\"=r\"(sp)); /* read esp */\n        asm volatile(\"mov %%ebp, %0\":\"=r\"(bp)); /* read ebp */\n#else\n        asm volatile(\"mov %%rsp, %0\":\"=r\"(sp)); /* read rsp */\n        asm volatile(\"mov %%rbp, %0\":\"=r\"(bp)); /* read rbp */\n#endif\n        ip = x86_read_ip();\n\n        if (ip == (uintptr_t) -1) {    /* Done switching */\n            return;\n        }\n\n#if ARCH_BITS==32\n        arch->eip = ip;\n        arch->esp = sp;\n        arch->ebp = bp;\n#else\n        arch->rip = ip;\n        arch->rsp = sp;\n        arch->rbp = bp;\n#endif\n    }\n\n    schedule();\n}\n\nvoid arch_sched_init(void)\n{\n    timer_period = platform_timer_setup(2000000, x86_sched_handler);\n}\n\nstatic void __arch_idle(void)\n{\n    for (;;) {\n        asm volatile(\"sti; hlt; cli;\");\n    }\n}\n\nstatic char __idle_stack[8192] __aligned(16);\n\nvoid arch_idle(void)\n{\n    curthread = NULL;\n\n    uintptr_t esp = VMA(0x100000);\n    x86_kernel_stack_set(esp);\n    uintptr_t stack = (uintptr_t) __idle_stack + 8192;\n    extern void x86_goto(uintptr_t eip, uintptr_t ebp, uintptr_t esp) __attribute__((noreturn));\n    x86_goto((uintptr_t) __arch_idle, stack, stack);\n}\n\nstatic void __arch_cur_thread_kill(void)\n{\n    thread_kill(curthread);    /* Will set the stack to VMA(0x100000) */\n    kfree(curthread);\n    curthread = NULL;\n    kernel_idle();\n}\n\nvoid arch_cur_thread_kill(void)\n{\n    uintptr_t stack = (uintptr_t) __idle_stack + 8192;\n\n    extern void x86_goto(uintptr_t eip, uintptr_t ebp, uintptr_t esp) __attribute__((noreturn));\n    x86_goto((uintptr_t) __arch_cur_thread_kill, stack, stack);\n}\n\nvoid arch_sleep(void)\n{\n    extern void x86_sleep(void);\n    x86_sleep();\n}\n"
  },
  {
    "path": "kernel/arch/i386/sys/signal.c",
    "content": "#include <core/system.h>\n#include <core/arch.h>\n#include <sys/signal.h>\n#include <sys/proc.h>\n#include <sys/sched.h>\n#include <cpu/cpu.h>\n\nvoid arch_handle_signal(int sig)\n{\n    uintptr_t handler = curproc->sigaction[sig].sa_handler;\n\n    /* can't signal a zmobie */\n    if (!curproc->running)\n        return;\n\n    if (handler == SIG_DFL)\n        handler = sig_default_action[sig];\n\n    struct x86_thread *arch = curthread->arch;\n\n    switch (handler) {\n        case SIGACT_IGNORE:\n            return;\n        case SIGACT_ABORT:\n        case SIGACT_TERMINATE:\n            curproc->exit = PROC_EXIT(sig, sig);\n            proc_kill(curproc);\n            arch_sleep();\n            break;  /* We should never reach this anyway */\n    }\n\n    arch->kstack -= sizeof(struct x86_regs);\n    x86_kernel_stack_set(arch->kstack);\n\n#if ARCH_BITS==32\n    uintptr_t sig_sp = arch->regs->esp;\n#else\n    uintptr_t sig_sp = arch->regs->rsp;\n#endif\n\n    /* Push signal number */\n    sig_sp -= sizeof(int);\n    *(int *) sig_sp = sig;\n\n    /* Push return address */\n    sig_sp -= sizeof(uintptr_t);\n    *(uintptr_t *) sig_sp = 0x0FFF;\n\n    extern void x86_jump_user(uintptr_t eax, uintptr_t eip, uintptr_t cs, uintptr_t eflags, uintptr_t esp, uintptr_t ss) __attribute__((noreturn));\n#if ARCH_BITS==32\n    x86_jump_user(0, handler, X86_CS, arch->eflags, sig_sp, X86_SS);\n#else\n    x86_jump_user(0, handler, X86_CS, arch->rflags, sig_sp, X86_SS);\n#endif\n}\n"
  },
  {
    "path": "kernel/arch/i386/sys/sys.h",
    "content": "#include <core/system.h>\n#include <cpu/cpu.h>\n#include <mm/mm.h>\n#include <sys/proc.h>\n\nvoid x86_jump_user(uintptr_t eax, uintptr_t eip, uintptr_t cs, uintptr_t eflags, uintptr_t esp, uintptr_t ss) __attribute__((noreturn));\nvoid x86_goto(uintptr_t eip, uintptr_t ebp, uintptr_t esp) __attribute__((noreturn));\n\n#define PUSH(stack, type, value)\\\n    do {\\\n        (stack) -= sizeof(type);\\\n        *((type *) (stack)) = (type) (value);\\\n    } while (0)\n"
  },
  {
    "path": "kernel/arch/i386/sys/syscall.c",
    "content": "#include <core/system.h>\n#include <core/arch.h>\n#include <sys/proc.h>\n#include <sys/sched.h>\n#include <sys/syscall.h>\n#include <bits/errno.h>\n\nvoid arch_syscall(struct x86_regs *r)\n{\n#if ARCH_BITS==32\n    if (r->eax >= syscall_cnt) {\n        printk(\"[%d:%d] %s: undefined syscall %d\\n\", curproc->pid, curthread->tid, curproc->name, r->eax);\n#else\n    if (r->rax >= syscall_cnt) {\n        printk(\"[%d:%d] %s: undefined syscall %ld\\n\", curproc->pid, curthread->tid, curproc->name, r->rax);\n#endif\n        arch_syscall_return(curthread,-ENOSYS);\n        return;\n    }\n\t\n#if ARCH_BITS==32\n    void (*syscall)(uintptr_t, uintptr_t, uintptr_t) = syscall_table[r->eax];\n    syscall(r->ebx, r->ecx, r->edx);\n#else\n    void (*syscall)() = syscall_table[r->rax];\n    syscall(r->rbx, r->rcx, r->rdx);\n#endif\n}\n\nvoid arch_syscall_return(struct thread *thread, uintptr_t val)\n{\n    struct x86_thread *arch = thread->arch;\n\n#if ARCH_BITS==32\n    if (thread->spawned) arch->regs->eax = val;\n    else arch->eax = val;\n#else\n    if (thread->spawned) arch->regs->rax = val;\n    else arch->rax = val;\n#endif\n}\n"
  },
  {
    "path": "kernel/arch/i386/sys/thread.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n#include <core/arch.h>\n#include <sys/proc.h>\n#include <sys/sched.h>\n#include <sys/signal.h>\n#include <ds/queue.h>\n#include <mm/pmap.h>\n\nMALLOC_DEFINE(M_KERN_STACK, \"kern-stack\", \"kernel stack\");\nMALLOC_DEFINE(M_X86_THREAD, \"x86-thread\", \"x86 thread structure\");\n\n#define PUSH(stack, type, value)\\\ndo {\\\n    (stack) -= sizeof(type);\\\n    *((type *) (stack)) = (type) (value);\\\n} while (0)\n\nvoid arch_thread_spawn(struct thread *thread)\n{\n    struct x86_thread *arch  = thread->arch;\n    struct pmap *pmap = thread->owner->vm_space.pmap;\n\n    pmap_switch(pmap);\n\n    x86_kernel_stack_set(arch->kstack);\n\n#if ARCH_BITS==32\n    x86_jump_user(arch->eax, arch->eip, X86_CS, arch->eflags, arch->esp, X86_SS);\n#else\n    x86_jump_user(arch->rax, arch->rip, X86_CS, arch->rflags, arch->rsp, X86_SS);\n#endif\n}\n\nvoid arch_thread_switch(struct thread *thread)\n{\n    //printk(\"[%d:%d] %s: arch_thread_switch(thread=%p)\\n\", thread->owner->pid, thread->tid, thread->owner->name, thread);\n\n    struct x86_thread *arch  = thread->arch;\n    struct pmap *pmap = thread->owner->vm_space.pmap;\n\n    pmap_switch(pmap);\n\n    x86_kernel_stack_set(arch->kstack);\n    x86_fpu_disable();\n\n    if (thread->owner->sig_queue->count) {\n        int sig = (int)(intptr_t) dequeue(thread->owner->sig_queue);\n        arch_handle_signal(sig);\n        /* if we get back here, the signal was ignored */\n    }\n\n#if ARCH_BITS==32\n    x86_goto(arch->eip, arch->ebp, arch->esp);\n#else\n    x86_goto(arch->rip, arch->rbp, arch->rsp);\n#endif\n}\n\nvoid arch_thread_create(struct thread *thread, uintptr_t stack, uintptr_t entry, uintptr_t uentry, uintptr_t arg)\n{\n    struct x86_thread *arch = kmalloc(sizeof(struct x86_thread), &M_X86_THREAD, M_ZERO);\n    if (!arch) {\n        /* TODO */\n    }\n\n    arch->kstack = (uintptr_t) kmalloc(KERN_STACK_SIZE, &M_KERN_STACK, 0) + KERN_STACK_SIZE;\n\n    /* dummy return address */\n    PUSH(arch->kstack, void *, 0);\n\n    /* dummy base pointer */\n    PUSH(arch->kstack, void *, 0);\n\n#if ARCH_BITS==32\n    arch->eflags = X86_EFLAGS;\n    arch->eip = entry;\n#else\n    arch->rflags = X86_EFLAGS;\n    arch->rip = entry;\n#endif\n\n    /* Push thread argument */\n    PUSH(stack, void *, arg);\n\n    /* Push user entry point */\n    PUSH(stack, void *, uentry);\n\n    /* Dummy return address */\n    PUSH(stack, void *, 0);\n\n#if ARCH_BITS==32\n    arch->esp = stack;\n#else\n    arch->rsp = stack;\n#endif\n    thread->arch = arch;\n}\n\nvoid arch_thread_kill(struct thread *thread)\n{\n    struct x86_thread *arch = (struct x86_thread *) thread->arch;\n\n    if (thread == curthread) {\n        /* We don't wanna die here */\n        uintptr_t esp = VMA(0x100000); /* XXX */\n        x86_kernel_stack_set(esp);\n    }\n\n    if (arch->kstack)\n        kfree((void *) (arch->kstack - KERN_STACK_SIZE));\n\n    if (arch->fpu_context)\n        kfree(arch->fpu_context);\n\n    extern struct thread *last_fpu_thread;\n    if (last_fpu_thread == thread)\n        last_fpu_thread = NULL;\n\n    kfree(arch);\n}\n\nvoid internal_arch_sleep()\n{\n    struct x86_thread *arch = curthread->arch;\n    extern uintptr_t x86_read_ip(void);\n\n    uintptr_t ip = 0, sp = 0, bp = 0;    \n#if ARCH_BITS==32\n    asm(\"mov %%esp, %0\":\"=r\"(sp)); /* read esp */\n    asm(\"mov %%ebp, %0\":\"=r\"(bp)); /* read ebp */\n#else\n    asm(\"mov %%rsp, %0\":\"=r\"(sp)); /* read rsp */\n    asm(\"mov %%rbp, %0\":\"=r\"(bp)); /* read rbp */\n#endif\n    ip = x86_read_ip();\n\n    if (ip == (uintptr_t) -1) {  /* Done switching */\n        return;\n    }\n\n#if ARCH_BITS==32\n    arch->eip = ip;\n    arch->esp = sp;\n    arch->ebp = bp;\n#else\n    arch->rip = ip;\n    arch->rsp = sp;\n    arch->rbp = bp;\n#endif\n    kernel_idle();\n}\n"
  },
  {
    "path": "kernel/arch/none/Build.mk",
    "content": "obj-y  += none.o\nelf    += kernel-$(VERSION).$(ARCH)\n\nkernel-$(VERSION).$(ARCH): builtin.o\n\t@echo -e \"  ELF     \" $@;\n\t@$(LD) $(LDFLAGS) -Tkernel.$(ARCH).ld -lgcc -o $@\n"
  },
  {
    "path": "kernel/arch/none/include/core/types.h",
    "content": "#ifndef _NONE_CORE_TYPES_H\n#define _NONE_CORE_TYPES_H\n\ntypedef uintptr_t paddr_t;\ntypedef uintptr_t vaddr_t;\n\n#include_next <core/types.h>\n\n#endif /* _NONE_CORE_TYPES_H */\n"
  },
  {
    "path": "kernel/arch/none/include/cpu/io.h",
    "content": "#ifndef _NONE_CPU_IO_H\n#define _NONE_CPU_IO_H\n\n#include_next <cpu/io.h>\n\nstatic inline uint8_t io_in8(struct ioaddr *io, uintptr_t off)\n{\n    return 0;\n}\n\nstatic inline uint16_t io_in16(struct ioaddr *io, uintptr_t off)\n{\n    return 0;\n}\n\nstatic inline uint32_t io_in32(struct ioaddr *io, uintptr_t off)\n{\n    return 0;\n}\n\nstatic inline void io_out8(struct ioaddr *io, uintptr_t off, uint8_t val)\n{\n}\n\nstatic inline void io_out16(struct ioaddr *io, uintptr_t off, uint16_t val)\n{\n}\n\nstatic inline void io_out32(struct ioaddr *io, uintptr_t off, uint32_t val)\n{\n}\n\n#endif /* ! _NONE_CPU_IO_H */\n"
  },
  {
    "path": "kernel/arch/none/include/mm/mm.h",
    "content": "#ifndef _NONE_MM_MM_H\n#define _NONE_MM_MM_H\n\n#define USER_STACK_BASE 0\n#define PAGE_SIZE   (0x1000)\n#define PAGE_MASK   (PAGE_SIZE - 1)\n\n#define ARCH_KVMEM_BASE 100\n#define ARCH_KVMEM_NODES_SIZE   0\n\n#define LMA(n)  (n)\n#define VMA(n)  (n)\n\n#include_next <mm/mm.h>\n\n#endif  /* _NONE_MM_MM_H */\n"
  },
  {
    "path": "kernel/arch/none/kernel.none.ld",
    "content": "OUTPUT_FORMAT(elf32-i386)\nENTRY(_start)\nINPUT(builtin.o ../../core/builtin.o ../../fs/builtin.o ../../dev/builtin.o ../../sys/builtin.o ../../mm/builtin.o ../../net/builtin.o)\nOUTPUT(kernel.elf)\n\nSECTIONS {\n\n    LMA = 0x100000;\n    . = LMA;\n\n    .boot.text : ALIGN(0x1000) {\n        *boot*.o(.text*)\n        *boot*.o(.rodata*)\n    }\n\n    .boot.data : ALIGN(0x1000) {\n        *boot*.o(.data)\n    }\n\n    .boot.bss (NOLOAD) : ALIGN(0x1000) {\n        *boot*.o(*)\n    }\n\n    boot_end = .;\n\n    _VMA = 0xC0000000;\n    . += _VMA;\n\n    .text : AT(ADDR(.text) - _VMA) ALIGN(0x1000) {\n        *(.text*)\n        *(.rodata*)\n    }\n\n    .__minit : AT(ADDR(.__minit) - _VMA) ALIGN(0x1000) {\n        __minit = .;\n        *(.__minit*)\n        __minit_end = .;\n    }\n    \n    .data : AT(ADDR(.data) - _VMA) ALIGN(0x1000) {\n        *(.data)\n    }\n    \n    .bss : AT(ADDR(.bss) - _VMA) ALIGN(0x1000) {\n        *(.bss)\n    }\n    \n    /DISCARD/ : {\n        *(.*)\n    }\n    \n    kernel_end = . - _VMA;\n}\n"
  },
  {
    "path": "kernel/arch/none/none.c",
    "content": ""
  },
  {
    "path": "kernel/core/Build.mk",
    "content": "obj-y += printk.o\nobj-y += main.o\nobj-y += module.o\nobj-y += snprintf.o\nobj-y += kargs.o\nobj-y += time.o\n"
  },
  {
    "path": "kernel/core/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/core/kargs.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n\n#define MAX_ARGS 128\n\nstatic struct {\n    const char *key;\n    const char *value;\n} kargs[MAX_ARGS];\n\nstatic int kargc;\n\nint kargs_parse(const char *_cmdline)\n{\n    printk(\"kernel: cmdline: %s\\n\", _cmdline);\n\n    /* TODO use hashmap */\n\n    if (!_cmdline || !*_cmdline)\n        return 0;\n\n    char **tokens = tokenize(_cmdline, ' ');\n\n    for (char **token_p = tokens; *token_p; ++token_p) {\n        char *token = *token_p;\n        int i, len = strlen(token);\n        for (i = 0; i < len; ++i) {\n            if (token[i] == '=') {\n                token[i] = 0;\n                kargs[kargc].key   = token;\n                kargs[kargc].value = &token[i+1];\n            }\n        }\n\n        if (i == len)\n            kargs[kargc].key = token;\n\n        ++kargc;\n    }\n\n    return kargc;\n}\n\nint kargs_get(const char *key, const char **value)\n{\n    for (int i = 0; i < kargc; ++i) {\n        if (!strcmp(kargs[i].key, key)) {\n            if (value)\n                *value = kargs[i].value;\n\n            return 0;\n        }\n    }\n\n    return -1;\n}\n"
  },
  {
    "path": "kernel/core/main.c",
    "content": "/**\n * \\defgroup core kernel/core\n * \\brief core system components\n */\n\n#include <core/printk.h>\n#include <core/panic.h>\n#include <core/string.h>\n#include <core/module.h>\n#include <core/arch.h>\n#include <mm/mm.h>\n#include <mm/pmap.h> /* XXX */\n#include <mm/vm.h>\n#include <dev/dev.h>\n#include <fs/vfs.h>\n#include <fs/initramfs.h>\n#include <sys/proc.h>\n#include <sys/sched.h>\n#include <sys/binfmt.h>\n#include <boot/boot.h>\n#include <console/earlycon.h>\n\n#include <ds/hashmap.h>\n\n/** \n * \\ingroup core\n * \\brief entry point of the kernel\n *\n * This is the function that gets executed after the bootstrapping and\n * platform initialization is completed.\n *\n * \\param boot structure representing system state after bootstrapping\n */\nvoid kmain(struct boot *boot)\n{\n    kdev_init();\n    vfs_init();\n    modules_init();\n\n    if (boot->modules_count)\n        load_ramdisk(&boot->modules[0]);\n    else\n        panic(\"No modules loaded: unable to load ramdisk\");\n\n    printk(\"kernel: loading init process\\n\");\n\n    struct proc *init;\n    int err;\n\n    if ((err = proc_new(&init))) {\n        panic(\"failed to allocate process structure for init\");\n    }\n\n    curthread = (struct thread *) init->threads.head;\n    curproc   = init;\n\n    pmap_switch(init->vm_space.pmap);\n\n    const char *init_p = \"/init\";\n\n    if ((err = binfmt_load(init, init_p, &init))) {\n        printk(\"kernel: failed to load %s: error: %d\\n\", init_p, -err);\n        panic(\"could not load init process\");\n    }\n\n    arch_proc_init(init);\n\n    char *cmdline = boot->modules[0].cmdline;\n    char *argp[] = {cmdline, 0};\n    char *envp[] = {0};\n\n    arch_init_execve(init, 2, argp, 1, envp);\n\n#if EARLYCON_DISABLE_ON_INIT\n    earlycon_disable();\n#endif\n\n    sched_init_spawn(init);\n\n    panic(\"Scheduler failed to spawn init\");\n}\n"
  },
  {
    "path": "kernel/core/module.c",
    "content": "#include <core/system.h>\n#include <core/module.h>\n\nextern char __minit, __minit_end;\n\ntypedef void (*__ctor)(void);\n\nint modules_init(void)\n{\n    printk(\"kernel: loading builtin modules\\n\");\n\n    /* Initalize built-in modules */\n    __ctor *f = (void *) &__minit;\n    __ctor *g = (void *) &__minit_end;\n\n    size_t nr = (g - f);\n\n    for (size_t i = 0; i < nr; ++i) {\n        if (f[i]) {\n            //((int (*)())f[i])();\n            f[i]();\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "kernel/core/printk.c",
    "content": "#include <core/system.h>\n\n#include <core/string.h>\n#include <console/earlycon.h>\n#include <ds/ringbuf.h>\n\n#define KMSG_SIZE   8192\nstruct ringbuf *kmsg = RINGBUF_NEW(KMSG_SIZE);\nstruct queue *kmsg_wait = QUEUE_NEW();\n\nstatic int use_earlycon = 1;\nvoid earlycon_disable()\n{\n    use_earlycon = 0;\n}\n\nstatic int putc(char c)\n{\n    ringbuf_write_overwrite(kmsg, 1, &c);\n\n    if (use_earlycon)\n        return earlycon_putc(c);\n    return 0;\n}\n\nstatic int puts(char *s)\n{\n    s = s? s : \"(null)\";\n\n    int len = strlen(s);\n    ringbuf_write_overwrite(kmsg, len, s);\n\n    if (use_earlycon)\n        return earlycon_puts(s);\n\n    return 0;\n}\n\nstatic int putx(uint32_t val)\n{\n    if (!val)\n        return puts(\"0\");\n\n    char *enc = \"0123456789ABCDEF\";\n    char buf[9];\n    buf[8] = '\\0';\n    uint8_t i = 8;\n\n    while (val && i) {\n        buf[--i] = enc[val & 0xF];\n        val >>= 4;\n    }\n\n    return puts(&buf[i]);\n}\n\nstatic int putlx(uint64_t val)\n{\n    char *enc = \"0123456789ABCDEF\";\n    char buf[17];\n    buf[16] = '\\0';\n    uint8_t i = 16;\n    while (i) {\n        buf[--i] = enc[val&0xF];\n        val >>= 4;\n    }\n    return puts(buf);\n}\n\nstatic int putud(uint32_t val)\n{\n    char buf[11];\n    buf[10] = '\\0';\n    if (!val) { buf[9] = '0'; return puts(&buf[9]); }\n    uint8_t i = 10;\n    while (val) {\n        buf[--i] = val%10 + '0';\n        val = (val-val%10)/10;\n    }\n    return puts(buf+i);\n}\n\nstatic int putul(uint64_t val)\n{\n    char buf[21];\n    buf[20] = '\\0';\n    if (!val) { buf[19] = '0'; return puts(&buf[19]); }\n    uint8_t i = 20;\n    while (val) {\n        buf[--i] = val%10 + '0';\n        val = (val-val%10)/10;\n    }\n    return puts(buf+i);\n}\n\nstatic int putb(uint8_t val)\n{\n    char buf[9];\n    buf[8] = '\\0';\n    uint8_t i = 8;\n    while (i) {\n        buf[--i] = '0' + (val & 1);\n        val >>= 1;\n    }\n    return puts(buf);\n}\n\nint vprintk(const char *fmt, va_list args)\n{\n    int ret = 0;\n    while (*fmt)\n    switch (*fmt) {\n        case '%':\n            ++fmt;\n            switch (*fmt) {\n                case 'c':   /* char */\n                    ret += putc((char)va_arg(args, int));\n                    break;\n                case 's':   /* char * */\n                    ret += puts((char*)va_arg(args, char*));\n                    break;\n                case 'd': /* decimal */\n                    ret += putud((uint32_t)va_arg(args, uint32_t));\n                    break;\n                case 'l':   /* long */\n                    switch (*++fmt) {\n                        case 'x':   /* long hex */\n                            ret += putlx((uint64_t)va_arg(args, uint64_t));\n                            break;\n                        case 'd':\n                            ret += putul((uint64_t)va_arg(args, uint64_t));\n                            break;\n                        default:\n                            ret += putc(*--fmt);\n                    }\n                    break;\n                \n                case 'b': /* binary */\n                    ret += putb((uint8_t)(uint32_t)va_arg(args, uint32_t));\n                    break;\n                case 'x': /* Hexadecimal */\n                    ret += putx((uint32_t)va_arg(args, uint32_t));\n                    break;\n                case 'p': /* Pointer */\n                    ret += puts(\"0x\");\n#if ARCH_BITS==32\n                    ret += putx((uint32_t)va_arg(args, uint32_t));\n#elif ARCH_BITS==64 \n                    ret += putlx((uint64_t)va_arg(args, uint64_t));\n#endif\n                    break;\n                default:\n                    ret += putc(*(--fmt));\n            }\n            ++fmt;\n            break;\n        default:\n            ret += putc(*fmt);\n            ++fmt;\n    }\n\n    return ret;\n}\n\nint printk(const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    int ret = vprintk(fmt, args);\n    va_end(args);\n\n    return ret;\n}\n"
  },
  {
    "path": "kernel/core/snprintf.c",
    "content": "#include <core/system.h>\n\nstatic int snputc(char *s, size_t n, char c)\n{\n    if (n) {\n        *s = c;\n        return 1;\n    }\n\n    return 0;\n}\n\nstatic int snputs(char *s, size_t n, char *str)\n{\n    unsigned i;\n    for (i = 0; i < n && str[i]; ++i)\n        s[i] = str[i];\n    return i;\n}\n\nstatic int snputx(char *s, size_t n, uint32_t val)\n{\n    if (n < 8)\n        return n;\n\n    char *enc = \"0123456789ABCDEF\";\n    char buf[9];\n    buf[8] = '\\0';\n    uint8_t i = 8;\n\n    while (i) {\n        buf[--i] = enc[val&0xF];\n        val >>= 4;\n    }\n\n    return snputs(s, 8, buf);\n}\n\nstatic int snputlx(char *s, size_t n, uint64_t val)\n{\n    if (n < 16)\n        return n;\n\n    char *enc = \"0123456789ABCDEF\";\n    char buf[17];\n    buf[16] = '\\0';\n    uint8_t i = 16;\n    while (i) {\n        buf[--i] = enc[val&0xF];\n        val >>= 4;\n    }\n    return snputs(s, 16, buf);\n}\n\nstatic int snputud(char *s, size_t n, uint32_t val)\n{\n    char buf[11];\n    buf[10] = '\\0';\n\n    if (!val)\n        return snputc(s, 1, '0');\n\n    uint8_t i = 10;\n\n    while (val) {\n        buf[--i] = val%10 + '0';\n        val = (val-val%10)/10;\n    }\n    \n    if (n < 10U-i)\n        return n;\n\n    return snputs(s, 10-i, buf+i);\n}\n\nstatic int snputul(char *s, size_t n, uint64_t val)\n{\n    char buf[21];\n    buf[20] = '\\0';\n    uint8_t i = 20;\n\n    while (val) {\n        buf[--i] = val%10 + '0';\n        val = (val-val%10)/10;\n    }\n\n    if (n < 20U-i)\n        return n;\n\n    return snputs(s, 20-i, buf+i);\n}\n\nstatic int snputb(char *s, size_t n, uint8_t val)\n{\n    if (n < 8)\n        return n;\n\n    char buf[9];\n    buf[8] = '\\0';\n    uint8_t i = 8;\n\n    while (i) {\n        buf[--i] = '0' + (val & 1);\n        val >>= 1;\n    }\n\n    return snputs(s, 8, buf);\n}\n\nint vsnprintf(char *s, size_t n, const char *fmt, va_list args)\n{\n    int ret = 0;\n\n    while (*fmt) {\n        switch (*fmt) {\n            case '%':\n                ++fmt;\n                switch (*fmt) {\n                    case 'c':   /* char */\n                        ret += snputc(s + ret, n - ret, (char)va_arg(args, int));\n                        break;\n                    case 's':   /* char * */\n                        ret += snputs(s + ret, n - ret, (char*)va_arg(args, char*));\n                        break;\n                    case 'd': /* decimal */\n                        ret += snputud(s + ret, n - ret, (uint32_t)va_arg(args, uint32_t));\n                        break;\n                    case 'l':   /* long */\n                        switch (*++fmt) {\n                            case 'x':   /* long hex */\n                                ret += snputlx(s + ret, n - ret, (uint64_t)va_arg(args, uint64_t));\n                                break;\n                            case 'd':\n                                ret += snputul(s + ret, n - ret, (uint64_t)va_arg(args, uint64_t));\n                                break;\n                            default:\n                                ret += snputc(s + ret, n - ret, *--fmt);\n                        }\n                        break;\n                    \n                    case 'b': /* binary */\n                        ret += snputb(s + ret, n - ret, (uint8_t)(uint32_t)va_arg(args, uint32_t));\n                        break;\n                    case 'x': /* Hexadecimal */\n                        ret += snputx(s + ret, n - ret, (uint32_t)va_arg(args, uint32_t));\n                        break;\n                    default:\n                        ret += snputc(s + ret, n - ret, *(--fmt));\n                }\n                ++fmt;\n                break;\n            default:\n                ret += snputc(s + ret, n - ret, *fmt);\n                ++fmt;\n        }\n    }\n\n    ret += snputc(s + ret, n - ret, '\\0');\n\n    return ret;\n}\n\nint snprintf(char *s, size_t n, const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    int ret = vsnprintf(s, n, fmt, args);\n    va_end(args);\n    return ret;\n}\n"
  },
  {
    "path": "kernel/core/time.c",
    "content": "#include <core/system.h>\n#include <core/time.h>\n#include <core/arch.h>\n\n/* XXX use a better name */\nint gettime(struct timespec *ts)\n{\n    return arch_time_get(ts);\n}\n\nint gettimeofday(struct timeval *tv, struct timezone *tz)\n{\n    int err = 0;\n\n    struct timespec ts;\n\n    if ((err = gettime(&ts)))\n        return err;\n\n    if (tz) {\n        tz->tz_minuteswest = 0;\n        tz->tz_dsttime = 0;\n    }\n\n    if (tv) {\n        tv->tv_sec  = ts.tv_sec;\n        tv->tv_usec = ts.tv_nsec / 1000;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "kernel/dev/Build.mk",
    "content": "dirs-y += pci/\ndirs-$(DEV_KEYBOARD) += kbd/\ndirs-$(DEV_FRAMEBUFFER) += fb/\ndirs-y += tty/\ndirs-$(DEV_MOUSE) += mouse/\ndirs-$(DEV_MEMDEV) += mem/\ndirs-y += rd/\ndirs-$(DEV_ATA) += ata/\n#dirs-$(DEV_FDC) += fdc/\nobj-y  += kdev.o\n"
  },
  {
    "path": "kernel/dev/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/ata/Build.mk",
    "content": "obj-y += ata.o\nobj-y += pio.o\n"
  },
  {
    "path": "kernel/dev/ata/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/ata/ata.c",
    "content": "/**\n * \\defgroup dev-ata kernel/dev/ata\n * \\brief ata device\n */\n\n#include <core/system.h>\n#include <core/module.h>\n\n#include <cpu/io.h>\n#include <dev/dev.h>\n#include <fs/vfs.h>\n#include <fs/devfs.h>\n#include <fs/posix.h>\n#include <fs/mbr.h>\n#include <bits/errno.h>\n\n#include <dev/pci.h>\n\n#include <ata.h>\n\n#define BLOCK_SIZE  512UL\n\nstatic struct ata_drive drives[4];\n\nvoid ata_select_drive(struct ata_drive *drive, uint32_t mode)\n{\n    static struct ata_drive *last_selected_drive = NULL;\n    static uint32_t last_selected_mode = -1;\n\n    if (drive != last_selected_drive || mode != last_selected_mode) {\n        if (mode & ATA_MODE_LBA48)\n            //io_out8(&drive->base, ATA_REG_HDDEVSEL, ATA_DRIVE_LBA48 | (drive->slave << 4) | (mode & 0xF));\n            io_out8(&drive->base, ATA_REG_HDDEVSEL, 0xE0 | (drive->slave << 4) | (mode & 0xF));\n        else\n            io_out8(&drive->base, ATA_REG_HDDEVSEL, 0xA0 | (drive->slave << 4) | (mode & 0xF));\n\n        ata_wait(drive);\n        ata_wait(drive);\n        ata_wait(drive);\n        ata_wait(drive);\n        ata_wait(drive);\n\n        last_selected_drive = drive;\n        last_selected_mode  = mode;\n    }\n}\n\nstatic char read_buf[BLOCK_SIZE] __aligned(16);\nstatic size_t ata_partition_offset(struct ata_drive *drive, size_t part)\n{\n    if (!part) /* Whole Disk */\n        return 0;\n\n    part -= 1;\n\n    if (drive->poff[part] != 0)\n        return drive->poff[part];\n\n    struct mbr *mbr;\n\n    drive->read(drive, 0, 1, read_buf);\n    mbr = (struct mbr *) read_buf;\n\n    /* TODO Support CHS */\n    return drive->poff[part] = mbr->ptab[part].start_lba;\n}\n\nstatic ssize_t ata_read(struct devid *dd, off_t offset, size_t size, void *buf)\n{\n    //printk(\"ata_read(dd=%p, offset=%d, size=%d, buf=%p)\\n\", dd, offset, size, buf);\n\n    /* Get drive and parition numbers */\n    size_t drive_id  = dd->minor / 64;\n    size_t partition = dd->minor % 64;\n\n    struct ata_drive *drive = &drives[drive_id];\n\n    offset += ata_partition_offset(drive, partition);\n    return drive->read(drive, offset, size, buf);\n}\n\nstatic ssize_t ata_write(struct devid *dd, off_t offset, size_t size, void *buf)\n{\n    /* Get drive and parition numbers */\n    size_t drive_id  = dd->minor / 64;\n    size_t partition = dd->minor % 64;\n\n    struct ata_drive *drive = &drives[drive_id];\n\n    offset += ata_partition_offset(drive, partition);\n\n    return drive->write(drive, offset, size, buf);\n}\n\nstatic uint8_t ata_detect_drive(struct ata_drive *drive)\n{\n    if (!drive->slave) {\n        /* reset device */\n        ata_soft_reset(drive);\n        ata_wait(drive);\n    }\n\n    ata_select_drive(drive, 0);\n    ata_poll(drive, 0);\n\n#if 0\n    uint8_t status = io_in8(&drive->base, ATA_REG_STATUS);\n\n    if (!status) {\n        /* no device, bail */\n        drive->type = ATADEV_NOTFOUND;\n        goto done;\n    }\n#endif\n\n    uint8_t  type_lo = io_in8(&drive->base, ATA_REG_LBA1);\n    uint8_t  type_hi = io_in8(&drive->base, ATA_REG_LBA2);\n    uint16_t type    = (type_hi << 8) | type_lo;\n\n    switch (type) {\n        case 0x0000:\n            type = ATADEV_PATA;\n            break;\n        case 0xC33C:\n            type = ATADEV_SATA;\n            break;\n        case 0xEB14:\n            type = ATADEV_PATAPI;\n            break;\n        case 0x9669:\n            type = ATADEV_SATAPI;\n            break;\n        default:\n            type = ATADEV_UNKOWN;\n            break;\n    }\n\n    if (type == ATADEV_UNKOWN) {\n        return ATADEV_UNKOWN;\n    }\n\n    drive->type = type;\n\n    uint8_t identify_command = 0;\n\n    if (type == ATADEV_PATAPI || type == ATADEV_SATAPI) {\n        identify_command = ATA_CMD_IDENTIFY_PACKET;\n    } else {\n        identify_command = ATA_CMD_IDENTIFY;\n    }\n\n    char ide_ident[512];\n    memset(ide_ident, 0, sizeof(ide_ident));\n\n    io_out8(&drive->base, ATA_REG_CMD, identify_command);\n    ata_poll(drive, 1);\n\n    for (int i = 0; i < 512; i += 2) {\n        uint16_t x = io_in16(&drive->base, ATA_REG_DATA);\n        ide_ident[i+0] = x & 0xFFFF;\n        ide_ident[i+1] = (x >> 8) & 0xFFFF;\n    }\n\n    drive->signature    = *(uint16_t *) (ide_ident + ATA_IDENT_DEVICETYPE);\n    drive->capabilities = *(uint16_t *) (ide_ident + ATA_IDENT_CAPABILITIES);\n    drive->command_sets = *(uint32_t *) (ide_ident + ATA_IDENT_COMMANDSETS);\n\n    if (drive->command_sets & (1 << 26)) {\n        /* 48-bit LBA */\n        uint32_t high  = *(uint32_t *) (ide_ident + ATA_IDENT_MAX_LBA);\n        uint32_t low   = *(uint32_t *) (ide_ident + ATA_IDENT_MAX_LBA_EXT);\n\n        drive->max_lba = ((uint64_t) high << 32) | low;\n        drive->mode    = ATA_MODE_LBA48;\n    } else {\n        /* 28-bit LBA */\n        drive->max_lba = *(uint32_t *) (ide_ident + ATA_IDENT_MAX_LBA);\n        drive->mode    = ATA_MODE_LBA28;\n    }\n\n    for (int i = 0; i < 40; i += 2) {\n        drive->model[i + 0] = ide_ident[ATA_IDENT_MODEL + i + 1];\n        drive->model[i + 1] = ide_ident[ATA_IDENT_MODEL + i + 0];\n    }\n    drive->model[40] = 0;\n\n    printk(\"ata%d: signature: 0x%x\\n\", drive->id, drive->signature);\n    printk(\"ata%d: capabilities: 0x%x\\n\", drive->id, drive->capabilities);\n    printk(\"ata%d: command Sets: 0x%x\\n\", drive->id, drive->command_sets);\n    printk(\"ata%d: max LBA: 0x%x\\n\", drive->id, drive->max_lba);\n    printk(\"ata%d: model: %s\\n\", drive->id, drive->model);\n    \ndone:\n    return drive->type;\n}\n\nstatic size_t ata_getbs(struct devid *dd __unused)\n{\n    return BLOCK_SIZE;\n}\n\nstatic int ata_probe()\n{\n    struct pci_dev ide;\n    int count;\n\n    printk(\"ata: scanning PCI bus for IDE controller(s)\\n\");\n\n    count = pci_scan_device(0x01, 0x01, &ide, 1);\n\n    if (!count) {\n        printk(\"ata: no IDE controller(s) found\\n\");\n        return -1;\n    }\n\n    if (count) {\n        printk(\"ata: found IDE controller: bus: 0x%x, dev: 0x%x, func: 0x%x\\n\", ide.bus, ide.dev, ide.func);\n\n        uint32_t base, control;\n\n        /* primary channel */\n        base    = pci_read_bar(&ide, 0);\n        control = pci_read_bar(&ide, 1);\n\n        if (base == 0 || base == 1)\n            base = ATA_PIO_PRI_PORT_BASE;\n\n        if (control == 0 || control == 1)\n            control = ATA_PIO_PRI_PORT_CONTROL;\n\n        printk(\"ata: IDE controller primary channel: base: 0x%x, control: 0x%x\\n\", base, control);\n\n        /* master device */\n        drives[0].id        = 0;\n        drives[0].base.addr = base;\n        drives[0].base.type = IOADDR_PORT;\n        drives[0].ctrl.addr = control;\n        drives[0].ctrl.type = IOADDR_PORT;\n        drives[0].slave     = 0;\n\n        /* slave device */\n        drives[1].id        = 1;\n        drives[1].base.addr = base;\n        drives[1].base.type = IOADDR_PORT;\n        drives[1].ctrl.addr = control;\n        drives[1].ctrl.type = IOADDR_PORT;\n        drives[1].slave     = 1;\n\n        /* secondary channel */\n        base    = pci_read_bar(&ide, 2);\n        control = pci_read_bar(&ide, 3);\n\n        if (base == 0 || base == 1)\n            base = ATA_PIO_SEC_PORT_BASE;\n\n        if (control == 0 || control == 1)\n            control = ATA_PIO_SEC_PORT_CONTROL;\n\n        printk(\"ata: IDE controller secondary channel: base: 0x%x, control: 0x%x\\n\", base, control);\n\n        /* master device */\n        drives[2].id        = 2;\n        drives[2].base.addr = base;\n        drives[2].base.type = IOADDR_PORT;\n        drives[2].ctrl.addr = control;\n        drives[2].ctrl.type = IOADDR_PORT;\n        drives[2].slave     = 0;\n\n        /* slave device */\n        drives[3].id        = 3;\n        drives[3].base.addr = base;\n        drives[3].base.type = IOADDR_PORT;\n        drives[3].ctrl.addr = control;\n        drives[3].ctrl.type = IOADDR_PORT;\n        drives[3].slave     = 1;\n    }\n\n    for (int i = 0; i < 4 * count; ++i) {\n        /* disable interrupts */\n        //io_out8(&drives[i].base, ATA_REG_CONTROL, 0x2);\n\n        uint8_t type = ata_detect_drive(&drives[i]);\n\n        switch (type) {\n            case ATADEV_PATA:\n                printk(\"ata%d: initializing ATA device (PIO)\\n\", i);\n                pio_init(&drives[i]);\n                break;\n            case ATADEV_SATA:\n                printk(\"ata%d: SATA is not supported\\n\", i);\n                break;\n            case ATADEV_PATAPI:\n                printk(\"ata%d: PATAPI is not supported\\n\", i);\n                break;\n            case ATADEV_SATAPI:\n                printk(\"ata%d: SATAPI is not supported\\n\", i);\n                break;\n            case ATADEV_NOTFOUND:\n                break;\n            default:\n                //printk(\"ata%d: unkown ATA type %d\\n\", i, drives[i].type);\n                break;\n        }\n    }\n\n    kdev_blkdev_register(3, &atadev);\n    return 0;\n}\n\nstruct dev atadev = {\n    .name  = \"ata\",\n    .probe = ata_probe,\n    .read  = ata_read,\n    .write = ata_write,\n    .getbs = ata_getbs,\n\n    .fops = {\n        .open  = posix_file_open,\n        .read  = posix_file_read,\n        .write = posix_file_write,\n    },\n};\n\nMODULE_INIT(ata, ata_probe, NULL)\n"
  },
  {
    "path": "kernel/dev/ata/ata.h",
    "content": "#ifndef _ATA_H\n#define _ATA_H\n\n/* definitions used in atadev driver */\n#define ATADEV_UNKOWN               0x000\n#define ATADEV_NOTFOUND             0x001\n#define ATADEV_PATA                 0x002\n#define ATADEV_SATA                 0x003\n#define ATADEV_PATAPI               0x004\n#define ATADEV_SATAPI               0x005\n\n/* default ports */\n#define ATA_PIO_PRI_PORT_BASE       0x1F0\n#define ATA_PIO_PRI_PORT_CONTROL    0x3F6\n#define ATA_PIO_SEC_PORT_BASE       0x170\n#define ATA_PIO_SEC_PORT_CONTROL    0x376\n\n/* ATA registers */\n#define ATA_REG_DATA                0x00\n#define ATA_REG_ERROR               0x01\n#define ATA_REG_FEATURES            0x01\n#define ATA_REG_SECCOUNT0           0x02\n#define ATA_REG_LBA0                0x03\n#define ATA_REG_LBA1                0x04\n#define ATA_REG_LBA2                0x05\n#define ATA_REG_HDDEVSEL            0x06\n#define ATA_REG_CMD                 0x07\n#define ATA_REG_STATUS              0x07\n#define ATA_REG_SECCOUNT1           0x08\n#define ATA_REG_LBA3                0x09\n#define ATA_REG_LBA4                0x0A\n#define ATA_REG_LBA5                0x0B\n#define ATA_REG_CONTROL             0x0C\n#define ATA_REG_ALTSTATUS           0x0C\n#define ATA_REG_DEVADDRESS          0x0D\n\n/* ATA commands */\n#define ATA_CMD_RESET               0x04\n#define ATA_CMD_READ_SECTORS        0x20\n#define ATA_CMD_READ_SECTORS_EXT    0x24\n#define ATA_CMD_WRITE_SECTORS       0x30\n#define ATA_CMD_WRITE_SECTORS_EXT   0x34\n#define ATA_CMD_READ_DMA            0xC8\n#define ATA_CMD_READ_DMA_EXT        0x25\n#define ATA_CMD_WRITE_DMA           0xCA\n#define ATA_CMD_WRITE_DMA_EXT       0x35\n#define ATA_CMD_CACHE_FLUSH         0xE7\n#define ATA_CMD_CACHE_FLUSH_EXT     0xEA\n#define ATA_CMD_PACKET              0xA0\n#define ATA_CMD_IDENTIFY_PACKET     0xA1\n#define ATA_CMD_IDENTIFY            0xEC\n\n#define ATA_DRIVE_LBA48             0x40\n\n#define ATA_STATUS_BSY              0x80    /* Busy */\n#define ATA_STATUS_DRDY             0x40    /* Drive ready */\n#define ATA_STATUS_DF               0x20    /* Drive write fault */\n#define ATA_STATUS_DSC              0x10    /* Drive seek complete */\n#define ATA_STATUS_DRQ              0x08    /* Data request ready */\n#define ATA_STATUS_CORR             0x04    /* Corrected data */\n#define ATA_STATUS_IDX              0x02    /* Inlex */\n#define ATA_STATUS_ERR              0x01    /* Error */\n\n#define ATA_ERROR_BBK               0x080   /* Bad block */\n#define ATA_ERROR_UNC               0x040   /* Uncorrectable data */\n#define ATA_ERROR_MC                0x020   /* Media changed */\n#define ATA_ERROR_IDNF              0x010   /* ID mark not found */\n#define ATA_ERROR_MCR               0x008   /* Media change request */\n#define ATA_ERROR_ABRT              0x004   /* Command aborted */\n#define ATA_ERROR_TK0NF             0x002   /* Track 0 not found */\n#define ATA_ERROR_AMNF              0x001   /* No address mark */\n\n\n#define ATA_IDENT_DEVICETYPE        0\n#define ATA_IDENT_CYLINDERS         2\n#define ATA_IDENT_HEADS             6\n#define ATA_IDENT_SECTORS           12\n#define ATA_IDENT_SERIAL            20\n#define ATA_IDENT_MODEL             54\n#define ATA_IDENT_CAPABILITIES      98\n#define ATA_IDENT_FIELDVALID        106\n#define ATA_IDENT_MAX_LBA           120\n#define ATA_IDENT_COMMANDSETS       164\n#define ATA_IDENT_MAX_LBA_EXT       200\n\n#define ATA_CAP_LBA                 0x200\n\n#define ATA_MODE_CHS                0x10\n#define ATA_MODE_LBA28              0x20\n#define ATA_MODE_LBA48              0x40\n\nstruct ata_drive {\n    struct ioaddr base;\n    struct ioaddr ctrl;\n\n    uint8_t  id;\n    uint8_t  mode;\n    uint16_t type;\n    uint8_t  slave;\n    size_t   poff[4];\n\n\n    uint16_t signature;\n    uint16_t capabilities;\n    uint32_t command_sets;\n    uint64_t max_lba;\n    char     model[41];\n\n    ssize_t (*read) (struct ata_drive *drive, uint64_t lba, size_t count, void *buf);\n    ssize_t (*write)(struct ata_drive *drive, uint64_t lba, size_t count, void *buf);\n};\n\nstatic const char *ata_error_string(uint8_t err)\n{\n    switch (err) {\n        case ATA_ERROR_BBK:   return \"Bad block\";\n        case ATA_ERROR_UNC:   return \"Uncorrectable data\";\n        case ATA_ERROR_MC:    return \"Media changed\";\n        case ATA_ERROR_IDNF:  return \"ID mark not found\";\n        case ATA_ERROR_MCR:   return \"Media change request\";\n        case ATA_ERROR_ABRT:  return \"Command aborted\";\n        case ATA_ERROR_TK0NF: return \"Track 0 not found\";\n        case ATA_ERROR_AMNF:  return \"No address mark\";\n        default:              return \"Unkown\";\n    }\n}\n\nstatic void ata_wait(struct ata_drive *drive)\n{\n    for (int i = 0; i < 4; ++i)\n        io_in8(&drive->base, ATA_REG_ALTSTATUS);\n}\n\nstatic int ata_poll(struct ata_drive *drive, int advanced_check)\n{\n    ata_wait(drive);\n\n    uint8_t s;\n\n    /* Wait until busy clears */\n    while ((s = io_in8(&drive->base, ATA_REG_STATUS)) & ATA_STATUS_BSY);\n\n    if (advanced_check) {\n        if ((s & ATA_STATUS_ERR) || (s & ATA_STATUS_DF)) {\n            ata_wait(drive);\n            uint8_t err = io_in8(&drive->base, ATA_REG_ERROR);\n            printk(\"ata: drive error: %s\\n\", ata_error_string(err));\n            return -err;\n        }\n\n        if (!(s & ATA_STATUS_DRQ)) {\n            printk(\"ata: drive error: DRQ not set\\n\");\n            return -1;\n        }\n    }\n\n    return 0;\n}\n\nstatic void ata_soft_reset(struct ata_drive *drive)\n{\n    io_out8(&drive->ctrl, 0, ATA_CMD_RESET);\n    ata_wait(drive);\n    io_out8(&drive->ctrl, 0, 0);\n}\n\n/* ata.c */\nvoid ata_select_drive(struct ata_drive *drive, uint32_t mode);\n\n/* pio.c */\nvoid pio_init(struct ata_drive *drive);\n\n#endif\n"
  },
  {
    "path": "kernel/dev/ata/pio.c",
    "content": "#include <core/system.h>\n#include <core/panic.h>\n#include <cpu/io.h>\n#include <dev/dev.h>\n#include <fs/vfs.h>\n#include <fs/devfs.h>\n#include <fs/posix.h>\n#include <fs/mbr.h>\n#include <bits/errno.h>\n#include <dev/pci.h>\n\n#include <ata.h>\n\n#define PIO_MAX_RETRIES 5\n\nstatic ssize_t pio_read(struct ata_drive *drive, uint64_t lba, size_t count, void *buf)\n{\n    //printk(\"pio_read(drive=%p, lba=%ld, count=%d, buf=%p)\\n\", drive, lba, count, buf);\n\n    int retry_count = 0;\n\nretry:\n    if (++retry_count == PIO_MAX_RETRIES)\n        return -EIO;\n\n    if (drive->capabilities & ATA_CAP_LBA) {\n        /* Use LBA mode */\n        ata_select_drive(drive, drive->mode);\n\n        /* Send NULL byte to error register */\n        io_out8(&drive->base, ATA_REG_ERROR, 0);\n\n        /* Send sectors count and LBA */\n        if (drive->mode == ATA_MODE_LBA48) {\n            io_out8(&drive->base, ATA_REG_SECCOUNT0, (count >> 8) & 0xFF);\n            io_out8(&drive->base, ATA_REG_LBA0, (uint8_t) (lba >> (8 * 3)));\n            io_out8(&drive->base, ATA_REG_LBA1, (uint8_t) (lba >> (8 * 4)));\n            io_out8(&drive->base, ATA_REG_LBA2, (uint8_t) (lba >> (8 * 5)));\n        }\n\n        io_out8(&drive->base, ATA_REG_SECCOUNT0, count & 0xFF);\n        io_out8(&drive->base, ATA_REG_LBA0, (uint8_t) (lba >> (8 * 0)));\n        io_out8(&drive->base, ATA_REG_LBA1, (uint8_t) (lba >> (8 * 1)));\n        io_out8(&drive->base, ATA_REG_LBA2, (uint8_t) (lba >> (8 * 2)));\n\n        /* Send read command */\n        ata_wait(drive);\n\n        if (drive->mode == ATA_MODE_LBA48)\n            io_out8(&drive->base, ATA_REG_CMD, ATA_CMD_READ_SECTORS_EXT);\n        else\n            io_out8(&drive->base, ATA_REG_CMD, ATA_CMD_READ_SECTORS);\n\n        ata_wait(drive);\n\n        size_t _count = count;\n\n        while (_count--) {\n            int err;\n            if ((err = ata_poll(drive, 1))) {\n\n                /* retry */\n                if (err == -ATA_ERROR_ABRT) {\n                    printk(\"ata: retrying...\\n\");\n\n                    for (int i = 0; i < 5; ++i)\n                        ata_wait(drive);\n                    goto retry;\n                }\n\n                return -EIO;\n            }\n\n            /* FIXME */\n            //__insw(drive->base.addr + ATA_REG_DATA, 256, buf);\n            char *_buf = buf;\n\n            for (int i = 0; i < 256; ++i) {\n                uint16_t x = io_in16(&drive->base, ATA_REG_DATA);\n                _buf[2*i+0] = x & 0xFFFF;\n                _buf[2*i+1] = (x >> 8) & 0xFFFF;\n            }\n\n            buf += 512;\n        }\n\n        if (ata_poll(drive, 0))\n            return -EINVAL;\n    } else {\n        /* TODO CHS */\n    }\n\n    return 0;\n}\n\nstatic ssize_t pio_write(struct ata_drive *drive, uint64_t lba, size_t count, void *buf)\n{\n    ata_select_drive(drive, ATA_MODE_LBA48);\n\n    /* Send NULL byte to error port */\n    io_out8(&drive->base, ATA_REG_ERROR, 0);\n\n    /* Send sectors count and LBA */\n    io_out8(&drive->base, ATA_REG_SECCOUNT0, (count >> 8) & 0xFF);\n    io_out8(&drive->base, ATA_REG_LBA0, (uint8_t) (lba >> (8 * 3)));\n    io_out8(&drive->base, ATA_REG_LBA1, (uint8_t) (lba >> (8 * 4)));\n    io_out8(&drive->base, ATA_REG_LBA2, (uint8_t) (lba >> (8 * 5)));\n    io_out8(&drive->base, ATA_REG_SECCOUNT0, count & 0xFF);\n    io_out8(&drive->base, ATA_REG_LBA0, (uint8_t) (lba >> (8 * 0)));\n    io_out8(&drive->base, ATA_REG_LBA1, (uint8_t) (lba >> (8 * 1)));\n    io_out8(&drive->base, ATA_REG_LBA2, (uint8_t) (lba >> (8 * 2)));\n\n    /* Send write command */\n    ata_wait(drive);\n    io_out8(&drive->base, ATA_REG_CMD, ATA_CMD_WRITE_SECTORS_EXT);\n\n    while (count--) {\n        uint16_t *_buf = (uint16_t *) buf;\n\n        if (ata_poll(drive, 1)) return -EINVAL;\n\n        for (int i = 0; i < 256; ++i)\n            io_out16(&drive->base, ATA_REG_DATA, _buf[i]);\n\n        buf += 512;\n    }\n\n    if (ata_poll(drive, 0)) return -EINVAL;\n    io_out8(&drive->base, ATA_REG_CMD, ATA_CMD_CACHE_FLUSH);\n    if (ata_poll(drive, 0)) return -EINVAL;\n\n    return 0;\n}\n\nvoid pio_init(struct ata_drive *drive)\n{\n    drive->read  = pio_read;\n    drive->write = pio_write;\n    ata_soft_reset(drive);\n}\n"
  },
  {
    "path": "kernel/dev/fb/Build.mk",
    "content": "dirs-y += fbdev/\ndirs-$(FBDEV_VESA) += vesa/\n"
  },
  {
    "path": "kernel/dev/fb/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/fb/fbdev/Build.mk",
    "content": "obj-y += fbdev.o\n"
  },
  {
    "path": "kernel/dev/fb/fbdev/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/fb/fbdev/fbdev.c",
    "content": "#include <core/system.h>\n#include <core/module.h>\n\n#include <dev/fbdev.h>\n#include <dev/ramdev.h>\n\n#include <fs/vfs.h>\n#include <fs/devfs.h>\n#include <fs/posix.h>\n\n#define MAX_FBDEV   2\n\nstatic struct fbdev registered_fbs[MAX_FBDEV];\nstatic size_t fbdev_cnt = 0;\n\nint fbdev_register(int type, void *data)\n{\n    if (fbdev_cnt == MAX_FBDEV)\n        return -1;\n\n    registered_fbs[fbdev_cnt].type = type;\n    registered_fbs[fbdev_cnt++].data = data;\n\n    return 0;\n}\n\nstatic ssize_t fbdev_read(struct devid *dd, off_t offset, size_t size, void *buf)\n{\n    struct fbdev *fb = &registered_fbs[dd->minor];\n    return fb->read(fb, offset, size, buf);\n}\n\nstatic ssize_t fbdev_write(struct devid *dd, off_t offset, size_t size, void *buf)\n{\n    struct fbdev *fb = &registered_fbs[dd->minor];\n    return fb->write(fb, offset, size, buf);\n}\n\nstatic int fbdev_ioctl(struct devid *dd, int request, void *argp)\n{\n    struct fbdev *fb = &registered_fbs[dd->minor];\n\n    switch (request) {\n    case FBIOGET_FSCREENINFO:\n        memcpy(argp, fb->fix_screeninfo, sizeof(struct fb_fix_screeninfo));\n        return 0;\n    case FBIOGET_VSCREENINFO:\n        memcpy(argp, fb->var_screeninfo, sizeof(struct fb_var_screeninfo));\n        return 0;\n    }\n\n    return -1;\n}\n\nstatic int fbdev_map(struct devid *dd, struct vm_space *vm_space, struct vm_entry *vm_entry)\n{\n    struct fbdev *fb = &registered_fbs[dd->minor];\n    return fb->map(fb, vm_space, vm_entry);\n}\n\nint fbdev_probe()\n{\n    for (size_t i = 0; i < fbdev_cnt; ++i) {\n        struct fbdev *fb = &registered_fbs[i];\n\n        switch (fb->type) {\n            case FBDEV_TYPE_VESA:\n                fbdev_vesa.probe(i, fb);\n                break;\n        }\n    }\n\n    kdev_chrdev_register(29, &fbdev);\n    return 0;\n}\n\nstruct dev fbdev = {\n    .name = \"fbdev\",\n\n    .probe  = fbdev_probe,\n    .read   = fbdev_read,\n    .write  = fbdev_write,\n    .ioctl  = fbdev_ioctl,\n    .map    = fbdev_map,\n\n    .fops = {\n        .open  = posix_file_open,\n        .write = posix_file_write,\n        .ioctl = posix_file_ioctl,\n        .lseek = posix_file_lseek,\n\n        .can_write = __vfs_can_always,\n        .can_read  = __vfs_can_never,\n        .eof       = __vfs_eof_never,\n    },\n};\n\nMODULE_INIT(fbdev, fbdev_probe, NULL)\n"
  },
  {
    "path": "kernel/dev/fb/vesa/Build.mk",
    "content": "obj-y += vesa.o\n"
  },
  {
    "path": "kernel/dev/fb/vesa/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/fb/vesa/vesa.c",
    "content": "#include <core/system.h>\n#include <dev/fbdev.h>\n#include <fs/devfs.h>\n#include <video/vesa.h>\n#include <mm/vm.h>\n\nstatic char *vmem = (char *) 0xE0000000;\n\nstatic struct vm_entry vesa_vm = {\n    .base = 0xE0000000,\n};\n\nstatic size_t len = 0;\n\nstatic struct fb_fix_screeninfo vesa_fix_screeninfo = {\n    .id = \"VESA FB\",\n};\n\nstatic struct fb_var_screeninfo vesa_var_screeninfo;\n\nstatic ssize_t fbdev_vesa_write(struct fbdev *fb, off_t offset, size_t size, void *buf)\n{\n    /* Maximum possible write size */\n    size = MIN(size, len - offset);\n    \n    /* Copy `size' bytes from buffer to ramdev */\n    memcpy((char *) vmem + offset, buf, size);\n\n    return size;\n}\n\nstatic int fbdev_vesa_map(struct fbdev *fb, struct vm_space *vm_space, struct vm_entry *vm_entry)\n{\n    printk(\"fbdev_vesa_map(fb=%p, vm_space=%p, vm_entry=%p {base=%p, off=0x%x, size=0x%x})\\n\", fb, vm_space, vm_entry, vm_entry->base, vm_entry->off, vm_entry->size);\n\n    /* We do not support private maps */\n    if (!(vm_entry->flags & VM_SHARED))\n        return -ENOTSUP;\n\n#if 0\n    /* Mapping framebuffer must start at 0 */\n    if (vm_entry->off != 0 || vm_entry->size > vesa_vm.size)\n        return -ENXIO;\n#endif\n\n    vm_entry->paddr = vesa_vm.paddr;\n    return vm_map(vm_space, vm_entry);\n}\n\nstatic int fbdev_vesa_prope(int i __unused, struct fbdev *fb)\n{\n    struct fbdev_vesa *data = (struct fbdev_vesa *) fb->data;\n\n    struct mode_info_block *info = data->mode_info;\n    size_t size = info->y_resolution * info->lin_bytes_per_scanline;\n\n    vesa_vm.paddr = info->phys_base_ptr;\n    vesa_vm.size  = size;\n    vesa_vm.flags = VM_KRW | VM_NOCACHE;\n\n    vm_map(&kvm_space, &vesa_vm);\n\n    //memset(vmem, 0x5A, size);\n\n    len = size;\n\n\n    fb->probe = fbdev_vesa_prope;\n    fb->write = fbdev_vesa_write;\n    fb->map   = fbdev_vesa_map;\n    fb->fix_screeninfo = &vesa_fix_screeninfo;\n    fb->var_screeninfo = &vesa_var_screeninfo;\n\n    /* Init fb structs */\n    vesa_fix_screeninfo.smem_start = (uintptr_t) vmem;\n    vesa_fix_screeninfo.smem_len   = size;\n    //vesa_fix_screenifo.type\n    //vesa_fix_screenifo.type_aux\n    //vesa_fix_screenifo.visual\n    vesa_fix_screeninfo.xpanstep      = 0;\n    vesa_fix_screeninfo.ypanstep      = 0;\n    vesa_fix_screeninfo.ywrapstep     = 0;\n    vesa_fix_screeninfo.line_length   = info->lin_bytes_per_scanline;\n    vesa_fix_screeninfo.mmio_start    = info->phys_base_ptr;\n    vesa_fix_screeninfo.mmio_len      = size;\n    //vesa_fix_screenifo.accel\n    //vesa_fix_screenifo.capabilities\n    //vesa_fix_screenifo.reserved[2]\n    //\n\n    vesa_var_screeninfo.xres          = info->x_resolution;\n    vesa_var_screeninfo.yres          = info->y_resolution;\n    vesa_var_screeninfo.xres_virtual  = info->x_resolution;\n    vesa_var_screeninfo.yres_virtual  = info->y_resolution;\n    vesa_var_screeninfo.xoffset       = 0;\n    vesa_var_screeninfo.yoffset       = 0;\n\n    vesa_var_screeninfo.bits_per_pixel = info->bits_per_pixel;\n    //vesa_var_screeninfo.grayscale\n    //struct fb_bitfield red;     /* bitfield in fb mem if true color, */\n    //struct fb_bitfield green;   /* else only length is significant */\n    //struct fb_bitfield blue;\n    //struct fb_bitfield transp;  /* transparency         */\n    //vesa_var_screeninfo.nonstd\n    //vesa_var_screeninfo.activate\n    //vesa_var_screeninfo.height\n    //vesa_var_screeninfo.width\n    //vesa_var_screeninfo.accel_flags\n    //vesa_var_screeninfo.pixclock\n    //vesa_var_screeninfo.left_margin\n    //vesa_var_screeninfo.right_margin\n    //vesa_var_screeninfo.upper_margin\n    //vesa_var_screeninfo.lower_margin\n    //vesa_var_screeninfo.hsync_len\n    //vesa_var_screeninfo.vsync_len\n    //vesa_var_screeninfo.sync\n    //vesa_var_screeninfo.vmode\n    //vesa_var_screeninfo.rotate\n    //vesa_var_screeninfo.colorspace\n    //vesa_var_screeninfo.reserved[4]\n\n    return 0;\n}\n\nstruct fbdev fbdev_vesa = {\n    .probe = fbdev_vesa_prope,\n    .write = fbdev_vesa_write,\n    .map   = fbdev_vesa_map,\n};\n"
  },
  {
    "path": "kernel/dev/fdc/Build.mk",
    "content": "obj-y += fdc.o\nobj-y += fdc_82077AA.o\n"
  },
  {
    "path": "kernel/dev/fdc/fdc.c",
    "content": "#include <core/system.h>\n#include <core/panic.h>\n#include <core/module.h>\n\n#include <cpu/io.h>\n#include <dev/dev.h>\n#include <bits/errno.h>\n\nstruct dev fdcdev;\n\nint fdc_probe()\n{\n    //kdev_blkdev_register(2, &fdcdev);\n    return 0;\n}\n\nstruct dev fdcdev = {\n    .name  = \"fdc\",\n    .probe = fdc_probe,\n};\n\nMODULE_INIT(fdc, fdc_probe, NULL)\n"
  },
  {
    "path": "kernel/dev/fdc/fdc_82077AA.c",
    "content": "#include <core/system.h>\n#include <core/panic.h>\n#include <core/module.h>\n#include <fs/posix.h>\n\n#include <cpu/io.h>\n#include <dev/dev.h>\n#include <bits/errno.h>\n#include <fdc_82077AA.h>\n\nstatic struct dev fdcdev;\nstatic struct ioaddr fdcio;\n\n#define SECTOR_SIZE  512UL\n#define FDC_COMMAND_TIMEOUT 500000\n\nstatic struct fdc_drive {\n    uint8_t dor;\n} drives[4];\n\nstatic int fdc_wait(int check_dio)\n{\n    int need_reset = 1;\n    check_dio = check_dio? FDC_MSR_DIO : 0;\n\n    for (int i = 0; i < FDC_COMMAND_TIMEOUT; ++i) {\n        uint8_t msr = io_in8(&fdcio, FDC_MSR);\n        if ((msr & (FDC_MSR_RQM | check_dio)) == FDC_MSR_RQM) {\n            need_reset = 0;\n            break;\n        }\n    }\n\n    return need_reset;\n}\n\nstatic int fdc_cmd_send(uint8_t cmd, int argc, const uint8_t argv[], int resc, uint8_t resv[])\n{\n    if (fdc_wait(1)) {\n        /* TODO */\n        panic(\"fdc: reset controller\\n\");\n    }\n\n    uint8_t msr;\n\n    /* Command Phase */\n    io_out8(&fdcio, FDC_FIFO, cmd);\n\n    for (int i = 0; i < argc; ++i) {\n        if (fdc_wait(1))\n            panic(\"fdc: need reset\\n\");\n\n        msr = io_in8(&fdcio, FDC_MSR);\n        io_out8(&fdcio, FDC_FIFO, argv[i]);\n    }\n\n    /* Execution Phase */\n    int count = 0;\n\n__next:\n    msr = io_in8(&fdcio, FDC_MSR);\n    while ((msr & (FDC_MSR_RQM | FDC_MSR_NDMA)) == (FDC_MSR_RQM | FDC_MSR_NDMA)) {\n        ++count;\n        uint8_t byte = io_in8(&fdcio, FDC_FIFO);\n        msr = io_in8(&fdcio, FDC_MSR);\n    }\n\n    if (msr & FDC_MSR_NDMA)\n        goto __next;\n\n    /* Result Phase */\n    //msr = io_in8(&fdcio, FDC_MSR);\n    if (fdc_wait(0))\n        panic(\"fdc: need reset\\n\");\n\n    /* read result */\n    for (int i = 0; i < resc; ++i) {\n        if (fdc_wait(0))\n            panic(\"fdc: need reset\\n\");\n\n        resv[i] = io_in8(&fdcio, FDC_FIFO);\n    }\n\n    msr = io_in8(&fdcio, FDC_MSR);\n    return 0;\n}\n\nstatic int fdc_cmd_version()\n{\n    uint8_t version;\n    fdc_cmd_send(FDC_CMD_VERSION, 0, 0, 1, &version);\n\n    return version;\n}\n\nstatic int fdc_cmd_sense()\n{\n    uint8_t resv[2];\n    fdc_cmd_send(FDC_CMD_SENSE_INTERRUPT, 0, 0, 2, resv);\n\n    //printk(\"resv[0] = %x, resv[1] = %x\\n\", resv[0], resv[1]);\n    return 0;\n}\n\nstatic int fdc_reset()\n{\n    printk(\"fdc: Reset controller\\n\");\n\n    uint8_t dor = io_in8(&fdcio, FDC_DOR);\n    //printk(\"dor = %x\\n\", dor);\n\n    io_out8(&fdcio, FDC_DOR, 0);\n    io_out8(&fdcio, FDC_DOR, dor | FDC_DOR_MOTA);\n\n    for (int i = 0; i < 4; ++i)\n        fdc_cmd_sense();\n\n    return 0;\n}\n\nstatic int fdc_configure()\n{\n    uint8_t params[] = {0, FDC_CONF_SEEK_EN | 8, 0};\n    fdc_cmd_send(FDC_CMD_CONFIGURE, 3, params, 0, 0);\n    return 0;\n}\n\nstatic int fdc_lock()\n{\n    uint8_t lock;\n    fdc_cmd_send(FDC_CMD_LOCK | FDC_CMD_MT, 0, 0, 1, &lock);\n    return 0;\n}\n\nstatic int fdc_recalibrate()\n{\n    uint8_t drive = 0;\n    fdc_cmd_send(FDC_CMD_RECALIBRATE, 1, &drive, 0, 0);\n    return 0;\n}\n\n#define FLOPPY_144_SECTORS_PER_TRACK    18\nstatic int fdc_sect_rw(int wr, size_t lba, void *_buf)\n{\n    uint8_t *buf  = (uint8_t *) _buf;\n    uint8_t drive = 0;\n    uint8_t cyln  = lba / (2 * FLOPPY_144_SECTORS_PER_TRACK);\n    uint8_t head  = ((lba % (2 * FLOPPY_144_SECTORS_PER_TRACK)) / FLOPPY_144_SECTORS_PER_TRACK);\n    uint8_t sect  = ((lba % (2 * FLOPPY_144_SECTORS_PER_TRACK)) % FLOPPY_144_SECTORS_PER_TRACK + 1);\n\n    uint8_t cmd = (wr? FDC_CMD_WRITE_DATA : FDC_CMD_READ_DATA) | FDC_CMD_MF;\n    uint8_t argv[8], resv[7];\n    int argc = 8, resc = 7;\n\n    argv[0] = (head << 2) | drive;\n    argv[1] = cyln;\n    argv[2] = head;\n    argv[3] = sect;\n    argv[4] = 2;\n    argv[5] = sect>=FLOPPY_144_SECTORS_PER_TRACK?FLOPPY_144_SECTORS_PER_TRACK:sect;\n    argv[6] = 0x1B;\n    argv[7] = 0xFF;\n\n    if (fdc_wait(1)) {\n        panic(\"fdc: reset controller\\n\");\n    }\n\n    uint8_t msr;\n\n    /* Command Phase */\n    io_out8(&fdcio, FDC_FIFO, cmd);\n\n    for (int i = 0; i < argc; ++i) {\n        if (fdc_wait(1))\n            panic(\"fdc: need reset\\n\");\n\n        msr = io_in8(&fdcio, FDC_MSR);\n        io_out8(&fdcio, FDC_FIFO, argv[i]);\n    }\n\n    /* Execution Phase */\n    int count = 0;\n\n__next:\n    msr = io_in8(&fdcio, FDC_MSR);\n    while ((msr & (FDC_MSR_RQM | FDC_MSR_NDMA)) == (FDC_MSR_RQM | FDC_MSR_NDMA)) {\n        if (wr) {\n            io_out8(&fdcio, FDC_FIFO, buf[count]);\n            ++count;\n        } else {\n            buf[count] = io_in8(&fdcio, FDC_FIFO);\n            ++count;\n        }\n\n        msr = io_in8(&fdcio, FDC_MSR);\n    }\n\n    if (msr & FDC_MSR_NDMA)\n        goto __next;\n\n    /* Result Phase */\n    if (fdc_wait(0))\n        panic(\"fdc: need reset\\n\");\n\n    /* read result */\n    for (int i = 0; i < resc; ++i) {\n        if (fdc_wait(0))\n            panic(\"fdc: need reset\\n\");\n\n        resv[i] = io_in8(&fdcio, FDC_FIFO);\n    }\n\n    msr = io_in8(&fdcio, FDC_MSR);\n    return 0;\n}\n\nstatic int fdc_probe()\n{\n    fdcio.addr = FDC_BASE;\n    fdcio.type = IOADDR_PORT;\n\n    fdc_reset();\n\n    if (fdc_cmd_version() != 0x90) {\n        printk(\"fdc: Controller not found\\n\");\n        return -1;\n    }\n\n    printk(\"fdc: Initializing\\n\");\n\n    fdc_reset();\n    fdc_configure();\n    fdc_lock();\n    fdc_reset();\n    fdc_recalibrate();\n\n    kdev_blkdev_register(2, &fdcdev);\n\n    return 0;\n}\n\nstatic size_t fdc_getbs(struct devid *dd __unused)\n{\n    return 512;\n}\n\nstatic ssize_t fdc_read(struct devid *dd, off_t offset, size_t size, void *buf)\n{\n    //printk(\"fdc_read(dd=%p, offset=%d, size=%d, buf=%p)\\n\", dd, offset, size, buf);\n    fdc_sect_rw(0, offset, buf);\n    return 512;\n}\n\nstatic struct dev fdcdev = {\n    .name  = \"fdc_82077AA\",\n    .probe = fdc_probe,\n    .read  = fdc_read,\n    .getbs = fdc_getbs,\n\n    .fops = {\n        .open  = posix_file_open,\n        .read  = posix_file_read,\n    },\n};\n\nMODULE_INIT(fdc_82077AA, fdc_probe, NULL)\n"
  },
  {
    "path": "kernel/dev/fdc/fdc_82077AA.h",
    "content": "#ifndef _FDC_H\n#define _FDC_H\n\n#define FDC_BASE 0x3F0\n\n#define FDC_SRA         0   /* Status Register A */\n#define FDC_SRB         1   /* Status Register B  */\n#define FDC_DOR         2   /* Digital Output Register */\n#define FDC_TDR         3   /* Tape Drive Register */\n#define FDC_MSR         4   /* Main Status Register */\n#define FDC_DSR         4   /* Datarate Select Register */\n#define FDC_FIFO        5   /* Data FIFO */\n#define FDC_DIR         7   /* Digital Input Register */\n#define FDC_CCR         7   /* Configuration Control Register */\n\n\n#define FDC_DOR_MOTD    0x80\n#define FDC_DOR_MOTC    0x40\n#define FDC_DOR_MOTB    0x20\n#define FDC_DOR_MOTA    0x10\n#define FDC_DOR_IRQ     0x08\n#define FDC_DOR_RESET   0x04\n#define FDC_DOR_DSEL    0x03\n\n#define FDC_MSR_RQM     0x80\n#define FDC_MSR_DIO     0x40\n#define FDC_MSR_NDMA    0x20\n#define FDC_MSR_CB      0x10\n#define FDC_MSR_ACTD    0x08\n#define FDC_MSR_ACTC    0x04\n#define FDC_MSR_ACTB    0x02\n#define FDC_MSR_ACTA    0x01\n\n#define FDC_CMD_MT  0x80\n#define FDC_CMD_MF  0x40\n#define FDC_CMD_SK  0x20\n\n#define FDC_CMD_READ_TRACK          2\n#define FDC_CMD_SPECIFY             3\n#define FDC_CMD_SENSE_DRIVE_STATUS  4\n#define FDC_CMD_WRITE_DATA          5\n#define FDC_CMD_READ_DATA           6\n#define FDC_CMD_RECALIBRATE         7\n#define FDC_CMD_SENSE_INTERRUPT     8\n#define FDC_CMD_WRITE_DELETED_DATA  9\n#define FDC_CMD_READ_ID             10\n#define FDC_CMD_READ_DELETED_DATA   12\n#define FDC_CMD_FORMAT_TRACK        13\n#define FDC_CMD_DUMPREG             14\n#define FDC_CMD_SEEK                15\n#define FDC_CMD_VERSION             16\n#define FDC_CMD_SCAN_EQUAL          17\n#define FDC_CMD_PERPENDICULAR_MODE  18\n#define FDC_CMD_CONFIGURE           19\n#define FDC_CMD_LOCK                20\n#define FDC_CMD_VERIFY              22\n#define FDC_CMD_SCAN_LOW_OR_EQUAL   25\n#define FDC_CMD_SCAN_HIGH_OR_EQUAL  29\n\n#define FDC_CONF_POLL_DIS   0x10\n#define FDC_CONF_FIFO_DIS   0x20\n#define FDC_CONF_SEEK_EN    0x40\n\n#endif /* ! _FDC_H */\n"
  },
  {
    "path": "kernel/dev/kbd/Build.mk",
    "content": "obj-$(DEV_KEYBOARD_PS2) += ps2kbd.o\n"
  },
  {
    "path": "kernel/dev/kbd/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/kbd/kbd.c",
    "content": "#include <core/system.h>\n#include <core/module.h>\n#include <sys/sched.h>\n#include <dev/dev.h>\n#include <ds/ringbuf.h>\n#include <ds/queue.h>\n\n#include <bits/errno.h>\n\n#define BUFSIZE    128\n\nstruct keyboard keyboards[4];\n\nstatic struct proc *proc = NULL; /* Current process using Keboard */\n\nstatic void ps2kbd_handler(int scancode)\n{\n    ringbuf_write(kbd_ring, sizeof(scancode), (char *) &scancode);\n    \n    if (kbd_read_queue->count)\n        thread_queue_wakeup(kbd_read_queue);\n}\n\nstatic void ps2kbd_register(void)\n{\n    x86_i8042_handler_register(1, ps2kbd_handler);\n}\n\nstatic ssize_t kbddev_read(struct devid *dd, off_t off, size_t sz, void *buf)\n{\n    (void) off;\n\n    int id = dd->minor;\n\n    if (id >= MAX_KEYBOARDS)\n        return -ENXIO;\n\n    if (keyboards[id].ring) {\n        ssize_t ret = ringbuf_write(kbd_ring, sizeof(scancode), (char *) &scancode);\n        \n        if (keyboards[id].read_queue->count)\n            thread_queue_wakeup(keyboards[id].read_queue);\n\n        return ret;\n    }\n\n    return -ENXIO;\n}\n\nstatic ssize_t kbddev_write(struct devid *dd, off_t off, size_t sz, void *buf)\n{\n    (void) off;\n\n    int id = dd->minor;\n\n    if (id >= MAX_KEYBOARDS)\n        return -ENXIO;\n\n    if (keyboards[id].ring)\n        return ringbuf_read(keyboards[id].ring, sz, buf);\n\n    return -ENXIO;\n}\n\nstatic int kbddev_probe(void)\n{\n    kdev_chrdev_register(11, &kbddev);\n    return 0;\n}\n\n/* File Operations */\nstatic int kbddev_file_open(struct file *file)\n{\n    if (proc) /* Only one process can open kbd */\n        return -EACCES;\n\n    proc = curproc;\n\n    /* This is either really smart or really dumb */\n    file->inode->read_queue = keyboards[0].read_queue;    \n\n    return posix_file_open(file);\n}\n\nint keyboard_register(struct keyboard *keyboard)\n{\n}\n\nstruct dev kbddev = {\n    .name  = \"kbddev\",\n\n    .probe = kbddev_probe,\n    .read  = kbddev_read,\n\n    .fops  = {\n        .open  = kbddev_file_open,\n        .read  = posix_file_read,\n\n        .can_read  = __always,\n        .can_write = __never,\n        .eof       = __never,\n    },\n};\n\nMODULE_INIT(kbddev, kbddev_probe, NULL)\n"
  },
  {
    "path": "kernel/dev/kbd/ps2kbd.c",
    "content": "/*\n *          PS/2 Keyboard driver\n *\n *\n *  This file is part of Aquila OS and is released under\n *  the terms of GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) 2016 Mohamed Anwar <mohamed_anwar@opmbx.org>\n */\n\n\n#include <core/system.h>\n#include <core/module.h>\n#include <core/arch.h>\n#include <cpu/cpu.h>\n\n#include <platform/misc.h>\n\n#include <sys/proc.h>\n#include <sys/sched.h>\n\n#include <dev/dev.h>\n#include <fs/devfs.h>\n#include <fs/posix.h>\n\n#include <ds/ringbuf.h>\n#include <ds/queue.h>\n\n#include <bits/errno.h>\n\n#define BUFSIZE    128\n\nstatic struct ringbuf *kbd_ring = RINGBUF_NEW(BUFSIZE);   /* Keboard Ring Buffer */\nstatic struct proc *proc = NULL; /* Current process using Keboard */\nstatic struct queue *kbd_read_queue = QUEUE_NEW(); /* Keyboard read queue */\n\nstatic void ps2kbd_handler(int scancode)\n{\n    ringbuf_write(kbd_ring, sizeof(scancode), (char *) &scancode);\n    \n    if (kbd_read_queue->count)\n        thread_queue_wakeup(kbd_read_queue);\n}\n\nstatic void ps2kbd_register(void)\n{\n    x86_i8042_handler_register(1, ps2kbd_handler);\n}\n\nstatic ssize_t ps2kbd_read(struct devid *dd, off_t off, size_t sz, void *buf)\n{\n    (void) dd;\n    (void) off;\n\n    return ringbuf_read(kbd_ring, sz, buf);\n}\n\nstatic int ps2kbd_probe(void)\n{\n    ps2kbd_register();\n    kdev_chrdev_register(11, &ps2kbddev);\n    return 0;\n}\n\n/* File Operations */\nstatic int ps2kbd_file_open(struct file *file)\n{\n    if (proc) /* Only one process can open kbd */\n        return -EACCES;\n\n    proc = curproc;\n\n    /* This is either really smart or really dumb */\n    file->vnode->read_queue = kbd_read_queue;    \n\n    return posix_file_open(file);\n}\n\nstatic int ps2kbd_file_can_read(struct file *file, size_t size)\n{\n    printk(\"ps2kbd_file_can_read(file=%p, size=%d)\\n\", file, size);\n\n    (void) file;\n    return ringbuf_available(kbd_ring);\n}\n\n\nstruct dev ps2kbddev = {\n    .name  = \"kbddev\",\n\n    .probe = ps2kbd_probe,\n    .read  = ps2kbd_read,\n\n    .fops  = {\n        .open  = ps2kbd_file_open,\n        .read  = posix_file_read,\n\n        .can_read  = ps2kbd_file_can_read,\n        .can_write = __vfs_can_never,\n        .eof       = __vfs_eof_never,\n    },\n};\n\nMODULE_INIT(ps2kbd, ps2kbd_probe, NULL)\n"
  },
  {
    "path": "kernel/dev/kdev.c",
    "content": "/**\n * \\defgroup kdev kernel/kdev\n * \\brief devices management\n */\n\n#include <core/system.h>\n#include <dev/dev.h>\n#include <fs/vfs.h>\n\nMALLOC_DEFINE(M_KDEV_BLK, \"kdev-blk\", \"kdev block buffer\");\n\nstruct dev *chrdev[256];\nstruct dev *blkdev[256];\n\nstatic inline struct dev *kdev_get(struct devid *dd)\n{\n    struct dev *dev = NULL;\n\n    switch (dd->type) {\n        case S_IFCHR:\n            dev = chrdev[dd->major];\n            break;\n        case S_IFBLK:\n            dev = blkdev[dd->major];\n            break;\n    }\n\n    if (dev && dev->mux) {  /* Mulitplexed Device? */\n        return dev->mux(dd);\n    }\n\n    return dev;\n}\n\nint kdev_close(struct devid *dev __unused)\n{\n    return 0;\n}\n\nssize_t kdev_bread(struct devid *dd, off_t offset, size_t size, void *buf)\n{\n    //printk(\"kdev_bread(dd=%p, offset=%d, size=%d, buf=%p)\\n\", dd, offset, size, buf);\n\n    struct dev *dev = kdev_get(dd);\n    size_t bs = dev->getbs(dd);\n\n    int err = 0;\n    ssize_t ret = 0;\n\n    char *cbuf = buf;\n    char *bbuf = NULL;\n\n    /* Read up to block boundary */\n    if (offset % bs) {\n        if (!bbuf && !(bbuf = kmalloc(bs, &M_KDEV_BLK, 0)))\n            return -ENOMEM;\n\n        size_t start = MIN(bs - offset % bs, size);\n\n        if (start) {\n            if ((err = dev->read(dd, offset/bs, 1, bbuf)) < 0)\n                goto error;\n\n            memcpy(cbuf, bbuf + (offset % bs), start);\n\n            ret    += start;\n            size   -= start;\n            cbuf   += start;\n            offset += start;\n\n            if (!size)\n                goto done;\n        }\n    }\n\n    /* Read entire blocks */\n    size_t count = size/bs;\n\n    if (count) {\n        if ((err = dev->read(dd, offset/bs, count, cbuf)) < 0)\n            goto error;\n\n        ret    += count * bs;\n        size   -= count * bs;\n        cbuf   += count * bs;\n        offset += count * bs;\n\n        if (!size)\n            goto done;\n    }\n\n    size_t end = size % bs;\n\n    if (end) {\n        if (!bbuf && !(bbuf = kmalloc(bs, &M_KDEV_BLK, 0)))\n            return -ENOMEM;\n\n        if ((err = dev->read(dd, offset/bs, 1, bbuf)) < 0)\n            goto error;\n\n        memcpy(cbuf, bbuf, end);\n        ret += end;\n    }\n\ndone:\n    if (bbuf)\n        kfree(bbuf);\n\n    return ret;\n\nerror:\n    if (bbuf)\n        kfree(bbuf);\n\n    return err;\n}\n\nssize_t kdev_bwrite(struct devid *dd, off_t offset, size_t size, void *buf)\n{\n    struct dev *dev = kdev_get(dd);\n    size_t bs = dev->getbs(dd);\n\n    ssize_t ret = 0;\n    char *cbuf = buf;\n    char *bbuf = NULL;\n\n    if (offset % bs) {\n        if (!bbuf && !(bbuf = kmalloc(bs, &M_KDEV_BLK, 0)))\n            return -ENOMEM;\n\n        /* Write up to block boundary */\n        size_t start = MIN(bs - offset % bs, size);\n\n        if (start) {\n            dev->read(dd, offset/bs, 1, bbuf);\n            memcpy(bbuf + (offset % bs), cbuf, start);\n            dev->write(dd, offset/bs, 1, bbuf);\n\n            ret    += start;\n            size   -= start;\n            cbuf   += start;\n            offset += start;\n\n            if (!size)\n                goto done;\n        }\n    }\n\n\n    /* Write entire blocks */\n    size_t count = size/bs;\n\n    if (count) {\n        dev->write(dd, offset/bs, count, cbuf);\n\n        ret    += count * bs;\n        size   -= count * bs;\n        cbuf   += count * bs;\n        offset += count * bs;\n\n        if (!size)\n            goto done;\n    }\n\n    size_t end = size % bs;\n\n    if (end) {\n        if (!bbuf && !(bbuf = kmalloc(bs, &M_KDEV_BLK, 0)))\n            return -ENOMEM;\n\n        dev->read(dd, offset/bs, 1, bbuf);\n        memcpy(bbuf, cbuf, end);\n        dev->write(dd, offset/bs, 1, bbuf);\n        ret += end;\n    }\n\ndone:\n    if (bbuf)\n        kfree(bbuf);\n\n    return ret;\n}\n\nssize_t kdev_read(struct devid *dd, off_t offset, size_t size, void *buf)\n{\n    //printk(\"kdev_read(dd=%p, offset=%d, size=%d, buf=%p)\\n\", dd, offset, size, buf);\n\n    struct dev *dev = NULL;\n    \n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->read)\n        return -ENXIO;\n\n    if (S_ISCHR(dd->type))\n        return dev->read(dd, offset, size, buf);\n    else\n        return kdev_bread(dd, offset, size, buf);\n}\n\nssize_t kdev_write(struct devid *dd, off_t offset, size_t size, void *buf)\n{\n    struct dev *dev = NULL;\n\n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->write)\n        return -ENXIO;\n\n    if (S_ISCHR(dd->type))\n        return dev->write(dd, offset, size, buf);\n    else\n        return kdev_bwrite(dd, offset, size, buf);\n}\n\nint kdev_ioctl(struct devid *dd, int request, void *argp)\n{\n    struct dev *dev = NULL;\n\n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->ioctl)\n        return -ENXIO;\n\n    return dev->ioctl(dd, request, argp);\n}\n\nint kdev_map(struct devid *dd, struct vm_space *vm_space, struct vm_entry *vm_entry)\n{\n    struct dev *dev = NULL;\n\n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->map)\n        return -ENXIO;\n\n    return dev->map(dd, vm_space, vm_entry);\n}\n\nint kdev_file_open(struct devid *dd, struct file *file)\n{\n    struct dev *dev = NULL;\n\n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->fops.open)\n        return -ENXIO;\n\n    return dev->fops.open(file);\n}\n\nssize_t kdev_file_read(struct devid *dd, struct file *file, void *buf, size_t size)\n{\n    struct dev *dev = NULL;\n\n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->fops.read)\n        return -ENXIO;\n\n    return dev->fops.read(file, buf, size);\n}\n\nssize_t kdev_file_write(struct devid *dd, struct file *file, void *buf, size_t size)\n{\n    struct dev *dev = NULL;\n\n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->fops.write)\n        return -ENXIO;\n\n    return dev->fops.write(file, buf, size);\n}\n\noff_t kdev_file_lseek(struct devid *dd, struct file *file, off_t offset, int whence)\n{\n    struct dev *dev = NULL;\n\n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->fops.lseek)\n        return -ENXIO;\n\n    return dev->fops.lseek(file, offset, whence);\n}\n\nssize_t kdev_file_close(struct devid *dd, struct file *file)\n{\n    struct dev *dev = NULL;\n\n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->fops.close)\n        return -EINVAL;\n\n    return dev->fops.close(file);\n}\n\nint kdev_file_ioctl(struct devid *dd, struct file *file, int request, void *argp)\n{\n    struct dev *dev = NULL;\n\n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->fops.ioctl)\n        return -ENXIO;\n\n    return dev->fops.ioctl(file, request, argp);\n}\n\nint kdev_file_can_read(struct devid *dd, struct file * file, size_t size)\n{\n    struct dev *dev = NULL;\n\n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->fops.can_read)\n        return -ENXIO;\n\n    return dev->fops.can_read(file, size);\n}\n\nint kdev_file_can_write(struct devid *dd, struct file * file, size_t size)\n{\n    struct dev *dev = NULL;\n\n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->fops.can_write)\n        return -ENXIO;\n\n    return dev->fops.can_write(file, size);\n}\n\nint kdev_file_eof(struct devid *dd, struct file *file)\n{\n    struct dev *dev = NULL;\n\n    if (!(dev = kdev_get(dd)))\n        return -ENXIO;\n\n    if (!dev->fops.eof)\n        return -ENXIO;\n\n    return dev->fops.eof(file);\n}\n\n/**\n * \\ingroup kdev\n * \\brief register a new character device\n */\nvoid kdev_chrdev_register(devid_t major, struct dev *dev)\n{\n    chrdev[major] = dev; /* XXX */\n    printk(\"kdev: registered chrdev %d: %s\\n\", major, dev->name);\n}\n\n/**\n * \\ingroup kdev\n * \\brief register a new block device\n */\nvoid kdev_blkdev_register(devid_t major, struct dev *dev)\n{\n    blkdev[major] = dev; /* XXX */\n    printk(\"kdev: registered blkdev %d: %s\\n\", major, dev->name);\n}\n\n/**\n * \\ingroup kdev\n * \\brief initialize kdev subsystem\n */\nvoid kdev_init()\n{\n    printk(\"kdev: initializing\\n\");\n}\n"
  },
  {
    "path": "kernel/dev/mem/Build.mk",
    "content": "obj-y += zero.o\nobj-y += null.o\nobj-y += kmsg.o\nobj-y += memdev.o\n"
  },
  {
    "path": "kernel/dev/mem/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/mem/kmsg.c",
    "content": "#include <core/system.h>\n#include <dev/dev.h>\n#include <fs/posix.h>\n#include <ds/ringbuf.h>\n#include <sys/sched.h>\n#include <console/earlycon.h>\n\n#include <memdev.h>\n\nstruct dev kmsgdev;\nextern struct ringbuf *kmsg;\nextern struct queue *kmsg_wait;\n\nstatic ssize_t kmsgdev_read(struct devid *dd __unused, off_t offset, size_t size, void *buf)\n{\n    //printk(\"kmsgdev_read(dd=%p, offset=%d, size=%d, buf=%p)\\n\", dd, offset, size, buf);\n    return ringbuf_read_noconsume(kmsg, offset, size, buf);\n}\n\nstatic ssize_t kmsgdev_write(struct devid *dd __unused, off_t offset, size_t size, void *buf)\n{\n    //printk(\"kmsg: [%d: %d] %s: \", cur_thread->owner->pid, cur_thread->tid, cur_thread->owner->name);\n    //char *_buf = (char *) buf;\n    //size_t sz = size;\n    //while (size--)\n    //    earlycon_putc(*_buf++);\n    //return sz;\n    //printk(\"\\n\");\n    //return ringbuf_write(kmsg, size, buf);\n\n    printk(\"%s\", buf);\n    return size;\n}\n\nstatic int kmsg_file_open(struct file *file)\n{\n    file->vnode->read_queue = kmsg_wait;\n    return posix_file_open(file);\n}\n\nstruct dev kmsgdev = {\n    .read  = kmsgdev_read,\n    .write = kmsgdev_write,\n\n    .fops  = {\n        .open  = kmsg_file_open,\n        .read  = posix_file_read,\n        .write = posix_file_write,\n        .close = posix_file_close,\n\n        .can_read  = __vfs_can_always,\n        .can_write = __vfs_can_always,\n        .eof       = __vfs_eof_never,\n    },\n};\n"
  },
  {
    "path": "kernel/dev/mem/memdev.c",
    "content": "#include <core/system.h>\n#include <core/module.h>\n#include <dev/dev.h>\n\n#include <memdev.h>\n\nstruct dev memdev;\n\nstruct dev *memdev_mux(struct devid *dd)\n{\n    switch (dd->minor) {\n        case 0:\n        case 1: /* /dev/mem */\n        case 2: /* /dev/kmem */\n            break;\n        case 3: /* /dev/null */\n            return &nulldev;\n        case 4: /* /dev/port */\n            //return &portdev;\n            break;\n        case 5: /* /dev/zero */\n            return &zerodev;\n        case 6: /* /dev/core */\n            break;\n        case 7: /* /dev/full */\n            break;\n        case 8: /* /dev/random */\n            break;\n        case 9: /* /dev/urandom */\n            break;\n        case 10: /* /dev/aio */\n            break;\n        case 11: /* /dev/kmsg */\n            return &kmsgdev;\n    }\n\n    return NULL;\n}\n\nint memdev_probe()\n{\n    kdev_chrdev_register(1, &memdev);\n    return 0;\n}\n\nstruct dev memdev = {\n    .name = \"memdev\",\n    .mux  = memdev_mux,\n};\n\nMODULE_INIT(memdev, memdev_probe, NULL)\n"
  },
  {
    "path": "kernel/dev/mem/memdev.h",
    "content": "#ifndef _MEMDEV_H\n#define _MEMDEV_H\n\n#include <dev/dev.h>\n\nextern struct dev nulldev;\n//extern struct dev portdev;\nextern struct dev zerodev;\nextern struct dev kmsgdev;\n\n#endif /* ! _MEMDEV_H */\n"
  },
  {
    "path": "kernel/dev/mem/null.c",
    "content": "#include <core/system.h>\n#include <dev/dev.h>\n#include <fs/posix.h>\n#include <bits/errno.h>\n\n#include <memdev.h>\n\nstruct dev nulldev;\n\nstatic ssize_t nulldev_read(struct devid *dd __unused, off_t offset __unused, size_t size __unused, void *buf __unused)\n{\n    return 0;\n}\n\nstatic ssize_t nulldev_write(struct devid *dd __unused, off_t offset __unused, size_t size, void *buf __unused)\n{\n    return size;\n}\n\nstruct dev nulldev = {\n    .read  = nulldev_read,\n    .write = nulldev_write,\n\n    .fops  = {\n        .open  = posix_file_open,\n        .read  = posix_file_read,\n        .write = posix_file_write,\n        .close = posix_file_close,\n\n        .can_read  = __vfs_can_always,\n        .can_write = __vfs_can_always,\n        .eof       = __vfs_eof_always,\n    },\n};\n"
  },
  {
    "path": "kernel/dev/mem/zero.c",
    "content": "#include <core/system.h>\n#include <dev/dev.h>\n#include <fs/posix.h>\n#include <bits/errno.h>\n\n#include <memdev.h>\n\nstruct dev zerodev;\n\nstatic ssize_t zerodev_read(struct devid *dd __unused, off_t offset __unused, size_t size, void *buf)\n{\n    memset(buf, 0, size);\n    return size;\n}\n\nstatic ssize_t zerodev_write(struct devid *dd __unused, off_t offset __unused, size_t size, void *buf __unused)\n{\n    return size;\n}\n\nstruct dev zerodev = {\n    .read  = zerodev_read,\n    .write = zerodev_write,\n\n    .fops  = {\n        .open  = posix_file_open,\n        .read  = posix_file_read,\n        .write = posix_file_write,\n        .close = posix_file_close,\n\n        .can_read  = __vfs_can_always,\n        .can_write = __vfs_can_always,\n        .eof       = __vfs_eof_never,\n    },\n};\n"
  },
  {
    "path": "kernel/dev/mouse/Build.mk",
    "content": "obj-y += ps2mouse.o\n"
  },
  {
    "path": "kernel/dev/mouse/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/mouse/ps2mouse.c",
    "content": "/*\n *          PS/2 Mouse driver\n *\n *\n *  This file is part of Aquila OS and is released under\n *  the terms of GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar\n */\n\n\n#include <core/system.h>\n#include <core/module.h>\n#include <core/arch.h>\n\n#include <cpu/cpu.h>\n\n#include <platform/misc.h>\n\n#include <sys/proc.h>\n#include <sys/sched.h>\n\n#include <dev/dev.h>\n#include <fs/devfs.h>\n#include <fs/posix.h>\n\n#include <ds/ringbuf.h>\n#include <ds/queue.h>\n\n#include <bits/errno.h>\n\nstruct dev ps2mousedev;\n\nstruct ioaddr mouse = {\n    .addr = 0x60,\n    .type = IOADDR_PORT,\n};\n\n#define MOUSE_CMD  0x04\n#define MOUSE_DATA 0x00\n\n#define SEND_CMD            0xD4\n#define ENABLE_AUX_PS2      0xA8\n#define GET_COMPAQ_STATUS   0x20\n#define SET_COMPAQ_STATUS   0x60\n#define USE_DEFAULTS        0xF6\n#define ENABLE_MOUSE        0xF4\n\n#define BUF_SIZE    128\n\nstatic struct ringbuf *mouse_ring = RINGBUF_NEW(BUF_SIZE);   /* Mouse ring Buffer */\nstatic struct proc *proc = NULL; /* Current process using mouse */\nstatic struct queue *mouse_read_queue = QUEUE_NEW(); /* Mouse read queue */\n\nstruct mouse_packet {\n    uint8_t left    : 1;\n    uint8_t right   : 1;\n    uint8_t mid     : 1;\n    uint8_t _1      : 1;\n    uint8_t x_sign  : 1;\n    uint8_t y_sign  : 1;\n    uint8_t x_over  : 1;\n    uint8_t y_over  : 1;\n} __packed;\n\nvoid ps2mouse_handler(int byte)\n{\n    static uint8_t cycle = 0;\n    static uint8_t mouse_data[3];\n    mouse_data[cycle++] = byte & 0xFF;\n\n    if (cycle == 1 && !(mouse_data[0] & 0x8))\n        cycle = 0;\n\n    if (cycle == 3) {\n        cycle = 0;  /* We are done .. reset */\n        struct mouse_packet *packet = (struct mouse_packet *) mouse_data;\n\n        if (packet->x_over || packet->y_over)\n            return;\n\n        ringbuf_write(mouse_ring, 3, (char *) mouse_data);\n        \n        if (mouse_read_queue->count)\n            thread_queue_wakeup(mouse_read_queue);\n    }\n}\n\nvoid ps2mouse_register(void)\n{\n    x86_i8042_handler_register(2, ps2mouse_handler);\n}\n\nstatic ssize_t ps2mouse_read(struct devid *dd __unused, off_t offset __unused, size_t size, void *buf)\n{\n    return ringbuf_read(mouse_ring, size, buf);\n}\n\nstatic void __mouse_wait(uint32_t i)\n{\n    return;\n#if 0\n    //printk(\"__mouse_wait(%d)\\n\", i);\n    if (!i)\n        while (!(io_in8(&mouse, MOUSE_CMD) & 1));\n    else\n        while (io_in8(&mouse, MOUSE_CMD) & 2);\n#endif\n}\n\nstatic uint8_t __mouse_read(void)\n{\n    __mouse_wait(0);\n    return io_in8(&mouse, MOUSE_DATA);\n}\n\nstatic void __mouse_write(uint8_t chr)\n{\n    __mouse_wait(1);\n    io_out8(&mouse, MOUSE_CMD, SEND_CMD);\n    __mouse_wait(1);\n    io_out8(&mouse, MOUSE_DATA, chr);\n}\n\nint ps2mouse_probe()\n{\n    __mouse_wait(1);\n    io_out8(&mouse, MOUSE_CMD, ENABLE_AUX_PS2);\n\n    __mouse_wait(1);\n    io_out8(&mouse, MOUSE_CMD, GET_COMPAQ_STATUS);\n    uint8_t status = __mouse_read() | 2;\n\n    __mouse_wait(1);\n    io_out8(&mouse, MOUSE_CMD, SET_COMPAQ_STATUS);\n\n    __mouse_wait(0);\n    io_out8(&mouse, MOUSE_DATA, status);\n\n    __mouse_write(USE_DEFAULTS);\n    __mouse_read();\n\n    __mouse_write(ENABLE_MOUSE);\n    __mouse_read();\n\n    ps2mouse_register();\n    kdev_chrdev_register(10, &ps2mousedev);\n\n    return 0;\n}\n\n/* File Operations */\n\nstatic int ps2mouse_file_open(struct file *file)\n{\n    if (proc) /* Only one process can open kbd */\n        return -EACCES;\n\n    proc = curproc;\n    file->vnode->read_queue = mouse_read_queue;    \n\n    return posix_file_open(file);\n}\n\nstatic int ps2mouse_file_can_read(struct file *file, size_t size)\n{\n    (void) file;\n    return ringbuf_available(mouse_ring);\n}\n\nstatic int ps2mouse_file_close(struct file *file)\n{\n    //printk(\"ps2mouse_file_close(file=%p)\\n\", file);\n    proc = NULL;\n    return posix_file_close(file);\n}\n\nstruct dev ps2mousedev = {\n    .name  = \"mousedev\",\n\n    .probe = ps2mouse_probe,\n    .read  = ps2mouse_read,\n\n    .fops  = {\n        .open  = ps2mouse_file_open,\n        .read  = posix_file_read,\n        .close = ps2mouse_file_close,\n\n        .can_read  = ps2mouse_file_can_read,\n        .can_write = __vfs_can_never,\n        .eof       = __vfs_eof_never,\n    },\n};\n\nMODULE_INIT(ps2mouse, ps2mouse_probe, NULL)\n"
  },
  {
    "path": "kernel/dev/pci/Build.mk",
    "content": "obj-y += pci.o\n"
  },
  {
    "path": "kernel/dev/pci/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/pci/pci.c",
    "content": "#include <core/system.h>\n#include <core/module.h>\n\n#include <dev/pci.h>\n#include <cpu/io.h>\n\nstatic struct ioaddr pci_ioaddr;\n\nstatic inline uint32_t pci_read_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg)\n{\n    union pci_address addr;\n    addr.raw = 0;\n\n    addr.structure.enable = 1;\n    addr.structure.bus = bus;\n    addr.structure.device = dev;\n    addr.structure.function = func;\n    addr.structure.reg = reg & 0xfc;\n\n    io_out32(&pci_ioaddr, PCI_CONFIG_ADDRESS, addr.raw);\n    return io_in32(&pci_ioaddr, PCI_CONFIG_DATA);\n}\n\nstatic inline void pci_write_dword(uint8_t bus, uint8_t dev, uint8_t func, uint8_t reg, uint32_t val)\n{\n    union pci_address addr;\n    addr.raw = 0;\n\n    addr.structure.enable = 1;\n    addr.structure.bus = bus;\n    addr.structure.device = dev;\n    addr.structure.function = func;\n    addr.structure.reg = reg & 0xfc;\n\n    io_out32(&pci_ioaddr, PCI_CONFIG_ADDRESS, addr.raw);\n    io_out32(&pci_ioaddr, PCI_CONFIG_DATA, val);\n}\n\nstatic inline uint16_t get_vendor_id(uint8_t bus, uint8_t dev, uint8_t func)\n{\n    return pci_read_dword(bus, dev, func, 0x00) & 0xFFFF;\n}\n\nstatic inline uint16_t get_device_id(uint8_t bus, uint8_t dev, uint8_t func)\n{\n    return (pci_read_dword(bus, dev, func, 0x00) >> 16) & 0xFFFF;\n}\n\nstatic inline uint8_t get_class_code(uint8_t bus, uint8_t dev, uint8_t func)\n{\n    return (pci_read_dword(bus, dev, func, 0x08) >> 24) & 0xFF;\n}\n\nstatic inline uint8_t get_subclass_code(uint8_t bus, uint8_t dev, uint8_t func)\n{\n    return (pci_read_dword(bus, dev, func, 0x08) >> 16) & 0xFF;\n}\n\nstatic inline uint8_t get_header_type(uint8_t bus, uint8_t dev, uint8_t func)\n{\n    return (pci_read_dword(bus, dev, func, 0x0C) >> 16) & 0xFF;\n}\n\nstatic inline uint32_t get_bar(uint8_t bus, uint8_t dev, uint8_t func, uint8_t id)\n{\n    return pci_read_dword(bus, dev, func, 0x10 + 4 * id);\n}\n\nint pci_device_scan(uint16_t vendor_id, uint16_t device_id, struct pci_dev *ref)\n{\n    /* TODO cache bus entries */\n    uint8_t bus = 0;\n    for (uint8_t dev = 0; dev < 32; ++dev) {\n        for (uint8_t func = 0; func < 8; ++func) {\n            uint16_t _vendor_id = get_vendor_id(bus, dev, func);\n            if (_vendor_id != 0xFFFF) {\n                uint16_t _device_id = get_device_id(bus, dev, func);\n                if (_vendor_id == vendor_id && _device_id == device_id) {\n                    if (ref) {\n                        ref->bus = bus;\n                        ref->dev = dev;\n                        ref->func = func;\n                    }\n\n                    return 0;\n                }\n            }\n        }\n    }\n\n    return -1;\n}\n\nuint8_t pci_reg8_read(struct pci_dev *dev, uint8_t off)\n{\n    return (pci_read_dword(dev->bus, dev->dev, dev->func, off) >> ((off & 3) * 8)) & 0xFF;\n}\n\nuint16_t pci_reg16_read(struct pci_dev *dev, uint8_t off)\n{\n    return (pci_read_dword(dev->bus, dev->dev, dev->func, off) >> ((off & 2) * 8)) & 0xFFFF;\n}\n\nuint32_t pci_reg32_read(struct pci_dev *dev, uint8_t off)\n{\n    return pci_read_dword(dev->bus, dev->dev, dev->func, off);\n}\n\nvoid pci_reg8_write(struct pci_dev *dev, uint8_t off, uint8_t val)\n{\n    uint32_t oval = pci_read_dword(dev->bus, dev->dev, dev->func, off);\n    oval = (oval & (~0xFFUL << (off & 3) * 8)) | (val << (off & 3) * 8);\n    pci_write_dword(dev->bus, dev->dev, dev->func, off, oval);\n}\n\nvoid pci_reg16_write(struct pci_dev *dev, uint8_t off, uint8_t val)\n{\n    uint32_t oval = pci_read_dword(dev->bus, dev->dev, dev->func, off);\n    oval = (oval & (~0xFFFFUL << (off & 2) * 8)) | (val << (off & 2) * 8);\n    pci_write_dword(dev->bus, dev->dev, dev->func, off, oval);\n}\n\nvoid pci_reg32_write(struct pci_dev *dev, uint8_t off, uint8_t val)\n{\n    pci_write_dword(dev->bus, dev->dev, dev->func, off, val);\n}\n\nstatic void scan_device(uint8_t bus, uint8_t dev)\n{\n    for (uint8_t func = 0; func < 8; ++func) {\n        uint16_t vendor_id = get_vendor_id(bus, dev, func);\n\n        if (vendor_id != 0xFFFF) {\n            uint32_t device_id = get_device_id(bus, dev, func);\n            uint32_t class_code = get_class_code(bus, dev, func);\n            uint32_t subclass_code = get_subclass_code(bus, dev, func);\n\n            printk(\"Bus: %d, Device: %d, Function %d\\n\", bus, dev, func);\n            printk(\"  -> Vendor ID: %x, Device ID: %x, Class: %x, Subclass: %x\\n\", vendor_id, device_id, class_code, subclass_code);\n            //printk(\"  -> Vednor: %s\\n\", get_vendor_name(vendor_id));\n            //printk(\"  -> Device: %s\\n\", get_device_name(vendor_id, device_id));\n        }\n    }\n}\n\nstatic void scan_bus(uint8_t bus)\n{\n    for (uint8_t dev = 0; dev < 32; ++dev) {\n        scan_device(bus, dev);\n    }\n}\n\nint pci_prope()\n{\n    //scan_bus(0);\n    return 0;\n}\n\nstruct dev pcidev = {\n    .probe = pci_prope,\n};\n\n/*\n * Used by chipset driver to initalize PCI bus\n */\nvoid pci_ioaddr_set(struct ioaddr *io)\n{\n    pci_ioaddr = *io;\n}\n\n\n/*\n * PCI Bus Interface\n */\n\nint pci_scan_device(uint8_t class, uint8_t subclass, struct pci_dev *_dev, size_t nr)\n{\n    size_t  idx = 0;\n    uint8_t bus = 0;\n\n    for (uint8_t dev = 0; dev < 32; ++dev) {\n        for (uint8_t func = 0; func < 8; ++func) {\n            uint16_t vendor_id = get_vendor_id(bus, dev, func);\n\n            if (vendor_id != 0xFFFF) {\n                uint32_t class_code = get_class_code(bus, dev, func);\n                uint32_t subclass_code = get_subclass_code(bus, dev, func);\n\n                if (class_code == class && subclass_code == subclass) {\n                    _dev[idx].bus  = bus;\n                    _dev[idx].dev  = dev;\n                    _dev[idx].func = func;\n                    ++idx;\n                    --nr;\n\n                    if (!nr)\n                        return idx;\n                }\n            }\n        }\n    }\n\n    return idx;\n}\n\nuint32_t pci_read_bar(struct pci_dev *dev, uint8_t id)\n{\n    return pci_read_dword(dev->bus, dev->dev, dev->func, 0x10 + 4 * id);\n}\n\nMODULE_INIT(pci, pci_prope, NULL)\n"
  },
  {
    "path": "kernel/dev/rd/Build.mk",
    "content": "obj-y += ramdisk.o\n"
  },
  {
    "path": "kernel/dev/rd/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/rd/ramdisk.c",
    "content": "#include <core/system.h>\n#include <core/module.h>\n#include <core/string.h>\n\n#include <boot/boot.h>\n#include <dev/dev.h>\n\nstatic void *rd_addr = NULL;\nsize_t rd_size = 0; /* XXX */\n\nstatic ssize_t rd_read(struct devid *dd __unused, off_t offset, size_t size, void *buf)\n{\n    /* Maximum possible read size */\n    size = MIN(size, rd_size - offset);\n    \n    /* Copy `size' bytes from ramdev into buffer */\n    memcpy(buf, (char *) rd_addr + offset, size);\n\n    return size;\n}\n\nstatic ssize_t rd_write(struct devid *dd __unused, off_t offset, size_t size, void *buf)\n{\n    /* Maximum possible write size */\n    size = MIN(size, rd_size - offset);\n    \n    /* Copy `size' bytes from buffer to ramdev */\n    memcpy((char *) rd_addr + offset, buf, size);\n\n    return size;\n}\n\nstatic int rd_probe()\n{\n    extern struct boot *__kboot;\n    module_t *rd_module = &__kboot->modules[0];\n    rd_addr = (void *) rd_module->addr;\n    rd_size = rd_module->size;\n\n    kdev_blkdev_register(1, &rddev);\n\n    return 0;\n}\n\nstatic size_t rd_getbs(struct devid *dd __unused)\n{\n    return 1;   /* FIXME */\n}\n\nstruct dev rddev = {\n    .name  = \"ramdisk\",\n    .probe = rd_probe,\n    .read  = rd_read,\n    .write = rd_write,\n    .getbs = rd_getbs,\n};\n\nMODULE_INIT(rd, rd_probe, NULL)\n"
  },
  {
    "path": "kernel/dev/tty/Build.mk",
    "content": "dirs-$(DEV_CONSOLE) += console/\ndirs-$(DEV_PTY)  += pty/\ndirs-$(DEV_UART) += uart/\nobj-y += tty.o\nobj-y += generic.o\n"
  },
  {
    "path": "kernel/dev/tty/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/tty/console/Build.mk",
    "content": "obj-y += console.o\n"
  },
  {
    "path": "kernel/dev/tty/console/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/tty/console/console.c",
    "content": "/*\n *          IBM VGA Text-Mode Console\n *\n *\n *  This file is part of Aquila OS and is released under\n *  the terms of GNU GPLv3 - See LICENSE.\n *\n */\n\n\n#include <core/system.h>\n#include <core/module.h>\n#include <core/string.h>\n\n#include <cpu/io.h>\n\n#include <mm/mm.h>\n\n#include <dev/dev.h>\n#include <fs/devfs.h>\n#include <fs/posix.h>\n\n#include <ds/queue.h>\n\n#define VGA_START   (VMA((char*)0xB8000))   /* FIXME */\n\nstatic char *vga = VGA_START;\nstatic struct ioaddr __console_ioaddr = {\n    .addr = 0x3D4,\n    .type = IOADDR_PORT,\n};\n\nstatic void scroll(int n)\n{\n    memcpy(VGA_START, VGA_START + 160 * n, 160 * (25 - n));\n    vga = VGA_START + 160 * (25 - n);\n\n    for (int i = 0; i < 80 * n; ++i) {\n        vga[2 * i + 0] = '\\0';\n        vga[2 * i + 1] = 0x07;\n    }\n}\n\nstatic void set_cursor(unsigned pos)\n{\n    io_out8(&__console_ioaddr, 0x00, 0x0F);\n    io_out8(&__console_ioaddr, 0x01, (uint8_t)(pos & 0xFF));\n\n    io_out8(&__console_ioaddr, 0x00, 0x0E);\n    io_out8(&__console_ioaddr, 0x01, (uint8_t)((pos >> 8) & 0xFF));\n}\n\nstatic ssize_t console_write(struct devid *dd __unused, off_t offset __unused, size_t size, void *buf)\n{\n    //printk(\"console_write(dd=%p, offset=%d, size=%d, buf=%p)\\n\", dd, offset, size, buf);\n    for (size_t i = 0; i < size; ++i) {\n        \n        char c = ((char *) buf)[i];\n\n        switch (c) {\n            case '\\0':  /* Null-character */\n                break;\n            case '\\n':  /* Newline */\n                vga = VGA_START + (vga - VGA_START) / 160 * 160 + 160;\n                if (vga - VGA_START >= 160 * 25)\n                    scroll(1);\n                break;\n            case '\\b':  /* Backspace */\n                if (vga - VGA_START >= 2) {\n                    vga -= 2;\n                    *vga = 0;\n                }\n                break;\n            default:\n                if(vga - VGA_START >= 160 * 25)\n                    scroll(1);\n                *vga = c;\n                vga += 2;\n        }\n    }\n\n    set_cursor((vga - VGA_START)/2);\n\n    return size;\n}\n\nstatic int console_probe()\n{\n    return 0;\n}\n\nstruct dev condev = {\n    .name = \"condev\",\n    .probe = console_probe,\n    .write = console_write,\n\n    .fops  = {\n        .open  = posix_file_open,\n        .write = posix_file_write,\n    },\n};\n\nMODULE_INIT(condev, console_probe, NULL)\n"
  },
  {
    "path": "kernel/dev/tty/generic.c",
    "content": "#include <core/system.h>\n#include <sys/sched.h>\n#include <dev/tty.h>\n\nMALLOC_DEFINE(M_TTY, \"tty\", \"tty structure\");\nMALLOC_DEFINE(M_TTY_COOK, \"tty-cook\", \"tty cooking buffer\");\n\nssize_t tty_master_write(struct tty *tty, size_t size, void *buf)\n{\n    ssize_t ret = size;\n\n    /* Process Slave Input */\n    if (tty->tios.c_lflag & ICANON) {   /* Canonical mode */\n        int echo = tty->tios.c_lflag & ECHO;\n        char *c = buf;\n\n        while (size) {\n            if (*c == tty->tios.c_cc[VEOF]) {\n                /* TODO */\n            } else if (*c == tty->tios.c_cc[VEOL]) {\n                /* TODO */\n            } else if (*c == tty->tios.c_cc[VERASE]) {\n                /* The ERASE character shall delete the last character in\n                 * the current line, if there is one.\n                 */\n                if (tty->pos > 0) {\n                    --tty->pos;\n                    tty->cook[tty->pos] = '\\0';\n\n                    if (tty->tios.c_lflag & ECHOE)\n                        tty_slave_write(tty, 3, \"\\b \\b\");\n                }\n\n                goto skip_echo;\n            } else if (*c == tty->tios.c_cc[VINTR]) {\n                signal_pgrp_send(tty->fg, SIGINT);\n                char cc[] = {'^', *c + '@', '\\n'};\n                tty_slave_write(tty, 3, cc);\n                goto skip_echo;\n            } else if (*c == tty->tios.c_cc[VKILL]) {\n                /* The KILL character shall delete all data in the current\n                 * line, if there is any.\n                 */\n            } else if (*c == tty->tios.c_cc[VQUIT]) {\n            } else if (*c == tty->tios.c_cc[VSTART]) {\n            } else if (*c == tty->tios.c_cc[VSUSP]) {\n            } else if (*c == '\\n' ||\n                    (*c == '\\r' && (tty->tios.c_iflag & ICRNL))) {\n                tty->cook[tty->pos++] = '\\n';\n\n                if (echo)\n                    tty_slave_write(tty, 1, \"\\n\");\n\n                tty->slave_write(tty, tty->pos, tty->cook);\n\n                tty->pos = 0;\n                ret = ret - size + 1;\n                return ret;\n            } else {\n                tty->cook[tty->pos++] = *c;\n            }\n\n            if (echo) {\n                if (*c < ' ') { /* Non-printable */\n                    char cc[] = {'^', *c + '@'};\n                    tty_slave_write(tty, 2, cc);\n                } else {\n                    tty_slave_write(tty, 1, c);\n                }\n            }\nskip_echo:\n            ++c;\n            --size;\n        }\n    } else {\n        return tty->slave_write(tty, size, buf);\n    }\n\n    return ret;\n}\n\nssize_t tty_slave_write(struct tty *tty, size_t size, void *_buf)\n{\n    const char *buf = (const char *) _buf;\n\n    if (tty->tios.c_oflag & OPOST) {\n        size_t written = 0;\n\n        for (written = 0; written < size; ++written) {\n            char c = buf[written];\n\n            if (c == '\\n' && (tty->tios.c_oflag & ONLCR)) {\n                /* If ONLCR is set, the NL character shall\n                 * be transmitted as the CR-NL character pair. \n                 */\n                if (tty->master_write(tty, 2, \"\\r\\n\") != 2)\n                    /* FIXME should handle special cases */\n                    break;\n            } else if (c == '\\r' && (tty->tios.c_oflag & OCRNL)) {\n                /* If OCRNL is set, the CR character shall\n                 * be transmitted as the NL character.\n                 */\n                if (tty->master_write(tty, 1, \"\\n\") != 1)\n                    break;\n            } else if (c == '\\r' && (tty->tios.c_oflag & ONOCR)) {\n                /* If ONOCR is set, no CR character shall be\n                 * transmitted when at column 0 (first position)\n                 */\n                if (tty->pos % tty->ws.ws_row)\n                    if (tty->master_write(tty, 1, &c) != 1)\n                        break;\n            } else if (c == '\\n' && (tty->tios.c_oflag & ONLRET)) {\n                /* If ONLRET is set, the NL character is assumed\n                 * to do the carriage-return function; the column\n                 * pointer shall be set to 0 and the delays specified\n                 * for CR shall be used. Otherwise, the NL character is\n                 * assumed to do just the line-feed function; the column\n                 * pointer remains unchanged. The column pointer shall also\n                 * be set to 0 if the CR character is actually transmitted.\n                 */\n\n                /* TODO */\n            } else {\n                if (tty->master_write(tty, 1, &c) != 1)\n                    break;\n            }\n        }\n        return written;\n    } else {\n        return tty->master_write(tty, size, _buf);\n    }\n}\n\nint tty_ioctl(struct tty *tty, int request, void *argp)\n{\n    switch (request) {\n        case TCGETS:\n            memcpy(argp, &tty->tios, sizeof(struct termios));\n            break;\n        case TCSETS:\n            memcpy(&tty->tios, argp, sizeof(struct termios));\n            break;\n        case TIOCGPGRP:\n            *(pid_t *) argp = tty->fg->pgid;\n            break;\n        case TIOCSPGRP:\n            /* XXX */\n            tty->fg = curproc->pgrp;\n            break;\n        case TIOCGWINSZ:\n            memcpy(argp, &tty->ws, sizeof(struct winsize));\n            break;\n        case TIOCSWINSZ:\n            memcpy(&tty->ws, argp, sizeof(struct winsize));\n            break;\n        case TIOCSCTTY:\n            /* FIXME */\n            tty->proc = curproc;\n            curproc->pgrp->session->ctty = tty->dev;\n            break;\n        default:\n            return -EINVAL;\n    }\n    \n    return 0;\n}\n\n/**\n * \\ingroup dev-tty\n * \\brief create a new generic tty interface\n */\nint tty_new(struct proc *proc, size_t buf_size, ttyio master,\n        ttyio slave, void *p, struct tty **ref)\n{\n    struct tty *tty = NULL;\n    \n    tty = kmalloc(sizeof(struct tty), &M_TTY, M_ZERO);\n    if (!tty) return -ENOMEM;\n\n    if (!buf_size)\n        buf_size = TTY_BUF_SIZE;\n\n    tty->cook = kmalloc(buf_size, &M_TTY_COOK, 0);\n\n    if (!tty->cook) {\n        kfree(tty);\n        return -ENOMEM;\n    }\n\n    tty->pos  = 0;\n\n    /* Defaults */\n    tty->tios.c_iflag = ICRNL | IXON;\n    tty->tios.c_oflag = OPOST | ONLCR;\n    tty->tios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;\n    //tty->tios.c_cc[VEOL]   = ;\n    tty->tios.c_cc[VERASE] = 0x08;  /* BS */\n    tty->tios.c_cc[VINTR]  = 0x03;  /* ^C */\n    tty->tios.c_cc[VKILL]  = 0x15;  /* ^U */\n    tty->tios.c_cc[VQUIT]  = 0x1C;  /* ^\\ */\n    tty->tios.c_cc[VSTART] = 0x11;  /* ^Q */\n    tty->tios.c_cc[VSUSP]  = 0x1A;  /* ^Z */\n\n    tty->ws.ws_row = 24;\n    tty->ws.ws_col = 80;\n\n    tty->fg = proc->pgrp;\n\n    /* Interface */\n    tty->master_write = master;\n    tty->slave_write  = slave;\n    tty->p = p;\n\n    if (ref)\n        *ref = tty;\n\n    return 0;\n}\n\nint tty_free(struct tty *tty)\n{\n    kfree(tty->cook);\n    kfree(tty);\n\n    return 0;\n}\n"
  },
  {
    "path": "kernel/dev/tty/pty/Build.mk",
    "content": "obj-y += pty.o\n"
  },
  {
    "path": "kernel/dev/tty/pty/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/tty/pty/pty.c",
    "content": "#include <core/system.h>\n#include <core/module.h>\n#include <fs/vfs.h>\n#include <fs/devpts.h>\n#include <fs/posix.h>\n#include <dev/dev.h>\n#include <dev/tty.h>\n#include <sys/sched.h>\n#include <bits/errno.h>\n#include <ds/ringbuf.h>\n\nMALLOC_DEFINE(M_PTY, \"pseudo-terminal\", \"pseudo-terminal structure\");\n\n/**\n * \\ingroup dev-tty\n * \\brief psuedo-terminal\n */\nstruct pty {\n    size_t id;\n    struct tty *tty;\n\n    struct vnode *master;\n    struct vnode *slave;\n\n    /** master input, slave output */\n    struct ringbuf *in;\n\n    /** slave input, master output */\n    struct ringbuf *out;\n\n    /** slave read, master write wait queue */\n    struct queue pts_read_queue;\n\n    /** slave write, master read wait queue */\n    struct queue pts_write_queue;\n};\n\n#define PTY_BUF 4096\n\nstatic struct pty *ptys[256] = {0};\n\nstruct dev ptmdev;\nstruct dev ptsdev;\n\n/* TTY Interface */\nssize_t pty_master_write(struct tty *tty, size_t size, void *buf)\n{\n    struct pty *pty = (struct pty *) tty->p;\n    size_t written = 0;\n\n    while (written < size) {\n        written += ringbuf_write(pty->out, size - written, (char *) buf + written);\n\n        if (written != size) {\n            /* writes must always complete */\n            if (thread_queue_sleep(&pty->pts_read_queue))\n                return -EINTR;\n        }\n    }\n\n    return written;\n}\n\nssize_t pty_slave_write(struct tty *tty, size_t size, void *buf)\n{\n    struct pty *pty = (struct pty *) tty->p;\n    size_t written = 0;\n\n    while (written < size) {\n        written += ringbuf_write(pty->in, size - written, (char *) buf + written);\n\n        if (written != size) {\n            /* writes must always complete */\n            if (thread_queue_sleep(&pty->pts_read_queue))\n                return -EINTR;\n        }\n    }\n\n    return written;\n}\n\n/*************************************\n *\n * Pseudo Terminal Master Helpers\n *\n *************************************/\n\nstatic int ptm_new(struct pty *pty, struct vnode **ref)\n{\n    /* anonymous file, not populated */\n    struct vnode *ptm = NULL;\n    \n    ptm = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n    if (ptm == NULL) return -ENOMEM;\n\n    ptm->rdev        = DEV(2, pty->id);\n    ptm->mode        = S_IFCHR;\n    ptm->read_queue  = &pty->pts_read_queue;\n    ptm->write_queue = &pty->pts_write_queue;\n    ptm->p           = pty;\n\n    if (ref)\n        *ref = ptm;\n\n    return 0;\n}\n\nstatic ssize_t ptm_read(struct devid *dd, off_t offset __unused, size_t size, void *buf)\n{\n    struct pty *pty = ptys[dd->minor];\n    size_t ret = ringbuf_read(pty->out, size, buf);  \n\n    thread_queue_wakeup(&pty->pts_read_queue);\n\n    return ret;\n}\n\nstatic ssize_t ptm_write(struct devid *dd, off_t offset __unused, size_t size, void *buf)\n{\n    struct pty *pty = ptys[dd->minor];\n    return tty_master_write(pty->tty, size, buf);  \n}\n\nstatic int pty_ioctl(struct devid *dd, int request, void *argp)\n{\n    struct pty *pty = ptys[dd->minor];\n\n    switch (request) {\n        case TIOCGPTN:\n            *(int *) argp = pty->id;\n            return 0;\n        case TIOCSPTLCK:\n            *(int *) argp = 0;  /* FIXME */\n            return 0;\n    }\n\n    return tty_ioctl(pty->tty, request, argp);  \n}\n\n/*************************************\n *\n * Pseudo Terminal Slave Helpers\n *\n *************************************/\n\nstatic int pts_new(struct pty *pty, struct vnode **ref)\n{\n    char name[12];\n    memset(name, 0, 12);\n    snprintf(name, 11, \"%d\", pty->id);\n\n    dev_t dev = DEV(136 + pty->id / 256, pty->id % 256);\n\n    struct uio uio = {0};\n\n    struct vnode *pts = NULL;\n    int err = 0;\n    if ((err = vfs_vmknod(devpts_root, name, S_IFCHR, dev, &uio, &pts)))\n        return err;\n\n    pts->read_queue = &pty->pts_read_queue;\n    pts->write_queue = &pty->pts_write_queue;\n\n    if (ref)\n        *ref = pts;\n\n    return 0;\n}\n\nssize_t pts_read(struct devid *dd, off_t offset __unused, size_t size, void *buf)\n{\n    /* FIXME check bounds */\n    struct pty *pty = ptys[dd->minor];\n    return ringbuf_read(pty->in, size, buf);\n}\n\nssize_t pts_write(struct devid *dd, off_t offset __unused, size_t size, void *buf)\n{\n    /* FIXME check bounds */\n    struct pty *pty = ptys[dd->minor];\n    return tty_slave_write(pty->tty, size, buf);\n}\n\nint pts_can_read(struct file *file, size_t size)\n{\n    struct devid *dd = &VNODE_DEV(file->vnode);\n    struct pty *pty = ptys[dd->minor];\n    return ringbuf_available(pty->in);\n}\n\n/*************************************\n *\n * Pseudo Terminal Helpers\n *\n *************************************/\n\nstatic inline size_t pty_id_get(void)\n{\n    /* XXX */\n    static size_t id = 0;\n    return id++;\n}\n\nint pty_new(struct proc *proc, struct vnode **master)\n{\n    int err = 0;\n    struct pty *pty = NULL;\n\n    pty = kmalloc(sizeof(struct pty), &M_PTY, M_ZERO);\n    if (!pty) goto e_nomem;\n\n    pty->id = pty_id_get();\n\n    if (!(pty->in = ringbuf_new(PTY_BUF))) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    if (!(pty->out = ringbuf_new(PTY_BUF))) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    if ((err = tty_new(proc, 0, pty_master_write, pty_slave_write, pty, &pty->tty)))\n        goto error;\n\n    pty->tty->dev = &ptmdev;\n\n    if ((err = ptm_new(pty, &pty->master)))\n        goto error;\n\n    if (master)\n        *master = pty->master;\n    \n    if ((err = pts_new(pty, &pty->slave)))\n        goto error;\n\n    ptys[pty->id] = pty;\n\n    return 0;\n\ne_nomem:\n    err = -ENOMEM;\nerror:\n    if (pty) {\n        if (pty->in)\n            ringbuf_free(pty->in);\n        if (pty->out)\n            ringbuf_free(pty->in);\n        if (pty->tty)\n            tty_free(pty->tty);\n\n        kfree(pty);\n    }\n\n    return err;\n}\n\nint ptmx_open(struct file *file)\n{   \n    return pty_new(curproc, &(file->vnode));\n}\n\nint pty_init()\n{\n    kdev_chrdev_register(2, &ptmdev);\n\n    for (devid_t i = 136; i < 144; ++i)\n        kdev_chrdev_register(i, &ptsdev);\n\n    return 0;\n}\n\nstruct dev ptsdev = {\n    .name  = \"ptsdev\",\n    .read  = pts_read,\n    .write = pts_write,\n    .ioctl = pty_ioctl,\n\n    .fops = {\n        .open  = posix_file_open,\n        .read  = posix_file_read,\n        .write = posix_file_write,\n        .ioctl = posix_file_ioctl,\n\n        .can_read  = pts_can_read,\n        .can_write = __vfs_can_always,\n        .eof       = __vfs_eof_never,\n    }\n};\n\nstruct dev ptmdev = {\n    .name = \"ptmdev\",\n    .read  = ptm_read,\n    .write = ptm_write,\n    .ioctl = pty_ioctl,\n\n    .fops = {\n        .open  = ptmx_open,\n        .read  = posix_file_read,\n        .write = posix_file_write,\n        .ioctl = posix_file_ioctl,\n\n        .can_read  = __vfs_can_always,\n        .can_write = __vfs_can_always,\n        .eof       = __vfs_eof_never,\n    },\n};\n\nMODULE_INIT(pty, pty_init, NULL)\n"
  },
  {
    "path": "kernel/dev/tty/tty.c",
    "content": "/**\n * \\defgroup dev-tty kernel/dev/tty\n * \\brief tty device\n */\n\n#include <core/system.h>\n#include <core/module.h>\n#include <dev/ttydev.h>\n#include <fs/posix.h>\n#include <sys/sched.h>\n\nstruct dev *sttydev_mux(struct devid *dd)\n{\n    if (dd->minor < 64) {\n        //return &vtty;\n    } else {\n        return &uart;\n    }\n\n    return NULL;\n}\n\nstruct dev *ttydev_mux(struct devid *dd)\n{\n    switch (dd->minor) {\n        case 0: /* /dev/tty */\n            return curproc->pgrp->session->ctty;\n        case 1: /* /dev/console */\n            return &condev;\n        case 2: /* /dev/ptmx */\n            return &ptmdev;\n    }\n\n    return NULL;\n}\n\nint ttydev_probe()\n{\n    kdev_chrdev_register(4, &sttydev);\n    kdev_chrdev_register(5, &ttydev);\n    return 0;\n}\n\nstruct dev sttydev = {\n    .name  = \"sttydev\",\n    .mux   = sttydev_mux,\n};\n\nstruct dev ttydev = {\n    .name  = \"ttydev\",\n    .mux   = ttydev_mux,\n};\n\nMODULE_INIT(ttydev, ttydev_probe, NULL)\n"
  },
  {
    "path": "kernel/dev/tty/uart/8250/8250.c",
    "content": "#include <core/system.h>\n#include <core/module.h>\n\n#include <dev/tty.h>\n#include <dev/uart.h>\n#include <dev/pci.h>\n#include <cpu/cpu.h>\n#include <cpu/io.h>\n\n#include <platform/misc.h>   /* XXX */\n\n#define UART_MMIO   0\n\n#define UART_IER    1\n#define UART_FCR    2\n#define UART_LCR    3\n#define UART_MCR    4\n#define UART_DLL    0\n#define UART_DLH    1\n#define UART_LCR_DLAB    0x80\n\nstruct uart uart_8250;\nstruct ioaddr io8250 = {\n#if UART_MMIO\n    .addr = 0xCF00B000,\n    .type = IOADDR_MMIO32,\n#else\n    .addr = 0x3F8,\n    .type = IOADDR_PORT,\n#endif\n};\n\n#define UART_8250_IRQ   4\n\n\nstatic int serial_empty(void)\n{\n    return io_in8(&io8250, 5) & 0x20;\n}\n\nstatic int serial_received(void)\n{\n   return io_in8(&io8250, 5) & 0x01;\n}\n\nchar uart_8250_receive(struct uart *u __unused)\n{\n    return io_in8(&io8250, 0);\n}\n\nssize_t uart_8250_transmit(struct uart *u __unused, char c)\n{\n    io_out8(&io8250, 0, c);\n    return 1;\n}\n\nvoid uart_8250_irq()\n{\n    if (serial_received()) {\n        if (uart_8250.vnode) /* If open */\n            uart_recieve_handler(&uart_8250, 1);\n    }\n\n    if (serial_empty()) {\n        if (uart_8250.vnode) /* If open */\n            uart_transmit_handler(&uart_8250, 1);\n    }\n}\n\nvoid uart_8250_comm_init(struct uart *u __unused)\n{\n    while (!serial_empty());    /* Flush all output before reseting */\n\n    io_out8(&io8250, UART_IER, 0x00);  /* Disable all interrupts */\n\n    io_out8(&io8250, UART_LCR, 0x03);  /* 8 bits, no parity, one stop bit */\n    io_out8(&io8250, UART_FCR, 0xC7);  /* Enalbe FIFO, clear, 14 byte threshold */\n    io_out8(&io8250, UART_MCR, 0x0B);  /* DTR + RTS */\n\n    /* Enable DLAB and set divisor */\n    int lcr = io_in8(&io8250, UART_LCR);\n    io_out8(&io8250, UART_LCR, lcr | UART_LCR_DLAB);  /* Enable DLAB */\n    io_out8(&io8250, UART_DLL, 0x03);  /* Set divisor to 3 */\n    io_out8(&io8250, UART_DLH, 0x00);\n    io_out8(&io8250, UART_LCR, lcr & ~UART_LCR_DLAB);\n\n    io_out8(&io8250, UART_IER, 0x01);  /* Enable Data/Empty interrupt */\n}\n\nint uart_8250_init()\n{\n    //serial_init();\n    x86_irq_handler_install(UART_8250_IRQ, uart_8250_irq);\n\n#if 0\n    struct pci_dev dev;\n    int ret = pci_device_scan(0x8086, 0x0936, &dev);\n\n    if (ret) {\n        printk(\"HSUART not found\\n\");\n        for (;;);\n    }\n\n    printk(\"HSUART found at bus %d, device %d, function %d\\n\", dev.bus, dev.dev, dev.func);\n    uint16_t cmd = pci_reg8_read(&dev, 0x4);\n    printk(\"cmd %x\\n\", cmd);\n\n    uint8_t intl = pci_reg8_read(&dev, 0x3C);\n    printk(\"intl %x\\n\", intl);\n    uint8_t intp = pci_reg8_read(&dev, 0x3D);\n    printk(\"intp %x\\n\", intp);\n    intl = UART_8250_IRQ;\n    pci_reg8_write(&dev, 0x3C, intl);\n    intl = pci_reg8_read(&dev, 0x3C);\n    printk(\"intl %x\\n\", intl);\n\n    for (;;)\n        asm volatile (\"sti; hlt;\");\n\n    for (;;) {\n        asm volatile (\"sti; hlt;\");\n\n        uintptr_t port = 0xCF00B000;\n        uint32_t stat = *(volatile uint32_t *) (port + (5 << 2));\n\n        //uint32_t _stat = *(volatile uint32_t *) (port + (4 << 2));\n\n        //printk(\"stat = %x\\n\", _stat);\n\n        if (stat & 0x01) { /* Got data */\n            uint32_t data = *(volatile uint32_t *) (port + (0 << 2));\n            printk(\"data = %c\\n\", data);\n        }\n\n        asm volatile (\"cli;\");\n    }\n#endif\n\n    uart_register(0, &uart_8250);\n    return 0;\n}\n\nstruct uart uart_8250 = {\n    .name     = \"8250\",\n    .init     = uart_8250_comm_init,\n    .transmit = uart_8250_transmit,\n    .receive  = uart_8250_receive,\n};\n\nMODULE_INIT(uart_8250, uart_8250_init, NULL)\n"
  },
  {
    "path": "kernel/dev/tty/uart/8250/Build.mk",
    "content": "obj-y += 8250.o\n"
  },
  {
    "path": "kernel/dev/tty/uart/8250/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/tty/uart/Build.mk",
    "content": "dirs-y += 8250/\nobj-y += uart.o\n"
  },
  {
    "path": "kernel/dev/tty/uart/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/dev/tty/uart/uart.c",
    "content": "#include <core/system.h>\n#include <dev/dev.h>\n#include <dev/tty.h>\n#include <dev/uart.h>\n#include <fs/posix.h>\n#include <ds/queue.h>\n#include <ds/ringbuf.h>\n#include <sys/sched.h>\n\n#define UART_BUF 64\nstatic struct uart *devices[192] = {0};   /* Registered devices */\n\n/* Called when data is received */\nvoid uart_recieve_handler(struct uart *u, size_t size)\n{\n    char buf[UART_BUF];\n\n    for (size_t i = 0; i < size; ++i) {\n        buf[i] = u->receive(u);\n    }\n\n    tty_master_write(u->tty, size, buf);  \n    thread_queue_wakeup(u->vnode->read_queue);\n}\n\n/* Called when data is ready to be transmitted */\nvoid uart_transmit_handler(struct uart *u, size_t size)\n{\n    size_t len = ringbuf_available(u->out);\n    len = MIN(size, len);\n\n    for (size_t i = 0; i < len; ++i) {\n        char c = 0;\n        ringbuf_read(u->out, 1, &c);\n        u->transmit(u, c);\n    }\n\n    thread_queue_wakeup(u->vnode->write_queue);\n}\n\n/* TTY Interface */\nssize_t uart_master_write(struct tty *tty, size_t size, void *buf)\n{\n    struct uart *u = (struct uart *) tty->p;\n    size_t s = ringbuf_write(u->out, size, buf);\n    uart_transmit_handler(u, s); /* XXX */\n    return s;\n}\n\nssize_t uart_slave_write(struct tty *tty, size_t size, void *buf)\n{\n    struct uart *u = (struct uart *) tty->p;\n    return ringbuf_write(u->in, size, buf);\n}\n\nssize_t uart_read(struct devid *dd, off_t offset __unused, size_t size, void *buf)\n{\n    struct uart *u = devices[dd->minor - 64];\n    if (!u) return -EIO;\n    return ringbuf_read(u->in, size, buf);\n}\n\nssize_t uart_write(struct devid *dd, off_t offset __unused, size_t size, void *buf)\n{\n    struct uart *u = devices[dd->minor - 64];\n    if (!u) return -EIO;\n    return tty_slave_write(u->tty, size, buf);\n}\n\nint uart_ioctl(struct devid *dd, int request, void *argp)\n{\n    struct uart *u = devices[dd->minor - 64];\n    if (!u) return -EIO;\n    return tty_ioctl(u->tty, request, argp);  \n}\n\nint uart_file_open(struct file *file)\n{\n    size_t id = (file->vnode->rdev & 0xFF) - 64;\n    struct uart *u = devices[id];\n    int err = 0;\n\n    if (u->vnode) { /* already open */\n        /* XXX */\n        file->vnode = u->vnode;\n    } else {\n        u->init(u);\n        u->vnode = file->vnode;\n        /* TODO Error checking */\n        u->in = ringbuf_new(UART_BUF);\n        u->out = ringbuf_new(UART_BUF);\n        tty_new(curproc, 0, uart_master_write, uart_slave_write, u, &u->tty);\n        file->vnode->read_queue  = queue_new();\n        file->vnode->write_queue = queue_new();\n    }\n\n    return 0;\n}\n\nint uart_register(int id, struct uart *u)\n{\n    if (id < 0) {   /* Allocated dynamically */\n        for (int i = 0; i < 192; ++i) {\n            if (!devices[i]) {\n                devices[i] = u;\n                id = i;\n                goto done;\n            }\n        }\n\n        return -1;  /* Failed */\n    }\n\ndone:\n    devices[id] = u;\n\n    printk(\"uart: registered uart %d: %s\\n\", id, u->name);\n    return id;\n}\n\nstruct dev uart = {\n    .name = \"uart\",\n\n    .read  = uart_read,\n    .write = uart_write,\n    .ioctl = uart_ioctl,\n\n    .fops = {\n        .open  = uart_file_open,\n        .read  = posix_file_read,\n        .write = posix_file_write,\n        .ioctl = posix_file_ioctl,\n\n        .can_write = __vfs_can_always,  /* XXX */\n        .eof       = __vfs_eof_never,\n    },\n};\n"
  },
  {
    "path": "kernel/fs/Build.mk",
    "content": "obj-y  += close.o\nobj-y  += fops.o\nobj-y  += ioctl.o\nobj-y  += lookup.o\nobj-y  += mknod.o\nobj-y  += mount.o\nobj-y  += readdir.o\nobj-y  += read.o\nobj-y  += stat.o\nobj-y  += sync.o\nobj-y  += trunc.o\nobj-y  += unlink.o\nobj-y  += vops.o\nobj-y  += write.o\n\nobj-y  += vfs.o\n\n# Mandatory targets\ndirs-y += pseudofs/\ndirs-y += initramfs/\ndirs-y += posix/\nobj-y  += pipe.o\nobj-y  += rofs.o\nobj-y  += vcache.o\nobj-y  += bcache.o\nobj-y  += vm_object.o\n\n# Optional targets\ndirs-$(FS_TMPFS)  += tmpfs/\ndirs-$(FS_DEVFS)  += devfs/\ndirs-$(FS_DEVPTS) += devpts/\ndirs-$(FS_EXT2)   += ext2/\ndirs-$(FS_PROCFS) += procfs/\ndirs-$(FS_MINIX)  += minix/\n"
  },
  {
    "path": "kernel/fs/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/fs/bcache.c",
    "content": "#include <core/system.h>\n#include <fs/bcache.h>\n\nMALLOC_DEFINE(M_BCACHE, \"bcache\", \"block cache structure\");\nMALLOC_DEFINE(M_CACHE_BLOCK, \"cache block\", \"cached block structure\");\n\n/**\n * \\ingroup vfs\n * \\brief cacehed block\n */\nstruct cache_block {\n    off_t off;\n    void *data;\n\n    int dirty;\n};\n\nstatic int bcache_eq(void *_a, void *_b)\n{\n    struct cache_block *a = (struct cache_block *) _a;\n    off_t *b = (off_t *) _b;\n\n    return a->off == *b;\n}\n\nvoid bcache_init(struct bcache *bcache)\n{\n    bcache->hashmap = hashmap_new(0, bcache_eq);\n}\n\nint bcache_insert(struct bcache *bcache, uint64_t off, void *data)\n{\n    if (!bcache)\n        return -EINVAL;\n\n    if (!bcache->hashmap)\n        bcache_init(bcache);\n\n    struct cache_block *block = kmalloc(sizeof(struct cache_block), &M_CACHE_BLOCK, M_ZERO);\n    if (!block) return -ENOMEM;\n\n    block->off = off;\n    block->data = data;\n\n    hash_t hash = hashmap_digest(&off, sizeof(off));\n    return hashmap_insert(bcache->hashmap, hash, block);\n}\n\nint bcache_remove(struct bcache *bcache, uint64_t off)\n{\n    if (!bcache || !bcache->hashmap)\n        return -1;\n\n    hash_t hash = hashmap_digest(&off, sizeof(off));\n\n    struct hashmap_node *node = hashmap_lookup(bcache->hashmap, hash, &off);\n\n    if (node) {\n        void *block = node->entry;\n        node->entry = NULL;\n        kfree(node->entry);\n        hashmap_node_remove(bcache->hashmap, node);\n        return 0;\n    }\n\n    return -1;\n}\n\nvoid *bcache_find(struct bcache *bcache, uint64_t off)\n{\n    if (!bcache || !bcache->hashmap)\n        return NULL;\n\n    hash_t hash = hashmap_digest(&off, sizeof(off));\n\n    struct hashmap_node *node = hashmap_lookup(bcache->hashmap, hash, &off);\n\n    if (node) {\n        struct cache_block *block = (struct cache_block *) node->entry;\n        return block->data;\n    }\n\n    return NULL;\n}\n\nvoid bcache_dirty(struct bcache *bcache, uint64_t off)\n{\n    if (!bcache || !bcache->hashmap)\n        return;\n\n    hash_t hash = hashmap_digest(&off, sizeof(off));\n\n    struct hashmap_node *node = hashmap_lookup(bcache->hashmap, hash, &off);\n\n    if (node) {\n        struct cache_block *block = (struct cache_block *) node->entry;\n        block->dirty = 1;\n    }\n}\n"
  },
  {
    "path": "kernel/fs/close.c",
    "content": "#include <core/system.h>\n#include <core/panic.h>\n#include <fs/vfs.h>\n\n/** close a vnode\n * \\ingroup vfs\n * \\brief closes a vnode (i.e. decrements reference counts)\n */\nint vfs_close(struct vnode *vnode)\n{\n    vfs_log(LOG_DEBUG, \"vfs_close(vnode=%p)\\n\", vnode);\n\n    /* invalid request */\n    if (!vnode || !vnode->fs)\n        return -EINVAL;\n\n    /* operation not supported */\n    if (!vnode->fs->vops.close)\n        return -ENOSYS;\n\n    if (!vnode->ref)\n        panic(\"closing an already closed vnode\");\n\n    vnode->ref--;\n\n    if (!vnode->ref) {\n        return vnode->fs->vops.close(vnode);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "kernel/fs/devfs/Build.mk",
    "content": "ifneq ($(FS_TMPFS),y)\n$(error \"devfs depends on tmpfs\")\nendif\n\nobj-y += devfs.o\n"
  },
  {
    "path": "kernel/fs/devfs/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/fs/devfs/devfs.c",
    "content": "/**********************************************************************\n *                  Device Filesystem (devfs) handler\n *\n *\n *  This file is part of Aquila OS and is released under the terms of\n *  GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) 2016 Mohamed Anwar <mohamed_anwar@opmbx.org>\n */\n\n#include <core/system.h>\n#include <core/module.h>\n#include <core/string.h>\n#include <core/time.h>\n\n#include <fs/vfs.h>\n#include <fs/devfs.h>\n#include <fs/tmpfs.h>\n\n#include <bits/errno.h>\n\n/* devfs root directory (usually mounted on '/dev') */\nstruct vnode *devfs_root = NULL;\n\nstatic int devfs_init()\n{\n    /* devfs is really just tmpfs */\n    devfs.vops = tmpfs.vops;\n    devfs.fops = tmpfs.fops;\n\n    devfs_root = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n    if (!devfs_root) return -ENOMEM;\n\n    devfs_root->ino   = (vino_t) devfs_root;\n    devfs_root->mode  = S_IFDIR | 0775;\n    devfs_root->nlink = 2;\n    devfs_root->fs    = &devfs;\n    devfs_root->ref   = 1;\n\n    struct timespec ts;\n    gettime(&ts);\n\n    devfs_root->ctime = ts;\n    devfs_root->atime = ts;\n    devfs_root->mtime = ts;\n\n    vfs_install(&devfs);\n\n    return 0;\n}\n\nstatic int devfs_mount(const char *dir, int flags, void *data)\n{\n    if (!devfs_root)\n        return -EINVAL;\n\n    return vfs_bind(dir, devfs_root);\n}\n\nstruct fs devfs = {\n    .name   = \"devfs\",\n    .nodev  = 1,\n    .init   = devfs_init,\n    .mount  = devfs_mount,\n};\n\nMODULE_INIT(devfs, devfs_init, NULL)\n"
  },
  {
    "path": "kernel/fs/devpts/Build.mk",
    "content": "obj-y += devpts.o\n"
  },
  {
    "path": "kernel/fs/devpts/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/fs/devpts/devpts.c",
    "content": "#include <core/system.h>\n#include <core/module.h>\n#include <core/time.h>\n\n#include <fs/vfs.h>\n#include <fs/tmpfs.h>\n#include <fs/devpts.h>\n\n/* devpts root directory (usually mounted on /dev/pts) */\nstruct vnode *devpts_root = NULL;\n\nint devpts_init()\n{\n    int err = 0;\n\n    /* devpts is really just tmpfs */\n    devpts.vops = tmpfs.vops;\n    devpts.fops = tmpfs.fops;\n\n    devpts_root = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n    if (!devpts_root) return -ENOMEM;\n\n    devpts_root->ino   = (vino_t) devpts_root;\n    devpts_root->mode  = S_IFDIR | 0775;\n    devpts_root->nlink = 2;\n    devpts_root->fs    = &devpts;\n\n    struct timespec ts;\n    gettime(&ts);\n\n    devpts_root->ctime = ts;\n    devpts_root->atime = ts;\n    devpts_root->mtime = ts;\n\n    err = vfs_install(&devpts);\n\n    if (err) {\n        kfree(devpts_root);\n        devpts_root = NULL;\n        return err;\n    }\n\n    return 0;\n}\n\nint devpts_mount(const char *dir, int flags, void *data)\n{\n    if (!devpts_root)\n        return -EINVAL;\n\n    return vfs_bind(dir, devpts_root);\n}\n\nstruct fs devpts = {\n    .name  = \"devpts\",\n    .nodev = 1,\n    .init  = devpts_init,\n    .mount = devpts_mount,\n};\n\nMODULE_INIT(devpts, devpts_init, NULL)\n"
  },
  {
    "path": "kernel/fs/ext2/Build.mk",
    "content": "obj-y += super.o\nobj-y += block.o\nobj-y += inode.o\nobj-y += dentry.o\nobj-y += vops.o\nobj-y += ext2.o\n"
  },
  {
    "path": "kernel/fs/ext2/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/fs/ext2/block.c",
    "content": "#include <ext2.h>\n#include <ds/bitmap.h>\n\nvoid ext2_bgd_table_rewrite(struct ext2 *desc)\n{\n    uint32_t bgd_table = (desc->bs == 1024)? 2048 : desc->bs;\n    size_t bgds_size = desc->ngroups * sizeof(struct ext2_group);\n    vfs_write(desc->supernode, bgd_table, bgds_size, desc->groups);\n}\n\nvoid *ext2_block_read(struct ext2 *desc, uint32_t number, void *buf)\n{\n    vfs_read(desc->supernode, number * desc->bs, desc->bs, buf);\n    return buf;\n}\n\nvoid *ext2_block_write(struct ext2 *desc, uint32_t number, void *buf)\n{\n    vfs_write(desc->supernode, number * desc->bs, desc->bs, buf);\n    return buf;\n}\n\nuint32_t ext2_block_alloc(struct ext2 *desc)\n{\n    uint32_t *buf = kmalloc(desc->bs, &M_BUFFER, 0);\n    uint32_t block = 0, real_block = 0, group = 0;\n    struct bitmap bm = {0};\n\n    for (unsigned i = 0; i < desc->ngroups; ++i) {\n        if (desc->groups[i].free_blocks) {\n            ext2_block_read(desc, desc->groups[i].bmap, buf);\n\n            bm.map = buf;\n            bm.max_idx = desc->superblock->gblocks;\n            \n            /* Look for a free block */\n            for (; bitmap_check(&bm, block); ++block);\n            group = i;\n            real_block = block + group * desc->superblock->gblocks;\n            break;\n        }\n    }\n\n    if (!block) {\n        /* Out of space */\n        kfree(buf);\n        return 0;\n    }\n\n    /* Update bitmap */\n    bitmap_set(&bm, block);\n    ext2_block_write(desc, desc->groups[group].bmap, buf);\n\n    /* Update block group descriptor */\n    desc->groups[group].free_blocks--;\n    ext2_bgd_table_rewrite(desc);\n\n    /* Update super block */\n    desc->superblock->free_blocks--;\n    ext2_superblock_rewrite(desc);\n\n    /* Clear block */\n    memset(buf, 0, desc->bs);\n    ext2_block_write(desc, real_block, buf);\n\n\n    kfree(buf);\n    return real_block;\n}\n\nvoid ext2_block_free(struct ext2 *desc, uint32_t block)\n{\n    uint32_t group = block % desc->superblock->gblocks;\n\n    uint32_t *buf = kmalloc(desc->bs, &M_BUFFER, 0);\n    struct bitmap bm = {0};\n\n    ext2_block_read(desc, desc->groups[group].bmap, buf);\n\n    bm.map = buf;\n    uint32_t block_idx = block - group * desc->superblock->gblocks;\n\n    /* Update bitmap */\n    bitmap_clear(&bm, block_idx);\n    ext2_block_write(desc, desc->groups[group].bmap, buf);\n\n    /* Update block group descriptor */\n    desc->groups[group].free_blocks++;\n    ext2_bgd_table_rewrite(desc);\n\n    /* Update super block */\n    desc->superblock->free_blocks++;\n    ext2_superblock_rewrite(desc);\n\n\n    kfree(buf);\n}\n"
  },
  {
    "path": "kernel/fs/ext2/dentry.c",
    "content": "#include <ext2.h>\n#include <core/panic.h> /* XXX */\n\nino_t ext2_dentry_find(struct ext2 *desc, struct ext2_inode *inode, const char *name)\n{\n    if ((inode->mode & S_IFMT) != S_IFDIR)\n        return -ENOTDIR;\n\n    size_t bs = desc->bs;\n    size_t blocks_nr = inode->size / bs;\n\n    char *buf = kmalloc(bs, &M_BUFFER, 0);\n    struct ext2_dentry *d;\n\n    for (size_t i = 0; i < blocks_nr; ++i) {\n        ext2_inode_block_read(desc, inode, i, buf);\n        d = (struct ext2_dentry *) buf;\n        while ((char *) d < (char *) buf + bs) {\n            char _name[d->length+1];\n            memcpy(_name, d->name, d->length);\n            _name[d->length] = 0;\n            if (!strcmp((char *) _name, name))\n                goto found;\n            d = (struct ext2_dentry *) ((char *) d + d->size);\n        }\n    }\n    \n    /* Not found */\n    kfree(buf);\n    return 0;\n\nfound:\n    kfree(buf);\n    return d->ino;\n}\n\nstatic inline uint8_t ext2_dentry_type(mode_t mode)\n{\n    switch (mode & S_IFMT) {\n        case S_IFSOCK: return EXT2_DENTRY_TYPE_SCKT;\n        case S_IFLNK:  return EXT2_DENTRY_TYPE_SLINK;\n        case S_IFREG:  return EXT2_DENTRY_TYPE_RGL;\n        case S_IFBLK:  return EXT2_DENTRY_TYPE_BLK;\n        case S_IFDIR:  return EXT2_DENTRY_TYPE_DIR;\n        case S_IFCHR:  return EXT2_DENTRY_TYPE_CHR;\n        case S_IFIFO:  return EXT2_DENTRY_TYPE_FIFO;\n        default:       return EXT2_DENTRY_TYPE_BAD;\n    }\n}\n\nint ext2_dentry_create(struct vnode *dir, const char *name, ino_t ino, mode_t mode)\n{\n    int err = 0;\n\n    /* not a directory */\n    if ((dir->mode & S_IFMT) != S_IFDIR)\n        return -ENOTDIR;\n\n    struct ext2 *desc = dir->p;\n\n    uint8_t type = ext2_dentry_type(mode);\n    size_t length = strlen(name);\n    size_t size = length + sizeof(struct ext2_dentry);\n    size = (size + 3) & ~3; /* Align to 4 bytes */\n\n    /* look for a candidate entry */\n    char *buf = kmalloc(desc->bs, &M_BUFFER, 0);\n    struct ext2_dentry *cur = NULL;\n\n    struct ext2_inode dir_inode;\n    if ((err = ext2_inode_read(desc, dir->ino, &dir_inode))) {\n        /* TODO Error checking */\n    }\n\n    size_t bs = desc->bs;\n    size_t blocks_nr = dir_inode.size / bs;\n    size_t flag = 0;    /* 0 => allocate, 1 => replace, 2 => split */\n    size_t block = 0;\n\n    for (block = 0; block < blocks_nr; ++block) {\n        ext2_inode_block_read(desc, &dir_inode, block, buf);\n        cur = (struct ext2_dentry *) buf;\n\n        while ((char *) cur < (char *) buf + bs) {\n            if ((!cur->ino) && cur->size >= size) {   /* unused entry */\n                flag = 1;   /* Replace */\n                goto done;\n            }\n\n            if ((((cur->length + sizeof(struct ext2_dentry) + 3) & ~3) + size) <= cur->size) {\n                flag = 2;   /* Split */\n                goto done;\n            }\n\n            cur = (struct ext2_dentry *) ((char *) cur + cur->size);\n        }\n    }\n\ndone:\n    if (flag == 1) {\n        /* replace */\n        memcpy(cur->name, name, length);\n        cur->ino    = ino;\n        cur->length = length;\n        cur->type   = type;\n\n        /* Update block */\n        ext2_inode_block_write(desc, &dir_inode, dir->ino, block, buf);\n    } else if (flag == 2) {\n        /* split */\n        size_t new_size = (cur->length + sizeof(struct ext2_dentry) + 3) & ~3;\n        struct ext2_dentry *next = (struct ext2_dentry *) ((char *) cur + new_size);\n\n        next->ino    = ino;\n        next->size   = cur->size - new_size;\n        next->length = length;\n        next->type   = type;\n        memcpy(next->name, name, length);\n\n        cur->size = new_size;\n\n        /* Update block */\n        ext2_inode_block_write(desc, &dir_inode, dir->ino, block, buf);\n    } else {\n        /* allocate */\n        panic(\"Not impelemented\\n\");\n    }\n\n    kfree(buf);\n    return 0;\n}\n"
  },
  {
    "path": "kernel/fs/ext2/ext2.c",
    "content": "/**\n * \\defgroup fs-ext2 kernel/fs/ext2\n * \\brief ext2 filesystem\n */\n#include <core/panic.h>\n#include <core/module.h>\n#include <fs/vfs.h>\n#include <fs/posix.h>\n#include <fs/vcache.h>\n#include <bits/errno.h>\n#include <ds/bitmap.h>\n\n#include <ext2.h>\n\nMALLOC_DEFINE(M_EXT2, \"ext2\", \"ext2 filesystem structure\");\nMALLOC_DEFINE(M_EXT2_SB, \"ext2-sb\", \"ext2 filesystem superblock structure\");\nMALLOC_DEFINE(M_EXT2_GROUP, \"ext2-group\", \"ext2 block group descriptor\");\n\nint ext2_inode_build(struct ext2 *desc, ino_t ino, struct vnode **ref_inode)\n{\n    int err = 0;\n    struct vnode *inode = NULL;\n\n    /* In open inode table? */\n    if ((inode = vcache_find(desc->vcache, ino)))\n        goto found;\n\n    printk(\"ext2_inode_build(desc=%p, ino=%d, ref_inode=%p)\\n\", desc, ino, ref_inode);\n    \n    inode = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n    if (!inode) {\n        /* TODO */\n    }\n\n    struct ext2_inode einode;\n    \n    if ((err = ext2_inode_read(desc, ino, &einode))) {\n\n    }\n\n    inode->ino   = ino;\n    inode->size  = einode.size;\n    inode->mode  = einode.mode;\n    inode->uid   = einode.uid;\n    inode->gid   = einode.gid;\n    inode->nlink = einode.nlink;\n\n    inode->atime.tv_sec  = einode.atime;\n    inode->atime.tv_nsec = 0;\n    inode->mtime.tv_sec  = einode.mtime;\n    inode->mtime.tv_nsec = 0;\n    inode->ctime.tv_sec  = einode.ctime;\n    inode->ctime.tv_nsec = 0;\n\n    inode->fs = &ext2fs;\n    inode->p = desc;\n\n    vcache_insert(desc->vcache, inode);\n\nfound:\n    if (ref_inode)\n        *ref_inode = inode;\n\n    return 0;\n}\n\nint ext2_inode_sync(struct vnode *inode)\n{\n    printk(\"ext2_inode_sync(inode=%p)\\n\", inode);\n\n    int err = 0;\n    \n    struct ext2 *desc = (struct ext2 *) inode->p;\n    struct ext2_inode ext2_inode;\n    memset(&ext2_inode, 0, sizeof(struct ext2_inode));\n\n    size_t bs = desc->bs;\n\n    ext2_inode.size   = inode->size;\n    ext2_inode.blocks = (inode->size + bs)/bs;\n    ext2_inode.mode   = inode->mode;\n    ext2_inode.uid    = inode->uid;\n    ext2_inode.gid    = inode->gid;\n    ext2_inode.nlink  = inode->nlink;\n\n    ext2_inode.atime = inode->atime.tv_sec;\n    ext2_inode.mtime = inode->mtime.tv_sec;\n    ext2_inode.ctime = inode->ctime.tv_sec;\n\n    if ((err = ext2_inode_write(desc, inode->ino, &ext2_inode))) {\n\n    }\n\n    return 0;\n}\n\n/* ================== VFS routines ================== */\n\nint ext2_init()\n{\n    return vfs_install(&ext2fs);\n}\n\nint ext2_load(struct vnode *dev, struct vnode **super)\n{\n    int err = 0;\n\n    struct ext2_superblock *sb = NULL;\n    struct ext2 *desc = NULL;\n\n    sb = kmalloc(sizeof(struct ext2_superblock), &M_EXT2_SB, M_ZERO);\n    if (!sb) goto e_nomem;\n\n    /* read superblock */\n    if ((err = vfs_read(dev, 1024, sizeof(struct ext2_superblock), sb)) < 0)\n        goto error;\n\n    /* valid ext2? */\n    if (sb->ext2_signature != EXT2_SIGNATURE) {\n        err = -EINVAL;\n        goto error;\n    }\n\n    /* build descriptor structure */\n    desc = kmalloc(sizeof(struct ext2), &M_EXT2, M_ZERO);\n    if (!desc) goto e_nomem;\n\n    desc->supernode = dev;\n    desc->superblock = sb;\n    desc->bs = 1024UL << sb->block_size;\n\n    /* read block group descriptor table */\n    uint32_t groups    = (desc->bs == 1024)? 2048 : desc->bs;\n    size_t   ngroups   = (sb->nblocks + sb->gblocks - 1)/ sb->gblocks;\n    size_t   groups_sz = ngroups * sizeof(struct ext2_group);\n\n    desc->ngroups = ngroups;\n    desc->groups  = kmalloc(groups_sz, &M_EXT2_GROUP, 0);\n    if (!desc->groups) goto e_nomem;\n\n    if ((err = vfs_read(desc->supernode, groups, groups_sz, desc->groups)) < 0)\n        return err;\n\n    desc->vcache = kmalloc(sizeof(struct vcache), &M_VCACHE, 0);\n    \n    if (!desc->vcache)\n        return -ENOMEM;\n\n    vcache_init(desc->vcache);\n\n    if (super)\n        ext2_inode_build(desc, 2, super);\n    \n    return 0;\n\ne_nomem:\n    err = -ENOMEM;\nerror:\n    if (sb) kfree(sb);\n    return err;\n}\n\nint ext2_mount(const char *dir, int flags, void *_args)\n{\n    printk(\"ext2_mount(dir=%s, flags=%x, args=%p)\\n\", dir, flags, _args);\n\n    struct {\n        char *dev;\n        char *opt;\n    } *args = _args;\n\n    struct vnode *dev = NULL;\n    int err;\n\n    struct uio uio = {0};   /* FIXME */\n\n    if ((err = vfs_lookup(args->dev, &uio, &dev, NULL)))\n        goto error;\n\n    struct vnode *fs;\n\n    if ((err = ext2fs.load(dev, &fs)))\n        goto error;\n\n    return vfs_bind(dir, fs);\n\nerror:\n    return err;\n}\n\nstruct fs ext2fs = {\n    .name  = \"ext2\",\n    .init  = ext2_init,\n    .load  = ext2_load,\n    .mount = ext2_mount,\n\n    .vops = {\n        .read    = ext2_read,\n        .write   = ext2_write,\n        .readdir = ext2_readdir,\n        .finddir = ext2_finddir,\n\n        .trunc   = ext2_trunc,\n        \n        .vmknod  = ext2_vmknod,\n        .vget    = ext2_vget,\n    },\n\n    .fops = {\n        .open    = posix_file_open,\n        .read    = posix_file_read,\n        .write   = posix_file_write,\n        .readdir = posix_file_readdir,\n        .lseek   = posix_file_lseek,\n        .trunc   = posix_file_trunc,\n\n        .eof     = posix_file_eof,\n    }\n};\n\nMODULE_INIT(ext2, ext2_init, NULL)\n"
  },
  {
    "path": "kernel/fs/ext2/ext2.h",
    "content": "#ifndef _EXT2_H\n#define _EXT2_H\n\n#include <core/system.h>\n#include <fs/vfs.h>\n\n#define EXT2_SIGNATURE  0xEF53\n\nstruct ext2_optional_features_flags {\n    uint8_t preallocate_for_directories : 1;\n    uint8_t afs_server_inodes : 1;\n    uint8_t has_journaling : 1;     // for EXT 3\n    uint8_t inodes_have_extended_attributes : 1;\n    uint8_t can_be_resized : 1;\n    uint8_t directories_use_hash_index : 1;\n} __packed;\n\nstruct ext2_required_features_flags {\n    uint8_t compressed : 1;\n    uint8_t directories_has_types : 1;\n    uint8_t needs_to_replay_journal : 1;\n    uint8_t uses_journal_device : 1;\n} __packed;\n\nstruct ext2_read_only_features_flags {\n    uint8_t sparse_sb_and_gdt : 1;\n    uint8_t uses_64bit_file_size : 1;\n    uint8_t directories_contents_are_binary_tree : 1;\n} __packed;\n\nstruct ext2_superblock {\n    /** number of inodes */\n    uint32_t    ninodes;\n    /** number of blocks */\n    uint32_t    nblocks;\n    /** number of reserved blocks */\n    uint32_t    nrblocks;\n    /** number of unallocated blocks */\n    uint32_t    free_blocks;\n    /** number of unallocated inodes */\n    uint32_t    free_inodes;\n    /** first data block */\n    uint32_t    dblock;\n    /** log(block size) */\n    uint32_t    block_size;\n    /** log(fragment size) */\n    uint32_t    frag_size;\n    /** number of blocks per block group */\n    uint32_t    gblocks;\n    /** number of fragments per block group */\n    uint32_t    gfrags;\n    /** number of inodes per block group */\n    uint32_t    ginodes;\n    /** last mount time */\n    uint32_t    mtime;\n    /** last write time */\n    uint32_t    wtime;\n\n    uint16_t    times_mounted;  // after last fsck\n    uint16_t    allowed_times_mounted;\n    uint16_t    ext2_signature;\n    uint16_t    filesystem_state;\n    uint16_t    on_error;\n    uint16_t    minor_version;\n    uint32_t    last_fsck;\n    uint32_t    time_between_fsck;  // Time allowed between fsck(s)\n    uint32_t    os_id;\n    uint32_t    major_version;\n    uint16_t    uid;\n    uint16_t    gid;\n\n    /* for extended superblock fields ... which is always assumed */\n    uint32_t    first_non_reserved_inode;\n    uint16_t    inode_size;\n    uint16_t    sb_block_group;\n\n    struct ext2_optional_features_flags   optional_features;\n    struct ext2_required_features_flags   required_features;\n    struct ext2_read_only_features_flags  read_only_features;\n\n    uint8_t     fsid[16];\n    uint8_t     name[16];\n    uint8_t     path_last_mounted_to[64];\n    uint32_t    compression_algorithms;\n    uint8_t     blocks_to_preallocate_for_files;\n    uint8_t     blocks_to_preallocate_for_directories;\n    uint16_t    __unused__;\n    uint8_t     jid[16];    // Journal ID\n    uint32_t    jinode;     // Journal inode\n    uint32_t    jdevice;    // Journal device\n    uint32_t    head_of_orphan_inode_list;  // What the hell is this !?\n} __packed;\n\n/*\n * \\ingroup fs-ext2\n * \\brief block group descriptor\n */\nstruct ext2_group {\n    /** blocks bitmap */\n    uint32_t    bmap;\n    /** inodes bitmap */\n    uint32_t    imap;\n    /** inode table */\n    uint32_t    inodes;\n    /** number of unallocated blocks */\n    uint16_t    free_blocks;\n    /** number of unallocated inodes */\n    uint16_t    free_inodes;\n    uint16_t    directories_count;\n    uint8_t     __unused__[14];\n} __packed;\n\n/**\n * \\ingroup fs-ext2\n * \\brief ext2 on disk inode\n */\nstruct ext2_inode {\n    uint16_t    mode;\n    uint16_t    uid;\n    uint32_t    size;\n    uint32_t    atime;\n    uint32_t    ctime;\n    uint32_t    mtime;\n    uint32_t    dtime;\n    uint16_t    gid;\n    uint16_t    nlink;\n    uint32_t    blocks;\n    uint32_t    flags;\n\n    uint32_t    os_specific1;\n    uint32_t    direct_pointer[12];\n    uint32_t    singly_indirect_pointer;\n    uint32_t    doubly_indirect_pointer;\n    uint32_t    triply_indirect_pointer;\n\n    uint32_t    generation_number;\n    uint32_t    extended_attribute_block;\n    uint32_t    size_high;\n    uint32_t    fragment;\n    uint8_t     os_specific2[12];\n} __packed;\n\n/**\n * \\ingroup fs-ext2\n * \\brief ext2 directory entry\n */\nstruct ext2_dentry {\n    /** inode number */\n    uint32_t    ino;\n    /** entry total size */\n    uint16_t    size;\n    /** name length */\n    uint8_t     length;\n    /** entry type */\n    uint8_t     type;\n    /** name will be here */\n    uint8_t     name[0];\n} __packed;\n\n#define EXT2_DENTRY_TYPE_BAD   0\n#define EXT2_DENTRY_TYPE_RGL   1\n#define EXT2_DENTRY_TYPE_DIR   2\n#define EXT2_DENTRY_TYPE_CHR   3\n#define EXT2_DENTRY_TYPE_BLK   4\n#define EXT2_DENTRY_TYPE_FIFO  5\n#define EXT2_DENTRY_TYPE_SCKT  6\n#define EXT2_DENTRY_TYPE_SLINK 7\n\n#define EXT2_DIRECT_POINTERS 12\n\n/**\n * \\ingroup fs-ext2\n * \\brief ext2 filesystem\n */\nstruct ext2 {\n    struct vnode *supernode;\n    struct ext2_superblock *superblock;\n    struct ext2_group *groups;\n\n    /** number of block group descriptors */\n    size_t ngroups;\n\n    size_t bs;\n    struct vcache *vcache;\n};\n\nextern struct fs ext2fs;\n\n/* super.c */\nvoid ext2_superblock_rewrite(struct ext2 *desc);\n\n/* block.c */\nvoid ext2_bgd_table_rewrite(struct ext2 *desc);\nvoid *ext2_block_read(struct ext2 *desc, uint32_t number, void *buf);\nvoid *ext2_block_write(struct ext2 *desc, uint32_t number, void *buf);\nuint32_t ext2_block_alloc(struct ext2 *desc);\nvoid ext2_block_free(struct ext2 *desc, uint32_t block);\n\n/* inode.c */\nint ext2_inode_read(struct ext2 *desc, ino_t inode, struct ext2_inode *ref);\nint ext2_inode_write(struct ext2 *desc, ino_t inode, struct ext2_inode *i);\n\nsize_t ext2_inode_block_read(struct ext2 *desc, struct ext2_inode *inode, size_t idx, void *buf);\nsize_t ext2_inode_block_write(struct ext2 *desc, struct ext2_inode *inode, uint32_t inode_nr, size_t idx, void *buf);\nino_t ext2_inode_alloc(struct ext2 *desc);\n\n/* dentry.c */\nuint32_t ext2_dentry_find(struct ext2 *desc, struct ext2_inode *inode, const char *name);\nint ext2_dentry_create(struct vnode *dir, const char *name, ino_t ino, mode_t mode);\n\n/* iops.c */\nssize_t ext2_read(struct vnode *node, off_t offset, size_t size, void *buf);\nssize_t ext2_write(struct vnode *node, off_t offset, size_t size, void *buf);\nssize_t ext2_readdir(struct vnode *dir, off_t offset, struct dirent *dirent);\nint ext2_finddir(struct vnode *dir, const char *fn, struct dirent *dirent);\n\nint ext2_trunc(struct vnode *inode, off_t len);\nint ext2_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref);\n\nint ext2_vget(struct vnode *super, ino_t ino, struct vnode **ref);\n\nint ext2_inode_build(struct ext2 *desc, ino_t ino, struct vnode **ref_inode);  /* XXX */\nint ext2_inode_sync(struct vnode *inode);\n\n#endif \n"
  },
  {
    "path": "kernel/fs/ext2/inode.c",
    "content": "#include <ext2.h>\n#include <ds/bitmap.h>\n#include <core/panic.h>\n\nstatic inline off_t ext2_inode_off(struct ext2 *desc, ino_t ino)\n{\n    /* invalid inode */\n    if (ino >= desc->superblock->ninodes)\n        return -EINVAL;\n\n    uint32_t group_id = (ino - 1) / desc->superblock->ginodes;\n    uint32_t index    = (ino - 1) % desc->superblock->ginodes;\n\n    struct ext2_group *group = &desc->groups[group_id];\n    return group->inodes * desc->bs + index * desc->superblock->inode_size;\n}\n\nint ext2_inode_read(struct ext2 *desc, ino_t ino, struct ext2_inode *ref)\n{\n    off_t off;\n    \n    if ((off = ext2_inode_off(desc, ino)) < 0)\n        return off;\n    \n    if (ref) {\n        size_t size = sizeof(struct ext2_inode);\n        ssize_t r;\n\n        if ((r = vfs_read(desc->supernode, off, size, ref)) != (ssize_t) size) {\n            if (r < 0)\n                return r;\n\n            /* FIXME Check for further errors? */\n            return -EINVAL;\n        }\n    }\n\n    return 0;\n}\n\nint ext2_inode_write(struct ext2 *desc, ino_t ino, struct ext2_inode *ext2_inode)\n{\n    off_t off = ext2_inode_off(desc, ino);\n    size_t inode_size = desc->superblock->inode_size;\n\n    if (off < 0)\n        return off;\n     \n    return vfs_write(desc->supernode, off, sizeof(struct ext2_inode), ext2_inode);\n}\n\nsize_t ext2_inode_block_read(struct ext2 *desc, struct ext2_inode *inode, size_t idx, void *buf)\n{\n    size_t bs = desc->bs;\n    size_t blocks_nr = (inode->size + bs - 1) / bs;\n    size_t p = desc->bs / 4;    /* Pointers per block */\n\n    if (idx >= blocks_nr) {\n        panic(\"Trying to get invalid block!\\n\");\n    }\n\n    if (idx < EXT2_DIRECT_POINTERS) {\n        ext2_block_read(desc, inode->direct_pointer[idx], buf);\n        return 0;\n    }\n\n    idx -= EXT2_DIRECT_POINTERS;\n    \n    if (idx < p) {\n        /* singly indirect */\n        uint32_t *tmp = kmalloc(desc->bs, &M_BUFFER, 0);\n        ext2_block_read(desc, inode->singly_indirect_pointer, tmp);\n        uint32_t block = tmp[idx];\n        kfree(tmp);\n        ext2_block_read(desc, block, buf);\n        return 0;\n    }\n\n    idx -= p;\n    \n    if (idx < p * p) {\n        /* doubly indirect */\n        uint32_t *tmp = kmalloc(desc->bs, &M_BUFFER, 0);\n        ext2_block_read(desc, inode->doubly_indirect_pointer, tmp);\n        uint32_t block = tmp[idx / p];\n\n        ext2_block_read(desc, block, tmp);\n        block = tmp[idx % p];\n        kfree(tmp);\n\n        ext2_block_read(desc, block, buf);\n        return 0;\n    }\n\n    panic(\"Not impelemented\");\n\n    /* unreachable */\n}\n\nsize_t ext2_inode_block_write(struct ext2 *desc, struct ext2_inode *inode, uint32_t inode_nr, size_t idx, void *buf)\n{\n    size_t p = desc->bs / 4;    /* Pointers per block */\n\n    if (idx < EXT2_DIRECT_POINTERS) {\n        if (!inode->direct_pointer[idx]) {    /* Allocate */\n            inode->direct_pointer[idx] = ext2_block_alloc(desc);\n            ext2_inode_write(desc, inode_nr, inode);\n        }\n        ext2_block_write(desc, inode->direct_pointer[idx], buf);\n    } else if (idx < EXT2_DIRECT_POINTERS + p) {\n        if (!inode->singly_indirect_pointer) {    /* Allocate */\n            inode->singly_indirect_pointer = ext2_block_alloc(desc);\n            ext2_inode_write(desc, inode_nr, inode);\n        }\n\n        uint32_t *tmp = kmalloc(desc->bs, &M_BUFFER, 0);\n        ext2_block_read(desc, inode->singly_indirect_pointer, tmp);\n        uint32_t block = tmp[idx - EXT2_DIRECT_POINTERS];\n\n        if (!block) {   /* Allocate */\n            tmp[idx - EXT2_DIRECT_POINTERS] = ext2_block_alloc(desc);\n            ext2_block_write(desc, inode->singly_indirect_pointer, tmp);\n        }\n\n        kfree(tmp);\n        ext2_block_write(desc, block, buf);\n    } else {\n        panic(\"Not impelemented\\n\");\n    }\n\n    return 0;\n}\n\nino_t ext2_inode_alloc(struct ext2 *desc)\n{\n    printk(\"ext2_inode_alloc(desc=%p)\\n\", desc);\n\n    uint32_t *buf = kmalloc(desc->bs, &M_BUFFER, 0);\n    uint32_t inode = 0, real_inode = 0, group = 0;\n    struct bitmap bm = {0};\n\n    for (unsigned i = 0; i < desc->ngroups; ++i) {\n        inode = 0;\n\n        if (desc->groups[i].free_inodes) {\n            ext2_block_read(desc, desc->groups[i].imap, buf);\n\n            bm.map = buf;\n            bm.max_idx = desc->superblock->ginodes;\n            \n            /* look for a free inode */\n            for (; bitmap_check(&bm, inode); ++inode);\n\n            if (inode == bm.max_idx)\n                continue;\n\n            group = i;\n            real_inode = inode + group * desc->superblock->ginodes + 1;\n            break;\n        }\n    }\n\n    if (!inode) {\n        /* Out of space */\n        kfree(buf);\n        return 0;\n    }\n\n    //printk(\"group %d, inode %d, real_inode %d\\n\", group, inode, real_inode);\n\n    /* Update bitmap */\n    bitmap_set(&bm, inode);\n    ext2_block_write(desc, desc->groups[group].imap, buf);\n\n    /* Update block group descriptor */\n    desc->groups[group].free_inodes--;\n    ext2_bgd_table_rewrite(desc);\n\n    /* Update super block */\n    desc->superblock->free_inodes--;\n    ext2_superblock_rewrite(desc);\n\n    kfree(buf);\n    return real_inode;\n}\n"
  },
  {
    "path": "kernel/fs/ext2/super.c",
    "content": "#include <ext2.h>\n\nvoid ext2_superblock_rewrite(struct ext2 *desc)\n{\n    vfs_write(desc->supernode, 1024, sizeof(struct ext2_superblock), desc->superblock);\n}\n"
  },
  {
    "path": "kernel/fs/ext2/vops.c",
    "content": "#include <ext2.h>\n#include <core/time.h>\n\nssize_t ext2_read(struct vnode *node, off_t offset, size_t size, void *buf)\n{\n    int err = 0;\n\n    struct ext2 *desc = node->p;\n\n    size_t bs = desc->bs;\n    struct ext2_inode inode;\n    \n    if ((err = ext2_inode_read(desc, node->ino, &inode))) {\n        /* TODO Error checking */\n    }\n\n    if ((size_t) offset >= inode.size)\n        return 0;\n\n    size = MIN(size, (size_t) (inode.size - offset));\n    \n    char *read_buf = NULL;\n\n    ssize_t ret = 0;\n    char *_buf = buf;\n\n    /* Read up to block boundary */\n    if (offset % bs) {\n        size_t start = MIN(bs - offset % bs, size);\n\n        if (start) {\n            read_buf = kmalloc(bs, &M_BUFFER, 0);\n            ext2_inode_block_read(desc, &inode, offset/bs, read_buf);\n            memcpy(_buf, read_buf + (offset % bs), start);\n\n            ret += start;\n            size -= start;\n            _buf += start;\n            offset += start;\n\n            if (!size)\n                goto free_resources;\n        }\n    }\n\n    /* Read whole blocks */\n    size_t count = size/bs;\n\n    while (count) {\n        ext2_inode_block_read(desc, &inode, offset/bs, _buf);\n\n        ret    += bs;\n        size   -= bs;\n        _buf   += bs;\n        offset += bs;\n        --count;\n    }\n\n    if (!size)\n        goto free_resources;\n\n    size_t end = size % bs;\n\n    if (end) {\n        if (!read_buf)\n            read_buf = kmalloc(bs, &M_BUFFER, 0);\n\n        ext2_inode_block_read(desc, &inode, offset/bs, read_buf);\n        memcpy(_buf, read_buf, end);\n        ret += end;\n    }\n\nfree_resources:\n    if (read_buf)\n        kfree(read_buf);\n    return ret;\n}\n\nssize_t ext2_write(struct vnode *node, off_t offset, size_t size, void *buf)\n{\n    printk(\"ext2_write(inode=%p, offset=%d, size=%d, buf=%p)\\n\", node, offset, size, buf);\n\n    int err = 0;\n    struct ext2 *desc = node->p;\n\n    size_t bs = desc->bs;\n    struct ext2_inode ext2_inode;\n    \n    if ((err = ext2_inode_read(desc, node->ino, &ext2_inode))) {\n\n    }\n\n    if ((size_t) offset + size > ext2_inode.size) {\n        ext2_inode.size = (size_t) offset + size;\n        ext2_trunc(node, (size_t) offset + size);\n    }\n\n    size = MIN(size, (size_t) (ext2_inode.size - offset));\n    \n    char *write_buf = NULL;\n\n    ssize_t ret = 0;\n    char *_buf = buf;\n\n    /* Write up to block boundary */\n    if (offset % bs) {\n        size_t start = MIN(bs - offset % bs, size);\n\n        if (start) {\n            write_buf = kmalloc(bs, &M_BUFFER, 0);\n            ext2_inode_block_read(desc, &ext2_inode, offset/bs, write_buf);\n            memcpy(write_buf + (offset % bs), _buf, start);\n            ext2_inode_block_write(desc, &ext2_inode, node->ino, offset/bs, write_buf);\n\n            ret += start;\n            size -= start;\n            _buf += start;\n            offset += start;\n\n            if (!size)\n                goto free_resources;\n        }\n    }\n\n    /* Write whole blocks */\n    size_t count = size/bs;\n\n    while (count) {\n        ext2_inode_block_write(desc, &ext2_inode, node->ino, offset/bs, _buf);\n\n        ret    += bs;\n        size   -= bs;\n        _buf   += bs;\n        offset += bs;\n        --count;\n    }\n\n    if (!size)\n        goto free_resources;\n\n    size_t end = size % bs;\n\n    if (end) {\n        if (!write_buf)\n            write_buf = kmalloc(bs, &M_BUFFER, 0);\n\n        ext2_inode_block_read(desc, &ext2_inode, offset/bs, write_buf);\n        memcpy(write_buf, _buf, end);\n        ext2_inode_block_write(desc, &ext2_inode, node->ino, offset/bs, write_buf);\n        ret += end;\n    }\n\nfree_resources:\n    if (write_buf)\n        kfree(write_buf);\n\n    return ret;\n}\n\nssize_t ext2_readdir(struct vnode *dir, off_t offset, struct dirent *dirent)\n{\n    int err = 0;\n\n    if (!S_ISDIR(dir->mode))\n        return -ENOTDIR;\n\n    struct ext2 *desc = dir->p;\n    struct ext2_inode inode;\n    \n    if ((err = ext2_inode_read(desc, dir->ino, &inode))) {\n        /* TODO Error */\n        printk(\"err = %d\\n\", err);\n    }\n\n    if (!S_ISDIR(inode.mode))\n        return -ENOTDIR;\n\n    size_t bs = desc->bs;\n    size_t blocks_nr = inode.size / bs;\n\n    char buf[bs];\n\n    struct ext2_dentry *dentry;\n    off_t idx = 0;\n    char found = 0;\n\n    for (size_t i = 0; i < blocks_nr; ++i) {\n\n        ext2_inode_block_read(desc, &inode, i, buf);\n        dentry = (struct ext2_dentry *) buf;\n\n        while ((char *) dentry < (char *) buf + bs) {\n            if (idx == offset) {\n                dirent->d_ino = dentry->ino;\n                memcpy(dirent->d_name, (char *) dentry->name, dentry->length);\n                dirent->d_name[dentry->length] = '\\0';\n                found = 1;\n                break;\n            }\n\n            dentry = (struct ext2_dentry *) ((char *) dentry + dentry->size);\n            ++idx;\n        }\n    }\n\n    return found;\n}\n\nint ext2_trunc(struct vnode *inode, off_t len)\n{\n    /* do nothing */\n    if ((size_t) len == inode->size)\n        return 0;\n\n    /* just extend inode size */\n    if ((size_t) len > inode->size) {\n        inode->size = len;\n        ext2_inode_sync(inode);\n        return 0;\n    }\n\n    /* otherwise the new size is smaller, we need to free the extra blocks */\n    /* TODO */\n\n    inode->size = len;\n    ext2_inode_sync(inode);\n    return 0;\n}\n\nint ext2_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)\n{\n    int err = 0;\n\n    if (!fn || !*fn)\n        return -EINVAL;\n\n    struct ext2 *desc = dir->p;\n    struct ext2_inode dir_inode;\n    \n    if ((err = ext2_inode_read(desc, dir->ino, &dir_inode))) {\n        /* TODO Error checking */\n    }\n\n    /* file exists */\n    if (ext2_dentry_find(desc, &dir_inode, fn))\n        return -EEXIST;\n\n    ino_t ino = ext2_inode_alloc(desc);\n    struct ext2_inode inode;\n    \n    if ((err = ext2_inode_read(desc, ino, &inode))) {\n        /* TODO Error checking */\n    }\n\n    memset(&inode, 0, sizeof(struct ext2_inode));\n\n    inode.mode = mode;\n\n    struct timespec ts;\n    gettime(&ts);\n\n    inode.ctime = ts.tv_sec;\n    inode.atime = ts.tv_sec;\n    inode.mtime = ts.tv_sec;\n\n    if (S_ISDIR(mode)) {   /* Initalize directory structure */\n        inode.nlink = 2;\n        inode.size = desc->bs;\n        \n        char *buf = kmalloc(desc->bs, &M_BUFFER, 0);\n        struct ext2_dentry *d = (struct ext2_dentry *) buf;\n        d->ino = ino;\n        d->size = 12;\n        d->length = 1;\n        d->type = EXT2_DENTRY_TYPE_DIR;\n        memcpy(d->name, \".\", 1);\n        d = (struct ext2_dentry *) ((char *) d + 12);\n        d->ino = dir->ino;\n        d->size = desc->bs - 12;\n        d->length = 2;\n        d->type = EXT2_DENTRY_TYPE_DIR;\n        memcpy(d->name, \"..\", 2);\n        ext2_inode_block_write(desc, &inode, ino, 0, buf);\n        kfree(buf);\n    } else {\n        inode.nlink = 1;\n        ext2_inode_write(desc, ino, &inode);\n    }\n\n    ext2_dentry_create(dir, fn, ino, inode.mode);\n\n    if (ref)\n        ext2_inode_build(desc, ino, ref);\n\n    return 0;\n}\n\nint ext2_finddir(struct vnode *dir, const char *fn, struct dirent *dirent)\n{\n    //printk(\"ext2_vfind(dir=%p, fn=%s, child=%p)\\n\", dir, fn, child);\n\n    int err = 0;\n\n    struct ext2 *desc = dir->p;\n\n    uint32_t inode = dir->ino;\n\n    struct ext2_inode i;\n    if ((err = ext2_inode_read(desc, inode, &i))) {\n        /* TODO Error checking */\n    }\n\n    uint32_t inode_nr = ext2_dentry_find(desc, &i, fn);\n\n    if (!inode_nr)  /* Not found */\n        return -ENOENT;\n\n    inode = inode_nr;\n\n    if (dirent) {\n        dirent->d_ino  = inode_nr;\n    }\n\n    return 0;\n}\n\nint ext2_vget(struct vnode *super, ino_t ino, struct vnode **ref)\n{\n    struct ext2 *desc = super->p;\n\n    if (ref) {\n        ext2_inode_build(desc, ino, ref);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "kernel/fs/fops.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <dev/dev.h>\n#include <net/socket.h>\n#include <bits/fcntl.h>\n\n/**\n * \\ingroup vfs\n * \\brief open a new file\n */\nint vfs_file_open(struct file *file)\n{\n    if (!file || !file->vnode || !file->vnode->fs)\n        return -EINVAL;\n\n    if (S_ISDIR(file->vnode->mode) && !(file->flags & O_SEARCH))\n        return -EISDIR;\n\n    if (ISDEV(file->vnode))\n        return kdev_file_open(&VNODE_DEV(file->vnode), file);\n\n    if (!file->vnode->fs->fops.open)\n        return -ENOSYS;\n\n    return file->vnode->fs->fops.open(file);\n}\n\n/**\n * \\ingroup vfs\n * \\brief read from an open file\n */\nssize_t vfs_file_read(struct file *file, void *buf, size_t nbytes)\n{\n    if (file && file->flags & FILE_SOCKET)\n        return socket_recv(file, buf, nbytes, 0);\n\n    if (!file || !file->vnode)\n        return -EINVAL;\n\n    if (ISDEV(file->vnode))\n        return kdev_file_read(&VNODE_DEV(file->vnode), file, buf, nbytes);\n\n    if (!file->vnode->fs)\n        return -EINVAL;\n\n    if (!file->vnode->fs->fops.read)\n        return -ENOSYS;\n\n    return file->vnode->fs->fops.read(file, buf, nbytes);\n}\n\n/**\n * \\ingroup vfs\n * \\brief write to an open file\n */\nssize_t vfs_file_write(struct file *file, void *buf, size_t nbytes)\n{\n    if (file && file->flags & FILE_SOCKET)\n        return socket_send(file, buf, nbytes, 0);\n\n    if (!file || !file->vnode)\n        return -EINVAL;\n\n    if (ISDEV(file->vnode))\n        return kdev_file_write(&VNODE_DEV(file->vnode), file, buf, nbytes);\n\n    if (!file->vnode->fs)\n        return -EINVAL;\n\n    if (!file->vnode->fs->fops.write)\n        return -ENOSYS;\n\n    return file->vnode->fs->fops.write(file, buf, nbytes);\n}\n\n/**\n * \\ingroup vfs\n * \\brief perform ioctl on an open file\n */\nint vfs_file_ioctl(struct file *file, int request, void *argp)\n{\n    if (!file || !file->vnode)\n        return -EINVAL;\n\n    if (ISDEV(file->vnode))\n        return kdev_file_ioctl(&VNODE_DEV(file->vnode), file, request, argp);\n\n    if (!file->vnode->fs)\n        return -EINVAL;\n\n    if (!file->vnode->fs->fops.ioctl)\n        return -ENOSYS;\n\n    return file->vnode->fs->fops.ioctl(file, request, argp);\n}\n\n/**\n * \\ingroup vfs\n * \\brief perform a seek in an open file\n */\noff_t vfs_file_lseek(struct file *file, off_t offset, int whence)\n{\n    if (!file || !file->vnode)\n        return -EINVAL;\n\n    if (ISDEV(file->vnode))\n        return kdev_file_lseek(&VNODE_DEV(file->vnode), file, offset, whence);\n\n    if (!file->vnode->fs)\n        return -EINVAL;\n\n    if (!file->vnode->fs->fops.lseek)\n        return -ENOSYS;\n\n    return file->vnode->fs->fops.lseek(file, offset, whence);\n}\n\n/**\n * \\ingroup vfs\n * \\brief read entries from an open directory\n */\nssize_t vfs_file_readdir(struct file *file, struct dirent *dirent)\n{\n    if (!file || !file->vnode || !file->vnode->fs)\n        return -EINVAL;\n\n    if (!S_ISDIR(file->vnode->mode))\n        return -ENOTDIR;\n\n    if (!file->vnode->fs->fops.readdir)\n        return -ENOSYS;\n\n    return file->vnode->fs->fops.readdir(file, dirent);\n}\n\n/**\n * \\ingroup vfs\n * \\brief close an open file\n */\nssize_t vfs_file_close(struct file *file)\n{\n    if (!file || !file->vnode)\n        return -EINVAL;\n\n    if (file->flags & FILE_SOCKET)\n        return socket_shutdown(file, SHUT_RDWR);\n\n    if (ISDEV(file->vnode))\n        return kdev_file_close(&VNODE_DEV(file->vnode), file);\n\n    if (!file->vnode->fs)\n        return -EINVAL;\n\n    if (!file->vnode->fs->fops.close)\n        return -ENOSYS;\n\n    return file->vnode->fs->fops.close(file);\n}\n\n/**\n * \\ingroup vfs\n * \\brief truncate an open file\n */\nint vfs_file_trunc(struct file *file, off_t len)\n{\n    if (file && file->flags & FILE_SOCKET)\n        return -EINVAL;\n\n    if (!file || !file->vnode)\n        return -EINVAL;\n\n    if (ISDEV(file->vnode))\n        return -EINVAL;\n\n    if (!file->vnode->fs)\n        return -EINVAL;\n\n    if (!file->vnode->fs->fops.trunc)\n        return -ENOSYS;\n\n    return file->vnode->fs->fops.trunc(file, len);\n}\n\nint vfs_file_can_read(struct file *file, size_t size)\n{\n    if (file && file->flags & FILE_SOCKET)\n        return socket_can_read(file, size);\n\n    if (!file || !file->vnode)\n        return -EINVAL;\n\n    if (ISDEV(file->vnode))\n        return kdev_file_can_read(&VNODE_DEV(file->vnode), file, size);\n\n    if (!file->vnode->fs)\n        return -EINVAL;\n\n    if (!file->vnode->fs->fops.can_read)\n        return -ENOSYS;\n\n    return file->vnode->fs->fops.can_read(file, size);\n}\n\nint vfs_file_can_write(struct file *file, size_t size)\n{\n    if (file && file->flags & FILE_SOCKET)\n        return socket_can_write(file, size);\n\n    if (!file || !file->vnode)\n        return -EINVAL;\n\n    if (ISDEV(file->vnode))\n        return kdev_file_can_write(&VNODE_DEV(file->vnode), file, size);\n\n    if (!file->vnode->fs)\n        return -EINVAL;\n\n    if (!file->vnode->fs->fops.can_write)\n        return -ENOSYS;\n\n    return file->vnode->fs->fops.can_write(file, size);\n}\n\nint vfs_file_eof(struct file *file)\n{\n    if (!file || !file->vnode)\n        return -EINVAL;\n\n    if (ISDEV(file->vnode))\n        return kdev_file_eof(&VNODE_DEV(file->vnode), file);\n\n    if (!file->vnode->fs)\n        return -EINVAL;\n\n    if (!file->vnode->fs->fops.eof)\n        return -ENOSYS;\n\n    return file->vnode->fs->fops.eof(file);\n}\n\n"
  },
  {
    "path": "kernel/fs/initramfs/Build.mk",
    "content": "obj-y += initramfs.o\ndirs-$(INITRAMFS_CPIO) += cpio/\n"
  },
  {
    "path": "kernel/fs/initramfs/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/fs/initramfs/cpio/Build.mk",
    "content": "obj-y += cpio.o\n"
  },
  {
    "path": "kernel/fs/initramfs/cpio/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/fs/initramfs/cpio/cpio.c",
    "content": "#include <core/system.h>\n#include <core/module.h>\n#include <core/panic.h>\n#include <core/time.h>\n\n#include <fs/vfs.h>\n#include <fs/initramfs.h>\n#include <fs/posix.h>\n#include <fs/rofs.h>\n\n#include <cpio.h>\n\nMALLOC_DEFINE(M_CPIO, \"cpio\", \"CPIO structure\");\n\nstatic int cpio_root_node(struct vnode *super, struct vnode **ref)\n{\n    int err = 0;\n    struct vnode *vnode = NULL;\n    struct cpio *p = NULL;\n\n    vnode = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n    if (vnode == NULL) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    p = kmalloc(sizeof(struct cpio), &M_CPIO, 0);\n    if (p == NULL) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    vnode->ino   = (ino_t) vnode;\n    vnode->size  = 0;\n    vnode->mode  = S_IFDIR | 0775;\n    vnode->uid   = 0;\n    vnode->gid   = 0;\n    vnode->nlink = 2;\n    vnode->ref   = 1;\n\n    struct timespec ts;\n    gettime(&ts);\n\n    vnode->ctime = ts;\n    vnode->atime = ts;\n    vnode->mtime = ts;\n\n    vnode->fs    = &cpiofs;\n    vnode->p     = p;\n\n    p->super     = super;\n    p->parent    = NULL;\n    p->dir       = NULL;\n    p->count     = 0;\n    p->data      = 0;\n    p->next      = NULL;\n\n    if (ref) *ref = vnode;\n\n    return 0;\n\nerror:\n    if (p)\n        kfree(p);\n    if (vnode)\n        kfree(vnode);\n\n    return err;\n}\n\nstatic int cpio_new_node(const char *name, struct cpio_hdr *hdr, size_t sz, size_t data, struct vnode *sp, struct vnode **ref)\n{\n    int err = 0;\n    struct vnode *vnode = NULL;\n    struct cpio *p = NULL;\n\n    vnode = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n\n    if (vnode == NULL) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    p = kmalloc(sizeof(struct cpio), &M_CPIO, 0);\n    if (p == NULL) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    vnode->ino   = (vino_t) vnode;\n    vnode->size  = sz;\n    vnode->uid   = 0;\n    vnode->gid   = 0;\n    vnode->mode  = hdr->mode;\n    vnode->nlink = hdr->nlink;\n    vnode->mtime = (struct timespec) {.tv_sec  = hdr->mtime[0] * 0x10000 + hdr->mtime[1], .tv_nsec = 0};\n    vnode->rdev  = hdr->rdev;\n\n    vnode->fs   = &cpiofs;\n    vnode->p    = p;\n\n    p->super  = sp;\n    p->parent = NULL;\n    p->dir    = NULL;\n    p->count  = 0;\n    p->data   = data;\n    p->next   = NULL;\n    p->name   = strdup(name);\n\n    if (ref) *ref = vnode;\n\n    return 0;\n\nerror:\n    if (p)\n        kfree(p);\n    if (vnode)\n        kfree(vnode);\n    return err;\n}\n\nstatic struct vnode *cpio_new_child_node(struct vnode *parent, struct vnode *child)\n{\n    if (!parent || !child)  /* invalid vnode */\n        return NULL;\n\n    if (!S_ISDIR(parent->mode)) /* Adding child to non directory parent */\n        return NULL;\n\n    struct cpio *pp = (struct cpio *) parent->p;\n    struct cpio *cp = (struct cpio *) child->p;\n\n    struct vnode *tmp = pp->dir;\n\n    cp->next = tmp;\n    pp->dir = child;\n\n    pp->count++;\n    cp->parent = parent;\n\n    return child;\n}\n\nstatic struct vnode *cpio_find(struct vnode *root, const char *path)\n{\n    char **tokens = tokenize(path, '/');\n\n    if (!S_ISDIR(root->mode))   /* Not even a directory */\n        return NULL;\n\n    struct vnode *cur = root;\n    struct vnode *dir = ((struct cpio *) cur->p)->dir;\n\n    if (!dir) { /* Directory has no children */\n        if (*tokens == NULL)\n            return root;\n        else\n            return NULL;\n    }\n\n    int flag;\n    for (char **token_p = tokens; *token_p; ++token_p) {\n        char *token = *token_p;\n\n        flag = 0;\n        for (struct vnode *e = dir; e; e = ((struct cpio *) e->p)->next) {\n            if (((struct cpio *) e->p)->name &&\n                    !strcmp(((struct cpio *) e->p)->name, token)) {\n                cur = e;\n                dir = ((struct cpio *) e->p)->dir;\n                flag = 1;\n                goto next;\n            }\n        }\n\n        next:\n\n        if (!flag)  /* No such file or directory */\n            return NULL;\n\n        continue;\n    }\n\n    free_tokens(tokens);\n\n    return cur;\n}\n\nstatic int cpio_finddir(struct vnode *root, const char *name, struct dirent *dirent)\n{\n    if (!S_ISDIR(root->mode))   /* Not even a directory */\n        return -ENOTDIR;\n\n    struct vnode *dir = ((struct cpio *) root->p)->dir;\n\n    if (!dir)   /* Directory has no children */\n        return -ENOENT;\n\n    for (struct vnode *e = dir; e; e = ((struct cpio *) e->p)->next) {\n        if (((struct cpio *) e->p)->name &&\n                !strcmp(((struct cpio *) e->p)->name, name)) {\n            if (dirent) {\n                dirent->d_ino = (vino_t) e;\n                strcpy(dirent->d_name, name);\n            }\n\n            return 0;\n        }\n    }\n\n    return -ENOENT;\n}\n\nstatic int cpio_vget(struct vnode *super, ino_t ino, struct vnode **vnode)\n{\n    *vnode = (struct vnode *) ino;\n    return 0;\n}\n\n#define MAX_NAMESIZE    1024\n\nstatic int cpio_load(struct vnode *dev, struct vnode **super)\n{\n    /* Allocate the root node */\n    struct vnode *rootfs = NULL;\n    cpio_root_node(dev, &rootfs);\n\n    struct cpio_hdr hdr;\n    size_t offset = 0;\n    size_t size = 0;\n\n    for (; offset < dev->size; \n          offset += sizeof(struct cpio_hdr) + (hdr.namesize+1)/2*2 + (size+1)/2*2) {\n\n        size_t data_offset = offset;\n        vfs_read(dev, data_offset, sizeof(struct cpio_hdr), &hdr);\n\n        if (hdr.magic != CPIO_BIN_MAGIC) { /* Invalid CPIO archive */\n            panic(\"Invalid CPIO archive\\n\");\n            //return -EINVAL;\n        }\n\n        size = hdr.filesize[0] * 0x10000 + hdr.filesize[1];\n        \n        data_offset += sizeof(struct cpio_hdr);\n        \n        char path[MAX_NAMESIZE];\n        vfs_read(dev, data_offset, hdr.namesize, path);\n\n        if (!strcmp(path, \".\")) continue;\n        if (!strcmp(path, \"TRAILER!!!\")) break; /* End of archive */\n\n        char *dir  = NULL;\n        char *name = NULL;\n\n        /* TODO implement strrchr */\n        for (int i = hdr.namesize - 1; i >= 0; --i) {\n            if (path[i] == '/') {\n                path[i] = '\\0';\n                name = &path[i+1];\n                dir  = path;\n                break;\n            }\n        }\n\n        if (!name) {\n            name = path;\n            dir  = \"/\";\n        }\n        \n        data_offset += hdr.namesize + (hdr.namesize % 2);\n\n        struct vnode *_node = NULL; \n        cpio_new_node(strdup(name), &hdr, size, data_offset, dev, &_node);\n\n        struct vnode *parent = cpio_find(rootfs, dir);\n        cpio_new_child_node(parent, _node);\n    }\n\n    if (super)\n        *super = rootfs;\n\n    return 0;\n}\n\nstatic ssize_t cpio_read(struct vnode *vnode, off_t offset, size_t len, void *buf)\n{\n    if ((size_t) offset >= vnode->size)\n        return 0;\n\n    len = MIN(len, vnode->size - offset);\n    struct cpio *p = vnode->p;\n    struct vnode *super = p->super;\n\n    return vfs_read(super, p->data + offset, len, buf);\n}\n\nstatic ssize_t cpio_readdir(struct vnode *node, off_t offset, struct dirent *dirent)\n{\n    if (offset == 0) {\n        strcpy(dirent->d_name, \".\");\n        return 1;\n    }\n\n    if (offset == 1) {\n        strcpy(dirent->d_name, \"..\");\n        return 1;\n    }\n\n    offset -= 2;\n\n    struct cpio *p = (struct cpio *) node->p;\n\n    if ((size_t) offset == p->count)\n        return 0;\n\n    int i = 0;\n    struct vnode *dir = p->dir;\n\n    for (struct vnode *e = dir; e; e = ((struct cpio *) e->p)->next) {\n        if (i == offset) {\n            dirent->d_ino = (size_t) e;\n            strcpy(dirent->d_name, ((struct cpio *) e->p)->name);   // FIXME\n            break;\n        }\n        ++i;\n    }\n\n    return i == offset;\n}\n\nstatic int cpio_close(struct vnode *vnode)\n{\n    return 0;\n}\n\nstatic int cpio_eof(struct file *file)\n{\n    if (S_ISDIR(file->vnode->mode)) {\n        return (size_t) file->offset >= ((struct cpio *) file->vnode->p)->count;\n    } else {\n        return (size_t) file->offset >= file->vnode->size;\n    }\n}\n\nstatic int cpio_init()\n{\n    return initramfs_archiver_register(&cpiofs);\n}\n\nstruct fs cpiofs = {\n    .name = \"cpio\",\n    .load = cpio_load,\n\n    .vops = {\n        .read    = cpio_read,\n        .readdir = cpio_readdir,\n        .finddir = cpio_finddir,\n        .vget    = cpio_vget,\n        .close   = cpio_close,\n\n        .write   = rofs_write,\n        .trunc   = rofs_trunc,\n        .vmknod  = rofs_vmknod,\n        .vunlink = rofs_vunlink,\n    },\n    \n    .fops = {\n        .open    = posix_file_open,\n        .close   = posix_file_close,\n        .read    = posix_file_read,\n        .write   = posix_file_write,\n        .readdir = posix_file_readdir,\n        .lseek   = posix_file_lseek,\n\n        .eof     = cpio_eof,\n    },\n};\n\nMODULE_INIT(initramfs_cpio, cpio_init, NULL)\n"
  },
  {
    "path": "kernel/fs/initramfs/cpio/cpio.h",
    "content": "#ifndef _CPIO_H\n#define _CPIO_H\n\n#include <core/system.h>\n#include <fs/vfs.h>\n\n#define CPIO_BIN_MAGIC    0070707\n\n/**\n * \\ingroup fs\n * \\brief cpio archive header\n */\nstruct cpio_hdr {\n    uint16_t magic;\n    uint16_t dev;\n    uint16_t ino;\n    uint16_t mode;\n    uint16_t uid;\n    uint16_t gid;\n    uint16_t nlink;\n    uint16_t rdev;\n    uint16_t mtime[2];\n    uint16_t namesize;\n    uint16_t filesize[2];\n} __packed;\n\n/**\n * \\ingroup fs\n * \\brief cpio archive\n */\nstruct cpio {\n    struct vnode *super;\n    struct vnode *parent;\n    struct vnode *dir;\n    size_t count;\n    size_t data; /* offset of data in the archive */\n\n    const char *name;\n    struct vnode *next;  /* For directories */\n};\n\nextern struct fs cpiofs;\n\n#endif /* !_CPIO_H */\n"
  },
  {
    "path": "kernel/fs/initramfs/initramfs.c",
    "content": "/*\n *          VFS => File System binding for CPIO archives\n *\n *\n *  This file is part of Aquila OS and is released under\n *  the terms of GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) 2016 Mohamed Anwar <mohamed_anwar@opmbx.org>\n */\n\n#include <core/system.h>\n#include <core/string.h>\n#include <core/panic.h>\n#include <mm/mm.h>\n\n#include <dev/ramdev.h>\n#include <fs/vfs.h>\n#include <fs/initramfs.h>\n#include <fs/devfs.h>\n#include <fs/posix.h>\n#include <bits/errno.h>\n\n#include <ds/queue.h>\n#include <boot/boot.h>\n\nstatic struct vnode *rd_dev = NULL;\nstatic struct queue *archivers = QUEUE_NEW();\n\nint initramfs_archiver_register(struct fs *fs)\n{\n    if (!enqueue(archivers, fs))\n        return -ENOMEM;\n\n    printk(\"initramfs: registered archiver: %s\\n\", fs->name);\n\n    return 0;\n}\n\nint load_ramdisk(module_t *module)\n{\n    printk(\"kernel: loading ramdisk\\n\");\n\n    rd_dev = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n    if (!rd_dev) return -ENOMEM;\n\n    extern size_t rd_size;\n\n    rd_dev->mode = S_IFBLK;\n    rd_dev->rdev = DEV(1, 0);\n    rd_dev->size = rd_size;\n    rd_dev->fs   = &devfs;\n\n    struct vnode *root = NULL;\n    int err = -1;\n\n    queue_for (node, archivers) {\n        struct fs *fs = node->value;\n\n        if (!(err = fs->load(rd_dev, &root)))\n            break;\n    }\n\n    if (err) {\n        printk(\"Error code = %d\\n\", err);\n        panic(\"Could not load ramdisk\\n\");\n    }\n\n    return vfs_mount_root(root);\n}\n"
  },
  {
    "path": "kernel/fs/ioctl.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <dev/dev.h>\n\nint vfs_ioctl(struct vnode *vnode, unsigned long request, void *argp)\n{\n    vfs_log(LOG_DEBUG, \"vfs_ioctl(vnode=%p, request=%ld, argp=%p)\\n\", vnode, request, argp);\n\n    /* TODO Basic ioctl handling */\n\n    /* Invalid request */\n    if (!vnode)\n        return -EINVAL;\n\n    /* Device node */\n    if (ISDEV(vnode))\n        return kdev_ioctl(&VNODE_DEV(vnode), request, argp);\n\n    /* Invalid request */\n    if (!vnode->fs)\n        return -EINVAL;\n\n    /* Operation not supported */\n    if (!vnode->fs->vops.ioctl)\n        return -ENOSYS;\n\n    return vnode->fs->vops.ioctl(vnode, request, argp);\n}\n\n"
  },
  {
    "path": "kernel/fs/lookup.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <bits/fcntl.h>\n\nstatic inline int vfs_follow(struct vnode *vnode, struct uio *uio, struct vnode **ref)\n{\n    /* TODO enforce limit */\n\n    int err = 0;\n    char *path = NULL;\n    \n    path = kmalloc(1024, &M_BUFFER, M_ZERO);\n    if (!path) goto e_nomem;\n\n    if ((err = vfs_read(vnode, 0, 1024, path)) < 0)\n        goto error;\n\n    if ((err = vfs_lookup(path, uio, ref, NULL)))\n        goto error;\n\n    kfree(path);\n    path = NULL;\n\n    return 0;\n\ne_nomem:\n    err = -ENOMEM;\n\nerror:\n    if (path) kfree(path);\n    return err;\n}\n\nint vfs_lookup(const char *path, struct uio *uio, struct vnode **ref, char **abs_path)\n{\n    vfs_log(LOG_DEBUG, \"vfs_lookup(path=%s, uio=%p, ref=%p, abs_path=%p)\\n\", path, uio, ref, abs_path);\n\n    int ret = 0;\n    struct vfs_path *vfs_path = NULL;\n    char **tokens = NULL;\n\n    if (!path || !*path)\n        return -ENOENT;\n\n    /* get real path (i.e. without . or ..) */\n    char *rpath = NULL;\n    if ((ret = vfs_parse_path(path, uio, &rpath)))\n        goto error;\n\n    tokens = tokenize_path(rpath);\n\n    /* Get mountpoint & path */\n    vfs_path = vfs_get_mountpoint(tokens);\n\n    struct vnode *dir = vfs_path->root;\n    dir->ref++;\n\n    for (char **token_p = vfs_path->tokens; *token_p; ++token_p) {\n        char *token = *token_p;\n\n        struct dirent dirent;\n        if ((ret = vfs_finddir(dir, token, &dirent)))\n            goto error;\n\n        if ((ret = vfs_vget(vfs_path->root, dirent.d_ino, &dir)))\n            goto error;\n    }\n\n    free_tokens(tokens);\n    kfree(vfs_path);\n\n    if (ref) *ref = dir;\n    if (abs_path) *abs_path = strdup(rpath);\n\n    kfree(rpath);\n\n    /* resolve symbolic links */\n    if (S_ISLNK(dir->mode) && !(uio->flags & O_NOFOLLOW))\n        return vfs_follow(dir, uio, ref);\n\n    return 0;\n\nerror:\n    if (tokens) free_tokens(tokens);\n    if (vfs_path) kfree(vfs_path);\n    if (rpath) kfree(rpath);\n\n    return ret;\n}\n\n"
  },
  {
    "path": "kernel/fs/minix/Build.mk",
    "content": "obj-y += super.o\nobj-y += block.o\nobj-y += inode.o\nobj-y += dentry.o\nobj-y += vops.o\nobj-y += minix.o\n"
  },
  {
    "path": "kernel/fs/minix/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/fs/minix/block.c",
    "content": "#include <ds/bitmap.h>\n#include <minix.h>\n\n/**\n * \\ingroup fs-minix\n * \\brief allocate a new block\n */\nblk_t minix_block_alloc(struct minix *desc)\n{\n    /* look for a free zone */\n    blk_t blk = 0;\n    for (; blk < desc->zmap.max_idx && bitmap_check(&desc->zmap, blk); ++blk);\n\n    /* out of zones */\n    if (blk == desc->zmap.max_idx)\n        return 0;\n\n    /* update bitmap */\n    bitmap_set(&desc->zmap, blk);\n\n    /* sync bitmap -- TODO defer */\n    vfs_write(desc->supernode, desc->zmap_off, desc->superblock->zmap_blocks * desc->bs, desc->zmap.map);\n\n    return desc->superblock->firstdatazone + blk - 1;\n}\n\n/**\n * \\ingroup fs-minix\n * \\brief free a block\n */\nvoid minix_block_free(struct minix *desc, blk_t blk)\n{\n    blk = blk - desc->superblock->firstdatazone + 1;\n\n    if (blk >= desc->zmap.max_idx)\n        /* TODO warn */\n        return;\n\n    /* update bitmap */\n    bitmap_clear(&desc->zmap, blk);\n\n    /* sync bitmap -- TODO defer */\n    vfs_write(desc->supernode, desc->zmap_off, desc->superblock->zmap_blocks * desc->bs, desc->zmap.map);\n}\n\n/**\n * \\ingroup fs-minix\n * \\brief read a block from device\n */\nssize_t minix_block_read(struct minix *desc, blk_t blk, void *buf)\n{\n    return vfs_read(desc->supernode, blk * desc->bs, desc->bs, buf);\n}\n\n/**\n * \\ingroup fs-minix\n * \\brief write a block to device\n */\nssize_t minix_block_write(struct minix *desc, blk_t blk, void *buf)\n{\n    return vfs_write(desc->supernode, blk * desc->bs, desc->bs, buf);\n}\n\n/**\n * \\ingroup fs-minix\n * \\brief get a block from block cache, cache in if not found\n */\nint minix_bcache_get(struct minix *desc, blk_t blk, void **data)\n{\n    int err = 0;\n    void *r = NULL;\n\n    if ((r = bcache_find(desc->bcache, blk))) {\n        *data = r;\n        return 0;\n    }\n\n    r = kmalloc(desc->bs, &M_BUFFER, 0);\n    if (!r) goto e_nomem;\n\n    if ((err = minix_block_read(desc, blk, r)) < 0)\n        goto error;\n\n    bcache_insert(desc->bcache, blk, r);\n\n    *data = r;\n    return 0;\n\ne_nomem:\n    err = -ENOMEM;\n\nerror:\n    return err;\n}\n"
  },
  {
    "path": "kernel/fs/minix/dentry.c",
    "content": "#include <core/panic.h>\n#include <minix.h>\n\nuint32_t minix_dentry_find(struct minix *desc, struct minix_inode *m_inode, const char *name)\n{\n    if (!S_ISDIR(m_inode->mode))\n        return -ENOTDIR;\n\n    size_t bs = desc->bs;\n    size_t nr_blocks = (m_inode->size + bs - 1) / bs;\n\n    char block[bs];\n\n    struct minix_dentry *dentry;\n\n    for (size_t i = 0; i < nr_blocks; ++i) {\n        minix_inode_block_read(desc, m_inode, i, block);\n\n        dentry = (struct minix_dentry *) block;\n\n        while ((char *) dentry < (char *) block + bs) {\n            char _name[desc->name_len+1];\n\n            memcpy(_name, dentry->name, desc->name_len);\n            _name[desc->name_len] = 0;\n\n            if (!strcmp((char *) _name, name))\n                goto found;\n\n            dentry = (struct minix_dentry *) ((char *) dentry + desc->dentry_size);\n        }\n    }\n    \n    /* not found */\n    return 0;\n\nfound:\n    return dentry->ino;\n}\n\nint minix_dentry_create(struct vnode *dir, const char *name, ino_t ino, mode_t mode)\n{\n    int err = 0;\n\n    if (!S_ISDIR(dir->mode))    /* Not a directory */\n        return -ENOTDIR;\n\n    struct minix *desc = dir->p;\n\n    size_t len = strlen(name);\n\n    struct minix_inode m_inode;\n    if ((err = minix_inode_read(desc, dir->ino, &m_inode))) {\n        /* TODO Error checking */\n    }\n\n    size_t bs = desc->bs;\n    size_t nr_blocks = (m_inode.size + bs - 1) / bs;\n\n    char block[bs];\n\n    struct minix_dentry *dentry;\n\n    for (size_t i = 0; i < nr_blocks; ++i) {\n        minix_inode_block_read(desc, &m_inode, i, block);\n\n        dentry = (struct minix_dentry *) block;\n\n        while ((char *) dentry < (char *) block + bs) {\n            if (!dentry->ino) {\n                memset(dentry->name, 0, desc->dentry_size);\n                dentry->ino = ino;\n                memcpy(dentry->name, name, MIN(len, desc->name_len));\n                minix_inode_block_write(desc, &m_inode, dir->ino, i, block);\n\n                /* update size */\n                size_t new_size = i * bs + (size_t)((char *) dentry - block) + desc->dentry_size;\n                if (m_inode.size < new_size) {\n                    m_inode.size = new_size;\n                    minix_inode_write(desc, dir->ino, &m_inode);\n                }\n\n                return 0;\n            }\n\n            dentry = (struct minix_dentry *) ((char *) dentry + desc->dentry_size);\n        }\n    }\n\n    /* TOOD allocate */\n    panic(\"Need to allocate a new block\\n\");\n}\n"
  },
  {
    "path": "kernel/fs/minix/inode.c",
    "content": "#include <ds/bitmap.h>\n#include <core/panic.h>\n#include <minix.h>\n\nstatic inline off_t minix_inode_off(struct minix *desc, ino_t ino)\n{\n    /* invalid inode */\n    if (!ino || ino >= desc->superblock->ninodes)\n        return -EINVAL;\n\n    return desc->inode_table + (ino - 1) * desc->inode_size;\n}\n\nint minix_inode_read(struct minix *desc, ino_t ino, struct minix_inode *ref)\n{\n    off_t off;\n\n    if ((off = minix_inode_off(desc, ino)) < 0)\n        return off;\n    \n    if (ref) {\n        size_t size = sizeof(struct minix_inode);\n        ssize_t r;\n\n        if ((r = vfs_read(desc->supernode, off, size, ref)) != (ssize_t) size) {\n            if (r < 0)\n                return r;\n\n            /* FIXME Check for further errors? */\n            return -EINVAL;\n        }\n    }\n\n    return 0;\n}\n\nint minix_inode_write(struct minix *desc, ino_t ino, struct minix_inode *ref)\n{\n    off_t off;\n\n    if ((off = minix_inode_off(desc, ino)) < 0)\n        return off;\n    \n    if (ref) {\n        size_t size = sizeof(struct minix_inode);\n        ssize_t r;\n\n        if ((r = vfs_write(desc->supernode, off, size, ref)) != (ssize_t) size) {\n            if (r < 0)\n                return r;\n\n            /* FIXME Check for further errors? */\n            return -EINVAL;\n        }\n    }\n\n    return 0;\n}\n\nssize_t minix_inode_block_read(struct minix *desc, struct minix_inode *m_inode, size_t idx, void *buf)\n{\n    size_t bs = desc->bs;\n    size_t nr_blocks = (m_inode->size + bs - 1) / bs;\n    size_t p = bs / sizeof(uint16_t);\n\n    int err = -EINVAL;\n\n    if (idx >= nr_blocks) {\n        return -EINVAL;\n    }\n\n    if (idx < MINIX_DIRECT_ZONES) {\n        return minix_block_read(desc, m_inode->zones[idx], buf);\n    }\n\n    idx -= MINIX_DIRECT_ZONES;\n\n    if (idx < p) {\n        uint16_t *iblock = NULL;\n        if ((err = minix_bcache_get(desc, m_inode->zones[MINIX_DIRECT_ZONES], (void **) &iblock)))\n            goto error;\n\n        blk_t block = iblock[idx];\n        return minix_block_read(desc, block, buf);\n    }\n\n    idx -= p;\n\n    if (idx < p * p) {\n        blk_t dizone = m_inode->zones[MINIX_DIRECT_ZONES+1];\n\n        if (!dizone)\n            panic(\"What0?\\n\");\n\n        uint16_t *iblock = NULL;\n        if ((err = minix_bcache_get(desc, m_inode->zones[MINIX_DIRECT_ZONES+1], (void **) &iblock)))\n            goto error;\n\n        blk_t block1 = iblock[idx / p];\n\n        if (!block1)\n            panic(\"What1?\\n\");\n\n        if ((err = minix_bcache_get(desc, block1, (void **) &iblock)))\n            goto error;\n\n        blk_t block2 = iblock[idx % p];\n\n        if (!block2)\n            panic(\"What2?\\n\");\n\n        return minix_block_read(desc, block2, buf);\n    }\n\n    return -EINVAL;\n\nerror:\n    return err;\n}\n\nssize_t minix_inode_block_write(struct minix *desc, struct minix_inode *inode, ino_t ino, size_t idx, void *buf)\n{\n    size_t p = desc->bs / 2;    /* pointers per block */\n\n    if (idx < MINIX_DIRECT_ZONES) {\n        if (!inode->zones[idx]) {    /* allocate */\n            inode->zones[idx] = minix_block_alloc(desc);\n            minix_inode_write(desc, ino, inode);\n        }\n\n        minix_block_write(desc, inode->zones[idx], buf);\n    } else if (idx < MINIX_DIRECT_ZONES + p) {\n        if (!inode->zones[MINIX_DIRECT_ZONES+1]) {    /* Allocate */\n            inode->zones[MINIX_DIRECT_ZONES+1] = minix_block_alloc(desc);\n            minix_inode_write(desc, ino, inode);\n        }\n\n        uint16_t *tmp = kmalloc(desc->bs, &M_BUFFER, 0);\n        minix_block_read(desc, inode->zones[MINIX_DIRECT_ZONES+1], tmp);\n\n        uint16_t block = tmp[idx - MINIX_DIRECT_ZONES];\n\n        if (!block) {   /* Allocate */\n            tmp[idx - MINIX_DIRECT_ZONES] = minix_block_alloc(desc);\n            minix_block_write(desc, inode->zones[MINIX_DIRECT_ZONES+1], tmp);\n        }\n\n        kfree(tmp);\n        minix_block_write(desc, block, buf);\n    } else {\n        panic(\"Not impelemented\\n\");\n    }\n\n    return 0;\n}\n\nino_t minix_inode_alloc(struct minix *desc)\n{\n    /* look for a free inode */\n    ino_t ino = 0;\n    for (; ino < desc->imap.max_idx && bitmap_check(&desc->imap, ino); ++ino);\n\n    /* out of inodes */\n    if (ino == desc->imap.max_idx)\n        return 0;\n\n    /* update bitmap */\n    bitmap_set(&desc->imap, ino);\n\n    /* sync bitmap -- TODO defer */\n    vfs_write(desc->supernode, desc->imap_off, desc->superblock->imap_blocks * desc->bs, desc->imap.map);\n\n    return ino;\n}\n\nvoid minix_inode_free(struct minix *desc, ino_t ino)\n{\n    if (ino >= desc->imap.max_idx)\n        /* TODO warn */\n        return;\n\n    /* update bitmap */\n    bitmap_clear(&desc->imap, ino);\n\n    /* sync bitmap -- TODO defer */\n    vfs_write(desc->supernode, desc->imap_off, desc->superblock->imap_blocks * desc->bs, desc->imap.map);\n}\n"
  },
  {
    "path": "kernel/fs/minix/minix.c",
    "content": "/**\n * \\defgroup fs-minix kernel/fs/minix\n * \\brief minix filesystem\n */\n#include <core/system.h>\n#include <core/module.h>\n\n#include <fs/vfs.h>\n#include <fs/posix.h>\n#include <fs/vcache.h>\n#include <fs/bcache.h>\n#include <bits/errno.h>\n#include <ds/bitmap.h>\n\n#include <minix.h>\n\nMALLOC_DEFINE(M_MINIX, \"minix\", \"minix filesystem structure\");\nMALLOC_DEFINE(M_MINIX_SB, \"minix-sb\", \"minix filesystem superblock structure\");\n\nint minix_inode_build(struct minix *desc, ino_t ino, struct vnode **ref)\n{\n    int err = 0;\n    struct vnode *inode = NULL;\n\n    /* In open inode table? */\n    if ((inode = vcache_find(desc->vcache, ino)))\n        goto found;\n\n    inode = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n    if (!inode) return -ENOMEM;\n\n    struct minix_inode minix_inode;\n    \n    if ((err = minix_inode_read(desc, ino, &minix_inode)))\n        goto error;\n\n    inode->ino   = ino;\n    inode->size  = minix_inode.size;\n    inode->mode  = minix_inode.mode;\n    inode->uid   = minix_inode.uid;\n    inode->gid   = minix_inode.gid;\n    inode->nlink = minix_inode.nlinks;\n\n    //node->atim.tv_sec  = i.last_access_time;\n    //node->atim.tv_nsec = 0;\n    inode->mtime.tv_sec  = minix_inode.mtime;\n    inode->mtime.tv_nsec = 0;\n    //node->ctim.tv_sec  = i.creation_time;\n    //node->ctim.tv_nsec = 0;\n\n    inode->fs = &minixfs;\n    inode->p  = desc;\n\n    vcache_insert(desc->vcache, inode);\n\nfound:\n    if (ref)\n        *ref = inode;\n\n    return 0;\n\nerror:\n    if (inode)\n        kfree(inode);\n\n    return err;\n}\n\nint minix_inode_sync(struct vnode *inode)\n{\n    int err = 0;\n\n    struct minix *desc = inode->p;\n    struct minix_inode minix_inode;\n    \n    if ((err = minix_inode_read(desc, inode->ino, &minix_inode)))\n        return err;\n\n    minix_inode.size   = inode->size;\n    minix_inode.mode   = inode->mode;\n    minix_inode.uid    = inode->uid;\n    minix_inode.gid    = inode->gid;\n    minix_inode.nlinks = inode->nlink;\n    minix_inode.mtime  = inode->mtime.tv_sec;\n\n    return minix_inode_write(desc, inode->ino, &minix_inode);\n}\n\n/* ================== VFS routines ================== */\n\nstatic int minix_init()\n{\n    return vfs_install(&minixfs);\n}\n\nstatic int minix_load(struct vnode *dev, struct vnode **super)\n{\n    int err = 0;\n\n    struct minix_superblock *sb = NULL;\n    struct minix *desc = NULL;\n   \n    sb = kmalloc(sizeof(struct minix_superblock), &M_MINIX_SB, 0);\n    if (sb == NULL) return -ENOMEM;\n\n    if ((err = vfs_read(dev, 1024, sizeof(*sb), sb)) < 0)\n        goto error;\n\n    int version = 0;\n    size_t name_len = 0;\n\n    switch (sb->magic) {\n        case MINIX_MAGIC:\n            version  = 1;\n            name_len = 14;\n            break;\n        case MINIX_MAGIC2:\n            version  = 1;\n            name_len = 30;\n            break;\n    }\n\n    if (!version) {\n        err = -EINVAL;\n        goto error;\n    }\n\n    /* Build descriptor structure */\n    desc = kmalloc(sizeof(struct minix), &M_MINIX, 0);\n    if (!desc) goto e_nomem;\n\n    desc->supernode   = dev;\n    desc->superblock  = sb;\n\n    if (version == 1) {\n        desc->bs          = 1024UL << sb->block_size;\n\n        desc->imap_off    = 1024UL + desc->bs;\n        desc->zmap_off    = 1024UL + (1 + sb->imap_blocks) * desc->bs;\n\n        desc->inode_table = 1024UL + (1 + sb->imap_blocks + sb->zmap_blocks) * desc->bs;\n\n        desc->inode_size  = 32;\n        desc->name_len    = name_len;\n        desc->dentry_size = name_len + 2;\n    } else {\n        kfree(desc);\n        return -ENOTSUP;\n    }\n\n    /* load inodes bitmap */\n    desc->imap.map = kmalloc(sb->imap_blocks * desc->bs, &M_BUFFER, 0);\n    desc->imap.max_idx = sb->ninodes;\n    vfs_read(desc->supernode, desc->imap_off, sb->imap_blocks * desc->bs, desc->imap.map);\n\n    /* load blocks bitmap */\n    desc->zmap.map = kmalloc(sb->zmap_blocks * desc->bs, &M_BUFFER, 0);\n    desc->zmap.max_idx = sb->nzones;\n    vfs_read(desc->supernode, desc->zmap_off, sb->zmap_blocks * desc->bs, desc->zmap.map);\n\n    desc->vcache = kmalloc(sizeof(struct vcache), &M_VCACHE, 0);\n    if (!desc->vcache) goto e_nomem;\n\n    vcache_init(desc->vcache);\n\n    desc->bcache = kmalloc(sizeof(struct bcache), &M_BCACHE, 0);\n    if (!desc->bcache) goto e_nomem;\n    bcache_init(desc->bcache);\n\n    if (super)\n        minix_inode_build(desc, 1, super);\n    \n    return 0;\n\ne_nomem:\n    err = -ENOMEM;\nerror:\n    if (sb)\n        kfree(sb);\n\n    return err;\n}\n\nstatic int minix_mount(const char *dir, int flags, void *_args)\n{\n    struct {\n        char *dev;\n        char *opt;\n    } *args = _args;\n\n    struct vnode *dev = NULL;\n    int err;\n\n    struct uio uio = {0};   /* FIXME */\n\n    if ((err = vfs_lookup(args->dev, &uio, &dev, NULL)))\n        goto error;\n\n    struct vnode *fs;\n\n    if ((err = minixfs.load(dev, &fs)))\n        goto error;\n\n    return vfs_bind(dir, fs);\n\nerror:\n    return err;\n}\n\nstruct fs minixfs = {\n    .name  = \"minix\",\n    .init  = minix_init,\n    .load  = minix_load,\n    .mount = minix_mount,\n\n    .vops = {\n        .read    = minix_read,\n        .write   = minix_write,\n        .readdir = minix_readdir,\n        .finddir = minix_finddir,\n        .trunc   = minix_trunc,\n        \n        .vmknod  = minix_vmknod,\n        .vget    = minix_vget,\n    },\n\n    .fops = {\n        .open    = posix_file_open,\n        .read    = posix_file_read,\n        .write   = posix_file_write,\n        .readdir = posix_file_readdir,\n        .lseek   = posix_file_lseek,\n        .trunc   = posix_file_trunc,\n\n        .eof     = posix_file_eof,\n    }\n};\n\nMODULE_INIT(minix, minix_init, NULL)\n"
  },
  {
    "path": "kernel/fs/minix/minix.h",
    "content": "#ifndef _MINIX_H\n#define _MINIX_H\n\n#include <core/system.h>\n#include <ds/bitmap.h>\n#include <ds/hashmap.h>\n\n#include <fs/vfs.h>\n#include <fs/vcache.h>\n#include <fs/bcache.h>\n\n#define MINIX_MAGIC    0x137F   /* Minix v1, 14 char names */\n#define MINIX_MAGIC2   0x138F   /* Minix v1, 30 char names */\n\n#define MINIX2_MAGIC   0x2468   /* Minix v2, 14 char names */\n#define MINIX2_MAGIC2  0x2478   /* Minix v2, 30 char names */\n\n#define MINIX3_MAGIC   0x4D5A   /* Minix v3, 60 char names */\n\n#define MINIX_DIRECT_ZONES  7\n\n/**\n * \\ingroup fs-minix\n * \\brief minix v1/v2 superblock\n */\nstruct minix_superblock {\n    uint16_t    ninodes;\n    uint16_t    nzones;\n    uint16_t    imap_blocks;\n    uint16_t    zmap_blocks;\n\n    uint16_t    firstdatazone;\n    uint16_t    block_size;\n\n    uint32_t    max_size;\n    uint16_t    magic;\n    uint16_t    state;\n};\n\n/**\n * \\ingroup fs-minix\n * \\brief minix v3 superblock\n */\nstruct minix3_superblock {\n\tuint32_t    ninodes;\n\tuint16_t    pad0;\n\tuint16_t    imap_blocks;\n\tuint16_t    zmap_blocks;\n\tuint16_t    firstdatazone;\n\tuint16_t    log_zone_size;\n\tuint16_t    pad1;\n\tuint32_t    max_size;\n\tuint32_t    zones;\n\tuint16_t    magic;\n\tuint16_t    pad2;\n\tuint16_t    blocksize;\n\tuint8_t     disk_version;\n};\n\n/**\n * \\ingroup fs-minix\n * \\brief minix on-disk inode\n */\nstruct minix_inode {\n    uint16_t    mode;\n    uint16_t    uid;\n    uint32_t    size;\n    uint32_t    mtime;\n    uint8_t     gid;\n    uint8_t     nlinks;\n    uint16_t    zones[9];\n};\n\n/**\n * \\ingroup fs-minix\n * \\brief minix directory entry\n */\nstruct minix_dentry {\n    uint16_t    ino;\n    uint8_t     name[0];    // Name will be here\n};\n\n/**\n * \\ingroup fs-minix\n * \\brief minix filesystem\n */\nstruct minix {\n    struct vnode *supernode;\n    struct minix_superblock *superblock;\n\n    size_t   inode_size;\n    size_t   dentry_size;\n    size_t   name_len;\n\n    uint32_t imap_off;\n    uint32_t zmap_off;\n\n    struct bitmap imap;\n    struct bitmap zmap;\n\n    int imap_dirty;\n    int zmap_dirty;\n\n    uint32_t inode_table;\n    uint32_t data_zone;\n    size_t bs;\n\n    struct vcache *vcache;\n    struct bcache *bcache;\n};\n\nextern struct fs minixfs;\n\n/* super.c */\nvoid minix_superblock_rewrite(struct minix *desc);\n\ntypedef uint32_t blk_t;\n\n/* block.c */\nblk_t minix_block_alloc(struct minix *desc);\nvoid  minix_block_free(struct minix *desc, blk_t blk);\nssize_t minix_block_read(struct minix *desc, blk_t blk, void *buf);\nssize_t minix_block_write(struct minix *desc, blk_t blk, void *buf);\nint minix_bcache_get(struct minix *desc, blk_t blk, void **data);\n\n/* inode.c */\nino_t minix_inode_alloc(struct minix *desc);\nvoid minix_inode_free(struct minix *desc, ino_t ino);\nint minix_inode_read(struct minix *desc, uint32_t id, struct minix_inode *ref);\nint minix_inode_write(struct minix *desc, uint32_t id, struct minix_inode *ref);\nssize_t minix_inode_block_read(struct minix *desc, struct minix_inode *m_inode, size_t idx, void *buf);\nssize_t minix_inode_block_write(struct minix *desc, struct minix_inode *inode, uint32_t id, size_t idx, void *buf);\n\n/* dentry.c */\nuint32_t minix_dentry_find(struct minix *desc, struct minix_inode *m_inode, const char *name);\nint minix_dentry_create(struct vnode *dir, const char *name, uint32_t inode, mode_t mode);\n\n/* iops.c */\nssize_t minix_read(struct vnode *inode, off_t offset, size_t size, void *buf);\nssize_t minix_write(struct vnode *inode, off_t offset, size_t size, void *buf);\n\nssize_t minix_readdir(struct vnode *dir, off_t offset, struct dirent *dirent);\nint minix_finddir(struct vnode *dir, const char *fn, struct dirent *dirent);\n\nint minix_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref);\nint minix_vget(struct vnode *super, ino_t ino, struct vnode **ref);\nint minix_trunc(struct vnode *inode, off_t len);\n\nint minix_inode_build(struct minix *desc, ino_t ino, struct vnode **ref);\nint minix_inode_sync(struct vnode *inode);\n\n#endif  /* ! _MINIX_H */\n"
  },
  {
    "path": "kernel/fs/minix/super.c",
    "content": "#include <minix.h>\n\nvoid minix_superblock_rewrite(struct minix *desc)\n{\n    vfs_write(desc->supernode, 1024, sizeof(struct minix_superblock), desc->superblock);\n}\n"
  },
  {
    "path": "kernel/fs/minix/vops.c",
    "content": "#include <minix.h>\n\nssize_t minix_read(struct vnode *vnode, off_t offset, size_t size, void *buf)\n{\n    //printk(\"minix_read(vnode=%p, offset=%d, size=%d, buf=%p)\\n\", vnode, offset, size, buf);\n\n    int err = 0;\n\n    struct minix *desc = vnode->p;\n\n    size_t bs = desc->bs;\n    struct minix_inode m_inode;\n    char *read_buf = NULL;\n    \n    if ((err = minix_inode_read(desc, vnode->ino, &m_inode)) < 0)\n        goto error;\n\n    if ((size_t) offset >= m_inode.size)\n        return 0;\n\n    size = MIN(size, (size_t) (m_inode.size - offset));\n\n    ssize_t ret = 0;\n    char *_buf = buf;\n\n    /* Read up to block boundary */\n    if (offset % bs) {\n        size_t start = MIN(bs - offset % bs, size);\n\n        if (start) {\n            read_buf = kmalloc(bs, &M_BUFFER, 0);\n\n            if ((err = minix_inode_block_read(desc, &m_inode, offset/bs, read_buf)) < 0)\n                goto error;\n\n            memcpy(_buf, read_buf + (offset % bs), start);\n\n            ret += start;\n            size -= start;\n            _buf += start;\n            offset += start;\n\n            if (!size)\n                goto done;\n        }\n    }\n\n    /* Read whole blocks */\n    size_t count = size/bs;\n\n    while (count) {\n        if ((err = minix_inode_block_read(desc, &m_inode, offset/bs, _buf)) < 0)\n            goto error;\n\n        ret    += bs;\n        size   -= bs;\n        _buf   += bs;\n        offset += bs;\n        --count;\n    }\n\n    if (!size)\n        goto done;\n\n    size_t end = size % bs;\n\n    if (end) {\n        if (!read_buf)\n            read_buf = kmalloc(bs, &M_BUFFER, 0);\n\n        if ((err = minix_inode_block_read(desc, &m_inode, offset/bs, read_buf)) < 0)\n            goto error;\n\n        memcpy(_buf, read_buf, end);\n        ret += end;\n    }\n\ndone:\n    if (read_buf)\n        kfree(read_buf);\n\n    return ret;\n\nerror:\n    if (read_buf)\n        kfree(read_buf);\n\n    return err;\n}\n\nssize_t minix_write(struct vnode *vnode, off_t offset, size_t size, void *buf)\n{\n    //printk(\"minix_write(vnode=%p, offset=%d, size=%d, buf=%p)\\n\", vnode, offset, size, buf);\n\n    int err = 0;\n\n    struct minix *desc = vnode->p;\n\n    if ((size_t) offset + size > vnode->size) {\n        minix_trunc(vnode, (size_t) offset + size);\n    }\n\n    size_t bs = desc->bs;\n    struct minix_inode m_inode;\n    char *write_buf = NULL;\n    \n    if ((err = minix_inode_read(desc, vnode->ino, &m_inode)) < 0)\n        goto error;\n\n    if ((size_t) offset >= m_inode.size) {\n        m_inode.size = offset + size;\n        if ((err = minix_inode_write(desc, vnode->ino, &m_inode)) < 0)\n            goto error;\n    }\n\n    size = MIN(size, (size_t) (m_inode.size - offset));\n\n    ssize_t ret = 0;\n    char *_buf = buf;\n\n    /* Write up to block boundary */\n    if (offset % bs) {\n        size_t start = MIN(bs - offset % bs, size);\n\n        if (start) {\n            write_buf = kmalloc(bs, &M_BUFFER, 0);\n\n            if ((err = minix_inode_block_read(desc, &m_inode, offset/bs, write_buf)) < 0)\n                goto error;\n\n            memcpy(write_buf + (offset % bs), _buf, start);\n\n            if ((err = minix_inode_block_write(desc, &m_inode, vnode->ino, offset/bs, write_buf)) < 0)\n                goto error;\n\n            ret += start;\n            size -= start;\n            _buf += start;\n            offset += start;\n\n            if (!size)\n                goto done;\n        }\n    }\n\n    /* Write whole blocks */\n    size_t count = size/bs;\n\n    while (count) {\n        if ((err = minix_inode_block_write(desc, &m_inode, vnode->ino, offset/bs, _buf)) < 0)\n            goto error;\n\n        ret    += bs;\n        size   -= bs;\n        _buf   += bs;\n        offset += bs;\n        --count;\n    }\n\n    if (!size)\n        goto done;\n\n    size_t end = size % bs;\n\n    if (end) {\n        if (!write_buf)\n            write_buf = kmalloc(bs, &M_BUFFER, 0);\n\n        if ((err = minix_inode_block_read(desc, &m_inode, offset/bs, write_buf)) < 0)\n            goto error;\n\n        memcpy(write_buf, _buf, end);\n\n        if ((err = minix_inode_block_write(desc, &m_inode, vnode->ino, offset/bs, write_buf)) < 0)\n            goto error;\n\n        ret += end;\n    }\n\ndone:\n    if (write_buf)\n        kfree(write_buf);\n\n    return ret;\n\nerror:\n    if (write_buf)\n        kfree(write_buf);\n\n    return err;\n}\n\nssize_t minix_readdir(struct vnode *dir, off_t off, struct dirent *dirent)\n{\n    int err = 0;\n\n    struct minix *desc = dir->p;\n    size_t bs = desc->bs;\n    char block[bs];\n\n    if (!S_ISDIR(dir->mode))\n        return -ENOTDIR;\n\n    struct minix_inode m_inode;\n    \n    if ((err = minix_inode_read(desc, dir->ino, &m_inode)))\n        goto error;\n\n    if (!S_ISDIR(m_inode.mode))\n        return -ENOTDIR;\n\n    size_t nr_blocks = (m_inode.size + bs - 1) / bs;\n\n    struct minix_dentry *dentry;\n    uint32_t inode_nr;\n    off_t idx = 0;\n\n    for (size_t i = 0; i < nr_blocks; ++i) {\n        minix_inode_block_read(desc, &m_inode, i, block);\n\n        dentry = (struct minix_dentry *) block;\n\n        while ((char *) dentry < (char *) block + bs) {\n            if (dentry->ino) {\n                if (idx++ == off) {\n                    dirent->d_ino = dentry->ino;\n\n                    memcpy(dirent->d_name, (char *) dentry->name, desc->name_len);\n                    dirent->d_name[desc->name_len] = '\\0';\n                    return 1;\n                }\n            }\n\n            dentry = (struct minix_dentry *) ((char *) dentry + desc->dentry_size);\n        }\n    }\n\n    /* not found */\n    return 0;\n\nerror:\n    return err;\n}\n\nint minix_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)\n{\n    //printk(\"minix_vmknod(dir=%p, fn=%s, mode=%d, dev=%x, uio=%p, ref=%p)\\n\", dir, fn, mode, dev, uio, ref);\n\n    int err = 0;\n\n    if (!fn || !*fn)\n        return -EINVAL;\n\n    struct minix *desc = dir->p;\n    struct minix_inode dir_inode;\n    \n    if ((err = minix_inode_read(desc, dir->ino, &dir_inode)))\n        goto error;\n\n    if (minix_dentry_find(desc, &dir_inode, fn)) {\n        /* File exists */\n        return -EEXIST;\n    }\n\n    ino_t ino = minix_inode_alloc(desc);\n\n    struct minix_inode m_inode;\n    \n    if ((err = minix_inode_read(desc, ino, &m_inode))) {\n        /* TODO Error checking */\n    }\n\n    memset(&m_inode, 0, sizeof(struct minix_inode));\n\n    m_inode.mode = mode;\n    m_inode.uid  = uio->uid;\n    m_inode.gid  = uio->gid;\n\n    if (S_ISDIR(mode)) {   /* Initalize directory structure */\n        m_inode.nlinks = 2;\n        m_inode.size   = 2 * desc->dentry_size;\n\n        char buf[desc->bs];\n        memset(buf, 0, sizeof(buf));\n\n        struct minix_dentry *dentry = (struct minix_dentry *) buf;\n        dentry->ino = ino;\n        memcpy(dentry->name, \".\", 1);\n\n        dentry = (struct minix_dentry *) ((char *) dentry + desc->dentry_size);\n        dentry->ino = dir->ino;\n        memcpy(dentry->name, \"..\", 2);\n\n        minix_inode_block_write(desc, &m_inode, ino, 0, buf);\n\n        /* update links count to parent directory */\n        struct vnode *parent_inode;\n        minix_inode_build(desc, dir->ino, &parent_inode);\n        //printk(\"parent vnode links %d\\n\", parent_inode->nlink);\n        parent_inode->nlink += 1;\n        minix_inode_sync(parent_inode);\n    } else {\n        m_inode.nlinks = 1;\n        m_inode.size   = 0;\n    }\n\n    minix_inode_write(desc, ino, &m_inode);\n    minix_dentry_create(dir, fn, ino, m_inode.mode);\n\n    if (ref)\n        minix_inode_build(desc, ino, ref);\n\nerror:\n    return 0;\n}\n\nint minix_finddir(struct vnode *dir, const char *fn, struct dirent *dirent)\n{\n    int err = 0;\n\n    struct minix *desc = dir->p;\n\n    uint32_t id = dir->ino;\n\n    struct minix_inode m_inode;\n\n    if ((err = minix_inode_read(desc, id, &m_inode)))\n        goto error;\n\n    ino_t ino = minix_dentry_find(desc, &m_inode, fn);\n\n    if (!ino)  /* Not found */\n        return -ENOENT;\n\n    if (dirent) {\n        dirent->d_ino  = ino;\n    }\n\n    return 0;\n\nerror:\n    return err;\n}\n\nint minix_vget(struct vnode *super, ino_t ino, struct vnode **ref)\n{\n    struct minix *desc = super->p;\n\n    if (ref) return minix_inode_build(desc, ino, ref);\n\n    return 0;\n}\n\nint minix_trunc(struct vnode *vnode, off_t len)\n{\n    /* do nothing */\n    if ((size_t) len == vnode->size)\n        return 0;\n\n    /* just extend vnode size */\n    if ((size_t) len > vnode->size) {\n        vnode->size = len;\n        minix_inode_sync(vnode);\n        return 0;\n    }\n\n    /* otherwise the new size is smaller, we need to free the extra blocks */\n    /* TODO */\n\n\n#if 0\n    blk_t old_blocks = (vnode->size  + desc->bs - 1) / desc->bs;\n    blk_t new_blocks = ((size_t) len + desc->bs - 1) / desc->bs;\n\n    for (blk_t blk = old_blocks + 1; blk < new_blocks; ++blk) {\n        printk(\"should free block %d\\n\", blk);\n        //minix_inode_block(struct minix *desc, ino_t ino, blk_t blk)\n    }\n#endif\n\n    vnode->size = len;\n    minix_inode_sync(vnode);\n    return 0;\n}\n"
  },
  {
    "path": "kernel/fs/mknod.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n\nint vfs_mknod(const char *path, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)\n{\n    int ret = 0;\n    struct vfs_path *p = NULL;\n    char **tokens = NULL;\n\n    /* if path is NULL pointer, or path is empty string, return NULL */\n    if (!path ||  !*path)\n        return -ENOENT;\n\n    char *_path = NULL;\n    if ((ret = vfs_parse_path(path, uio, &_path)))\n        goto error;\n\n    /* Canonicalize Path */\n    tokens = tokenize_path(_path);\n\n    /* Get mountpoint & path */\n    p = vfs_get_mountpoint(tokens);\n\n    struct vnode *dir = p->root;\n    char *name = NULL;\n    char **tok = p->tokens;\n\n    while (tok) {\n        char *token = *tok;\n\n        if (!*(tok + 1)) {\n            name = token;\n            break;\n        }\n\n        struct dirent dirent;\n        if ((ret = vfs_finddir(dir, token, &dirent)))\n            goto error;\n\n        if ((ret = vfs_vget(p->root, dirent.d_ino, &dir)))\n            goto error;\n\n        ++tok;\n    }\n\n    if ((ret = vfs_vmknod(dir, name, mode, dev, uio, ref)))\n        goto error;\n\n    free_tokens(tokens);\n    kfree(p);\n    kfree(_path);\n    return 0;\n\nerror:\n    if (tokens)\n        free_tokens(tokens);\n    if (p)\n        kfree(p);\n    if (_path)\n        kfree(_path);\n    return ret;\n}\n\nint vfs_mkdir(const char *path, mode_t mode, struct uio *uio, struct vnode **ref)\n{\n    return vfs_mknod(path, S_IFDIR | mode, 0, uio, ref);\n}\n\nint vfs_creat(const char *path, mode_t mode, struct uio *uio, struct vnode **ref)\n{\n    return vfs_mknod(path, S_IFREG | mode, 0, uio, ref);\n}\n"
  },
  {
    "path": "kernel/fs/mount.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <ds/queue.h>\n\nstruct queue *mounts = QUEUE_NEW();\n\nMALLOC_DEFINE(M_MOUNTPOINT, \"mountpoint\", \"mount point structure\");\n\nint vfs_mount(const char *type, const char *dir, int flags, void *data, struct uio *uio)\n{\n    struct fs *fs = NULL;\n\n    /* Look up filesystem */\n    for (struct fs_list *entry = registered_fs; entry; entry = entry->next) {\n        if (!strcmp(entry->name, type)) {\n            fs = entry->fs;\n            break;\n        }\n    }\n\n    if (!fs)\n        return -EINVAL;\n\n    /* Directory path must be absolute */\n    int ret = 0;\n    char *_dir = NULL;\n    if ((ret = vfs_parse_path(dir, uio, &_dir))) {\n        if (_dir)\n            kfree(_dir);\n        return ret;\n    }\n\n    int err = 0;\n    err = fs->mount(_dir, flags, data);\n    \n    if (err == 0) {\n        struct mountpoint *mp = kmalloc(sizeof(struct mountpoint), &M_MOUNTPOINT, 0);\n        struct {\n            char *dev;\n            char *opt;\n        } *args = data;\n        mp->dev = args->dev? strdup(args->dev) : \"none\";\n        mp->type = strdup(type);\n        mp->path = strdup(_dir);\n        mp->options = \"\";\n        enqueue(mounts, mp);\n    }\n\n    kfree(_dir);\n\n    return err;\n}\n"
  },
  {
    "path": "kernel/fs/pipe.c",
    "content": "#include <core/system.h>\n\n#include <ds/ringbuf.h>\n#include <bits/fcntl.h>\n\n#include <fs/pipe.h>\n#include <fs/posix.h>\n\nMALLOC_DEFINE(M_PIPE, \"pipe\", \"pipe structure\");\n\nstatic ssize_t pipefs_read(struct vnode *node, off_t offset __unused, size_t size, void *buf)\n{\n    struct pipe *pipe = node->p;\n    return ringbuf_read(pipe->ring, size, buf);\n}\n\nstatic ssize_t pipefs_write(struct vnode *node, off_t offset __unused, size_t size, void *buf)\n{\n    struct pipe *pipe = node->p;\n    return ringbuf_write(pipe->ring, size, buf);\n}\n\nstatic int pipefs_can_read(struct file *file, size_t size)\n{\n    struct vnode *node = file->vnode;\n    struct pipe *pipe = node->p;\n    return size <= ringbuf_available(pipe->ring);\n}\n\nstatic int pipefs_can_write(struct file *file, size_t size)\n{\n    struct vnode *node = file->vnode;\n    struct pipe *pipe = node->p;\n    return size >= pipe->ring->size - ringbuf_available(pipe->ring);\n}\n\nstatic int pipefs_mkpipe(struct pipe **ref)\n{\n    struct pipe *pipe;\n\n    pipe = kmalloc(sizeof(struct pipe), &M_PIPE, M_ZERO);\n    if (!pipe) return -ENOMEM;\n\n    pipe->ring = ringbuf_new(PIPE_BUFLEN);\n    \n    if (!pipe->ring) {\n        kfree(pipe);\n        return -ENOMEM;\n    }\n\n    if (ref) *ref = pipe;\n\n    return 0;\n}\n\nstatic void pipefs_pfree(struct pipe *pipe)\n{\n    if (pipe) {\n        if (pipe->ring)\n            ringbuf_free(pipe->ring);\n        kfree(pipe);\n    }\n}\n\nint pipefs_pipe(struct file *read, struct file *write)\n{\n    int err = 0;\n    struct pipe *pipe = NULL;\n\n    if (!read || !write)\n        return -EINVAL;\n\n    err = pipefs_mkpipe(&pipe);\n    if (err) return err;\n\n    read->vnode  = kmalloc(sizeof(struct vnode), &M_VNODE, 0);\n    if (!read->vnode) {\n        pipefs_pfree(pipe);\n        return -ENOMEM;\n    }\n\n    write->vnode = kmalloc(sizeof(struct vnode), &M_VNODE, 0);\n    if (!write->vnode) {\n        kfree(read->vnode);\n        pipefs_pfree(pipe);\n        return -ENOMEM;\n    }\n\n    read->vnode->read_queue   = queue_new();\n    if (!read->vnode->read_queue) {\n        kfree(read->vnode);\n        kfree(write->vnode);\n        pipefs_pfree(pipe);\n        return -ENOMEM;\n    }\n\n    write->vnode->write_queue = read->vnode->read_queue;\n\n    read->vnode->fs  = &pipefs;\n    read->vnode->p   = pipe;\n\n    write->vnode->fs = &pipefs;\n    write->vnode->p  = pipe;\n    write->flags     = O_WRONLY;\n    return 0;\n}\n\nstruct fs pipefs = {\n    .name = \"pipefs\",\n\n    .vops = {\n        .read  = pipefs_read,\n        .write = pipefs_write,\n    },\n\n    .fops = {\n        .read      = posix_file_read,\n        .write     = posix_file_write,\n        .can_read  = pipefs_can_read,\n        .can_write = pipefs_can_write,\n        .eof       = __vfs_eof_never\n    },\n};\n"
  },
  {
    "path": "kernel/fs/posix/Build.mk",
    "content": "obj-y += open.o\nobj-y += close.o\nobj-y += read.o\nobj-y += readdir.o\nobj-y += write.o\nobj-y += ioctl.o\nobj-y += lseek.o\nobj-y += trunc.o\nobj-y += helpers.o\n"
  },
  {
    "path": "kernel/fs/posix/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/fs/posix/close.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <fs/posix.h>\n\nint posix_file_close(struct file *file)\n{\n    return vfs_close(file->vnode);\n}\n"
  },
  {
    "path": "kernel/fs/posix/helpers.c",
    "content": "#include <fs/posix.h>\n\nint posix_file_can_read(struct file *file, size_t size)\n{\n    return (size_t) file->offset + size < file->vnode->size;\n}\n\nint posix_file_can_write(struct file *file, size_t size)\n{\n    return (size_t) file->offset + size < file->vnode->size;\n}\n\nint posix_file_eof(struct file *file)\n{\n    return (size_t) file->offset >= file->vnode->size;\n}\n"
  },
  {
    "path": "kernel/fs/posix/ioctl.c",
    "content": "#include <core/system.h>\n\n#include <fs/vfs.h>\n#include <bits/errno.h>\n\n/**\n * posix_file_ioctl\n *\n * Conforming to `IEEE Std 1003.1, 2013 Edition'\n *\n */\n\nint posix_file_ioctl(struct file *file, int request, void *argp)\n{\n    return vfs_ioctl(file->vnode, request, argp);\n}\n"
  },
  {
    "path": "kernel/fs/posix/lseek.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <bits/errno.h>\n\n/**\n * posix_file_lseek\n *\n * Conforming to `IEEE Std 1003.1, 2013 Edition'\n *\n */\n\nssize_t posix_file_lseek(struct file *file, off_t offset, int whence)\n{\n    struct vnode *vnode = file->vnode;\n\n    switch (whence) {\n        case 0: /* SEEK_SET */\n            file->offset = offset;\n            break;\n        case 1: /* SEEK_CUR */\n            file->offset += offset;\n            break;\n        case 2: /* SEEK_END */\n            file->offset = vnode->size + offset;\n            break;\n    }\n\n    return file->offset;\n}\n"
  },
  {
    "path": "kernel/fs/posix/open.c",
    "content": "#include <fs/posix.h>\n#include <bits/fcntl.h>\n#include <fs/stat.h>\n#include <sys/sched.h>\n\nint posix_file_open(struct file *file)\n{\n    if (file->flags & O_TRUNC) {\n        return vfs_file_trunc(file, 0);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "kernel/fs/posix/read.c",
    "content": "/*\n *          VFS => Generic file read function\n *\n *\n *  This file is part of Aquila OS and is released under\n *  the terms of GNU GPLv3 - See LICENSE.\n *\n */\n\n#include <core/system.h>\n\n#include <fs/vfs.h>\n\n#include <bits/fcntl.h>\n#include <bits/errno.h>\n#include <bits/dirent.h>\n\n/**\n *\n * Reads up to `size` bytes from a file to `buf`.\n *\n * Conforming to `IEEE Std 1003.1, 2013 Edition'\n * \n * @param file    File Descriptor for the function to operate on.\n * @param buf     Buffer to write to.\n * @param size    Number of bytes to read.\n * @param returns read bytes on success, or error-code on failure.\n */\n\nssize_t posix_file_read(struct file *file, void *buf, size_t size)\n{\n    if (file->flags & O_WRONLY) /* File is not opened for reading */\n        return -EBADFD;\n\n    if (!size)\n        return 0;\n    \n    int retval;\n    for (;;) {\n        if ((retval = vfs_read(file->vnode, file->offset, size, buf)) > 0) {\n            /* Update file offset */\n            file->offset += retval;\n            \n            /* Wake up all sleeping writers if a `write_queue' is attached */\n            if (file->vnode->write_queue)\n                thread_queue_wakeup(file->vnode->write_queue);\n\n            /* Return read bytes count */\n            return retval;\n        } else if (retval < 0) {    /* Error */\n            return retval;\n        } else if (vfs_file_eof(file)) {\n            /* Reached end-of-file */\n            return 0;\n        } else if (file->flags & O_NONBLOCK) {\n            /* Can not satisfy read operation, would block */\n            return -EAGAIN;\n        } else {\n            /* Block until some data is available */\n            /* Sleep on the file readers queue */\n            if (thread_queue_sleep(file->vnode->read_queue))\n                return -EINTR;\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/fs/posix/readdir.c",
    "content": "/*\n *          VFS => Generic file readdir function\n *\n *\n *  This file is part of Aquila OS and is released under\n *  the terms of GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) 2016-2017 Mohamed Anwar <mohamed_anwar@opmbx.org>\n *\n */\n\n#include <core/system.h>\n\n#include <fs/vfs.h>\n\n#include <bits/fcntl.h>\n#include <bits/errno.h>\n#include <bits/dirent.h>\n\n/**\n * posix_file_readdir\n *\n * Conforming to `IEEE Std 1003.1, 2013 Edition'\n * \n * @file    File Descriptor for the function to operate on.\n * @dirent  Buffer to write to.\n */\n\nssize_t posix_file_readdir(struct file *file, struct dirent *dirent)\n{\n    if (file->flags & O_WRONLY) /* File is not opened for reading */\n        return -EBADFD;\n    \n    int retval = vfs_readdir(file->vnode, file->offset, dirent);\n\n    /* Update file offset */\n    file->offset += retval;\n        \n    /* Return read bytes count */\n    return retval;\n}\n"
  },
  {
    "path": "kernel/fs/posix/trunc.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <fs/posix.h>\n\nint posix_file_trunc(struct file *file, off_t len)\n{\n    return vfs_trunc(file->vnode, len);\n}\n"
  },
  {
    "path": "kernel/fs/posix/write.c",
    "content": "/*\n *          VFS => Generic file write function\n *\n *\n *  This file is part of Aquila OS and is released under\n *  the terms of GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) 2016 Mohamed Anwar <mohamed_anwar@opmbx.org>\n */\n\n#include <core/system.h>\n\n#include <fs/vfs.h>\n\n#include <bits/fcntl.h>\n#include <bits/errno.h>\n\n/**\n * posix_file_write\n *\n * Writes up to `size' bytes from `buf' into a file.\n *\n * @file    File Descriptor for the function to operate on.\n * @buf     Buffer to read from.\n * @size    Number of bytes to write.\n * @returns written bytes on success, or error-code on failure.\n */\n\nssize_t posix_file_write(struct file *file, void *buf, size_t size)\n{\n    if (!(file->flags & (O_WRONLY | O_RDWR)))   /* File is not opened for writing */\n        return -EBADFD;\n    \n    if (file->flags & O_NONBLOCK) { /* Non-blocking I/O */\n        if (vfs_file_can_write(file, size)) {\n            /* write up to `size' from `buf' into file */\n            ssize_t retval = vfs_write(file->vnode, file->offset, size, buf);\n\n            /* Update file offset */\n            file->offset += retval;\n            \n            /* Wake up all sleeping readers if a `read_queue' is attached */\n            if (file->vnode->read_queue)\n                thread_queue_wakeup(file->vnode->read_queue);\n\n            /* Return written bytes count */\n            return retval;\n        } else {\n            /* Can not satisfy write operation, would block */\n            return -EAGAIN;\n        }\n    } else {    /* Blocking I/O */\n        ssize_t retval = size;\n        \n        while (size) {\n            size -= vfs_write(file->vnode, file->offset, size, buf);\n\n            /* No bytes left to be written, or reached END-OF-FILE */\n            if (!size || vfs_file_eof(file))    /* Done writting */\n                break;\n\n            /* Sleep on the file writers queue */\n            thread_queue_sleep(file->vnode->write_queue);\n        }\n        \n        /* Store written bytes count */\n        retval -= size;\n\n        /* Update file offset */\n        file->offset += retval;\n\n        /* Wake up all sleeping readers if a `read_queue' is attached */\n        if (file->vnode->read_queue)\n            thread_queue_wakeup(file->vnode->read_queue);\n\n        return retval;\n    }\n}\n"
  },
  {
    "path": "kernel/fs/procfs/Build.mk",
    "content": "obj-y += procfs.o\n"
  },
  {
    "path": "kernel/fs/procfs/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/fs/procfs/procfs.c",
    "content": "#include <core/system.h>\n#include <core/arch.h>\n#include <core/module.h>\n#include <core/string.h>\n#include <core/time.h>\n#include <bits/errno.h>\n#include <boot/boot.h>\n\n#include <fs/vfs.h>\n#include <fs/devfs.h>\n#include <fs/posix.h>\n#include <fs/vcache.h>\n\n#include <sys/proc.h>\n#include <sys/sched.h>\n\n#include <mm/vm.h>\n#include <mm/buddy.h>\n#include <ds/buddy.h>\n\nstruct fs procfs;\n\nstruct procfs_entry {\n    char *name;\n    ssize_t (*read)(off_t off, size_t size, char *buf);\n};\n\n/* procfs root directory (usually mounted on /proc) */\nstruct vnode *procfs_root = NULL;\nstruct vcache procfs_vcache = {0};\n\n/* proc/meminfo */\nstatic ssize_t procfs_meminfo(off_t off, size_t size, char *buf)\n{\n    char meminfo_buf[512];\n    extern size_t k_total_mem, k_used_mem, kvmem_used, kvmem_obj_cnt;\n\n    int sz = snprintf(meminfo_buf, 512, \n            \"MemTotal: %d kB\\n\"\n            \"MemFree: %d kB\\n\"\n            \"KVMemUsed: %d KB\\n\"\n            \"KVMemObjCnt: %d\\n\",\n            k_total_mem/1024,\n            (k_total_mem-k_used_mem)/1024,\n            kvmem_used/1024,\n            kvmem_obj_cnt\n            );\n\n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, meminfo_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\n/* proc/kvmem */\nstatic ssize_t procfs_kvmem(off_t off, size_t size, char *buf)\n{\n    //printk(\"procfs_kvmem(off=%d, size=%d, buf=%p)\\n\", off, size, buf);\n\n    extern struct queue *malloc_types;\n\n    char kvmem_buf[1024];\n    int sz = 0;\n\n    queue_for (node, malloc_types) {\n        struct malloc_type *type = (struct malloc_type *) node->value;\n        sz += snprintf(kvmem_buf + sz, sizeof(kvmem_buf) - sz,\n                \"%s %d %d\\n\", type->name, type->nr, type->total) - 1;\n\n        if ((size_t) sz >= sizeof(kvmem_buf))\n            break;\n    }\n\n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, kvmem_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\n/* proc/version */\nstatic ssize_t procfs_version(off_t off, size_t size, char *buf)\n{\n    char version_buf[512];\n\n    int sz = snprintf(version_buf, 512,\n            \"%s version %s (%s version %s) %s\\n\",\n            UTSNAME_SYSNAME, UTSNAME_RELEASE,\n            __CONFIG_COMPILER__,\n            __CONFIG_COMPILER_VERSION__,\n            __CONFIG_TIMESTAMP__\n            );\n\n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, version_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\n/* proc/uptime */\nstatic ssize_t procfs_uptime(off_t off, size_t size, char *buf)\n{\n    char uptime_buf[64];\n\n    int sz = snprintf(uptime_buf, 64, \"%ld\\n\", arch_rtime_ms() / 1000);\n\n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, uptime_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\n/* proc/filesystems */\nstatic ssize_t procfs_filesystems(off_t off, size_t size, char *buf)\n{\n    char fs_buf[512];\n\n    extern struct fs_list *registered_fs;\n\n    int sz = 0;\n\n    for (struct fs_list *fs = registered_fs; fs; fs = fs->next) {\n        sz += snprintf(fs_buf + sz, sizeof(fs_buf) - sz, \"%s\\t%s\\n\", fs->fs->nodev? \"nodev\" : \"\", fs->name);\n        if ((size_t) sz >= sizeof(fs_buf))\n            break;\n    }\n\n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, fs_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\n/* proc/cmdline */\nstatic ssize_t procfs_cmdline(off_t off, size_t size, char *buf)\n{\n    char cmdline_buf[512];\n\n    extern struct boot *__kboot;\n\n    int sz = snprintf(cmdline_buf, 512, \"%s\\n\", __kboot->cmdline);\n\n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, cmdline_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\n/* proc/rdcmdline */\nstatic ssize_t procfs_rdcmdline(off_t off, size_t size, char *buf)\n{\n    char rdcmdline_buf[512];\n\n    extern struct boot *__kboot;\n    module_t *rd_module = &__kboot->modules[0];\n\n    int sz = snprintf(rdcmdline_buf, 512, \"%s\\n\", rd_module->cmdline);\n\n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, rdcmdline_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\n/* proc/mounts */\nstatic ssize_t procfs_mounts(off_t off, size_t size, char *buf)\n{\n    char mounts_buf[4096];\n\n    extern struct queue *mounts;\n    int sz = 0;\n\n    queue_for (node, mounts) {\n        struct mountpoint *mp = node->value;\n        sz += snprintf(mounts_buf + sz, sizeof(mounts_buf) - sz,\n                \"%s %s %s %s\\n\", mp->dev, mp->path, mp->type, mp->options);\n        if ((size_t) sz >= sizeof(mounts_buf))\n            break;\n    }\n\n\n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, mounts_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\n/* proc/buddyinfo */\nstatic ssize_t procfs_buddyinfo(off_t off, size_t size, char *buf)\n{\n    char buddyinfo_buf[4096];\n\n    extern struct buddy buddies[BUDDY_ZONE_NR][BUDDY_MAX_ORDER+1];\n\n    int sz = 0;\n\n    /*\n    sz += snprintf(buddyinfo_buf + sz, sizeof(buddyinfo_buf) - sz, \"Zone DMA\\n\");\n    for (int i = 0; i < BUDDY_MAX_ORDER + 1; ++i) {\n        sz += snprintf(buddyinfo_buf + sz, sizeof(buddyinfo_buf) - sz, \"2^%d: %d\\n\",\n                12 + i, buddies[0][i].usable);\n    }\n    */\n\n    sz += snprintf(buddyinfo_buf + sz, sizeof(buddyinfo_buf) - sz, \"\\nZone Normal\\n\");\n    for (int i = 0; i < BUDDY_MAX_ORDER + 1; ++i) {\n        sz += snprintf(buddyinfo_buf + sz, sizeof(buddyinfo_buf) - sz, \"2^%d: %d\\n\",\n                12 + i, buddies[1][i].usable);\n    }\n\n    sz += snprintf(buddyinfo_buf + sz, sizeof(buddyinfo_buf) - sz, \"\\n\");\n\n\n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, buddyinfo_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\n/* proc/devices */\nstatic ssize_t procfs_devices(off_t off, size_t size, char *buf)\n{\n    char dev_buf[512];\n\n    int sz = 0;\n\n    extern struct dev *chrdev[256];\n    extern struct dev *blkdev[256];\n\n    sz += snprintf(dev_buf + sz, sizeof(dev_buf) - sz, \"chrdev:\\n\");\n    for (int i = 0; i < 256; ++i) {\n        if (chrdev[i]) {\n            sz += snprintf(dev_buf + sz, sizeof(dev_buf) - sz, \"%d\\t%s\\n\", i, chrdev[i]->name);\n            if ((size_t) sz >= sizeof(dev_buf))\n                break;\n        }\n    }\n\n    sz += snprintf(dev_buf + sz, sizeof(dev_buf) - sz, \"\\nblkdev:\\n\");\n    for (int i = 0; i < 256; ++i) {\n        if (blkdev[i]) {\n            sz += snprintf(dev_buf + sz, sizeof(dev_buf) - sz, \"%d\\t%s\\n\", i, blkdev[i]->name);\n            if ((size_t) sz >= sizeof(dev_buf))\n                break;\n        }\n    }\n\n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, dev_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\nstatic struct procfs_entry entries[] = {\n    {\"meminfo\", procfs_meminfo},\n    {\"cmdline\", procfs_cmdline},\n    {\"rdcmdline\", procfs_rdcmdline},\n    {\"version\", procfs_version},\n    {\"uptime\",  procfs_uptime},\n    {\"filesystems\",  procfs_filesystems},\n    //{\"zoneinfo\",  procfs_zoneinfo},\n    {\"buddyinfo\", procfs_buddyinfo},\n    {\"kvmem\", procfs_kvmem},\n    {\"mounts\", procfs_mounts},\n    {\"devices\", procfs_devices},\n};\n\n#define PROCFS_ENTRIES  (sizeof(entries)/sizeof(entries[0]))\n\nstatic ssize_t procfs_proc_status(int pid, off_t off, size_t size, void *buf)\n{\n    struct proc *proc = proc_pid_find(pid);\n\n    if (!proc)\n        return -ENONET;\n\n    char status_buf[512];\n\n    int sz = snprintf(status_buf, 512,\n            \"name: %s\\n\"\n            \"pid: %d\\n\"\n            \"ppid: %d\\n\"\n            \"cwd: %s\\n\"\n            \"umask: %x\\n\"\n            \"uid: %d\\n\"\n            \"gid: %d\\n\"\n            \"heap: 0x%x\\n\"\n            \"threads_nr: %d\\n\",\n            proc->name,\n            proc->pid,\n            proc->parent ? proc->parent->pid : 0,\n            proc->cwd,\n            proc->mask,\n            proc->uid,\n            proc->gid,\n            proc->heap,\n            proc->threads.count\n            );\n\n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, status_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\nstatic ssize_t procfs_proc_maps(int pid, off_t off, size_t size, void *buf)\n{\n    struct proc *proc = proc_pid_find(pid);\n\n    if (!proc)\n        return -ENONET;\n\n    char maps_buf[4096];\n\n    int sz = 0;\n\n    struct queue *vm_entries = &proc->vm_space.vm_entries;\n    queue_for (node, vm_entries) {\n        struct vm_entry *vm_entry = node->value;\n\n        char perm[5] = {0};\n        perm[0] = vm_entry->flags & VM_UR? 'r' : '-';\n        perm[1] = vm_entry->flags & VM_UW? 'w' : '-';\n        perm[2] = vm_entry->flags & VM_UX? 'x' : '-';\n        perm[3] = vm_entry->flags & VM_SHARED? 's' : 'p';\n\n        char *desc = \"\";\n\n        if (vm_entry == proc->stack_vm)\n            desc = \"[stack]\";\n\n        if (vm_entry == proc->heap_vm)\n            desc = \"[heap]\";\n\n        struct vnode *vnode = NULL;\n\n        if (vm_entry->vm_object && vm_entry->vm_object->type == VMOBJ_FILE)\n            vnode = (struct vnode *) vm_entry->vm_object->p;\n\n        sz += snprintf(maps_buf + sz, sizeof(maps_buf) - sz,\n                \"%x-%x %s %x %x %x %s\\n\",\n                vm_entry->base,  /* Start address */\n                vm_entry->base + vm_entry->size,  /* End address */\n                perm,   /* Access permissions */\n                vm_entry->off, /* Offset in file */\n                vnode? vnode->dev : 0, /* Device ID */\n                vnode? vnode->ino : 0, /* Inode ID */\n                desc); \n    }\n    \n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, maps_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\nstatic ssize_t procfs_proc_vmstats(int pid, off_t off, size_t size, void *buf)\n{\n    struct proc *proc = proc_pid_find(pid);\n\n    if (!proc)\n        return -ENONET;\n\n    char vmstats_buf[4096];\n\n    int sz = 0;\n\n    struct queue *vm_entries = &proc->vm_space.vm_entries;\n\n    queue_for (node, vm_entries) {\n        struct vm_entry *vm_entry = node->value;\n\n        char perm[5] = {0};\n        perm[0] = vm_entry->flags & VM_UR? 'r' : '-';\n        perm[1] = vm_entry->flags & VM_UW? 'w' : '-';\n        perm[2] = vm_entry->flags & VM_UX? 'x' : '-';\n        perm[3] = vm_entry->flags & VM_SHARED? 's' : 'p';\n\n        const char *type = \"\";\n        switch (vm_entry->vm_object->type) {\n            case VMOBJ_FILE: type = \"file\"; break;\n            case VMOBJ_ZERO: type = \"anon\"; break;\n            //case VMOBJ_SHADOW: type = \"shadow\"; break;\n        }\n\n        /*\n        printk(\"%p-%p %s %p %p %s\\n\",\n                vm_entry->base,\n                vm_entry->base + vm_entry->size,\n                perm,\n                vm_entry->off,\n                vm_entry->vm_object,\n                type); \n                */\n\n        sz += snprintf(vmstats_buf + sz, sizeof(vmstats_buf) - sz,\n                \"%p-%p %s %p %p %s\\n\",\n                vm_entry->base,\n                vm_entry->base + vm_entry->size,\n                perm,\n                vm_entry->off,\n                vm_entry->vm_object,\n                0); //type); \n    }\n    \n    if (off < sz) {\n        ssize_t ret = MIN(size, (size_t)(sz - off));\n        memcpy(buf, vmstats_buf + off, ret);\n        return ret;\n    }\n\n    return 0;\n}\n\nstruct procfs_proc_entry {\n    char *name;\n    ssize_t (*read)(int pid, off_t off, size_t size, void *buf);\n};\n\nstatic struct procfs_proc_entry proc_entries[] = {\n    {\"status\", procfs_proc_status},\n    {\"maps\", procfs_proc_maps},\n    {\"vmstats\", procfs_proc_vmstats},\n};\n\n#define PROCFS_PROC_ENTRIES  (sizeof(proc_entries)/sizeof(proc_entries[0]))\n\nstatic ssize_t procfs_read(struct vnode *node, off_t offset, size_t size, void *buf)\n{\n    size_t id = (size_t) node->p;\n\n    if ((ssize_t) node->ino < 0) {\n        if (id < PROCFS_ENTRIES)\n            return entries[id].read(offset, size, buf);\n    } else {\n        size_t pid = node->ino / (PROCFS_PROC_ENTRIES + 1);\n        id -= 1;\n        if (id < PROCFS_PROC_ENTRIES)\n            return proc_entries[id].read(pid, offset, size, buf);\n    }\n\n    return -ENOSYS;\n}\n\nstatic ssize_t procfs_readdir(struct vnode *vnode, off_t offset, struct dirent *dirent)\n{\n    //printk(\"procfs_readdir(vnode=%p, offset=%d, dirent=%p)\\n\", vnode, offset, dirent);\n\n    if (vnode == procfs_root) {\n        if (offset == 0) {\n            dirent->d_ino = 0;\n            strcpy(dirent->d_name, \".\");\n            return 1;\n        } else if (offset == 1) {\n            dirent->d_ino = 1;\n            strcpy(dirent->d_name, \"..\");\n            return 1;\n        }\n\n        offset -= 2;\n\n        if ((size_t) offset < PROCFS_ENTRIES) {\n            //dirent->d_ino = entries[offset].id;\n            strcpy(dirent->d_name, entries[offset].name);\n            return 1;\n        }\n\n        /* Processes go here */\n        offset -= PROCFS_ENTRIES;\n        \n        if (!offset) {\n            snprintf(dirent->d_name, 10, \"self\");\n            return 1;\n        }\n\n        --offset;\n\n        queue_for (node, procs) {\n            if (!offset) {\n                struct proc *proc = node->value;\n                snprintf(dirent->d_name, 10, \"%d\", proc->pid);\n                return 1;\n            }\n\n            --offset;\n        }\n    } else if (vnode->ino > 0) {\n        size_t pid = vnode->ino / (PROCFS_PROC_ENTRIES + 1);\n\n        if (offset == 0) {\n            dirent->d_ino = 0;\n            strcpy(dirent->d_name, \".\");\n            return 1;\n        } else if (offset == 1) {\n            dirent->d_ino = 1;\n            strcpy(dirent->d_name, \"..\");\n            return 1;\n        }\n\n        offset -= 2;\n\n        if ((size_t) offset < PROCFS_PROC_ENTRIES) {\n            strcpy(dirent->d_name, proc_entries[offset].name);\n            return 1;\n        }\n    }\n\n    return 0;\n}\n\nstatic int procfs_finddir(struct vnode *parent, const char *name, struct dirent *dirent)\n{\n    //printk(\"procfs_finddir(parent=%p, name=%s, dirent=%p)\\n\", parent, name, dirent);\n\n    if (parent->ino == (ino_t) procfs_root) {\n        for (size_t i = 0; i < PROCFS_ENTRIES; ++i) {\n            if (!strcmp(name, entries[i].name)) {\n                dirent->d_ino  = -(i + 1);\n                return 0;\n            }\n        }\n\n        if (!strcmp(name, \"self\")) {\n            dirent->d_ino = curproc->pid * (PROCFS_PROC_ENTRIES + 1);\n            return 0;\n        }\n\n        queue_for (node, procs) {\n            struct proc *proc = node->value;\n            char buf[10];\n            snprintf(buf, 10, \"%d\", proc->pid);\n\n            if (!strcmp(buf, name)) {\n                dirent->d_ino = proc->pid * (PROCFS_PROC_ENTRIES + 1);\n                return 0;\n            }\n        }\n    } else if (parent->ino > 0) {\n        size_t pid = parent->ino / (PROCFS_PROC_ENTRIES + 1);\n\n        for (size_t i = 0; i < PROCFS_PROC_ENTRIES; ++i) {\n            if (!strcmp(proc_entries[i].name, name)) {\n                dirent->d_ino  = pid * (PROCFS_PROC_ENTRIES + 1) + i + 1;\n                return 0;\n            }\n        }\n    }\n\n    return -ENOENT;\n}\n\nstatic int procfs_vget(struct vnode *super, ino_t ino, struct vnode **vnode)\n{\n    //printk(\"procfs_vget(super=%p, ino=%d, vnode=%p)\\n\", super, ino, vnode);\n\n    int err = 0;\n\n    if (ino == (vino_t) procfs_root) {\n        if (vnode) *vnode = procfs_root;\n        return 0;\n    } else if ((ssize_t) ino < 0) {\n        intptr_t id = -ino - 1;\n\n        if ((size_t) id < PROCFS_ENTRIES) {\n            struct vnode *node = NULL;\n            if (!(node = vcache_find(&procfs_vcache, id))) { /* Not in open vnode table? */\n                node = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n                if (!node) goto e_nomem;\n\n                node->ino  = ino;\n                node->mode = S_IFREG | 0555;\n                node->fs   = &procfs;\n                node->p    = (void *) id;\n\n                struct timespec ts;\n                gettime(&ts);\n\n                node->ctime = ts;\n                node->atime = ts;\n                node->mtime = ts;\n\n                vcache_insert(&procfs_vcache, node);\n            }\n\n            if (vnode) *vnode = node;\n            return 0;\n        } else {\n            return -ENONET;\n        }\n    } else {\n        size_t pid = ino / (PROCFS_PROC_ENTRIES + 1);\n        size_t id  = ino % (PROCFS_PROC_ENTRIES + 1);\n        struct vnode *node = NULL;\n\n        if (!(node = vcache_find(&procfs_vcache, ino))) { /* Not in open vnode table? */\n            node = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n            if (!node) goto e_nomem;\n\n            node->ino = ino;\n\n            if (id) {\n                //node->name = proc_entries[id].name;\n                node->mode = S_IFREG | 0555;\n            } else {\n                node->mode = S_IFDIR | 0555;\n            }\n\n            node->fs   = &procfs;\n            node->p    = (void *) id;\n\n            struct timespec ts;\n            gettime(&ts);\n\n            node->ctime = ts;\n            node->atime = ts;\n            node->mtime = ts;\n\n            vcache_insert(&procfs_vcache, node);\n        }\n\n        if (vnode) *vnode = node;\n\n        return 0;\n    }\n\ne_nomem:\n    err = -ENOMEM;\nerror:\n    return err;\n}\n\nstatic int procfs_close(struct vnode *vnode)\n{\n    /* we can't free the root vnode */\n    if (vnode == procfs_root) {\n        /* should we panic here? */\n        return 0;\n    }\n\n    if (vnode->ref == 0) {\n        if (vcache_find(&procfs_vcache, vnode->ino))\n            vcache_remove(&procfs_vcache, vnode);\n\n        kfree(vnode);\n    }\n\n    return 0;\n}\n\nstatic int procfs_init()\n{\n    procfs_root = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n    if (!procfs_root) return -ENOMEM;\n\n    procfs_root->mode = S_IFDIR | 0555;\n    procfs_root->ino  = (vino_t) procfs_root;\n    procfs_root->fs   = &procfs;\n    procfs_root->ref  = 1;\n\n    struct timespec ts;\n    gettime(&ts);\n\n    procfs_root->ctime = ts;\n    procfs_root->atime = ts;\n    procfs_root->mtime = ts;\n\n    vcache_init(&procfs_vcache);\n\n    vfs_install(&procfs);\n    return 0;\n}\n\nstatic int procfs_mount(const char *dir, int flags, void *data)\n{\n    vfs_bind(dir, procfs_root);\n    return 0;\n}\n\nstruct fs procfs = {\n    .name  = \"procfs\",\n    .nodev = 1,\n    .init  = procfs_init,\n    .mount = procfs_mount,\n\n    .vops = {\n        .read    = procfs_read,\n        .readdir = procfs_readdir,\n        .finddir = procfs_finddir,\n        .vget    = procfs_vget,\n        .close   = procfs_close,\n    },\n\n    .fops = {\n        .open    = posix_file_open,\n        .read    = posix_file_read,\n        .readdir = posix_file_readdir,\n        .close   = posix_file_close,\n\n        .eof     = __vfs_eof_always, /* XXX */\n    },\n};\n\nMODULE_INIT(procfs, procfs_init, NULL)\n"
  },
  {
    "path": "kernel/fs/pseudofs/Build.mk",
    "content": "obj-y += pseudofs.o\n"
  },
  {
    "path": "kernel/fs/pseudofs/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/fs/pseudofs/pseudofs.c",
    "content": "#include <core/system.h>\n#include <core/time.h>\n\n#include <fs/pseudofs.h>\n\nMALLOC_DEFINE(M_PSEUDOFS_DENT, \"pseudofs-dirent\", \"pseudofs directory entry\");\n\nint pseudofs_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)\n{\n    int err = 0;\n    struct vnode *vnode = NULL;\n    struct pseudofs_dirent *dirent = NULL;\n\n    struct dirent dirent_tmp;\n    if (!pseudofs_finddir(dir, fn, &dirent_tmp)) {\n        err = -EEXIST;\n        goto error;\n    }\n\n    vnode = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n    if (!vnode) goto error_nomem;\n    \n    vnode->ino   = (ino_t) vnode;\n    vnode->mode  = mode;\n    vnode->size  = 0;\n    vnode->uid   = uio->uid;\n    vnode->gid   = uio->gid;\n    vnode->nlink = S_ISDIR(mode)? 2 : 1;\n    vnode->rdev  = dev;\n\n    struct timespec ts;\n    gettime(&ts);\n\n    vnode->ctime = ts;\n    vnode->atime = ts;\n    vnode->mtime = ts;\n\n    vnode->fs = dir->fs;    /* Copy filesystem from directory */\n\n    struct pseudofs_dirent *cur_dir = (struct pseudofs_dirent *) dir->p;\n\n    dirent = kmalloc(sizeof(struct pseudofs_dirent), &M_PSEUDOFS_DENT, 0);\n    if (!dirent) goto error_nomem;\n\n    dirent->d_ino  = vnode;\n    dirent->d_name = strdup(fn);\n\n    if (!dirent->d_name) goto error_nomem;\n\n    dirent->next  = cur_dir;\n    dir->p        = dirent;\n\n    if (ref)\n        *ref = vnode;\n\n    return 0;\n\nerror_nomem:\n    err = -ENOMEM;\n    goto error;\n\nerror:\n    if (vnode)\n        kfree(vnode);\n\n    if (dirent) {\n        if (dirent->d_name)\n            kfree((void *) dirent->d_name);\n\n        kfree(dirent);\n    }\n\n    return err;\n}\n\nint pseudofs_vunlink(struct vnode *vnode, const char *fn, struct uio *uio)\n{\n    int err = 0;\n    struct pseudofs_dirent *dir;\n    struct vnode *next;\n    struct pseudofs_dirent *prev, *cur;\n\n    if (!S_ISDIR(vnode->mode))\n        return -ENOTDIR;\n\n    dir   = (struct pseudofs_dirent *) vnode->p;\n    next  = NULL;\n\n    if (!dir)  /* Directory not initialized */\n        return -ENOENT;\n\n    prev = cur = NULL;\n    for (struct pseudofs_dirent *dirent = dir; dirent; dirent = dirent->next) {\n        if (!strcmp(dirent->d_name, fn)) {\n            cur = dirent;\n            goto found;\n        }\n\n        prev = dirent;\n    }\n\n    return -ENOENT;    /* File not found */\n\nfound:\n    if (prev)\n        prev->next = cur->next;\n    else\n        vnode->p   = cur->next;\n\n    cur->d_ino->nlink = 0;   /* XXX */\n\n    if (cur->d_ino->ref == 0) {\n        cur->d_ino->ref = 1; /* vfs_close will decrement ref */\n        vfs_close(cur->d_ino);\n    }\n\n    return 0;\n}\n\nssize_t pseudofs_readdir(struct vnode *dir, off_t offset, struct dirent *dirent)\n{\n    if (offset == 0) {\n        strcpy(dirent->d_name, \".\");\n        return 1;\n    }\n\n    if (offset == 1) {\n        strcpy(dirent->d_name, \"..\");\n        return 1;\n    }\n\n    struct pseudofs_dirent *_dirent = (struct pseudofs_dirent *) dir->p;\n\n    if (!_dirent)\n        return 0;\n\n    int found = 0;\n\n    offset -= 2;\n\n    int i = 0;\n    for (struct pseudofs_dirent *e = _dirent; e; e = e->next) {\n        if (i == offset) {\n            found = 1;\n            dirent->d_ino = e->d_ino->ino;\n            strcpy(dirent->d_name, e->d_name);\n            break;\n        }\n        ++i;\n    }\n\n    return found;\n}\n\nint pseudofs_finddir(struct vnode *dir, const char *name, struct dirent *dirent)\n{\n    if (!dir || !name || !dirent)\n        return -EINVAL;\n\n    if (!S_ISDIR(dir->mode))\n        return -ENOTDIR;\n\n    struct pseudofs_dirent *_dirent = (struct pseudofs_dirent *) dir->p;\n    if (!_dirent) return -ENOENT;\n\n    for (struct pseudofs_dirent *e = _dirent; e; e = e->next) {\n        if (!strcmp(name, e->d_name)) {\n            dirent->d_ino = e->d_ino->ino;\n            strcpy(dirent->d_name, e->d_name);\n            return 0;\n        }\n    }\n\n    return -ENOENT;\n}\n\nint pseudofs_close(struct vnode *vnode)\n{\n    /* XXX */\n    //kfree(inode->name);\n    kfree(vnode);\n    return 0;\n}\n"
  },
  {
    "path": "kernel/fs/read.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <dev/dev.h>\n\n/**\n * \\ingroup vfs\n * \\brief read data from a vnode\n */\nssize_t vfs_read(struct vnode *vnode, off_t off, size_t size, void *buf)\n{\n    vfs_log(LOG_DEBUG, \"vfs_read(vnode=%p, off=%d, size=%d, buf=%p)\\n\", vnode, off, size, buf);\n\n    /* invalid request */\n    if (!vnode)\n        return -EINVAL;\n\n    /* device node */\n    if (ISDEV(vnode))\n        return kdev_read(&VNODE_DEV(vnode), off, size, buf);\n\n    /* invalid request */\n    if (!vnode->fs)\n        return -EINVAL;\n\n    /* operation not supported */\n    if (!vnode->fs->vops.read)\n        return -ENOSYS;\n\n    return vnode->fs->vops.read(vnode, off, size, buf);\n}\n"
  },
  {
    "path": "kernel/fs/readdir.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n\n/** read entries from a directory vnode\n * \\ingroup vfs\n */\nssize_t vfs_readdir(struct vnode *dir, off_t off, struct dirent *dirent)\n{\n    vfs_log(LOG_DEBUG, \"vfs_readdir(dir=%p, off=%d, dirent=%p)\\n\", dir, off, dirent);\n\n    /* Invalid request */\n    if (!dir || !dir->fs)\n        return -EINVAL;\n\n    if (!S_ISDIR(dir->mode))\n        return -ENOTDIR;\n\n    /* Operation not supported */\n    if (!dir->fs->vops.readdir)\n        return -ENOSYS;\n\n    return dir->fs->vops.readdir(dir, off, dirent);\n}\n\nint vfs_finddir(struct vnode *dir, const char *name, struct dirent *dirent)\n{\n    vfs_log(LOG_DEBUG, \"vfs_finddir(dir=%p, name=%s, dirent=%p)\\n\", dir, name, dirent);\n\n    if (!dir || !dir->fs)\n        return -EINVAL;\n\n    if (!S_ISDIR(dir->mode))\n        return -ENOTDIR;\n\n    if (!dir->fs->vops.finddir)\n        return -ENOSYS;\n\n    return dir->fs->vops.finddir(dir, name, dirent);\n}\n"
  },
  {
    "path": "kernel/fs/rofs.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <fs/rofs.h>\n\nssize_t rofs_write(struct vnode *vnode, off_t offset, size_t size, void *buf)\n{\n    return -EROFS;\n}\n\nint rofs_trunc(struct vnode *vnode, off_t len)\n{\n    return -EROFS;\n}\n\nint rofs_vmknod(struct vnode *dir, const char *fn, uint32_t mode, dev_t dev, struct uio *uio, struct vnode **ref)\n{\n    return -EROFS;\n}\n\nint rofs_vunlink(struct vnode *dir, const char *fn, struct uio *uio)\n{\n    return -EROFS;\n}\n"
  },
  {
    "path": "kernel/fs/stat.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <fs/stat.h>\n\nint vfs_stat(struct vnode *vnode, struct stat *buf)\n{\n    vfs_log(LOG_DEBUG, \"vfs_stat(vnode=%p, buf=%p)\\n\", vnode, buf);\n\n    buf->st_dev   = vnode->dev;\n    buf->st_ino   = vnode->ino;\n    buf->st_mode  = vnode->mode;\n    buf->st_nlink = vnode->nlink;\n    buf->st_uid   = vnode->uid;\n    buf->st_gid   = vnode->gid;\n    buf->st_rdev  = vnode->rdev;\n    buf->st_size  = vnode->size;\n    buf->st_mtime = vnode->mtime;\n    buf->st_atime = vnode->atime;\n    buf->st_ctime = vnode->ctime;\n\n    return 0;\n}\n\n"
  },
  {
    "path": "kernel/fs/sync.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <bits/errno.h>\n\n/**\n * \\ingroup vfs\n * \\brief sync the metadata and/or data associated with a vnode\n */\nint vfs_vsync(struct vnode *vnode, int mode)\n{\n    return -ENOTSUP;\n}\n\n/**\n * \\ingroup vfs\n * \\brief sync the metadata and/or data associated with a filesystem\n */\nint vfs_fssync(struct vnode *super, int mode)\n{\n    return -ENOTSUP;\n}\n\n/**\n * \\ingroup vfs\n * \\brief sync all metadata and/or data of all filesystems\n */\nint vfs_sync(int mode)\n{\n    return -ENOTSUP;\n}\n"
  },
  {
    "path": "kernel/fs/tmpfs/Build.mk",
    "content": "obj-y += tmpfs.o\n"
  },
  {
    "path": "kernel/fs/tmpfs/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/fs/tmpfs/tmpfs.c",
    "content": "/**\n * \\defgroup fs-tmpfs kernel/fs/tmpfs\n * \\brief temporary filesystem (tmpfs) handler\n */\n\n#include <core/system.h>\n#include <core/module.h>\n#include <core/string.h>\n#include <core/panic.h>\n#include <core/time.h>\n\n#include <mm/mm.h>\n\n#include <fs/vfs.h>\n#include <fs/pseudofs.h>\n#include <fs/tmpfs.h>\n#include <fs/posix.h>\n\n#include <bits/errno.h>\n#include <bits/dirent.h>\n\nstatic int tmpfs_vget(struct vnode *super, ino_t ino, struct vnode **vnode)\n{\n    /* vnode is always present in memory */\n    struct vnode *node = (struct vnode *) ino;\n    if (vnode) *vnode = node;\n\n    return 0;\n}\n\nstatic int tmpfs_close(struct vnode *vnode)\n{\n    /* Inode is always present in memory */\n\n    if (!vnode->ref && !vnode->nlink) {\n        /* vnode is no longer referenced */\n        kfree(vnode->p);\n        pseudofs_close(vnode);\n    }\n\n    return 0;\n}\n\nstatic ssize_t tmpfs_read(struct vnode *node, off_t offset, size_t size, void *buf)\n{\n    if (!node->size)\n        return 0;\n\n    ssize_t r = MIN(node->size - offset, size);\n    memcpy(buf, (char *) node->p + offset, r);\n    return r;\n}\n\nstatic ssize_t tmpfs_write(struct vnode *node, off_t offset, size_t size, void *buf)\n{\n    if (!node->size) {\n        size_t sz = (size_t) offset + size;\n        node->p = kmalloc(sz, &M_BUFFER, 0);\n        node->size = sz;\n    }\n\n    if (((size_t) offset + size) > node->size) {    /* Reallocate */\n        size_t sz = (size_t) offset + size;\n        void *new = kmalloc(sz, &M_BUFFER, 0);\n        memcpy(new, node->p, node->size);\n        kfree(node->p);\n        node->p = new;\n        node->size = sz;\n    }\n\n    memcpy((char *) node->p + offset, buf, size);\n    return size;\n}\n\nstatic int tmpfs_trunc(struct vnode *vnode, off_t len)\n{\n    if (!vnode)\n        return -EINVAL;\n\n    if ((size_t) len == vnode->size)\n        return 0;\n\n    if (len == 0) {\n        kfree(vnode->p);\n        vnode->size = 0;\n        return 0;\n    }\n\n    size_t sz = MIN((size_t) len, vnode->size);\n    char *buf = kmalloc(len, &M_BUFFER, 0);\n\n    if (!buf)\n        panic(\"failed to allocate buffer\");\n\n    memcpy(buf, vnode->p, sz);\n\n    if ((size_t) len > vnode->size)\n        memset(buf + vnode->size, 0, len - vnode->size);\n\n    kfree(vnode->p);\n    vnode->p    = buf;\n    vnode->size = len;\n    return 0;\n}\n\n/* ================ File Operations ================ */\n\nstatic int tmpfs_file_can_read(struct file *file, size_t size)\n{\n    if ((size_t) file->offset + size < file->vnode->size)\n        return 1;\n\n    return 0;\n}\n\nstatic int tmpfs_file_can_write(struct file *file __unused, size_t size __unused)\n{\n    /* TODO impose limit */\n    return 1;\n}\n\nstatic int tmpfs_file_eof(struct file *file)\n{\n    return (size_t) file->offset == file->vnode->size;\n}\n\nstatic int tmpfs_init()\n{\n    return vfs_install(&tmpfs);\n}\n\nstatic int tmpfs_mount(const char *dir, int flags __unused, void *data __unused)\n{\n    /* Initalize new */\n    struct vnode *tmpfs_root = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);\n    if (!tmpfs_root) return -ENOMEM;\n\n    uint32_t mode = 0777;\n\n    struct mdata {\n        char *dev;\n        char *opt;\n    } *mdata = data;\n\n    if (mdata->opt) {\n        char **tokens = tokenize(mdata->opt, ',');\n        for (char **token_p = tokens; *token_p; ++token_p) {\n            char *token = *token_p;\n            if (!strncmp(token, \"mode=\", 5)) {    /* ??? */\n                char *t = token + 5;\n                mode = 0;\n                while (*t) {\n                    mode <<= 3;\n                    mode |= (*t++ - '0');\n                }\n            }\n        }\n    }\n\n    tmpfs_root->ino   = (vino_t) tmpfs_root;\n    tmpfs_root->mode  = S_IFDIR | mode;\n    tmpfs_root->size  = 0;\n    tmpfs_root->nlink = 2;\n    tmpfs_root->fs    = &tmpfs;\n    tmpfs_root->p     = NULL;\n    tmpfs_root->ref   = 1;\n\n    struct timespec ts;\n    gettime(&ts);\n\n    tmpfs_root->ctime = ts;\n    tmpfs_root->atime = ts;\n    tmpfs_root->mtime = ts;\n\n    vfs_bind(dir, tmpfs_root);\n\n    return 0;\n}\n\nstruct fs tmpfs = {\n    .name   = \"tmpfs\",\n    .nodev  = 1,\n    .init   = tmpfs_init,\n    .mount  = tmpfs_mount,\n\n    .vops = {\n        .read    = tmpfs_read,\n        .write   = tmpfs_write,\n        .close   = tmpfs_close,\n        .trunc   = tmpfs_trunc,\n\n        .readdir = pseudofs_readdir,\n        .finddir = pseudofs_finddir,\n\n        .vmknod  = pseudofs_vmknod,\n        .vunlink = pseudofs_vunlink,\n        .vget    = tmpfs_vget,\n    },\n    \n    .fops = {\n        .open    = posix_file_open,\n        .close   = posix_file_close,\n        .read    = posix_file_read,\n        .write   = posix_file_write, \n        .ioctl   = posix_file_ioctl,\n        .lseek   = posix_file_lseek,\n        .readdir = posix_file_readdir,\n        .trunc   = posix_file_trunc,\n\n        .can_read  = tmpfs_file_can_read,\n        .can_write = tmpfs_file_can_write,\n        .eof       = tmpfs_file_eof,\n    },\n};\n\nMODULE_INIT(tmpfs, tmpfs_init, NULL)\n"
  },
  {
    "path": "kernel/fs/trunc.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <dev/dev.h>\n\nint vfs_trunc(struct vnode *vnode, off_t len)\n{\n    vfs_log(LOG_DEBUG, \"vfs_trunc(vnode=%p, len=%d)\\n\", vnode, len);\n\n    /* Invalid request */\n    if (!vnode)\n        return -EINVAL;\n\n    /* Device node */\n    if (ISDEV(vnode))\n        return -EINVAL;\n\n    /* Invalid request */\n    if (!vnode->fs)\n        return -EINVAL;\n\n    /* Operation not supported */\n    if (!vnode->fs->vops.trunc)\n        return -ENOSYS;\n\n    return vnode->fs->vops.trunc(vnode, len);\n}\n\n"
  },
  {
    "path": "kernel/fs/unlink.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n\nint vfs_unlink(const char *path, struct uio *uio)\n{\n    int ret = 0;\n    struct vfs_path *p = NULL;\n    char **tokens = NULL;\n\n    /* if path is NULL pointer, or path is empty string, return NULL */\n    if (!path ||  !*path)\n        return -ENOENT;\n\n    char *_path = NULL;\n    if ((ret = vfs_parse_path(path, uio, &_path)))\n        goto error;\n\n    /* Canonicalize Path */\n    tokens = tokenize_path(_path);\n\n    /* Get mountpoint & path */\n    p = vfs_get_mountpoint(tokens);\n\n    struct vnode *dir = p->root;\n    char *name = NULL;\n    char **tok = p->tokens;\n\n    while (tok) {\n        char *token = *tok;\n\n        if (!*(tok + 1)) {\n            name = token;\n            break;\n        }\n\n        struct dirent dirent;\n        if ((ret = vfs_finddir(dir, token, &dirent)))\n            goto error;\n\n        if ((ret = vfs_vget(p->root, dirent.d_ino, &dir)))\n            goto error;\n\n        ++tok;\n    }\n\n    if ((ret = vfs_vunlink(dir, name, uio)))\n        goto error;\n\n    free_tokens(tokens);\n    kfree(p);\n    kfree(_path);\n    return 0;\n\nerror:\n    if (tokens)\n        free_tokens(tokens);\n    if (p)\n        kfree(p);\n    if (_path)\n        kfree(_path);\n    return ret;\n}\n"
  },
  {
    "path": "kernel/fs/vcache.c",
    "content": "#include <core/system.h>\n#include <fs/vcache.h>\n\nMALLOC_DEFINE(M_VCACHE, \"vcache\", \"vnode cache structure\");\n\nstatic int vcache_eq(void *_a, void *_b)\n{\n    struct vnode *a = (struct vnode *) _a;\n    ino_t *b = (ino_t *) _b;\n\n    return a->ino == *b;\n}\n\n/**\n * \\ingroup vfs\n * \\brief initialize vnode caching structure\n */\nvoid vcache_init(struct vcache *vcache)\n{\n    vcache->hashmap = hashmap_new(0, vcache_eq);\n}\n\nint vcache_insert(struct vcache *vcache, struct vnode *vnode)\n{\n    if (!vcache)\n        return -EINVAL;\n\n    if (!vcache->hashmap)\n        vcache_init(vcache);\n\n    hash_t hash = hashmap_digest(&vnode->ino, sizeof(vnode->ino));\n    return hashmap_insert(vcache->hashmap, hash, vnode);\n}\n\nint vcache_remove(struct vcache *vcache, struct vnode *vnode)\n{\n    if (!vcache || !vcache->hashmap)\n        return -1;\n\n    hash_t hash = hashmap_digest(&vnode->ino, sizeof(ino_t));\n\n    struct hashmap_node *node = hashmap_lookup(vcache->hashmap, hash, &vnode->ino);\n\n    if (node) {\n        hashmap_node_remove(vcache->hashmap, node);\n        return 0;\n    }\n\n    return -1;\n}\n\nstruct vnode *vcache_find(struct vcache *vcache, ino_t ino)\n{\n    if (!vcache || !vcache->hashmap)\n        return NULL;\n\n    hash_t hash = hashmap_digest(&ino, sizeof(ino));\n\n    struct hashmap_node *node = hashmap_lookup(vcache->hashmap, hash, &ino);\n\n    if (node) {\n        return (struct vnode *) node->entry;\n    }\n\n    return NULL;\n}\n"
  },
  {
    "path": "kernel/fs/vfs.c",
    "content": "/**\n * \\defgroup vfs kernel/vfs\n * \\brief virtual filesystem\n */\n\n#include <core/system.h>\n#include <core/string.h>\n#include <mm/mm.h>\n#include <fs/vfs.h>\n#include <sys/proc.h>\n#include <sys/sched.h>\n#include <bits/fcntl.h>\n#include <bits/errno.h>\n#include <dev/dev.h>\n#include <net/socket.h>\n\nMALLOC_DEFINE(M_VNODE, \"vnode\", \"vnode structure\");\nMALLOC_DEFINE(M_VFS_PATH, \"vfs-path\", \"vfs path structure\");\nMALLOC_DEFINE(M_VFS_NODE, \"vfs-node\", \"vfs node structure\");\nMALLOC_DEFINE(M_FS_LIST, \"fs-list\", \"filesystems list\");\n\nstatic int vfs_log_level = LOG_NONE;\nLOGGER_DEFINE(vfs, vfs_log, vfs_log_level)\n\n/** list of registered filesystems */\nstruct fs_list *registered_fs = NULL;\n\n/* vfs mountpoints graph */\nstruct vfs_node {\n    const char *name;\n    struct vfs_node *children;\n    struct vfs_node *next;\n\n    /* reference to node */\n    struct vnode *vnode;\n} vfs_graph = {\n    .name = \"/\",\n};\n\n/* ================== VFS Graph helpers ================== */\n\nstruct vnode *vfs_root = NULL;\nint vfs_mount_root(struct vnode *vnode)\n{\n    /* TODO Flush mountpoints */\n    vfs_root = vnode;\n    vfs_graph.vnode = vnode;\n    vfs_graph.children = NULL;  /* XXX */\n\n    return 0;\n}\n\nchar **tokenize_path(const char * const path)\n{\n    /* Tokenize slash seperated words in path into tokens */\n    char **tokens = tokenize(path, '/');\n    return tokens;\n}\n\nint vfs_parse_path(const char *path, struct uio *uio, char **abs_path)\n{\n    if (!path || !*path)\n        return -ENOENT;\n\n    char *cwd = uio->cwd;\n\n    if (*path == '/') { /* Absolute path */\n        cwd = \"/\";\n    }\n\n    size_t cwd_len = strlen(cwd), path_len = strlen(path);\n    char *buf = kmalloc(cwd_len + path_len + 2, &M_BUFFER, 0);\n\n    memcpy(buf, cwd, cwd_len);\n\n    buf[cwd_len] = '/';\n    memcpy(buf + cwd_len + 1, path, path_len);\n    buf[cwd_len + path_len + 1] = 0;\n\n    /* Tokenize slash seperated words in path into tokens */\n    char **tokens = tokenize(buf, '/');\n    char *out = kmalloc(cwd_len + path_len + 1, &M_BUFFER, 0);\n\n    char *valid_tokens[512];\n    size_t i = 0;\n\n    for (char **token_p = tokens; *token_p; ++token_p) {\n        char *token = *token_p;\n        if (token[0] == '.') {\n            if (token[1] == '\\0')\n                continue;\n\n            if (token[1] == '.') {\n                if (token[2] == '\\0') {\n                    if (i > 0)\n                        valid_tokens[--i] = NULL;\n                    continue;\n                }\n            }\n\n        }\n\n        if (*token) valid_tokens[i++] = token;\n    }\n\n    valid_tokens[i] = NULL;\n\n    out[0] = '/';\n\n    size_t j = 1;\n    for (char **token_p = valid_tokens; *token_p; ++token_p) {\n        char *token = *token_p;\n        size_t len = strlen(token);\n        memcpy(out + j, token, len);\n        j += len;\n        out[j] = '/';\n        ++j;\n    }\n\n    out[j > 1? --j : 1] = 0;\n\n    free_tokens(tokens);\n    kfree(buf);\n\n    if (abs_path)\n        *abs_path = out;\n    else\n        kfree(out);\n\n    return 0;\n}\n\nstruct vfs_path *vfs_get_mountpoint(char **tokens)\n{\n    struct vfs_path *path = kmalloc(sizeof(struct vfs_path), &M_VFS_PATH, 0);\n    path->tokens = tokens;\n\n    struct vfs_node *cur_node = &vfs_graph;\n    struct vfs_node *last_target_node = cur_node;\n\n    size_t token_i = 0;\n    int check_last_node = 0;\n\n    for (char **token_p = tokens; *token_p; ++token_p) {\n        char *token = *token_p;\n\n        check_last_node = 0;\n\n        if (cur_node->vnode) {\n            last_target_node = cur_node;\n            path->tokens = tokens + token_i;\n        }\n\n        if (cur_node->children) {\n            cur_node = cur_node->children;\n            for (struct vfs_node *m_node = cur_node; m_node; m_node = m_node->next) {\n                if (!strcmp(token, m_node->name)) {\n                    cur_node = m_node;\n                    check_last_node = 1;\n                    goto next;\n                }\n            }\n            /* Not found, break! */\n            break;\n        } else {\n            /* No children, break! */\n            break;\n        }\nnext:;\n        ++token_i;\n    }\n\n    if (check_last_node && cur_node->vnode) {\n        last_target_node = cur_node;\n        path->tokens = tokens + token_i;\n    }\n\n    path->root = last_target_node->vnode;\n\n    return path;\n}\n\n/**\n * \\ingroup vfs\n * \\brief  bind a vfs path to a vnode\n */\nint vfs_bind(const char *path, struct vnode *target)\n{\n    /* if path is NULL pointer, or path is empty string, or no target return EINVAL */\n    if (!path ||  !*path || !target)\n        return -EINVAL;\n\n    if (!strcmp(path, \"/\")) {\n        vfs_mount_root(target);\n        return 0;\n    }\n\n    /* Canonicalize Path */\n    char **tokens = tokenize_path(path);\n    \n    /* FIXME: should check for existence */\n\n    struct vfs_node *cur_node = &vfs_graph;\n\n    for (char **token_p = tokens; *token_p; ++token_p) {\n        char *token = *token_p;\n\n        if (cur_node->children) {\n            cur_node = cur_node->children;\n\n            /* Look for token in node children */\n            struct vfs_node *last_node = NULL;\n            for (struct vfs_node *node = cur_node; node; node = node->next) {\n                last_node = node;\n                if (!strcmp(node->name, token)) {   /* Found */\n                    cur_node = node;\n                    goto next;\n                }\n            }\n\n            /* Not found, create it */\n            struct vfs_node *new_node = kmalloc(sizeof(struct vfs_node), &M_VFS_NODE, M_ZERO);\n            if (!new_node) {\n                /* TODO */\n            }\n\n            new_node->name = strdup(token);\n            last_node->next = new_node;\n            cur_node = new_node;\n        } else {\n            struct vfs_node *new_node = kmalloc(sizeof(struct vfs_node), &M_VFS_NODE, M_ZERO);\n            if (!new_node) {\n                /* TODO */\n            }\n            new_node->name = strdup(token);\n            cur_node->children = new_node;\n            cur_node = new_node;\n        }\nnext:;\n    }\n\n    cur_node->vnode = target;\n    return 0;\n}\n\nvoid vfs_init(void)\n{\n    vfs_log(LOG_INFO, \"initializing\\n\");\n}\n\n/**\n * \\ingroup vfs\n * \\brief register a new filesystem handler\n */\nint vfs_install(struct fs *fs)\n{\n    struct fs_list *node = kmalloc(sizeof(struct fs_list), &M_FS_LIST, 0);\n    if (!node) return -ENOMEM;\n\n    node->name = fs->name;\n    node->fs   = fs;\n\n    node->next = registered_fs;\n    registered_fs = node;\n\n    vfs_log(LOG_INFO, \"registered filesystem %s\\n\", fs->name);\n\n    return 0;\n}\n\n/* ================== VFS high level mappings ================== */\n\nint vfs_perms_check(struct file *file, struct uio *uio)\n{\n    if (uio->uid == 0) {    /* Root */\n        return 0;\n    }\n\n    mode_t mode = file->vnode->mode;\n    uid_t  uid  = file->vnode->uid;\n    gid_t  gid  = file->vnode->gid;\n\nread_perms:\n    /* Read permissions */\n    if ((file->flags & O_ACCMODE) == O_RDONLY && (file->flags & O_ACCMODE) != O_WRONLY) {\n        if (uid == uio->uid) {\n            if (mode & S_IRUSR)\n                goto write_perms;\n        } else if (gid == uio->gid) {\n            if (mode & S_IRGRP)\n                goto write_perms;\n        } else {\n            if (mode & S_IROTH)\n                goto write_perms;\n        }\n\n        return -EACCES;\n    }\n\nwrite_perms:\n    /* Write permissions */\n    if (file->flags & (O_WRONLY | O_RDWR)) { \n        if (uid == uio->uid) {\n            if (mode & S_IWUSR)\n                goto exec_perms;\n        } else if (gid == uio->gid) {\n            if (mode & S_IWGRP)\n                goto exec_perms;\n        } else {\n            if (mode & S_IWOTH)\n                goto exec_perms;\n        }\n\n        return -EACCES;\n    }\n\nexec_perms:\n    /* Execute permissions */\n    if (file->flags & O_EXEC) { \n        if (uid == uio->uid) {\n            if (mode & S_IXUSR)\n                goto done;\n        } else if (gid == uio->gid) {\n            if (mode & S_IXGRP)\n                goto done;\n        } else {\n            if (mode & S_IXOTH)\n                goto done;\n        }\n\n        return -EACCES;\n    }\n    \ndone:\n    return 0;\n}\n"
  },
  {
    "path": "kernel/fs/vm_object.c",
    "content": "#include <core/system.h>\n#include <mm/vm.h>\n\nstatic struct vm_pager vnode_pager;\n\nstatic int vm_page_eq(void *_a, void *_b)\n{\n    struct vm_page *a = (struct vm_page *) _a;\n    size_t *b = (size_t *) _b;\n\n    return a->off == *b;\n}\n\n/**\n * \\ingroup vfs\n * \\brief create a new `vm_object` associated with a `vnode`\n */\nstruct vm_object *vm_object_vnode(struct vnode *vnode)\n{\n    if (!vnode)\n        return NULL;\n\n    if (!vnode->vm_object) {\n        struct vm_object *vm_object;\n\n        vm_object = kmalloc(sizeof(struct vm_object), &M_VM_OBJECT, M_ZERO);\n        if (!vm_object) return NULL;\n\n        vm_object->type  = VMOBJ_FILE;\n        vm_object->pages = hashmap_new(0, vm_page_eq);\n\n        if (!vm_object->pages) {\n            kfree(vm_object);\n            return NULL;\n        }\n\n        vm_object->pager = &vnode_pager;\n        vm_object->p = vnode;\n\n        vnode->vm_object = vm_object;\n    }\n\n    return vnode->vm_object;\n}\n\n\nstatic char __load[PAGE_SIZE] __aligned(PAGE_SIZE);\nstruct vm_page *vnode_page_in(struct vm_object *vm_object, size_t off)\n{\n    struct vm_page *vm_page = mm_page_alloc();\n    if (!vm_page) return NULL;\n\n    vm_page->vm_object = vm_object;\n    vm_page->off = PAGE_ALIGN(off);\n    vm_page->ref = 1;\n\n    struct vnode *vnode = (struct vnode *) vm_object->p;\n\n    mm_page_map(kvm_space.pmap, (vaddr_t) __load, vm_page->paddr, VM_KW);\n    vfs_read(vnode, vm_page->off, PAGE_SIZE, (void *) __load);\n\n    vm_object_page_insert(vm_object, vm_page);\n\n    return vm_page;\n}\n\nstatic struct vm_pager vnode_pager = {\n    .in = vnode_page_in,\n    .out = NULL,\n};\n"
  },
  {
    "path": "kernel/fs/vops.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n\nint vfs_vmknod(struct vnode *dir, const char *name, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)\n{\n    /* Invalid request */\n    if (!dir || !dir->fs)\n        return -EINVAL;\n\n    /* Not a directory */\n    if (!S_ISDIR(dir->mode))\n        return -ENOTDIR;\n\n    /* Operation not supported */\n    if (!dir->fs->vops.vmknod)\n        return -ENOSYS;\n\n    int ret = dir->fs->vops.vmknod(dir, name, mode, dev, uio, ref);\n\n    if (!ret && ref && *ref)\n        (*ref)->ref++;\n\n    return ret;\n}\n\nint vfs_vcreat(struct vnode *dir, const char *name, struct uio *uio, struct vnode **ref)\n{\n    return vfs_vmknod(dir, name, S_IFREG, 0, uio, ref);\n}\n\nint vfs_vmkdir(struct vnode *dir, const char *name, struct uio *uio, struct vnode **ref)\n{\n    return vfs_vmknod(dir, name, S_IFDIR, 0, uio, ref);\n}\n\nint vfs_vunlink(struct vnode *dir, const char *fn, struct uio *uio)\n{\n    /* Invalid request */\n    if (!dir|| !dir->fs)\n        return -EINVAL;\n\n    /* Operation not supported */\n    if (!dir->fs->vops.vunlink)\n        return -ENOSYS;\n\n    return dir->fs->vops.vunlink(dir, fn, uio);\n}\n\nint vfs_vget(struct vnode *super, ino_t ino, struct vnode **ref)\n{\n    int err = 0;\n    struct vnode *vnode = NULL;\n\n    if (!super || !super->fs)\n        return -EINVAL;\n\n    if (!super->fs->vops.vget)\n        return -ENOSYS;\n\n    if ((err = super->fs->vops.vget(super, ino, &vnode)))\n        return err;\n\n    if (vnode) vnode->ref++;\n    if (ref) *ref = vnode;\n\n    return err;\n}\n\nint vfs_map(struct vm_space *vm_space, struct vm_entry *vm_entry)\n{\n    if (!vm_entry || !vm_entry->vm_object || vm_entry->vm_object->type != VMOBJ_FILE)\n        return -EINVAL;\n\n    struct vnode *vnode = (struct vnode *) vm_entry->vm_object->p;\n\n    if (!vnode || !vnode->fs)\n        return -EINVAL;\n\n    if (ISDEV(vnode))\n        return kdev_map(&VNODE_DEV(vnode), vm_space, vm_entry);\n\n    if (!vnode->fs->vops.map)\n        return -ENOSYS;\n\n    return vnode->fs->vops.map(vm_space, vm_entry);\n}\n"
  },
  {
    "path": "kernel/fs/write.c",
    "content": "#include <core/system.h>\n#include <fs/vfs.h>\n#include <dev/dev.h>\n\nssize_t vfs_write(struct vnode *vnode, off_t off, size_t size, void *buf)\n{\n    vfs_log(LOG_DEBUG, \"vfs_write(vnode=%p, off=%d, size=%d, buf=%p)\\n\", vnode, off, size, buf);\n\n    /* Invalid request */\n    if (!vnode)\n        return -EINVAL;\n\n    /* Device node */\n    if (ISDEV(vnode))\n        return kdev_write(&VNODE_DEV(vnode), off, size, buf);\n\n    /* Invalid request */\n    if (!vnode->fs)\n        return -EINVAL;\n\n    /* Operation not supported */\n    if (!vnode->fs->vops.write)\n        return -ENOSYS;\n\n    return vnode->fs->vops.write(vnode, off, size, buf);\n}\n\n"
  },
  {
    "path": "kernel/include/bits/dirent.h",
    "content": "#ifndef _BITS_DIRENT_H\n#define _BITS_DIRENT_H\n\n#include <stdint.h>\n\n#define MAXNAMELEN 256\n\n/**\n * \\ingroup vfs\n * \\brief directory entry\n */\nstruct dirent {\n    size_t d_ino;   // FIXME \n    char d_name[MAXNAMELEN];\n};\n\n#endif\n"
  },
  {
    "path": "kernel/include/bits/errno.h",
    "content": "#ifndef _ERRNO_H\n#define _ERRNO_H\n\n#define EPERM            1\n#define ENOENT           2\n#define ESRCH            3\n#define EINTR            4\n#define EIO              5\n#define ENXIO            6\n#define E2BIG            7\n#define ENOEXEC          8\n#define EBADF            9\n#define ECHILD          10\n#define EAGAIN          11\n#define ENOMEM          12\n#define EACCES          13\n#define EFAULT          14\n#define ENOTBLK         15\n#define EBUSY           16\n#define EEXIST          17\n#define EXDEV           18\n#define ENODEV          19\n#define ENOTDIR         20\n#define EISDIR          21\n#define EINVAL          22\n#define ENFILE          23\n#define EMFILE          24\n#define ENOTTY          25\n#define ETXTBSY         26\n#define EFBIG           27\n#define ENOSPC          28\n#define ESPIPE          29\n#define EROFS           30\n#define EMLINK          31\n#define EPIPE           32\n#define EDOM            33\n#define ERANGE          34\n#define EDEADLK         35\n#define ENAMETOOLONG    36\n#define ENOLCK          37\n#define ENOSYS          38\n#define ENOTEMPTY       39\n#define ELOOP           40\n#define EWOULDBLOCK     EAGAIN\n#define ENOMSG          42\n#define EIDRM           43\n#define ECHRNG          44\n#define EL2NSYNC        45\n#define EL3HLT          46\n#define EL3RST          47\n#define ELNRNG          48\n#define EUNATCH         49\n#define ENOCSI          50\n#define EL2HLT          51\n#define EBADE           52\n#define EBADR           53\n#define EXFULL          54\n#define ENOANO          55\n#define EBADRQC         56\n#define EBADSLT         57\n#define EDEADLOCK       EDEADLK\n#define EBFONT          59\n#define ENOSTR          60\n#define ENODATA         61\n#define ETIME           62\n#define ENOSR           63\n#define ENONET          64\n#define ENOPKG          65\n#define EREMOTE         66\n#define ENOLINK         67\n#define EADV            68\n#define ESRMNT          69\n#define ECOMM           70\n#define EPROTO          71\n#define EMULTIHOP       72\n#define EDOTDOT         73\n#define EBADMSG         74\n#define EOVERFLOW       75\n#define ENOTUNIQ        76\n#define EBADFD          77\n#define EREMCHG         78\n#define ELIBACC         79\n#define ELIBBAD         80\n#define ELIBSCN         81\n#define ELIBMAX         82\n#define ELIBEXEC        83\n#define EILSEQ          84\n#define ERESTART        85\n#define ESTRPIPE        86\n#define EUSERS          87\n#define ENOTSOCK        88\n#define EDESTADDRREQ    89\n#define EMSGSIZE        90\n#define EPROTOTYPE      91\n#define ENOPROTOOPT     92\n#define EPROTONOSUPPORT 93\n#define ESOCKTNOSUPPORT 94\n#define EOPNOTSUPP      95\n#define ENOTSUP         EOPNOTSUPP\n#define EPFNOSUPPORT    96\n#define EAFNOSUPPORT    97\n#define EADDRINUSE      98\n#define EADDRNOTAVAIL   99\n#define ENETDOWN        100\n#define ENETUNREACH     101\n#define ENETRESET       102\n#define ECONNABORTED    103\n#define ECONNRESET      104\n#define ENOBUFS         105\n#define EISCONN         106\n#define ENOTCONN        107\n#define ESHUTDOWN       108\n#define ETOOMANYREFS    109\n#define ETIMEDOUT       110\n#define ECONNREFUSED    111\n#define EHOSTDOWN       112\n#define EHOSTUNREACH    113\n#define EALREADY        114\n#define EINPROGRESS     115\n#define ESTALE          116\n#define EUCLEAN         117\n#define ENOTNAM         118\n#define ENAVAIL         119\n#define EISNAM          120\n#define EREMOTEIO       121\n#define EDQUOT          122\n#define ENOMEDIUM       123\n#define EMEDIUMTYPE     124\n#define ECANCELED       125\n#define ENOKEY          126\n#define EKEYEXPIRED     127\n#define EKEYREVOKED     128\n#define EKEYREJECTED    129\n#define EOWNERDEAD      130\n#define ENOTRECOVERABLE 131\n#define ERFKILL         132\n#define EHWPOISON       133\n\n#endif /* ! _ERRNO_H */\n"
  },
  {
    "path": "kernel/include/bits/fcntl.h",
    "content": "#ifndef _FCNTL_H\n#define _FCNTL_H\n\n#include <core/system.h>\n\n#define O_ACCMODE   (O_RDONLY|O_WRONLY|O_RDWR)\n\n#define O_RDONLY    0x000000\n#define O_WRONLY    0x000001\n#define O_RDWR      0x000002\n#define O_APPEND    0x000008\n#define O_CREAT     0x000200\n#define O_TRUNC     0x000400\n#define O_EXCL      0x000800\n#define O_SYNC      0x002000\n#define O_DSYNC     O_SYNC\n#define O_RSYNC     O_SYNC\n#define O_NONBLOCK  0x004000\n#define O_NOCTTY    0x008000\n#define O_CLOEXEC   0x040000\n#define O_NOFOLLOW  0x100000\n#define O_DIRECTORY 0x200000\n#define O_EXEC      0x400000 \n#define O_SEARCH    O_EXEC\n\n/* fcntl(2) requests */\n#define F_DUPFD         0   /* Duplicate fildes */\n#define F_GETFD         1   /* Get fildes flags (close on exec) */\n#define F_SETFD         2   /* Set fildes flags (close on exec) */\n#define F_GETFL         3   /* Get file flags */\n#define F_SETFL         4   /* Set file flags */\n#define F_GETOWN        5   /* Get owner - for ASYNC */\n#define F_SETOWN        6   /* Set owner - for ASYNC */\n#define F_GETLK         7   /* Get record-locking information */\n#define F_SETLK         8   /* Set or Clear a record-lock (Non-Blocking) */\n#define F_SETLKW        9   /* Set or Clear a record-lock (Blocking) */\n#define F_RGETLK        10  /* Test a remote lock to see if it is blocked */\n#define F_RSETLK        11  /* Set or unlock a remote lock */\n#define F_CNVT          12  /* Convert a fhandle to an open fd */\n#define F_RSETLKW       13  /* Set or Clear remote record-lock(Blocking) */\n#define F_DUPFD_CLOEXEC 14  /* As F_DUPFD, but set close-on-exec flag */\n\n#define FD_CLOEXEC      1\n\n#endif\n"
  },
  {
    "path": "kernel/include/bits/mman.h",
    "content": "#ifndef _BITS_MMAN_H\n#define _BITS_MMAN_H\n\n#define PROT_NONE   0x00000\n#define PROT_READ   0x00001\n#define PROT_WRITE  0x00002\n#define PROT_EXEC   0x00004\n\n#define MAP_FAILED  ((void *) 0)\n#define MAP_FIXED   0x00001\n#define MAP_PRIVATE 0x00002\n#define MAP_SHARED  0x00004\n\n#endif\n"
  },
  {
    "path": "kernel/include/bits/utsname.h",
    "content": "#ifndef _UTSNAME\n#define _UTSNAME\n\n#define MAX_LENGTH 64\n\nstruct utsname {\n    char  sysname[MAX_LENGTH];\n    char  nodename[MAX_LENGTH];\n    char  release[MAX_LENGTH];\n    char  version[MAX_LENGTH];\n    char  machine[MAX_LENGTH];\n};\n\n#endif /* ! _UTSNAME */\n"
  },
  {
    "path": "kernel/include/boot/boot.h",
    "content": "#ifndef _BOOT_H\n#define _BOOT_H\n\n#include <core/system.h>\n#include <sys/elf.h>\n\ntypedef struct {\n    void *addr;\n    size_t size;\n    char *cmdline;\n} module_t;\n\nenum mmap_type {\n    MMAP_USABLE   = 1,\n    MMAP_RESERVED = 2\n};\n\ntypedef struct {\n    enum mmap_type type;\n    uintptr_t start;\n    uintptr_t end;\n} mmap_t;\n\nstruct boot {\n    char *cmdline;\n    uintptr_t total_mem;\n    \n    int modules_count;\n    int mmap_count;\n    module_t *modules;\n    mmap_t *mmap;\n\n    struct elf32_shdr *shdr;\n    uint32_t shdr_num;\n\n    struct elf32_shdr *symtab;\n    size_t symnum;\n\n    struct elf32_shdr *strtab;\n};\n\n#endif\n"
  },
  {
    "path": "kernel/include/config.h",
    "content": "#ifndef _CONFIG_H\n#define _CONFIG_H\n\n/* test __GNUC__ last because some compilers report\n * compatability with gcc using __GNUC__\n */\n#if defined(__clang__)\n  #define __CONFIG_COMPILER__             \"clang\"\n  #define __CONFIG_COMPILER_VERSION__     __VERSION__\n#elif defined(__PCC__)\n  #define __CONFIG_COMPILER__             \"pcc\"\n  #define __CONFIG_COMPILER_VERSION__     __VERSION__\n#elif defined(__TINYC__)\n  #define __CONFIG_COMPILER__             \"tcc\"\n  #define __CONFIG_COMPILER_VERSION__     \"0.9.27\"\n#elif defined(__GNUC__)\n  #define __CONFIG_COMPILER__             \"gcc\"\n  #define __CONFIG_COMPILER_VERSION__     __VERSION__\n#else\n  #define __CONFIG_COMPILER__             \"unkown\"\n  #define __CONFIG_COMPILER_VERSION__     \"?\"\n#endif\n\n#define UTSNAME_SYSNAME  \"AquilaOS\"\n#define UTSNAME_RELEASE  \"v0.0.2\"\n#define UTSNAME_NODENAME \"aquila\"\n#define UTSNAME_VERSION  (__DATE__ \" \" __TIME__)\n\n#define __CONFIG_TIMESTAMP__            __DATE__ \" \" __TIME__\n\n/* Maximum number of file descriptors per process */\n#define FDS_COUNT   64\n\n/* Maximum user stack size */\n#define USER_STACK_SIZE (8192 * 1024U)\n\n#endif /* ! _CONFIG_H */\n"
  },
  {
    "path": "kernel/include/console/earlycon.h",
    "content": "#ifndef _EARLY_CONSOLE_H\n#define _EARLY_CONSOLE_H\n\n/**\n * \\brief early console\n */\nstruct earlycon {\n    void (*init)(void);\n    int  (*puts)(char *);\n    int  (*putc)(char);\n};\n\nvoid earlycon_init(void);\nvoid earlycon_reinit(void);\nint  earlycon_puts(char*);\nint  earlycon_putc(char);\n\n/* defined in core/printk.c */\nvoid earlycon_disable(void);\n\n#endif\n"
  },
  {
    "path": "kernel/include/core/arch.h",
    "content": "#ifndef _CORE_ARCH_H\n#define _CORE_ARCH_H\n\n#include <core/types.h>\n#include <sys/proc.h>\n\n/* arch/ARCH/sys/proc.c */\nvoid arch_proc_init(struct proc *proc);\nvoid arch_proc_kill(struct proc *proc);\nvoid arch_init_execve(struct proc *proc, int argc, char * const _argp[], int envc, char * const _envp[]);\nvoid arch_sleep(void);\n\n/* arch/ARCH/sys/thread.c */\nvoid arch_thread_create(struct thread *thread, uintptr_t stack, uintptr_t entry, uintptr_t uentry, uintptr_t arg);\nvoid arch_thread_kill(struct thread *thread);\nvoid arch_thread_spawn(struct thread *thread);\nvoid arch_thread_switch(struct thread *thread); // __attribute__((noreturn));\nvoid arch_idle(void);\n\n/* arch/ARCH/sys/fork.c */\nint arch_proc_fork(struct thread *thread, struct proc *fork);\n\n/* arch/ARCH/sys/syscall.c */\nvoid arch_syscall_return(struct thread *thread, uintptr_t val);\n\n/* arch/ARCH/sys/sched.c */\nvoid arch_sched_init(void);\nvoid arch_sched();\nvoid arch_cur_thread_kill(void);// __attribute__((noreturn));\n\n/* arch/ARCH/sys/execve.c */\nvoid arch_sys_execve(struct proc *proc, int argc, char * const argp[], int envc, char * const envp[]);\n\n/* arch/ARCH/sys/signal.c */\nvoid arch_handle_signal(int sig);\n\n/* arch/ARCH/mm/mm.c */\nvoid arch_mm_setup(void);\n\npaddr_t arch_page_get_mapping(struct pmap *pmap, vaddr_t vaddr);\n\nvoid arch_disable_interrupts(void);\n\nvoid arch_reboot(void);\n\nuint64_t arch_rtime_ns(void);\nuint64_t arch_rtime_us(void);\nuint64_t arch_rtime_ms(void);\n\nint arch_time_get(struct timespec *ts);\n\nvoid arch_stack_trace(void);\n\n#endif /* ! _CORE_ARCH_H */\n"
  },
  {
    "path": "kernel/include/core/assert.h",
    "content": "#ifndef _CORE_ASSERT_H\n#define _CORE_ASSERT_H\n\n#define assert(x) \\\n    if (!(x)) \\\n        panic(\"Assertion \" #x \" failed\");\n\n#define assert_sizeof(o, sz) \\\n    if (sizeof(o) != sz) \\\n        panic(\"Assertion sizeof(\" #o \") == \" #sz \" failed\");\n\n#define assert_alignof(o, al) \\\n    if (((uintptr_t) o) & (al - 1)) \\\n        panic(\"Assertion alignof(\" #o \") == \" #al \" failed\");\n\n#endif /* ! _CORE_ASSERT_H */\n"
  },
  {
    "path": "kernel/include/core/kargs.h",
    "content": "#ifndef _KARGS_H\n#define _KARGS_H\n\nint kargs_parse(const char *_cmdline);\nint kargs_get(const char *key, const char * const *value);\n\n#endif /* ! _KARGS_H */\n"
  },
  {
    "path": "kernel/include/core/module.h",
    "content": "#ifndef _MODULE_H\n#define _MODULE_H\n\n#define __CAT(a, b) a ## b\n#define MODULE_INIT(name, i, f) \\\n    __section(\".__minit\") void * __CAT(__minit_, name) = i;\\\n    __section(\".__mfini\") void * __CAT(__mfini_, name) = f;\\\n\nint modules_init(void);\n\n#endif\n"
  },
  {
    "path": "kernel/include/core/panic.h",
    "content": "#ifndef _CORE_PANIC_H\n#define _CORE_PANIC_H\n\n#include <core/system.h>\n#include <core/printk.h>\n#include <core/arch.h>\n\n#define __PANIC_MSG \"Bailing out. You are on your own. Good luck.\\n\"\n\n#define panic(s) \\\n{\\\n    printk(\"KERNEL PANIC:\\n%s [%d] %s: %s\\n\" __PANIC_MSG, \\\n        __FILE__, __LINE__, __func__, s);\\\n    arch_stacktrace(); \\\n    arch_disable_interrupts(); \\\n    for(;;); \\\n}\\\n\n#endif /* ! _CORE_PANIC_H */\n"
  },
  {
    "path": "kernel/include/core/printk.h",
    "content": "#ifndef _PRINTK_H\n#define _PRINTK_H\n\n#include <stdarg.h>\n\n#define LOG_NONE    0\n#define LOG_EMERG   1\n#define LOG_ALERT   2\n#define LOG_CRIT    3\n#define LOG_ERR     4\n#define LOG_WARNING 5\n#define LOG_NOTICE  6\n#define LOG_INFO    7\n#define LOG_DEBUG   8\n\nint vprintk(const char *fmt, va_list args);\nint printk(const char *fmt, ...);\n\n#define LOGGER_DEFINE(module, name, _level) \\\nint name(int level, const char *fmt, ...) \\\n{ \\\n    if (level <= _level) { \\\n        va_list args; \\\n        va_start(args, fmt); \\\n        printk(\"%s: \", #module); \\\n        vprintk(fmt, args); \\\n        va_end(args); \\\n    } \\\n    return 0; \\\n}\n\n#define LOGGER_DECLARE(name) \\\nint name(int level, const char *fmt, ...);\n\n#endif /* ! _PRINTK_H */\n"
  },
  {
    "path": "kernel/include/core/qsort.h",
    "content": "#ifndef _QSORT_H\n#define _QSORT_H\n\n#include <core/system.h>\n#include <core/string.h>\n\nstatic inline void __qsort_swap(char *a, char *b, size_t size)\n{\n    char t;\n    while (size--) {\n        t = *a;\n        *a = *b;\n        *b = t;\n        ++a; ++b;\n    }\n}\n\nstatic inline void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *))\n{\n    if (nmemb <= 1 || size == 0) return;\n\n    void *pivot = (char *) base + (nmemb - 1) * size;\n    void *cur = base;\n    void *wall = base;\n\n    for (size_t i = 0; i < nmemb - 1; ++i) {\n        if (compar(cur, pivot)) {\n            __qsort_swap(cur, wall, size);\n            wall = (char *) wall + size;\n        }\n        cur = (char *) cur + size;\n    }\n\n    __qsort_swap(wall, pivot, size);\n\n    size_t idx = ((char *) wall - (char *) base) / size;\n\n    qsort(base, idx, size, compar);\n    qsort((char *) wall + size, nmemb - idx, size, compar);\n}\n\n#endif /* ! _QSORT_H */\n"
  },
  {
    "path": "kernel/include/core/string.h",
    "content": "#ifndef _STRING_H\n#define _STRING_H\n\n#include <core/system.h>\n\nint snprintf(char *s, size_t n, const char *fmt, ...);\n\nstatic inline void *memmove(void *dest, const void *src, size_t n)\n{\n    void *_dest = dest;\n\n    if ((uintptr_t) dest < (uintptr_t) src) {\n        while (n-- != 0)\n            *(char *) dest++ = *(char *) src++;\n    } else if ((uintptr_t) dest > (uintptr_t) src) {\n        while (n != 0) {\n            --n;\n            *((char *) dest + n) = *((char *) src + n);\n        }\n    }\n\n    return _dest;\n}\n\nstatic inline void *memcpy(void *dest, const void *src, size_t n)\n{\n    void *_dest = dest;\n    while (n-- != 0)\n        *(char *) dest++ = *(char *) src++;\n\n    return _dest;\n}\n\nstatic inline void *memset(void *s, int c, size_t n)\n{\n    void *_s = s;\n\n    while (n-- != 0) {\n        *(char *) s++ = (char) c;\n    }\n\n    return _s;\n}\n\nstatic inline int strcmp(const char *s1, const char *s2)\n{\n    if (s1 == NULL || s2 == NULL)\n        return 0;   // FIXME\n\n    while (*s1 != '\\0' && *s2 != '\\0' && *s1 == *s2) {s1++; s2++;}\n\n    return (int)(*s1 - *s2);\n}\n\nstatic inline int strncmp(const char *s1, const char *s2, size_t n)\n{\n    while (n-- != 0\n            && *s1 != '\\0'\n            && *s2 != '\\0'\n            && *s1 == *s2) {s1++; s2++;}\n\n    return (int)(*s1 - *s2);\n}\n\nstatic inline int strlen(const char *s)\n{\n    const char *_s = s;\n    while (*_s) _s++;\n    return _s - s;\n}\n\nstatic inline char *strdup(const char *s)\n{\n    int len = strlen(s);\n    char *ret = kmalloc(len + 1, &M_BUFFER, 0);\n    (void) memcpy(ret, s, len + 1);\n    return ret;\n}\n\nstatic inline char *strcpy(char *dst, const char *src)\n{\n    char *retval = dst;\n    \n    while (*src != '\\0')\n        *dst++ = *src++;\n\n    *dst = *src;    /* NULL terminator */\n\n    return retval;\n}\n\nstatic inline char **tokenize(const char *s, char c)\n{\n    if (s == NULL || *s == '\\0')\n        return NULL;\n\n    while (*s == c)\n        ++s;\n\n    char *tokens = strdup(s);\n\n    if (tokens == NULL)\n        return NULL;\n\n    int len = strlen(s);\n\n    if (!len) {\n        char **ret = kmalloc(sizeof(char *), &M_BUFFER, 0);\n        *ret = NULL;\n        return ret;\n    }\n\n    int i, count = 0;\n    for (i = 0; i < len; ++i) {\n        if (tokens[i] == c) {\n            tokens[i] = 0;\n            ++count;\n        }\n    }\n\n    if (s[len-1] != c)\n        ++count;\n    \n    char **ret = kmalloc(sizeof(char *) * (count + 1), &M_BUFFER, 0);\n\n    int j = 0;\n    ret[j++] = tokens;\n\n    for (i = 0; i < strlen(s) - 1; ++i)\n        if (tokens[i] == 0)\n            ret[j++] = &tokens[i+1];\n\n    ret[j] = NULL;\n\n    return ret;\n}\n\nstatic inline void free_tokens(char **ptr)\n{\n    if (!ptr) return;\n    if (*ptr)\n        kfree(*ptr);\n    kfree(ptr);\n}\n\n#endif /* !_STRING_H */\n"
  },
  {
    "path": "kernel/include/core/system.h",
    "content": "#ifndef _CORE_SYSTEM_H\n#define _CORE_SYSTEM_H\n\n#define _BV(b) (1 << (b))\n#define MAX(a, b) ((a) > (b) ? (a) : (b))\n#define MIN(a, b) ((a) < (b) ? (a) : (b))\n#define ABS(a) ((a) < 0? -(a) : (a))\n\n#define MEMBER_SIZE(type, member) (sizeof(((type *)0)->member))\n\n#if defined(__TINYC__) || defined(__clang__) || defined(__PCC__)\n  #undef __unused\n  #define __unused\n#else\n  #ifndef __unused\n    #define __unused    __attribute__((unused))\n  #endif\n#endif\n\n\n#define __packed     __attribute__((packed))\n#define __aligned(n) __attribute__((aligned(n)))\n#define __section(s) __attribute__((section(s)))\n\n#if defined(__TINYC__) || defined(__PCC__)\n#include <stddef.h>\n#else\n#include_next <stddef.h>\n#include_next <stdint.h>\n#endif\n\n#include <core/printk.h>\n#include <mm/kvmem.h>\n\n#include <config.h>\n#include <core/types.h>\n\n#endif /* ! _CORE_SYSTEM_H */\n"
  },
  {
    "path": "kernel/include/core/time.h",
    "content": "#ifndef _CORE_TIME_H\n#define _CORE_TIME_H\n\n#include <core/types.h>\n\nint gettime(struct timespec *ts);\n\nint gettimeofday(struct timeval *tv, struct timezone *tz);\nint settimeofday(const struct timeval *tv, const struct timezone *tz);\n\n#endif /* ! _CORE_TIME_H */\n"
  },
  {
    "path": "kernel/include/core/types.h",
    "content": "#ifndef _TYPES_H\n#define _TYPES_H\n\n#include <stdint.h>\n\ntypedef int       pid_t;\ntypedef pid_t     tid_t;\ntypedef long int  off_t;\n\n#if !defined(__TINYC__) || !defined(__clang__)\ntypedef long int  ssize_t;\n#endif\n\ntypedef uintptr_t vino_t;    /* vino_t should be large enough to hold a pointer */\ntypedef uint32_t  mode_t;\ntypedef uint8_t   mask_t;\ntypedef uint8_t   devid_t;\ntypedef uint16_t  dev_t;\n\ntypedef uint32_t  uid_t;\ntypedef uint32_t  gid_t;\ntypedef uint32_t  nlink_t;\ntypedef uintptr_t ino_t;\ntypedef struct timespec _time_t;\n\ntypedef uint64_t time_t;\ntypedef unsigned long sigset_t;\ntypedef long suseconds_t;\n\nstruct timespec {\n    time_t   tv_sec;\n    uint32_t tv_nsec;\n};\n\nstruct timeval {\n    time_t      tv_sec;     /* seconds */\n    suseconds_t tv_usec;    /* microseconds */\n};\n\nstruct timezone {\n    int tz_minuteswest;     /* minutes west of Greenwich */\n    int tz_dsttime;         /* type of DST correction */\n};\n\nstruct utimbuf {\n    time_t actime;\n    time_t modtime;\n};\n\n#endif\n"
  },
  {
    "path": "kernel/include/cpu/cpu.h",
    "content": "#ifndef _CPU_H\n#define _CPU_H\n\n/* Override with arch specific CPU header */\n\n#endif /* _CPU_H */\n"
  },
  {
    "path": "kernel/include/cpu/io.h",
    "content": "#ifndef _CPU_IO_H\n#define _CPU_IO_H\n\n#include <stdint.h>\n\n#define IOADDR_PORT    1\n#define IOADDR_MMIO8   2\n#define IOADDR_MMIO16  3\n#define IOADDR_MMIO32  4\n\nstruct ioaddr {\n    char type;\n    uintptr_t addr;\n};\n\nstatic inline char *ioaddr_type_str(struct ioaddr *io)\n{\n    switch (io->type) {\n        case IOADDR_PORT:\n            return \"pio\";\n        case IOADDR_MMIO8:\n            return \"mmio8\";\n        case IOADDR_MMIO16:\n            return \"mmio16\";\n        case IOADDR_MMIO32:\n            return \"mmio32\";\n    }\n\n    return NULL;\n}\n\n#endif /* ! _CPU_IO_H */\n"
  },
  {
    "path": "kernel/include/dev/console.h",
    "content": "#ifndef _CONSOLE_H\n#define _CONSOLE_H\n\n#include <core/system.h>\n#include <dev/dev.h>\n\nextern struct dev console;\n\n#endif  /* !_CONSOLE_H */\n"
  },
  {
    "path": "kernel/include/dev/dev.h",
    "content": "#ifndef _DEVICE_H\n#define _DEVICE_H\n\n#include <core/system.h>\n\nstruct devid;\nstruct dev;\n\n#include <mm/vm.h>\n#include <fs/vfs.h>\n#include <sys/proc.h>\n\n/**\n * \\ingroup kdev\n * \\brief device identifier\n */\nstruct devid {\n    mode_t  type;\n    devid_t major;\n    devid_t minor;\n};\n\n/**\n * \\ingroup kdev\n * \\brief device\n */\nstruct dev {\n    char    *name;\n\n    int     (*probe)(void);\n    ssize_t (*read) (struct devid *dev, off_t offset, size_t size, void *buf);\n    ssize_t (*write)(struct devid *dev, off_t offset, size_t size, void *buf);\n    int     (*ioctl)(struct devid *dev, int request, void *argp);\n    int     (*map)  (struct devid *dev, struct vm_space *vm_space, struct vm_entry *vm_entry);\n\n    struct fops fops;\n\n    struct dev *(*mux)(struct devid *dev);    /* Device Multiplexr */\n    size_t  (*getbs)(struct devid *dev);      /* Block size, for blkdev */\n};\n\n/* Kernel Device Subsystem Handlers */\nvoid    kdev_init(void);\nvoid    kdev_chrdev_register(devid_t major, struct dev *dev);\nvoid    kdev_blkdev_register(devid_t major, struct dev *dev);\n\nssize_t kdev_read(struct devid *dd, off_t offset, size_t size, void *buf);\nssize_t kdev_write(struct devid *dd, off_t offset, size_t size, void *buf);\nint     kdev_ioctl(struct devid *dd, int request, void *argp);\nint     kdev_map(struct devid *dd, struct vm_space *vm_space, struct vm_entry *vm_entry);\n\nint     kdev_file_open(struct devid *dd, struct file *file);\nssize_t kdev_file_read(struct devid *dd, struct file *file, void *buf, size_t size);    \nssize_t kdev_file_write(struct devid *dd, struct file *file, void *buf, size_t size);\noff_t   kdev_file_lseek(struct devid *dd, struct file *file, off_t offset, int whence);\nssize_t kdev_file_close(struct devid *dd, struct file *file);\nint     kdev_file_ioctl(struct devid *dd, struct file *file, int request, void *argp);\nint     kdev_file_can_read(struct devid *dd, struct file * file, size_t size);\nint     kdev_file_can_write(struct devid *dd, struct file * file, size_t size);\nint     kdev_file_eof(struct devid *dd, struct file *file);\n\n/* Useful Macros */\n#define DEV(major, minor) ((dev_t)(((major) & 0xFF) << 8) | ((minor) & 0xFF))\n#define DEV_MAJOR(dev)    ((devid_t)(((dev) >> 8) & 0xFF))\n#define DEV_MINOR(dev)    ((devid_t)(((dev) >> 0) & 0xFF))\n#define VNODE_DEV(vnode)  ((struct devid){.type = (vnode)->mode & S_IFMT, .major = DEV_MAJOR((vnode)->rdev), .minor = DEV_MINOR((vnode)->rdev)})\n\n/* Devices -- XXX */\nextern struct dev i8042dev;\nextern struct dev ps2kbddev;\nextern struct dev condev;\nextern struct dev ttydev;\nextern struct dev pcidev;\nextern struct dev atadev;\nextern struct dev fbdev;\nextern struct dev rddev;\n\n#endif\n"
  },
  {
    "path": "kernel/include/dev/fbdev.h",
    "content": "#ifndef _DEV_FB_H\n#define _DEV_FB_H\n\nint fbdev_register(int, void*);\n\n#define FBDEV_TYPE_VESA 1\nextern struct fbdev fbdev_vesa;\n\n/* Linux framebuffer API */\n#define FBIOGET_VSCREENINFO 0x4600\n#define FBIOPUT_VSCREENINFO 0x4601\n#define FBIOGET_FSCREENINFO 0x4602\n\nstruct fb_fix_screeninfo {\n    char id[16];            /* identification string eg \"TT Builtin\" */\n    uintptr_t smem_start;   /* Start of frame buffer mem (physical address) */\n    uint32_t smem_len;      /* Length of frame buffer mem */\n    uint32_t type;          /* see FB_TYPE_* */\n    uint32_t type_aux;      /* Interleave for interleaved Planes */\n    uint32_t visual;        /* see FB_VISUAL_* */\n    uint16_t xpanstep;      /* zero if no hardware panning */\n    uint16_t ypanstep;      /* zero if no hardware panning */\n    uint16_t ywrapstep;     /* zero if no hardware ywrap */\n    uint32_t line_length;   /* length of a line in bytes */\n    uintptr_t mmio_start;   /* Start of Memory Mapped I/O (physical address) */\n    uint32_t mmio_len;      /* Length of Memory Mapped I/O  */\n    uint32_t accel;         /* Indicate to driver which specific chip/card we have */\n    uint16_t capabilities;  /* see FB_CAP_* */\n    uint16_t reserved[2];   /* Reserved for future compatibility */\n};\n\nstruct fb_bitfield {\n    uint32_t offset;    /* beginning of bitfield    */\n    uint32_t length;    /* length of bitfield       */\n    uint32_t msb_right; /* != 0 : Most significant bit is right */\n};\n\nstruct fb_var_screeninfo {\n    uint32_t xres;              /* visible X resolution */\n    uint32_t yres;              /* visible Y resolution */\n    uint32_t xres_virtual;      /* virtual X resolution */\n    uint32_t yres_virtual;      /* virtual Y resolution */\n    uint32_t xoffset;           /* X offset from virtual to visible resolution */\n    uint32_t yoffset;           /* Y offset from virtual to visible resolution */\n\n    uint32_t bits_per_pixel;    /* guess what */\n    uint32_t grayscale;         /* 0 = color, 1 = grayscale, >1 = FOURCC */\n    struct fb_bitfield red;     /* bitfield in fb mem if true color, */\n    struct fb_bitfield green;   /* else only length is significant */\n    struct fb_bitfield blue;\n    struct fb_bitfield transp;  /* transparency */\n\n    uint32_t nonstd;            /* != 0 Non standard pixel format */\n\n    uint32_t activate;          /* see FB_ACTIVATE_* */\n\n    uint32_t height;            /* height of picture in mm */\n    uint32_t width;             /* width of picture in mm */\n\n    uint32_t accel_flags;       /* (OBSOLETE) see fb_info.flags */\n\n    /* Timing: All values in pixclocks, except pixclock (of course) */\n    uint32_t pixclock;          /* pixel clock in ps (pico seconds) */\n    uint32_t left_margin;       /* time from sync to picture */\n    uint32_t right_margin;      /* time from picture to sync */\n    uint32_t upper_margin;      /* time from sync to picture */\n    uint32_t lower_margin;\n    uint32_t hsync_len;         /* length of horizontal sync */\n    uint32_t vsync_len;         /* length of vertical sync */\n    uint32_t sync;              /* see FB_SYNC_* */\n    uint32_t vmode;             /* see FB_VMODE_* */\n    uint32_t rotate;            /* angle we rotate counter clockwise */\n    uint32_t colorspace;        /* colorspace for FOURCC-based modes */\n    uint32_t reserved[4];       /* Reserved for future compatibility */\n};\n\n/* Aquila driver API */\n\n#include <mm/vm.h>\nstruct fbdev {\n    int type;\n    void *data;\n    struct fb_fix_screeninfo *fix_screeninfo;\n    struct fb_var_screeninfo *var_screeninfo;\n\n    int     (*probe)(int id, struct fbdev *fb);\n    ssize_t (*read) (struct fbdev *fb, off_t offset, size_t size, void *buf);\n    ssize_t (*write)(struct fbdev *fb, off_t offset, size_t size, void *buf);\n    int     (*ioctl)(struct fbdev *fb, int request, void *argp);\n    int     (*map)  (struct fbdev *fb, struct vm_space *vm_space, struct vm_entry *vm_entry);\n};\n\n#endif /* ! _DEV_FB_H */\n"
  },
  {
    "path": "kernel/include/dev/kbd.h",
    "content": "#ifndef _DEV_KBD_H\n#define _DEV_KBD_H\n\n#include <core/system.h>\n#include <ds/ringbuf.h>\n\nstruct keyboard {\n    const char     *name;\n\n    struct queue   *read_queue;\n    struct ringbuf *ring;\n};\n\n#endif /* ! _DEV_KBD_H */\n"
  },
  {
    "path": "kernel/include/dev/pci.h",
    "content": "#ifndef _DEV_PCI_H\n#define _DEV_PCI_H\n\n#include <core/system.h>\n\nunion pci_address;\nstruct pci_dev;\n\n#include <dev/dev.h>\n#include <cpu/io.h>\n\n#define PCI_CONFIG_ADDRESS  0x00\n#define PCI_CONFIG_DATA     0x04\n\nunion pci_address {\n    struct  {\n        uint8_t reg      : 8;\n        uint8_t function : 3;\n        uint8_t device   : 5;\n        uint8_t bus      : 8;\n        uint8_t reserved : 7;\n        uint8_t enable   : 1;\n    } structure;\n    uint32_t raw;\n} __packed;\n\nstruct pci_dev {\n    uint8_t bus;\n    uint8_t dev;\n    uint8_t func;\n};\n\nextern struct dev pci_bus;\nvoid pci_ioaddr_set(struct ioaddr *io);\n\n/*\n * PCI Interface\n */\n\nint      pci_scan_device(uint8_t class, uint8_t subclass, struct pci_dev *_dev, size_t nr);\nint      pci_device_scan(uint16_t vendor_id, uint16_t device_id, struct pci_dev *ref);\nuint8_t  pci_reg8_read(struct pci_dev *dev, uint8_t off);\nuint16_t pci_reg16_read(struct pci_dev *dev, uint8_t off);\nuint32_t pci_reg32_read(struct pci_dev *dev, uint8_t off);\nvoid     pci_reg8_write(struct pci_dev *dev, uint8_t off, uint8_t val);\nvoid     pci_reg16_write(struct pci_dev *dev, uint8_t off, uint8_t val);\nvoid     pci_reg32_write(struct pci_dev *dev, uint8_t off, uint8_t val);\nuint32_t pci_read_bar(struct pci_dev *dev, uint8_t id);\n\n#endif /* ! _DEV_PCI_H */\n"
  },
  {
    "path": "kernel/include/dev/ramdev.h",
    "content": "#ifndef _DEV_RAMDEV_H\n#define _DEV_RAMDEV_H\n\n#include <core/system.h>\n\nstruct ramdev_priv {\n    void *addr;\n};\n\n#include <dev/dev.h>\n\nextern struct dev ramdev;\n\n#endif /* ! _DEV_RAMDEV_H */\n"
  },
  {
    "path": "kernel/include/dev/tty.h",
    "content": "#ifndef _DEV_TTY_H\n#define _DEV_TTY_H\n\n#include <core/system.h>\n\nstruct tty;\n\n#include <fs/termios.h>\n#include <fs/ioctl.h>\n#include <sys/proc.h>\n\ntypedef ssize_t (*ttyio)(struct tty *tty, size_t size, void *buf);\n\n/**\n * \\ingroup dev-tty\n * \\brief generic tty interface\n */\nstruct tty {\n    /** cooking buffer */\n    char *cook;\n\n    /** current position in cooking buffer */\n    size_t pos;\n\n    struct termios tios;\n    struct winsize ws;\n\n    /** associated device */\n    struct dev *dev;\n\n    /** controlling process */\n    struct proc *proc;\n\n    /** foreground process group */\n    struct pgroup *fg;\n\n    /* interface */\n\n    /** specific handler private data */\n    void *p;\n\n    /** master write handelr */\n    ttyio   master_write;\n\n    /** slave write handler */\n    ttyio   slave_write;\n};\n\n#define TTY_BUF_SIZE 512\n\nint     tty_new(struct proc *proc, size_t buf_size, ttyio master, ttyio slave, void *p, struct tty **ref);\nint     tty_free(struct tty *tty);\nssize_t tty_master_write(struct tty *tty, size_t size, void *buf);\nssize_t tty_slave_write(struct tty *tty, size_t size, void *buf);\nint     tty_ioctl(struct tty *tty, int request, void *argp);\n\n#endif /* ! _DEV_TTY_H */\n"
  },
  {
    "path": "kernel/include/dev/ttydev.h",
    "content": "#ifndef _DEV_TTYDEV_H\n#define _DEV_TTYDEV_H\n\n#include <core/system.h>\n#include <dev/dev.h>\n\nextern struct dev sttydev;\nextern struct dev ttydev;\nextern struct dev condev;\nextern struct dev ptmdev;\nextern struct dev uart;\n\n#endif /* ! _DEV_TTYDEV_H */\n"
  },
  {
    "path": "kernel/include/dev/uart.h",
    "content": "#ifndef _DEV_UART_H\n#define _DEV_UART_H\n\n#include <fs/vfs.h>\n#include <dev/tty.h>\n\nstruct uart {\n    char *name;\n\n    struct ringbuf *in;\n    struct ringbuf *out;\n\n    struct tty   *tty;\n    struct vnode *vnode;    /* vnode associated with uart device */\n\n    void    (*init)    (struct uart *u);\n    ssize_t (*transmit)(struct uart *u, char c);\n    char    (*receive) (struct uart *u);\n};\n\nint  uart_register(int id, struct uart *u);\nvoid uart_recieve_handler(struct uart *u, size_t size);\nvoid uart_transmit_handler(struct uart *u, size_t size);\n\n#endif /* ! _DEV_UART_H */\n"
  },
  {
    "path": "kernel/include/ds/bitmap.h",
    "content": "#ifndef _DS_BITMAP_H\n#define _DS_BITMAP_H\n\n#include <core/system.h>\n#include <core/string.h>\n\n/* All operations are uniform regardless of endianess */\ntypedef uint32_t bitmap_t;\n\n/**\n * \\ingroup ds\n * \\brief bitmap\n */\nstruct bitmap {\n    bitmap_t *map;\n    size_t   max_idx;   /* max index */\n};\n\n/* Number of bits in block */\n#define BITMAP_BLOCK_SIZE (32)\n/* Block mask */\n#define BITMAP_BLOCK_MASK (BITMAP_BLOCK_SIZE - 1)\n/* Number of bits in index to encode offset in block */\n#define BITMAP_LOG2_BLOCK_SIZE  (5)\n/* Offset of the block in bitmap */\n#define BITMAP_BLOCK_OFFSET(__bitmap__i__)  ((__bitmap__i__) >> BITMAP_LOG2_BLOCK_SIZE)\n/* Offset of bit in block */\n#define BITMAP_BIT_OFFSET(__bitmap__i__)    ((__bitmap__i__) & (BITMAP_BLOCK_SIZE - 1))\n\n#define BITMAP_SIZE(n) ((n) + BITMAP_BLOCK_MASK) / BITMAP_BLOCK_SIZE * MEMBER_SIZE(struct bitmap, map[0])\n#define BITMAP_NEW(n)  (&(struct bitmap){.map = (bitmap_t[BITMAP_SIZE(n)]){0}, .max_idx = (n) - 1})\n\nstatic inline size_t bitmap_size(size_t n)\n{\n    return (n + BITMAP_BLOCK_MASK) / BITMAP_BLOCK_SIZE * MEMBER_SIZE(struct bitmap, map[0]);\n}\n\nstatic inline void bitmap_set(struct bitmap *bitmap, size_t index)\n{\n    bitmap->map[BITMAP_BLOCK_OFFSET(index)] |= 1 << BITMAP_BIT_OFFSET(index);\n}\n\nstatic inline void bitmap_clear(struct bitmap *bitmap, size_t index)\n{\n    bitmap->map[BITMAP_BLOCK_OFFSET(index)] &= ~(1 << BITMAP_BIT_OFFSET(index));\n}\n\nstatic inline int bitmap_check(struct bitmap *bitmap, size_t index)\n{\n    return bitmap->map[BITMAP_BLOCK_OFFSET(index)] & (1 << BITMAP_BIT_OFFSET(index));\n}\n\nstatic inline void bitmap_set_range(struct bitmap *bitmap, size_t findex, size_t lindex)\n{\n    size_t i = findex;\n\n    /* Set non block-aligned indices */\n    while (i & BITMAP_BLOCK_MASK && i <= lindex) { \n        bitmap_set(bitmap, i);\n        ++i;\n    }\n\n    /* Set block-aligned indices */\n    if (i < lindex) \n        memset(&bitmap->map[BITMAP_BLOCK_OFFSET(i)], -1, (lindex - i)/BITMAP_BLOCK_SIZE * MEMBER_SIZE(struct bitmap, map[0]));\n\n    i += (lindex - i)/BITMAP_BLOCK_SIZE * BITMAP_BLOCK_SIZE;\n\n    /* Set non block-aligned indices */\n    while (i <= lindex) {\n        bitmap_set(bitmap, i); ++i;\n    }\n}\n\nstatic inline void bitmap_clear_range(struct bitmap *bitmap, size_t findex, size_t lindex)\n{\n    size_t i = findex;\n\n    /* Set non block-aligned indices */\n    while (i & BITMAP_BLOCK_MASK && i <= lindex) { \n        bitmap_clear(bitmap, i);\n        ++i;\n    }\n\n    /* Set block-aligned indices */\n    if (i < lindex) \n        memset(&bitmap->map[BITMAP_BLOCK_OFFSET(i)], 0, (lindex - i)/BITMAP_BLOCK_SIZE * MEMBER_SIZE(struct bitmap, map[0]));\n\n    i += (lindex - i)/BITMAP_BLOCK_SIZE * BITMAP_BLOCK_SIZE;\n\n    /* Set non block-aligned indices */\n    while (i <= lindex) {\n        bitmap_clear(bitmap, i);\n        ++i;\n    }\n}\n\n#endif /* ! _DS_BITMAP_H */\n"
  },
  {
    "path": "kernel/include/ds/buddy.h",
    "content": "#ifndef _DS_BUDDY_H\n#define _DS_BUDDY_H\n\n#include <core/system.h>\n#include <ds/bitmap.h>\n\n/**\n * \\ingroup ds\n * \\brief buddy structure\n */\nstruct buddy {\n    size_t first_free_idx;\n    size_t usable;\n    struct bitmap bitmap;\n};\n\n#define BUDDY_IDX(idx) ((idx) ^ 0x1)\n\n#endif /* ! _DS_BUDDY_H */\n"
  },
  {
    "path": "kernel/include/ds/ds.dox",
    "content": "/**\n * \\defgroup ds kernel/ds\n * \\brief data structures\n */\n\n/* vim: set ft=c: */\n"
  },
  {
    "path": "kernel/include/ds/hashmap.h",
    "content": "#ifndef _DS_HASHMAP_H\n#define _DS_HASHMAP_H\n\n#include <core/system.h>\n\nstruct hashmap;\nstruct hashmap_node;\n\n#include <core/string.h>\n#include <bits/errno.h>\n#include <ds/queue.h>\n\ntypedef uintptr_t hash_t;\n\n#define HASHMAP_DEFAULT 20\n\n/**\n * \\ingroup ds\n * \\brief hashmap\n */\nstruct hashmap {\n    size_t count;\n\n    size_t buckets_nr;\n    struct queue *buckets;\n\n    int (*eq)(void *a, void *b);\n};\n\n/**\n * \\ingroup ds\n * \\brief hashmap node\n */\nstruct hashmap_node {\n    hash_t hash;\n    void *entry;\n    struct qnode *qnode;\n};\n\n/**\n * \\ingroup ds\n * \\brief iterate over hashmap elements\n */\n#define hashmap_for(n, h) \\\n    for (size_t __i__ = 0; __i__ < (h)->buckets_nr; ++__i__) \\\n        queue_for ((n), &(h)->buckets[__i__])\n\n/**\n * \\ingroup ds\n * \\brief create a new statically allocated hashmap\n */\n#define HASHMAP_NEW(n) &(struct hashmap) {\\\n    .count = 0, \\\n    .buckets_nr = HASHMAP_DEFAULT, \\\n    .buckets = &(struct queue[n]){0}, \\\n}\n\n/**\n * \\ingroup ds\n * \\brief create a new dynamically allocated hashmap\n */\nstatic inline struct hashmap *hashmap_new(size_t n, int (*eq)(void *, void *))\n{\n    if (!n) n = HASHMAP_DEFAULT;\n\n    struct hashmap *hashmap;\n\n    hashmap = kmalloc(sizeof(struct hashmap), &M_HASHMAP, 0);\n    if (!hashmap) return NULL;\n\n    //printk(\"hashmap_new(%d) -> %p\\n\", n, hashmap);\n\n    memset(hashmap, 0, sizeof(struct hashmap));\n\n    hashmap->eq = eq;\n    hashmap->buckets = kmalloc(n * sizeof(struct queue), &M_QUEUE, 0);\n\n    if (!hashmap->buckets) {\n        kfree(hashmap);\n        return NULL;\n    }\n\n    memset(hashmap->buckets, 0, n * sizeof(struct queue));\n\n    hashmap->buckets_nr = n;\n\n    return hashmap;\n}\n\n/**\n * \\ingroup ds\n * \\brief get the digest of the hash function\n */\nstatic inline hash_t hashmap_digest(const void *_id, size_t size)\n{\n    const char *id = (const char *) _id;\n\n    hash_t hash = 0;\n\n    while (size) {\n        hash += *id;\n        ++id;\n        --size;\n    }\n\n    return hash;\n}\n\n/**\n * \\ingroup ds\n * \\brief insert a new element into a hashmap\n */\nstatic inline int hashmap_insert(struct hashmap *hashmap, hash_t hash, void *entry) \n{\n    if (!hashmap || !hashmap->buckets_nr || !hashmap->buckets)\n        return -EINVAL;\n\n    struct hashmap_node *node;\n    \n    node = kmalloc(sizeof(struct hashmap_node), &M_HASHMAP_NODE, 0);\n\n    if (!node) return -ENOMEM;\n\n    node->hash  = hash;\n    node->entry = entry;\n\n    size_t idx = hash % hashmap->buckets_nr;\n\n    node->qnode = enqueue(&hashmap->buckets[idx], node);\n\n    if (!node->qnode) {\n        kfree(node);\n        return -ENOMEM;\n    }\n\n    hashmap->count++;\n\n    return 0;\n}\n\n/**\n * \\ingroup ds\n * \\brief lookup for an element in the hashmap using the hash and the key\n */\nstatic inline struct hashmap_node *hashmap_lookup(struct hashmap *hashmap, hash_t hash, void *key)\n{\n    if (!hashmap || !hashmap->buckets || !hashmap->buckets_nr || !hashmap->count)\n        return NULL;\n\n    size_t idx = hash % hashmap->buckets_nr;\n    struct queue *queue = &hashmap->buckets[idx];\n\n    queue_for (node, queue) {\n        struct hashmap_node *hnode = (struct hashmap_node *) node->value;\n        if (hnode && hnode->hash == hash && hashmap->eq(hnode->entry, key))\n            return hnode;\n    }\n\n    return NULL;\n}\n\n/**\n * \\ingroup ds\n * \\brief replace an element in the hashmap using the hash and the key\n */\nstatic inline int hashmap_replace(struct hashmap *hashmap, hash_t hash, void *key, void *entry)\n{\n    if (!hashmap || !hashmap->buckets || !hashmap->buckets_nr || !hashmap->count)\n        return -EINVAL;\n\n    size_t idx = hash % hashmap->buckets_nr;\n    struct queue *queue = &hashmap->buckets[idx];\n\n    queue_for (node, queue) {\n        struct hashmap_node *hnode = (struct hashmap_node *) node->value;\n        if (hnode && hnode->hash == hash && hashmap->eq(hnode->entry, key)) {\n            hnode->entry = entry;\n            return 0;\n        }\n    }\n\n    return hashmap_insert(hashmap, hash, entry);\n}\n\n/**\n * \\ingroup ds\n * \\brief remove an element from the hashmap given the hashmap node\n */\nstatic inline void hashmap_node_remove(struct hashmap *hashmap, struct hashmap_node *node)\n{\n    if (!hashmap || !hashmap->buckets ||\n        !hashmap->buckets_nr || !node || !node->qnode)\n        return;\n\n    size_t idx = node->hash % hashmap->buckets_nr;\n    struct queue *queue = &hashmap->buckets[idx];\n\n    queue_node_remove(queue, node->qnode);\n    kfree(node);\n    hashmap->count--;\n}\n\n#if 0\nstatic inline void hashmap_remove(struct hashmap *hashmap, hash_t id)\n{\n    struct hashmap_node *node = hashmap_lookup(hashmap, id);\n\n    if (node)\n        hashmap_node_remove(hashmap, node);\n}\n#endif\n\n/**\n * \\ingroup ds\n * \\brief free all resources associated with a hashmap\n */\nstatic inline void hashmap_free(struct hashmap *hashmap)\n{\n    for (size_t i = 0; i < hashmap->buckets_nr; ++i) {\n        struct queue *queue = &hashmap->buckets[i];\n\n        struct hashmap_node *node;\n        while ((node = dequeue(queue))) {\n            kfree(node);\n        }\n    }\n\n    kfree(hashmap->buckets);\n    kfree(hashmap);\n}\n\n#endif /* ! _DS_QUEUE_H */\n"
  },
  {
    "path": "kernel/include/ds/queue.h",
    "content": "#ifndef _DS_QUEUE_H\n#define _DS_QUEUE_H\n\n#include <core/system.h>\n\nstruct qnode;\nstruct queue;\n\n#include <core/string.h>\n\n/**\n * \\ingroup ds\n * \\brief queue node\n */\nstruct qnode {\n    void *value;\n    struct qnode *prev;\n    struct qnode *next;\n};\n\n#define QUEUE_TRACE 1\n\n/**\n * \\ingroup ds\n * \\brief queue\n */\nstruct queue {\n    size_t count;\n    struct qnode *head;\n    struct qnode *tail;\n    int flags;\n};\n\n/**\n * \\ingroup ds\n * \\brief iterate over queue elements\n */\n#define queue_for(n, q) for (struct qnode *(n) = (q)->head; (n); (n) = (n)->next)\n\n/**\n * \\ingroup ds\n * \\brief create a new statically allocated queue\n */\n#define QUEUE_NEW() &(struct queue){0}\n\n/**\n * \\ingroup ds\n * \\brief create a new dynamically allocated queue\n */\nstatic inline struct queue *queue_new(void)\n{\n    struct queue *queue;\n\n    queue = kmalloc(sizeof(struct queue), &M_QUEUE, 0);\n    if (!queue) return NULL;\n\n    memset(queue, 0, sizeof(struct queue));\n    return queue;\n}\n\n/**\n * \\ingroup ds\n * \\brief insert a new element in a queue\n */\nstatic inline struct qnode *enqueue(struct queue *queue, void *value) \n{\n    if (!queue)\n        return NULL;\n\n    int trace = queue->flags & QUEUE_TRACE;\n\n    if (trace) printk(\"qtrace: enqueue(%p, %p)\\n\", queue, value);\n\n    struct qnode *node;\n    \n    node = kmalloc(sizeof(struct qnode), &M_QNODE, 0);\n    if (!node) return NULL;\n\n    memset(node, 0, sizeof(struct qnode));\n\n    if (trace) printk(\"qtrace: allocated node %p\\n\", node);\n\n    node->value = value;\n\n    if (!queue->count) {\n        /* Queue is not initalized */\n        queue->head = queue->tail = node;\n    } else {\n        node->prev = queue->tail;\n        queue->tail->next = node;\n        queue->tail = node;\n    }\n\n    ++queue->count;\n    return node;\n}\n\n/**\n * \\ingroup ds\n * \\brief get an element from a queue and remove it\n */\nstatic inline void *dequeue(struct queue *queue)\n{\n    if (!queue || !queue->count)\n        return NULL;\n\n    --queue->count;\n    struct qnode *head = queue->head;\n\n    queue->head = head->next;\n\n    if (queue->head)\n        queue->head->prev = NULL;\n\n    if (head == queue->tail)\n        queue->tail = NULL;\n\n    void *value = head->value;\n    kfree(head);\n\n    return value;\n}\n\n/**\n * \\ingroup ds\n * \\brief remove an element matching a specific value from a queue\n */\nstatic inline void queue_remove(struct queue *queue, void *value)\n{\n    if (!queue || !queue->count)\n        return;\n\n    queue_for (node, queue) {\n        if (node->value == value) {\n            if (!node->prev) {    /* Head */\n                dequeue(queue);\n            } else if (!node->next) {   /* Tail */\n                --queue->count;\n                queue->tail = queue->tail->prev;\n                queue->tail->next = NULL;\n                kfree(node);\n            } else {\n                --queue->count;\n                node->prev->next = node->next;\n                node->next->prev = node->prev;\n                kfree(node);\n            }\n\n            break;\n        }\n    }\n}\n\n/**\n * \\ingroup ds\n * \\brief remove an element from a queue given the queue node\n */\nstatic inline void queue_node_remove(struct queue *queue, struct qnode *node)\n{\n    if (!queue || !queue->count || !node)\n        return;\n\n    if (node->prev)\n        node->prev->next = node->next;\n    if (node->next)\n        node->next->prev = node->prev;\n    if (queue->head == node)\n        queue->head = node->next;\n    if (queue->tail == node)\n        queue->tail = node->prev;\n\n    --queue->count;\n    kfree(node);\n    return;\n}\n\n#endif /* ! _DS_QUEUE_H */\n"
  },
  {
    "path": "kernel/include/ds/ringbuf.h",
    "content": "#ifndef _DS_RINGBUF_H\n#define _DS_RINGBUF_H\n\n#include <core/system.h>\n#include <mm/mm.h>\n\n#define RING_INDEX(ring, i) ((i) % ((ring)->size))\n\n/**\n * \\ingroup ds\n * \\brief ring buffer\n */\nstruct ringbuf {\n    char *buf;\n    size_t size;\n    size_t head;\n    size_t tail;\n};\n\n/**\n * \\ingroup ds\n * \\brief create a new statically allocated ring buffer\n */\n#define RINGBUF_NEW(sz) (&(struct ringbuf){.buf = (char[sz]){0}, .size = sz, .head = 0, .tail = 0})\n\n/**\n * \\ingroup ds\n * \\brief create a new dynamically allocated ring buffer\n */\nstatic inline struct ringbuf *ringbuf_new(size_t size)\n{\n    struct ringbuf *ring = kmalloc(sizeof(struct ringbuf), &M_BUFFER, 0);\n\n    if (!ring)\n        return NULL;\n\n    ring->buf  = kmalloc(size, &M_BUFFER, 0);\n\n    if (!ring->buf) {\n        kfree(ring);\n        return NULL;\n    }\n\n    ring->size = size;\n    ring->head = 0;\n    ring->tail = 0;\n\n    return ring;\n}\n\n/**\n * \\ingroup ds\n * \\brief free a dynamically allocated ring buffer\n */\nstatic inline void ringbuf_free(struct ringbuf *r)\n{\n    if (!r)\n        return;\n\n    kfree(r->buf);\n    kfree(r);\n}\n\n/** \n * \\ingroup ds\n * \\brief read from a ring buffer\n */\nstatic inline size_t ringbuf_read(struct ringbuf *ring, size_t n, char *buf)\n{\n    size_t size = n;\n\n    while (n) {\n        if (ring->head == ring->tail)   /* Ring is empty */\n            break;\n        if (ring->head == ring->size)\n            ring->head = 0;\n        *buf++ = ring->buf[ring->head++];\n        n--;\n    }\n\n    return size - n;\n}\n\n/** \n * \\ingroup ds\n * \\brief peek (non-destructive read) from a ring buffer\n */\nstatic inline size_t ringbuf_read_noconsume(struct ringbuf *ring, off_t off, size_t n, char *buf)\n{\n    size_t size = n;\n    size_t head = ring->head + off;\n\n    if (ring->head < ring->tail && head > ring->tail)\n        return 0;\n\n    while (n) {\n        if (head == ring->size)\n            head = 0;\n        if (head == ring->tail)   /* Ring is empty */\n            break;\n        *buf++ = ring->buf[head++];\n        n--;\n    }\n\n    return size - n;\n}\n\nstatic inline size_t ringbuf_write(struct ringbuf *ring, size_t n, char *buf)\n{\n    size_t size = n;\n\n    while (n) {\n        if (RING_INDEX(ring, ring->head) == RING_INDEX(ring, ring->tail) + 1) /* Ring is full */\n            break;\n\n        if (ring->tail == ring->size)\n            ring->tail = 0;\n        \n        ring->buf[ring->tail++] = *buf++;\n        n--;\n    }\n\n    return size - n;\n}\n\nstatic inline size_t ringbuf_write_overwrite(struct ringbuf *ring, size_t n, char *buf)\n{\n    size_t size = n;\n\n    while (n) {\n        if (RING_INDEX(ring, ring->head) == RING_INDEX(ring, ring->tail) + 1) {\n            /* move head to match */\n            ring->head = RING_INDEX(ring, ring->head) + 1;\n        }\n\n        if (ring->tail == ring->size)\n            ring->tail = 0;\n        \n        ring->buf[ring->tail++] = *buf++;\n        n--;\n    }\n\n    return size - n;\n}\n\nstatic inline size_t ringbuf_available(struct ringbuf *ring)\n{\n    if (ring->tail >= ring->head)\n        return ring->tail - ring->head;\n\n    return ring->tail + ring->size - ring->head;\n}\n\n#endif /* ! _DS_RINGBUF_H */\n"
  },
  {
    "path": "kernel/include/fs/bcache.h",
    "content": "#ifndef _FS_BCACHE_H\n#define _FS_BCACHE_H\n\n#include <fs/vfs.h>\n#include <ds/hashmap.h>\n\n/**\n * \\ingroup vfs\n * \\brief block cache\n */\nstruct bcache {\n    struct hashmap *hashmap;\n};\n\nvoid bcache_init(struct bcache *bcache);\nint bcache_insert(struct bcache *bcache, uint64_t off, void *data);\nint bcache_remove(struct bcache *bcache, uint64_t off);\nvoid *bcache_find(struct bcache *bcache, uint64_t off);\n\nMALLOC_DECLARE(M_BCACHE);\nMALLOC_DECLARE(M_CACHE_BLOCK);\n\n#endif  /* ! _FS_BCACHE_H */\n\n"
  },
  {
    "path": "kernel/include/fs/devfs.h",
    "content": "#ifndef _FS_DEVFS_H\n#define _FS_DEVFS_H\n\n#include <fs/vfs.h>\n\nextern struct fs devfs;\nextern struct vnode *devfs_root;\n\n#endif /* ! _FS_DEVFS_H */\n"
  },
  {
    "path": "kernel/include/fs/devpts.h",
    "content": "#ifndef _FS_DEVPTS_H\n#define _FS_DEVPTS_H\n\n#include <fs/vfs.h>\n\nextern struct fs devpts;\nextern struct vnode *devpts_root;\n\n#endif /* ! _FS_DEVPTS_H */\n"
  },
  {
    "path": "kernel/include/fs/initramfs.h",
    "content": "#ifndef _FS_INITRAMFS_H\n#define _FS_INITRAMFS_H\n\n#include <fs/vfs.h>\n#include <boot/boot.h>\n\nextern struct fs initramfs;\n\nint initramfs_archiver_register(struct fs *fs);\nint load_ramdisk(module_t *module);\n\n#endif /* ! _FS_INITRAMFS_H */\n"
  },
  {
    "path": "kernel/include/fs/ioctl.h",
    "content": "#ifndef _FS_IOCTL_H\n#define _FS_IOCTL_H\n\nstruct winsize {\n    unsigned short ws_row;\n    unsigned short ws_col;\n    unsigned short ws_xpixel;\n    unsigned short ws_ypixel;\n};\n\n#define _IOC(a,b,c,d) ( ((a)<<30) | ((b)<<8) | (c) | ((d)<<16) )\n#define _IOC_NONE  0U\n#define _IOC_WRITE 1U\n#define _IOC_READ  2U\n\n#define _IO(a,b) _IOC(_IOC_NONE,(a),(b),0)\n#define _IOW(a,b,c) _IOC(_IOC_WRITE,(a),(b),sizeof(c))\n#define _IOR(a,b,c) _IOC(_IOC_READ,(a),(b),sizeof(c))\n#define _IOWR(a,b,c) _IOC(_IOC_READ|_IOC_WRITE,(a),(b),sizeof(c))\n\n#define TCGETS              0x5401\n#define TCSETS              0x5402\n#define TCSETSW             0x5403\n#define TCSETSF             0x5404\n#define TCGETA              0x5405\n#define TCSETA              0x5406\n#define TCSETAW             0x5407\n#define TCSETAF             0x5408\n#define TCSBRK              0x5409\n#define TCXONC              0x540A\n#define TCFLSH              0x540B\n#define TIOCEXCL            0x540C\n#define TIOCNXCL            0x540D\n#define TIOCSCTTY           0x540E\n#define TIOCGPGRP           0x540F\n#define TIOCSPGRP           0x5410\n#define TIOCOUTQ            0x5411\n#define TIOCSTI             0x5412\n#define TIOCGWINSZ          0x5413\n#define TIOCSWINSZ          0x5414\n#define TIOCMGET            0x5415\n#define TIOCMBIS            0x5416\n#define TIOCMBIC            0x5417\n#define TIOCMSET            0x5418\n#define TIOCGSOFTCAR        0x5419\n#define TIOCSSOFTCAR        0x541A\n#define FIONREAD            0x541B\n#define TIOCINQ             FIONREAD\n#define TIOCLINUX           0x541C\n#define TIOCCONS            0x541D\n#define TIOCGSERIAL         0x541E\n#define TIOCSSERIAL         0x541F\n#define TIOCPKT             0x5420\n#define FIONBIO             0x5421\n#define TIOCNOTTY           0x5422\n#define TIOCSETD            0x5423\n#define TIOCGETD            0x5424\n#define TCSBRKP             0x5425\n#define TIOCTTYGSTRUCT      0x5426\n#define TIOCSBRK            0x5427\n#define TIOCCBRK            0x5428\n#define TIOCGSID            0x5429\n#define TIOCGPTN            0x80045430\n#define TIOCSPTLCK          0x40045431\n#define TCGETX              0x5432\n#define TCSETX              0x5433\n#define TCSETXF             0x5434\n#define TCSETXW             0x5435\n\n#define FIONCLEX            0x5450\n#define FIOCLEX             0x5451\n#define FIOASYNC            0x5452\n#define TIOCSERCONFIG       0x5453\n#define TIOCSERGWILD        0x5454\n#define TIOCSERSWILD        0x5455\n#define TIOCGLCKTRMIOS      0x5456\n#define TIOCSLCKTRMIOS      0x5457\n#define TIOCSERGSTRUCT      0x5458\n#define TIOCSERGETLSR       0x5459\n#define TIOCSERGETMULTI     0x545A\n#define TIOCSERSETMULTI     0x545B\n\n#define TIOCMIWAIT          0x545C\n#define TIOCGICOUNT         0x545D\n#define TIOCGHAYESESP       0x545E\n#define TIOCSHAYESESP       0x545F\n#define FIOQSIZE            0x5460\n\n#define TIOCPKT_DATA        0\n#define TIOCPKT_FLUSHREAD   1\n#define TIOCPKT_FLUSHWRITE  2\n#define TIOCPKT_STOP        4\n#define TIOCPKT_START       8\n#define TIOCPKT_NOSTOP      16\n#define TIOCPKT_DOSTOP      32\n#define TIOCPKT_IOCTL       64\n\n#define TIOCSER_TEMT        0x01\n\n#define TIOCM_LE            0x001\n#define TIOCM_DTR           0x002\n#define TIOCM_RTS           0x004\n#define TIOCM_ST            0x008\n#define TIOCM_SR            0x010\n#define TIOCM_CTS           0x020\n#define TIOCM_CAR           0x040\n#define TIOCM_RNG           0x080\n#define TIOCM_DSR           0x100\n#define TIOCM_CD            TIOCM_CAR\n#define TIOCM_RI            TIOCM_RNG\n#define TIOCM_OUT1          0x2000\n#define TIOCM_OUT2          0x4000\n#define TIOCM_LOOP          0x8000\n#define TIOCM_MODEM_BITS    TIOCM_OUT2\n\n#define N_TTY               0\n#define N_SLIP              1\n#define N_MOUSE             2\n#define N_PPP               3\n#define N_STRIP             4\n#define N_AX25              5\n#define N_X25               6\n#define N_6PACK             7\n#define N_MASC              8\n#define N_R3964             9\n#define N_PROFIBUS_FDL      10\n#define N_IRDA              11\n#define N_SMSBLOCK          12\n#define N_HDLC              13\n#define N_SYNC_PPP          14\n#define N_HCI               15\n\n#define FIOSETOWN           0x8901\n#define SIOCSPGRP           0x8902\n#define FIOGETOWN           0x8903\n#define SIOCGPGRP           0x8904\n#define SIOCATMARK          0x8905\n#define SIOCGSTAMP          0x8906\n\n#define SIOCADDRT           0x890B\n#define SIOCDELRT           0x890C\n#define SIOCRTMSG           0x890D\n\n#define SIOCGIFNAME         0x8910\n#define SIOCSIFLINK         0x8911\n#define SIOCGIFCONF         0x8912\n#define SIOCGIFFLAGS        0x8913\n#define SIOCSIFFLAGS        0x8914\n#define SIOCGIFADDR         0x8915\n#define SIOCSIFADDR         0x8916\n#define SIOCGIFDSTADDR      0x8917\n#define SIOCSIFDSTADDR      0x8918\n#define SIOCGIFBRDADDR      0x8919\n#define SIOCSIFBRDADDR      0x891a\n#define SIOCGIFNETMASK      0x891b\n#define SIOCSIFNETMASK      0x891c\n#define SIOCGIFMETRIC       0x891d\n#define SIOCSIFMETRIC       0x891e\n#define SIOCGIFMEM          0x891f\n#define SIOCSIFMEM          0x8920\n#define SIOCGIFMTU          0x8921\n#define SIOCSIFMTU          0x8922\n#define SIOCSIFHWADDR       0x8924\n#define SIOCGIFENCAP        0x8925\n#define SIOCSIFENCAP        0x8926\n#define SIOCGIFHWADDR       0x8927\n#define SIOCGIFSLAVE        0x8929\n#define SIOCSIFSLAVE        0x8930\n#define SIOCADDMULTI        0x8931\n#define SIOCDELMULTI        0x8932\n#define SIOCGIFINDEX        0x8933\n#define SIOGIFINDEX         SIOCGIFINDEX\n#define SIOCSIFPFLAGS       0x8934\n#define SIOCGIFPFLAGS       0x8935\n#define SIOCDIFADDR         0x8936\n#define SIOCSIFHWBROADCAST  0x8937\n#define SIOCGIFCOUNT        0x8938\n\n#define SIOCGIFBR           0x8940\n#define SIOCSIFBR           0x8941\n\n#define SIOCGIFTXQLEN       0x8942\n#define SIOCSIFTXQLEN       0x8943\n\n#define SIOCDARP            0x8953\n#define SIOCGARP            0x8954\n#define SIOCSARP            0x8955\n\n#define SIOCDRARP           0x8960\n#define SIOCGRARP           0x8961\n#define SIOCSRARP           0x8962\n\n#define SIOCGIFMAP          0x8970\n#define SIOCSIFMAP          0x8971\n\n#define SIOCADDDLCI         0x8980\n#define SIOCDELDLCI         0x8981\n\n#define SIOCDEVPRIVATE      0x89F0\n#define SIOCPROTOPRIVATE    0x89E0\n\n#endif  /* ! _FS_IOCTL_H */\n"
  },
  {
    "path": "kernel/include/fs/mbr.h",
    "content": "#ifndef _FS_MBR_H\n#define _FS_MBR_H\n\n#include <core/system.h>\n\nstruct mbr_part;\nstruct mbr;\n\n#define MBR_TYPE_UNUSED     0x00\n#define MBR_BOOT_SIGNATURE  0xAA55\n\nstruct mbr_part {\n    uint8_t   status;\n    struct {\n        uint8_t   h;\n        uint16_t  cs;\n    } __packed start_chs;\n    uint8_t   type;\n    struct {\n        uint8_t   h;\n        uint16_t  cs;\n    } __packed end_chs;\n    uint32_t  start_lba;\n    uint32_t  sectors_count;\n} __packed;\n\nstruct mbr {\n    /* bootloader code */\n    uint8_t bootloader[440];\n    uint32_t disk_signiture;\n    uint16_t copy_protected;\n\n    /* partition table */\n    struct mbr_part ptab[4];\n    uint16_t boot_signature;\n} __packed;\n\n#endif /* ! _FS_MBR_H */\n"
  },
  {
    "path": "kernel/include/fs/pipe.h",
    "content": "#ifndef _FS_PIPE_H\n#define _FS_PIPE_H\n\n#include <core/system.h>\n\nstruct pipe;\n\n#include <fs/vfs.h>\n#include <ds/ringbuf.h>\n\n#define PIPE_BUFLEN 1024\n\n/**\n * \\ingroup vfs\n * \\brief unix pipe\n */\nstruct pipe {\n    /** readers reference count */\n    unsigned r_ref;\n\n    /** writers reference count */\n    unsigned w_ref;\n\n    /** ring buffer */\n    struct ringbuf *ring;\n};\n\nextern struct fs pipefs;\nint pipefs_pipe(struct file *read, struct file *write);\n\n#endif /* ! _FS_PIPE_H */\n"
  },
  {
    "path": "kernel/include/fs/posix.h",
    "content": "#ifndef __FS_POSIX_H\n#define __FS_POSIX_H\n\n#include <fs/vfs.h>\n\nint     posix_file_open(struct file *file);\nint     posix_file_close(struct file *file);\nssize_t posix_file_read(struct file *file, void *buf, size_t size);\nssize_t posix_file_write(struct file *file, void *buf, size_t size);\nssize_t posix_file_readdir(struct file *file, struct dirent *dirent);\nint     posix_file_ioctl(struct file *file, int request, void *argp);\noff_t   posix_file_lseek(struct file *file, off_t offset, int whence);\nint     posix_file_trunc(struct file *file, off_t len);\n\n/* helpers */\nint     posix_file_can_read(struct file *file, size_t size);\nint     posix_file_can_write(struct file *file, size_t size);\nint     posix_file_eof(struct file *file);\n\n#endif /* ! __FS_POSIX_H */\n"
  },
  {
    "path": "kernel/include/fs/pseudofs.h",
    "content": "#ifndef _FS_PSEUDOFS_H\n#define _FS_PSEUDOFS_H\n\n#include <fs/vfs.h>\n\nstruct pseudofs_dirent {\n    const char        *d_name;\n    struct vnode      *d_ino;\n\n    struct pseudofs_dirent *next;\n};\n\nint pseudofs_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref);\nint pseudofs_vunlink(struct vnode *dir, const char *fn, struct uio *uio);\n\nssize_t pseudofs_readdir(struct vnode *dir, off_t offset, struct dirent *dirent);\nint pseudofs_finddir(struct vnode *dir, const char *name, struct dirent *dirent);\n\nint pseudofs_close(struct vnode *vnode);\n\n#endif /* ! _FS_PSEUDOFS_H */\n"
  },
  {
    "path": "kernel/include/fs/rofs.h",
    "content": "#ifndef _FS_ROFS_H\n#define _FS_ROFS_H\n\nssize_t rofs_write(struct vnode *vnode, off_t offset, size_t size, void *buf);\nint rofs_trunc(struct vnode *vnode, off_t len);\nint rofs_vmknod(struct vnode *dir, const char *fn, uint32_t mode, dev_t dev, struct uio *uio, struct vnode **ref);\nint rofs_vunlink(struct vnode *dir, const char *fn, struct uio *uio);\n\n#endif /* _FS_ROFS_H */\n"
  },
  {
    "path": "kernel/include/fs/stat.h",
    "content": "#ifndef _FS_STAT_H\n#define _FS_STAT_H\n\n#include <core/system.h>\n\nstruct  stat;\n\n#include <core/types.h>\n\n/**\n * \\ingroup vfs\n */\nstruct  stat {\n    uint16_t  st_dev;\n    uint16_t  st_ino;\n    uint32_t  st_mode;\n    uint16_t  st_nlink;\n    uint32_t  st_uid;\n    uint32_t  st_gid;\n    uint16_t  st_rdev;\n    uint32_t  st_size;\n    \n    struct timespec  st_atime;\n    struct timespec  st_mtime;\n    struct timespec  st_ctime;\n    \n    uint32_t   st_blksize;\n    uint32_t   st_blocks;\n};\n\n#define S_IFMT      0170000UL /* type of file */\n#define S_IFSOCK    0140000UL /* socket */\n#define S_IFLNK     0120000UL /* symbolic link */\n#define S_IFREG     0100000UL /* regular */\n#define S_IFBLK     0060000UL /* block special */\n#define S_IFDIR     0040000UL /* directory */\n#define S_IFCHR     0020000UL /* character special */\n#define S_IFIFO     0010000UL /* fifo */\n\n#define S_ENFMT     0002000UL /* enforcement-mode locking */\n#define S_ISUID     0004000UL /* set user id on execution */\n#define S_ISGID     0002000UL /* set group id on execution */\n#define S_ISVTX     0001000UL /* sticky bit */\n\n#define S_IREAD     0000400UL /* read permission, owner */\n#define S_IWRITE    0000200UL /* write permission, owner */\n#define S_IEXEC     0000100UL /* execute/search permission, owner */\n\n#define S_IRUSR     0000400 /* read permission, owner */\n#define S_IWUSR     0000200 /* write permission, owner */\n#define S_IXUSR     0000100 /* execute/search permission, owner */\n#define S_IRWXU     (S_IRUSR | S_IWUSR | S_IXUSR)\n\n#define S_IRGRP     0000040 /* read permission, group */\n#define S_IWGRP     0000020 /* write permission, grougroup */\n#define S_IXGRP     0000010 /* execute/search permission, group */\n#define S_IRWXG     (S_IRGRP | S_IWGRP | S_IXGRP)\n\n#define S_IROTH     0000004 /* read permission, other */\n#define S_IWOTH     0000002 /* write permission, other */\n#define S_IXOTH     0000001 /* execute/search permission, other */\n#define S_IRWXO     (S_IROTH | S_IWOTH | S_IXOTH)\n\n#define S_ISSOCK(n) (((n) & S_IFMT) == S_IFSOCK)\n#define S_ISLNK(n)  (((n) & S_IFMT) == S_IFLNK)\n#define S_ISREG(n)  (((n) & S_IFMT) == S_IFREG)\n#define S_ISBLK(n)  (((n) & S_IFMT) == S_IFBLK)\n#define S_ISDIR(n)  (((n) & S_IFMT) == S_IFDIR)\n#define S_ISCHR(n)  (((n) & S_IFMT) == S_IFCHR)\n#define S_ISIFO(n)  (((n) & S_IFMT) == S_IFIFO)\n\n#endif /* ! _FS_STAT_H */\n"
  },
  {
    "path": "kernel/include/fs/termios.h",
    "content": "#ifndef _FS_TERMIOS_H\n#define _FS_TERMIOS_H\n\n#include <core/system.h>\n\ntypedef unsigned char cc_t;\ntypedef unsigned int  speed_t;\ntypedef unsigned int  tcflag_t;\n\n#define NCCS 32\n\n/**\n * \\ingroup vfs\n * \\brief terminal I/O structure\n */\nstruct termios {\n    tcflag_t c_iflag;\n    tcflag_t c_oflag;\n    tcflag_t c_cflag;\n    tcflag_t c_lflag;\n    cc_t c_line;\n    cc_t c_cc[NCCS];\n    speed_t __c_ispeed;\n    speed_t __c_ospeed;\n};\n\n#define VINTR       0\n#define VQUIT       1\n#define VERASE      2\n#define VKILL       3\n#define VEOF        4\n#define VTIME       5\n#define VMIN        6\n#define VSWTC       7\n#define VSTART      8\n#define VSTOP       9\n#define VSUSP       10\n#define VEOL        11\n#define VREPRINT    12\n#define VDISCARD    13\n#define VWERASE     14\n#define VLNEXT      15\n#define VEOL2       16\n\n#define IGNBRK      0000001\n#define BRKINT      0000002\n#define IGNPAR      0000004\n#define PARMRK      0000010\n#define INPCK       0000020\n#define ISTRIP      0000040\n#define INLCR       0000100\n#define IGNCR       0000200\n#define ICRNL       0000400\n#define IUCLC       0001000\n#define IXON        0002000\n#define IXANY       0004000\n#define IXOFF       0010000\n#define IMAXBEL     0020000\n#define IUTF8       0040000\n\n#define OPOST       0000001\n#define OLCUC       0000002\n#define ONLCR       0000004\n#define OCRNL       0000010\n#define ONOCR       0000020\n#define ONLRET      0000040\n#define OFILL       0000100\n#define OFDEL       0000200\n#define NLDLY       0000400\n#define NL0         0000000\n#define NL1         0000400\n#define CRDLY       0003000\n#define CR0         0000000\n#define CR1         0001000\n#define CR2         0002000\n#define CR3         0003000\n#define TABDLY      0014000\n#define TAB0        0000000\n#define TAB1        0004000\n#define TAB2        0010000\n#define TAB3        0014000\n#define BSDLY       0020000\n#define BS0         0000000\n#define BS1         0020000\n#define FFDLY       0100000\n#define FF0         0000000\n#define FF1         0100000\n\n#define VTDLY       0040000\n#define VT0         0000000\n#define VT1         0040000\n\n#define B0          0000000\n#define B50         0000001\n#define B75         0000002\n#define B110        0000003\n#define B134        0000004\n#define B150        0000005\n#define B200        0000006\n#define B300        0000007\n#define B600        0000010\n#define B1200       0000011\n#define B1800       0000012\n#define B2400       0000013\n#define B4800       0000014\n#define B9600       0000015\n#define B19200      0000016\n#define B38400      0000017\n\n#define B57600      0010001\n#define B115200     0010002\n#define B230400     0010003\n#define B460800     0010004\n#define B500000     0010005\n#define B576000     0010006\n#define B921600     0010007\n#define B1000000    0010010\n#define B1152000    0010011\n#define B1500000    0010012\n#define B2000000    0010013\n#define B2500000    0010014\n#define B3000000    0010015\n#define B3500000    0010016\n#define B4000000    0010017\n\n#define CBAUD       0010017\n\n#define CSIZE       0000060\n#define CS5         0000000\n#define CS6         0000020\n#define CS7         0000040\n#define CS8         0000060\n#define CSTOPB      0000100\n#define CREAD       0000200\n#define PARENB      0000400\n#define PARODD      0001000\n#define HUPCL       0002000\n#define CLOCAL      0004000\n\n#define ISIG        0000001\n#define ICANON      0000002\n#define ECHO        0000010\n#define ECHOE       0000020\n#define ECHOK       0000040\n#define ECHONL      0000100\n#define NOFLSH      0000200\n#define TOSTOP      0000400\n#define IEXTEN      0100000\n\n#define ECHOCTL     0001000\n#define ECHOPRT     0002000\n#define ECHOKE      0004000\n#define FLUSHO      0010000\n#define PENDIN      0040000\n\n#define TCOOFF      0\n#define TCOON       1\n#define TCIOFF      2\n#define TCION       3\n\n#define TCIFLUSH    0\n#define TCOFLUSH    1\n#define TCIOFLUSH   2\n\n#define TCSANOW     0\n#define TCSADRAIN   1\n#define TCSAFLUSH   2\n\n#endif /* ! _FS_TERMIOS_H */\n"
  },
  {
    "path": "kernel/include/fs/tmpfs.h",
    "content": "#ifndef _FS_TMPFS_H\n#define _FS_TMPFS_H\n\n#include <fs/vfs.h>\n\nextern struct fs tmpfs;\n\n#endif /* ! _FS_TMPFS_H */\n"
  },
  {
    "path": "kernel/include/fs/vcache.h",
    "content": "#ifndef _FS_VCACHE_H\n#define _FS_VCACHE_H\n\n#include <fs/vfs.h>\n#include <ds/hashmap.h>\n\n/**\n * \\ingroup vfs\n * \\brief vnode cache\n */\nstruct vcache {\n    struct hashmap *hashmap;\n};\n\nvoid vcache_init(struct vcache *vcache);\nint vcache_insert(struct vcache *vcache, struct vnode *vnode);\nint vcache_remove(struct vcache *vcache, struct vnode *vnode);\nstruct vnode *vcache_find(struct vcache *vcache, ino_t ino);\n\nMALLOC_DECLARE(M_VCACHE);\n\n#endif  /* ! _FS_VCACHE_H */\n"
  },
  {
    "path": "kernel/include/fs/vfs.h",
    "content": "#ifndef _FS_VFS_H\n#define _FS_VFS_H\n\n#include <core/system.h>\n\nLOGGER_DECLARE(vfs_log);\n\nstruct fs;\nstruct vnode;\nstruct file;\nstruct uio;\nstruct vops;\n\n#include <bits/dirent.h>\n\n/**\n * \\ingroup vfs\n * \\brief file operations\n */\nstruct fops {\n    int         (*open)    (struct file *file);\n    ssize_t     (*read)    (struct file *file, void *buf, size_t size);    \n    ssize_t     (*write)   (struct file *file, void *buf, size_t size);\n    ssize_t     (*readdir) (struct file *file, struct dirent *dirent);  \n    off_t       (*lseek)   (struct file *file, off_t offset, int whence);\n    int         (*close)   (struct file *file);\n    int         (*ioctl)   (struct file *file, int request, void *argp);\n    int         (*trunc)   (struct file *file, off_t len);\n\n    /* helpers */\n    int         (*can_read)  (struct file *file, size_t size);\n    int         (*can_write) (struct file *file, size_t size);\n    int         (*eof)       (struct file *);\n};\n\n#include <bits/errno.h>\n#include <sys/proc.h>\n#include <ds/queue.h>\n#include <fs/stat.h>\n#include <mm/vm.h>\n\nMALLOC_DECLARE(M_VNODE);\n\n/**\n * \\ingroup vfs\n * \\brief user I/O operation\n */\nstruct uio {\n    char     *root; /* Root Directory */\n    char     *cwd;  /* Current Working Directory */\n    uid_t    uid;\n    gid_t    gid;\n    mode_t   mask;\n    uint32_t flags;\n};\n\n/**\n * \\ingroup vfs\n * \\brief vnode operations\n */\nstruct vops {\n    ssize_t (*read)    (struct vnode *vnode, off_t offset, size_t size, void *buf);\n    ssize_t (*write)   (struct vnode *vnode, off_t offset, size_t size, void *buf);\n    int     (*ioctl)   (struct vnode *vnode, int request, void *argp);\n    int     (*close)   (struct vnode *vnode);\n    int     (*trunc)   (struct vnode *vnode, off_t len);\n\n    ssize_t (*readdir) (struct vnode *dir, off_t offset, struct dirent *dirent);\n    int     (*finddir) (struct vnode *dir, const char *name, struct dirent *dirent);\n\n    int     (*vmknod)  (struct vnode *dir, const char *fn, uint32_t mode, dev_t dev, struct uio *uio, struct vnode **ref);\n    int     (*vunlink) (struct vnode *dir, const char *fn, struct uio *uio);\n\n    int     (*vget)    (struct vnode *super, ino_t ino, struct vnode **vnode);\n\n    int     (*vsync)   (struct vnode *vnode, int mode);\n    int     (*sync)    (struct vnode *super, int mode);\n\n    int     (*map)     (struct vm_space *vm_space, struct vm_entry *vm_entry);\n};\n\n/**\n * \\ingroup vfs\n */\nstruct vfs_path {\n    struct vnode *root;\n    char **tokens;\n};\n\n/**\n * \\ingroup vfs\n * \\brief filesystem structure\n */\nstruct fs {\n    char *name;\n    int (*init)  ();\n    int (*load)  (struct vnode *dev, struct vnode **super);  /* Read superblock */\n    int (*mount) (const char *dir, int flags, void *data);\n\n    struct vops vops;\n    struct fops fops;\n\n    /* flags */\n    int nodev;\n};\n\n/**\n * \\ingroup vfs\n * \\brief in-core inode structure (vnode)\n */\nstruct vnode {\n    ino_t       ino;\n    size_t      size;\n    dev_t       dev;\n    dev_t       rdev;\n    mode_t      mode;\n    uid_t       uid;\n    gid_t       gid;\n    nlink_t     nlink;\n\n    _time_t     atime;\n    _time_t     mtime;\n    _time_t     ctime;\n\n    struct fs   *fs;\n\n    /** filesystem handler private data */\n    void *p;\n\n    /** number of processes referencing this vnode */\n    size_t ref;\n\n    struct queue *read_queue;\n    struct queue *write_queue;\n\n    /** virtual memory object associated with vnode */\n    struct vm_object *vm_object;\n};\n\nstruct file {\n    union {\n        struct vnode *vnode;\n        struct socket *socket;\n    };\n\n    off_t offset;\n    int flags;\n    //int ref;\n};\n\n/**\n * \\ingroup vfs\n * \\brief list of registered filesystems\n */\nstruct fs_list {\n    /** filesystem name */\n    const char *name;\n\n    /** filesystem structure */\n    struct fs  *fs;\n\n    /** next entry in the list */\n    struct fs_list *next;\n};\n\n/* XXX */\nstruct vfs_path *vfs_get_mountpoint(char **tokens);\nchar **tokenize_path(const char * const path);\nint vfs_parse_path(const char *path, struct uio *uio, char **abs_path);\n\nextern struct fs_list *registered_fs;\nextern struct vnode *vfs_root;\n\nstatic inline int __vfs_can_always(struct file *f, size_t s){return 1;}\nstatic inline int __vfs_can_never (struct file *f, size_t s){return 0;}\nstatic inline int __vfs_eof_always(struct file *f){return 1;}\nstatic inline int __vfs_eof_never (struct file *f){return 0;}\n\n#define ISDEV(vnode) (S_ISCHR((vnode)->mode) || S_ISBLK((vnode)->mode))\n\n/* Filesystem operations */\nvoid    vfs_init(void);\nint     vfs_install(struct fs *fs);\nint     vfs_mount_root(struct vnode *vnode);\nint     vfs_bind(const char *path, struct vnode *target);\nint     vfs_mount(const char *type, const char *dir, int flags, void *data, struct uio *uio);\n\n/* vnode operations mappings */\nint     vfs_vmknod(struct vnode *dir, const char *fn, uint32_t mode, dev_t dev, struct uio *uio, struct vnode **ref);\nint     vfs_vcreat(struct vnode *dir, const char *fn, struct uio *uio, struct vnode **ref);\nint     vfs_vmkdir(struct vnode *dir, const char *dname, struct uio *uio, struct vnode **ref);\nint     vfs_vunlink(struct vnode *dir, const char *fn, struct uio *uio);\nint     vfs_vget(struct vnode *super, ino_t ino, struct vnode **vnode);\n\nint     vfs_map(struct vm_space *vm_space, struct vm_entry *vm_entry);\n\nssize_t vfs_read(struct vnode *vnode, off_t offset, size_t size, void *buf);\nssize_t vfs_write(struct vnode *vnode, off_t offset, size_t size, void *buf);\nint     vfs_ioctl(struct vnode *vnode, unsigned long request, void *argp);\nint     vfs_close(struct vnode *vnode);\nint     vfs_trunc(struct vnode *vnode, off_t len);\n\nstruct vm_page *vfs_pagein(struct vnode *vnode, off_t offset);\n\n/* sync */\n#define FS_MSYNC    0x0001\n#define FS_DSYNC    0x0002\nint vfs_vsync(struct vnode *vnode, int mode);\nint vfs_fssync(struct vnode *super, int mode);\nint vfs_sync(int mode);\n\nssize_t vfs_readdir(struct vnode *dir, off_t offset, struct dirent *dirent);\nint     vfs_finddir(struct vnode *dir, const char *name, struct dirent *dirent);\n\n/* file operations mappings */\nint     vfs_file_open(struct file *file);\nssize_t vfs_file_read(struct file *file, void *buf, size_t size);    \nssize_t vfs_file_write(struct file *file, void *buf, size_t size);\nssize_t vfs_file_readdir(struct file *file, struct dirent *dirent);  \noff_t   vfs_file_lseek(struct file *file, off_t offset, int whence);\nssize_t vfs_file_close(struct file *file);\nint     vfs_file_ioctl(struct file *file, int request, void *argp);\nint     vfs_file_trunc(struct file *file, off_t len);\n\n/* helpers */\nint     vfs_file_can_read(struct file * file, size_t size);\nint     vfs_file_can_write(struct file * file, size_t size);\nint     vfs_file_eof(struct file *);\n\n/* Path resolution and lookup */\nint     vfs_relative(const char * const rel, const char * const path, char **abs_path);\nint     vfs_lookup(const char *path, struct uio *uio, struct vnode **vnode, char **abs_path);\n\n/* Higher level functions */\nint     vfs_creat(const char *path, mode_t mode, struct uio *uio, struct vnode **ref);\nint     vfs_mkdir(const char *path, mode_t mode, struct uio *uio, struct vnode **ref);\nint     vfs_mknod(const char *path, uint32_t mode, dev_t dev, struct uio *uio, struct vnode **ref);\nint     vfs_unlink(const char *path, struct uio *uio);\nint     vfs_stat(struct vnode *vnode, struct stat *buf);\nint     vfs_perms_check(struct file *file, struct uio *uio);\n\n/* XXX */\n\nstruct mountpoint {\n    const char *dev;\n    const char *path;\n    const char *type;\n    const char *options;\n};\n\n#endif /* ! _FS_VFS_H */\n"
  },
  {
    "path": "kernel/include/mm/buddy.h",
    "content": "#ifndef _MM_BUDDY_H\n#define _MM_BUDDY_H\n\n#include <mm/mm.h>\n\n/** max buddy order */\n#define BUDDY_MAX_ORDER (10)\n/** buddy minimum block size */\n#define BUDDY_MIN_BS    (4096)\n/** buddy maximum block size */\n#define BUDDY_MAX_BS    (BUDDY_MIN_BS << BUDDY_MAX_ORDER)\n\n#define BUDDY_ZONE_NR       2\n#define BUDDY_ZONE_DMA      0\n#define BUDDY_ZONE_NORMAL   1\n\nint     buddy_setup(size_t total_mem);\npaddr_t buddy_alloc(int zone, size_t size);\nvoid    buddy_free(int zone, paddr_t paddr, size_t size);\nvoid    buddy_set_unusable(paddr_t paddr, size_t size);\n\n#endif /* !_MM_BUDDY_H */\n"
  },
  {
    "path": "kernel/include/mm/heap.h",
    "content": "#ifndef _HEAP_H\n#define _HEAP_H\n\n/* FIXME */\nextern char *kernel_heap;\nstatic inline void *heap_alloc(size_t size, size_t align)\n{\n    char *ret = (char *)((uintptr_t)(kernel_heap + align - 1) & (~(align - 1)));\n    kernel_heap = ret + size;\n\n    memset(ret, 0, size);   /* We always clear the allocated area */\n\n    return ret;\n}\n\n#endif /* _HEAP_H */\n"
  },
  {
    "path": "kernel/include/mm/kvmem.h",
    "content": "#ifndef _MM_KVMEM_H\n#define _MM_KVMEM_H\n\nstruct malloc_type {\n    const char *name;\n    const char *desc;\n    size_t nr;\n    size_t total;\n    struct qnode *qnode;\n};\n\n#define M_ZERO  0x0001\n\n#define MALLOC_DECLARE(type) extern struct malloc_type (type)\n#define MALLOC_DEFINE(type, name, desc) struct malloc_type (type) = {(name), (desc), 0, 0, NULL}\n\nMALLOC_DECLARE(M_BUFFER);\nMALLOC_DECLARE(M_RINGBUF);\nMALLOC_DECLARE(M_QUEUE);\nMALLOC_DECLARE(M_QNODE);\nMALLOC_DECLARE(M_HASHMAP);\nMALLOC_DECLARE(M_HASHMAP_NODE);\n\nvoid *kmalloc(size_t, struct malloc_type *type, int flags);\nvoid kfree(void *);\nextern int debug_kmalloc;\n\n#ifdef DEBUG_KMALLOC\n#define kmalloc(s) ((debug_kmalloc? printk(\"%s [%d]: kmalloc(%d)\\n\", __func__, __LINE__, (s)): 0), (kmalloc)((s)))\n#define kfree(s) ((debug_kmalloc? printk(\"%s [%d]: kfree(%p)\\n\", __func__,  __LINE__, (s)): 0), (kfree)((s)))\n#endif\n\n#endif /* ! _MM_KVMEM_H */\n"
  },
  {
    "path": "kernel/include/mm/mm.h",
    "content": "#ifndef _MM_MM_H\n#define _MM_MM_H\n\n#include <core/system.h>\n\n#define PAGE_ALIGN(ptr) ((ptr) & ~PAGE_MASK)\n#define PAGE_ROUND(ptr) (((ptr) + PAGE_MASK) & ~PAGE_MASK)\n\n#include <boot/boot.h>\n\n#define PF_PRESENT  0x001\n#define PF_READ     0x002\n#define PF_WRITE    0x004\n#define PF_EXEC     0x008\n#define PF_USER     0x010\n\nvoid mm_setup(struct boot *boot);\n\nstruct vm_page *mm_page(paddr_t paddr);\nstruct vm_page *mm_page_alloc(void);\nvoid   mm_page_incref(paddr_t paddr);\nvoid   mm_page_decref(paddr_t paddr);\nsize_t mm_page_ref(paddr_t paddr);\nvoid mm_page_dealloc(paddr_t paddr);\n\nint  mm_page_map(struct pmap *pmap, vaddr_t vaddr, paddr_t paddr, int flags);\nint  mm_map(struct pmap *pmap, paddr_t paddr, vaddr_t vaddr, size_t size, int flags);\nvoid mm_unmap(struct pmap *pmap, vaddr_t addr, size_t size);\nvoid mm_unmap_full(struct pmap *pmap, vaddr_t vaddr, size_t size);\n\nvoid mm_page_fault(vaddr_t vaddr, int flags);\n\n#endif /* !_MM_MM_H */\n"
  },
  {
    "path": "kernel/include/mm/pmap.h",
    "content": "#ifndef _MM_PMAP_H\n#define _MM_PMAP_H\n\nvoid pmap_init(void);\nstruct pmap *pmap_switch(struct pmap *pmap);\nstruct pmap *pmap_create(void);\nvoid pmap_incref(struct pmap *pmap);\nvoid pmap_decref(struct pmap *pmap);\nint  pmap_add(struct pmap *pmap, vaddr_t va, paddr_t pa, uint32_t flags);\nvoid pmap_remove(struct pmap *pmap, vaddr_t sva, vaddr_t eva);\nvoid pmap_protect(struct pmap *pmap, vaddr_t sva, vaddr_t eva, uint32_t prot);\nvoid pmap_page_copy(paddr_t src, paddr_t dst);\nvoid pmap_remove_all(struct pmap *pmap);\nint pmap_page_read(paddr_t paddr, off_t off, size_t size, void *buf);\nint pmap_page_write(paddr_t paddr, off_t off, size_t size, void *buf);\n\n#endif /* _MM_PMAP_H */\n"
  },
  {
    "path": "kernel/include/mm/vm.h",
    "content": "#ifndef _MM_VM_H\n#define _MM_VM_H\n\n#include <core/system.h>\n#include <core/printk.h>\n\nstruct vm_space;\nstruct vm_entry;\nstruct vm_object;\nstruct vm_page;\n\nMALLOC_DECLARE(M_VM_ENTRY);\nMALLOC_DECLARE(M_VM_OBJECT);\nMALLOC_DECLARE(M_VM_ANON);\nMALLOC_DECLARE(M_VM_AREF);\n\n#include <ds/queue.h>\n\n/** \n * \\ingroup mm\n * \\brief virtual memory space\n *\n * This structure holds the entire mapping of a virtual memory \n * space/view\n */\nstruct vm_space {\n    /** physical memory mapper (arch-specific) */\n    struct pmap  *pmap;\n\n    /** virtual memory regions inside the vm space */\n    struct queue  vm_entries;\n};\n\n#include <fs/vfs.h>\n#include <mm/mm.h>\n#include <ds/hashmap.h>\n\n/* vm entry flags */\n#define VM_KR         0x0001         /**< kernel read */\n#define VM_KW         0x0002         /**< kernel write */\n#define VM_KX         0x0004         /**< kernel execute */\n#define VM_UR         0x0008         /**< user read */\n#define VM_UW         0x0010         /**< user write */\n#define VM_UX         0x0020         /**< user execute */\n#define VM_PERM       0x003F         /**< permissions mask */\n#define VM_NOCACHE    0x0040         /**< disable caching */\n#define VM_SHARED     0x0080         /**< shared mapping */\n#define VM_COPY       0x0100         /**< needs copy */\n\n#define VM_KRW  (VM_KR|VM_KW)        /**< kernel read/write */\n#define VM_KRX  (VM_KR|VM_KX)        /**< kernel read/execute */\n#define VM_KWX  (VM_KW|VM_KX)        /**< kernel write/execute */\n#define VM_KRWX (VM_KR|VM_KW|VM_KX)  /**< kernel read/write/execute */\n#define VM_URW  (VM_UR|VM_UW)        /**< user read/write */\n#define VM_URX  (VM_UR|VM_UX)        /**< user read/execute */\n#define VM_UWX  (VM_UW|VM_UX)        /**< user write/execute */\n#define VM_URWX (VM_UR|VM_UW|VM_UX)  /**< user read/write/execute */\n\n/* object types */\n#define VMOBJ_ZERO    0x0000         /**< zero fill */\n#define VMOBJ_FILE    0x0001         /**< file backed */\n\n/** \n * \\ingroup mm\n * \\brief virtual memory region\n *\n * This structure represents a region in virtual memory\n * space with access permissions and backening objects\n */\nstruct vm_entry {\n    /** Physical Address, 0 means anywhere - XXX */\n    paddr_t  paddr;\n\n    /** address of the vm entry inside the `vm_space` */\n    vaddr_t base;\n\n    /** size of the vm entry */\n    size_t size;\n\n    /** permissions flags */\n    uint32_t flags;\n\n    /** anon layer object */\n    struct vm_anon *vm_anon;\n\n    /** backening object */\n    struct vm_object *vm_object;\n\n    /** offset inside object */\n    size_t off;\n\n    /** the queue node this vm entry is stored in */\n    struct qnode *qnode;\n};\n\n/**\n * \\ingroup mm\n * \\brief pager\n */\nstruct vm_pager {\n    /** page in */\n    struct vm_page *(*in)(struct vm_object *vm_object, size_t off);\n\n    /** page out */\n    int (*out)(struct vm_object *vm_object, size_t off);\n};\n\n/**\n * \\ingroup mm\n * \\brief anonymous memory object reference\n *\n * The `vm_aref` acts as a container of a `vm_page` with reference count\n * of anonymous memory regions (`vm_anon`) referencing/using that page.\n */\nstruct vm_aref {\n    /** vm page associated with the aref */\n    struct vm_page *vm_page;\n\n    /** number of references to the aref */\n    size_t ref;\n\n    /** flags associated with this aref */\n    uint32_t flags;\n};\n\n/**\n * \\ingroup mm\n * \\brief anonymous memory object\n */\nstruct vm_anon {\n    /** hashmap of `vm_aref` structures loaded/contained in this anon */\n    struct hashmap *arefs;\n\n    /** number of `vm_entry` structures referencing this anon */\n    size_t ref;\n\n    /** flags associated with the anon */\n    int flags;\n};\n\n/**\n * \\ingroup mm\n * \\brief cached object\n */\nstruct vm_object {\n    /** `vm_page`s loaded/contained in the vm object */\n    struct hashmap *pages;\n\n    /** type of the object */\n    int type;\n\n    /** number of vm entries referencing this object */\n    size_t ref;\n\n    /** pager for the vm object */\n    struct vm_pager *pager;\n\n    /** pager private data */\n    void *p;\n};\n\n/** \n * \\ingroup mm\n * \\brief physical page\n */\nstruct vm_page {\n    paddr_t  paddr; /**< physical address of the page */\n\n    struct vm_object *vm_object; /**< the object this page belongs to */\n\n    size_t off; /**< offset of page inside the object */\n\n    size_t ref; /**< number of processes referencing this page */\n};\n\nextern struct vm_page pages[];\nextern struct vm_space kvm_space;\n\nvoid kvmem_setup(void);\n\n/* mm/vmm.c XXX */\nint  vm_map(struct vm_space *vm_space, struct vm_entry *vm_entry);\nvoid vm_unmap(struct vm_space *vm_space, struct vm_entry *vm_entry);\nvoid vm_unmap_full(struct vm_space *vm_space, struct vm_entry *vm_entry);\n\n/* mm/vm_space.c */\nint  vm_space_fork(struct vm_space *parent, struct vm_space *child);\nvoid vm_space_destroy(struct vm_space *vm_space);\nstruct vm_entry *vm_space_find(struct vm_space *vm_space, vaddr_t vaddr);\nint  vm_space_insert(struct vm_space *vm_space, struct vm_entry *vm_entry);\n\n/* mm/vm_entry.c */\nstruct vm_entry *vm_entry_new(void);\nvoid vm_entry_destroy(struct vm_entry *vm_entry);\n\n/* mm/vm_anon.c */\nstruct vm_anon *vm_anon_new(void);\nstruct vm_anon *vm_anon_copy(struct vm_anon *vm_anon);\nvoid vm_anon_incref(struct vm_anon *vm_anon);\nvoid vm_anon_decref(struct vm_anon *vm_anon);\nvoid vm_anon_destroy(struct vm_anon *vm_anon);\n\n/* mm/vm_object.c */\nstruct vm_object *vm_object_vnode(struct vnode *vnode);\nstruct vm_page *vm_object_page_get(struct vm_object *vm_object, size_t off);\nvoid vm_object_page_insert(struct vm_object *vm_object, struct vm_page *vm_page);\nvoid vm_object_incref(struct vm_object *vm_object);\nvoid vm_object_decref(struct vm_object *vm_object);\n\n#endif  /* ! _MM_VM_H */\n"
  },
  {
    "path": "kernel/include/net/socket.h",
    "content": "#ifndef _NET_SOCKET_H\n#define _NET_SOCKET_H\n\n#include <core/system.h>\n#include <fs/vfs.h>\n\ntypedef uint32_t socklen_t;\ntypedef uint32_t sa_family_t;\n\nstruct sockaddr {\n    sa_family_t sa_family;\n    char        sa_data[];\n};\n\nstruct socket {\n    int domain;\n    int type;\n    int protocol;\n\n    /* Socket handler */\n    struct sock_ops *ops;\n\n    /* Private data */\n    void *p;\n\n    ssize_t ref;\n};\n\nstruct sock_ops {\n    int (*accept) (struct file *socket, struct file *conn, const struct sockaddr *addr, socklen_t *len);\n    int (*bind)   (struct file *socket, const struct sockaddr *addr, socklen_t len);\n    int (*connect)(struct file *socket, const struct sockaddr *addr, socklen_t len);\n    int (*listen) (struct file *socket, int backlog);\n\n    ssize_t (*recv)(struct file *socket, void *buf, size_t len, int flags);\n    ssize_t (*send)(struct file *socket, void *buf, size_t len, int flags);\n\n    int (*can_read)(struct file *socket, size_t len);\n    int (*can_write)(struct file *socket, size_t len);\n\n    int (*shutdown) (struct file *socket, int how);\n};\n\n#define SOCK_DGRAM      0x0001\n#define SOCK_RAW        0x0002\n#define SOCK_SEQPACKET  0x0003\n#define SOCK_STREAM     0x0004\n\n#define SOMAXCONN       1024\n\n#define AF_INET         0x0001\n#define AF_INET6        0x0002\n#define AF_UNIX         0x0003\n#define AF_UNSPEC       0x0004\n\n#define FILE_SOCKET     0x80000000\n\n#define MSG_CTRUNC      0x0001\n#define MSG_DONTROUTE   0x0002\n#define MSG_EOR         0x0004\n#define MSG_OOB         0x0008\n#define MSG_NOSIGNAL    0x0010\n#define MSG_PEEK        0x0020\n#define MSG_TRUNC       0x0040\n#define MSG_WAITALL     0x0080\n\n#define SHUT_RD         0x0001\n#define SHUT_WR         0x0002\n#define SHUT_RDWR       (SHUT_RD|SHUT_WR)\n\nint socket_create(struct file *file, int domain, int type, int protocol);\nint socket_bind(struct file *file, const struct sockaddr *addr, uint32_t len);\nint socket_accept(struct file *file, struct file *conn, const struct sockaddr *addr, socklen_t *len);\nint socket_connect(struct file *file, const struct sockaddr *addr, uint32_t len);\nint socket_listen(struct file *file, int backlog);\nint socket_send(struct file *file, void *buf, size_t len, int flags);\nint socket_recv(struct file *file, void *buf, size_t len, int flags);\nint socket_can_read(struct file *file, size_t len);\nint socket_can_write(struct file *file, size_t len);\nint socket_shutdown(struct file *file, int how);\n\n/* AF_UNIX */\nint socket_unix_create(struct file *file, int domain, int type, int protocol);\n\n#endif /* ! _NET_SOCKET_H */\n"
  },
  {
    "path": "kernel/include/stdarg.h",
    "content": "#ifndef _STDARG_H\n#define _STDARG_H\n\n#define va_list         __builtin_va_list\n#define va_start(v,l)\t__builtin_va_start(v,l)\n#define va_end(v)\t    __builtin_va_end(v)\n#define va_arg(v,l)\t    __builtin_va_arg(v,l)\n\n#endif\n"
  },
  {
    "path": "kernel/include/stddef.h",
    "content": "#ifndef _STDDEF_H\n#define _STDDEF_H\n\ntypedef __SIZE_TYPE__ size_t;\ntypedef __PTRDIFF_TYPE__ ssize_t;\ntypedef __WCHAR_TYPE__ wchar_t;\ntypedef __PTRDIFF_TYPE__ ptrdiff_t;\ntypedef __PTRDIFF_TYPE__ intptr_t;\ntypedef __SIZE_TYPE__ uintptr_t;\n\n#ifndef __int8_t_defined\n#define __int8_t_defined\ntypedef signed char int8_t;\ntypedef signed short int int16_t;\ntypedef signed int int32_t;\ntypedef signed long long int int64_t;\ntypedef unsigned char uint8_t;\ntypedef unsigned short int uint16_t;\ntypedef unsigned int uint32_t;\ntypedef unsigned long long int uint64_t;\n#endif\n\n#ifndef NULL\n#define NULL ((void*)0)\n#endif\n\n#ifndef offsetof\n#define offsetof(type, field) ((size_t)&((type *)0)->field)\n#endif\n\nvoid *alloca(size_t size);\n\n#endif\n"
  },
  {
    "path": "kernel/include/stdint.h",
    "content": "#include <stddef.h>\n"
  },
  {
    "path": "kernel/include/sys/binfmt.h",
    "content": "#ifndef _SYS_BINFMT_H\n#define _SYS_BINFMT_H\n\n#include <core/system.h>\n#include <fs/vfs.h>\n#include <sys/proc.h>\n\n/**\n * \\ingroup sys\n * \\brief binary format\n */\nstruct binfmt {\n    int (*check)(struct vnode *vnode);\n    int (*load)(struct proc *proc, const char *path, struct vnode *vnode);\n};\n\nint binfmt_load(struct proc *proc, const char *path, struct proc **ref);\n\n/* sys/binfmt/elf.c */\nint binfmt_elf_check(struct vnode *vnode);\nint binfmt_elf_load(struct proc *proc, const char *path, struct vnode *vnode);\n\n#endif /* ! _SYS_BINFMT_H */\n"
  },
  {
    "path": "kernel/include/sys/elf.h",
    "content": "#ifndef _ELF_H\n#define _ELF_H\n\n#include <stdint.h>\n\ntypedef int32_t  elf32_sword;\ntypedef uint32_t elf32_word;\ntypedef uint32_t elf32_addr;\ntypedef uint32_t elf32_off;\ntypedef uint16_t elf32_half;\n\n#define ET_NONE     0x0000\n#define ET_REL      0x0001\n#define ET_EXEC     0x0002\n#define ET_DYN      0x0003\n#define ET_CORE     0x0004\n#define ET_LOPROC   0xff00\n#define ET_HIPROC   0xffff\n\n#define EM_NONE     0x0000\n#define EM_M32      0x0001\n#define EM_SPARC    0x0002\n#define EM_386      0x0003\n#define EM_68K      0x0004\n#define EM_88K      0x0005\n#define EM_860      0x0007\n#define EM_MIPS     0x0008\n\n#define EV_NONE     0x0000\n#define EV_CURRENT  0x0001\n\n#define EI_MAG0     0\n#define EI_MAG1     1\n#define EI_MAG2     2\n#define EI_MAG3     3\n#define EI_CLASS    4\n#define EI_DATA     5\n#define EI_VERSION  6\n#define EI_PAD      7\n#define EI_NIDENT   16\n\n#define ELFMAG0     0x7f\n#define ELFMAG1     'E'\n#define ELFMAG2     'L'\n#define ELFMAG3     'F'\n\n#define ELFCLASSNONE    0\n#define ELFCLASS32      1\n#define ELFCLASS64      2\n\n#define SHN_UNDEF       0x0000\n#define SHN_LORESERVE   0xff00\n#define SHN_LOPROC      0xff00\n#define SHN_HIPROC      0xff1f\n#define SHN_ABS         0xfff1\n#define SHN_COMMON      0xfff2\n#define SHN_HIRESERVE   0xffff\n\n#define SHT_NULL        0\n#define SHT_PROGBITS    1\n#define SHT_SYMTAB      2\n#define SHT_STRTAB      3\n#define SHT_RELA        4\n#define SHT_HASH        5\n#define SHT_DYNAMIC     6\n#define SHT_NOTE        7\n#define SHT_NOBITS      8\n#define SHT_REL         9\n#define SHT_SHLIB       10\n#define SHT_DYNSYM      11\n#define SHT_LOPROC      0x70000000\n#define SHT_HIPROC      0x7fffffff\n#define SHT_LOUSER      0x80000000\n#define SHT_HIUSER      0xffffffff\n\n#define DT_NULL     0\n#define DT_NEEDED   1\n#define DT_PLTRELSZ 2\n#define DT_PLTGOT   3\n#define DT_HASH     4\n#define DT_STRTAB   5\n#define DT_SYMTAB   6\n#define DT_RELA     7\n#define DT_RELASZ   8\n#define DT_RELAENT  9\n#define DT_STRSZ    10\n#define DT_SYMENT   11\n#define DT_INIT     12\n#define DT_FINI     13\n#define DT_SONAME   14\n#define DT_RPATH    15\n#define DT_SYMBOLIC 16\n#define DT_REL      17\n#define DT_RELSZ    18\n#define DT_RELENT   19\n#define DT_PLTREL   20\n#define DT_DEBUG    21\n#define DT_TEXTREL  22\n#define DT_JMPREL   23\n#define DT_LOPROC   0x70000000\n#define DT_HIPROC   0x7fffffff\n\n#define PT_NULL     0\n#define PT_LOAD     1\n#define PT_DYNAMIC  2\n#define PT_INTERP   3\n#define PT_NOTE     4\n#define PT_SHLIB    5\n#define PT_PHDR     6\n#define PT_LOPROC   0x70000000\n#define PT_HIPROC   0x7fffffff\n\n#define PF_X        0x1\n#define PF_W        0x2\n#define PF_R        0x4\n#define PF_MASKPROC 0xf0000000\n\n#define ELF32_ST_BIND(i) ((i) >> 4)\n#define ELF32_ST_TYPE(i) ((i) & 0xf)\n#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf))\n\n#define STB_LOCAL   0\n#define STB_GLOBAL  1\n#define STB_WEAK    2\n#define STB_LOPROC  13\n#define STB_HIPROC  15\n\n#define STT_NOTYPE  0\n#define STT_OBJECT  1\n#define STT_FUNC    2\n#define STT_SECTION 3\n#define STT_FILE    4\n#define STT_LOPROC  13\n#define STT_HIPROC  15\n\n/**\n * \\ingroup binfmt\n * \\brief elf32 file header\n */\nstruct elf32_hdr {\n    uint8_t     e_ident[EI_NIDENT];\n    elf32_half  e_type;\n    elf32_half  e_machine;\n    elf32_word  e_version;\n    elf32_addr  e_entry;\n    elf32_off   e_phoff;\n    elf32_off   e_shoff;\n    elf32_word  e_flags;\n    elf32_half  e_ehsize;\n    elf32_half  e_phentsize;\n    elf32_half  e_phnum;\n    elf32_half  e_shentsize;\n    elf32_half  e_shnum;\n    elf32_half  e_shstrndx;\n};\n\n/**\n * \\ingroup binfmt\n * \\brief elf32 section header\n */\nstruct elf32_shdr {\n    elf32_word  sh_name;\n    elf32_word  sh_type;\n    elf32_word  sh_flags;\n    elf32_addr  sh_addr;\n    elf32_off   sh_offset;\n    elf32_word  sh_size;\n    elf32_word  sh_link;\n    elf32_word  sh_info;\n    elf32_word  sh_addralign;\n    elf32_word  sh_entsize;\n};\n\n/**\n * \\ingroup binfmt\n * \\brief elf32 symbol\n */\nstruct elf32_sym {\n    elf32_word  st_name;\n    elf32_word  st_value;\n    elf32_word  st_size;\n    uint8_t     st_info;\n    uint8_t     st_other;\n    elf32_half  st_shndx;\n};\n\n/**\n * \\ingroup binfmt\n * \\brief elf32 program header\n */\nstruct elf32_phdr {\n    elf32_word  p_type;\n    elf32_off   p_offset;\n    elf32_addr  p_vaddr;\n    elf32_addr  p_paddr;\n    elf32_word  p_filesz;\n    elf32_word  p_memsz;\n    elf32_word  p_flags;\n    elf32_word  p_align;\n};\n\n/**\n * \\ingroup binfmt\n * \\brief elf32 dynamic entry\n */\nstruct elf32_dyn {\n    elf32_sword     d_tag;\n    union {\n        elf32_word  d_val;\n        elf32_addr  d_ptr;\n    } d_un;\n};\n\n#endif /* ! _ELF_H */\n"
  },
  {
    "path": "kernel/include/sys/proc.h",
    "content": "#ifndef _SYS_PROC_H\n#define _SYS_PROC_H\n\n#include <core/system.h>\n\nstruct proc;\nstruct pgroup;\nstruct session;\n\n#include <mm/vm.h>\n#include <fs/vfs.h>\n#include <ds/queue.h>\n#include <sys/thread.h>\n#include <sys/signal.h>\n#include <dev/dev.h>\n\n/**\n * \\ingroup sys\n * \\brief session\n */\nstruct session {\n    /** Session ID */\n    pid_t sid;\n\n    /** Process Groups */\n    struct queue *pgps;\n\n    /** Session Leader */\n    struct proc *leader;\n\n    /* Controlling Terminal */\n    struct dev *ctty;\n\n    /** Session node on sessions queue */\n    struct qnode *qnode;\n};\n\n/**\n * \\ingroup sys\n * \\brief process Group\n */\nstruct pgroup {\n    /** Process Group ID */\n    pid_t pgid;\n\n    /** Associated Session */\n    struct session *session;\n\n    /** Session Queue Node */\n    struct qnode *session_node;\n\n    /** Processes */\n    struct queue *procs;\n\n    /** Process Group Leader */\n    struct proc *leader;\n\n    /** Group node on pgroups queue */\n    struct qnode *qnode;\n};\n\n/**\n * \\ingroup sys\n * \\brief process\n */\nstruct proc {\n    /** Process ID */\n    pid_t pid;\n\n    /** Associated Process Group */\n    struct pgroup *pgrp;\n    struct qnode  *pgrp_node;\n\n    /** Process name - XXX */\n    char *name;\n\n    /** Open file descriptors */\n    struct file *fds;\n\n    /** Parent process */\n    struct proc *parent;\n\n    /** Current Working Directory */\n    char *cwd;\n\n    /** File mode creation mask */\n    mode_t mask;\n\n    /** User ID */\n    uid_t uid;\n\n    /** Groupd ID */\n    gid_t gid;\n\n    /** Process initial heap pointer */\n    uintptr_t heap_start;\n\n    /** Process current heap pointer */\n    uintptr_t heap;\n\n    /** Process entry point */  \n    uintptr_t entry;\n\n    /** Virtual memory regions */\n    struct vm_space vm_space;\n\n    struct vm_entry *heap_vm;\n    struct vm_entry *stack_vm;\n\n    /** Process threads */\n    struct queue threads;\n\n    /** Threads join wait queue */\n    struct queue thread_join;\n\n    /** Recieved signals queue */\n    struct queue *sig_queue;\n\n    /** Dummy queue for children wait */\n    struct queue wait_queue;\n\n    /** Registered signal handlers */\n    struct sigaction sigaction[SIG_MAX+1];\n\n    /** Exit status of process */\n    int exit;\n\n    /** Process is running? */\n    int running;\n};\n\n/* sys/fork.c */\nint proc_fork(struct thread *thread, struct proc **ref);\n\n/* sys/execve.c */\nint proc_execve(struct thread *thread, const char *fn, char * const argv[], char * const env[]);\n\n/* sys/proc.c */\npid_t proc_pid_alloc(void);\nvoid  proc_pid_free(int pid);\nstruct proc *proc_pid_find(pid_t pid);\n\nint proc_new(struct proc **ref);\nint session_new(struct proc *proc);\nint pgrp_new(struct proc *proc, struct pgroup **ref_pgrp);\n\nvoid proc_kill(struct proc *proc);\nint  proc_reap(struct proc *proc);\nint  proc_fd_get(struct proc *proc);\nvoid proc_fd_release(struct proc *proc, int fd);\nvoid proc_dump(struct proc *proc);\n\nint  proc_init(struct proc *proc);\n\n#define PROC_EXIT(info, code) ((((info) & 0xff) << 8) | ((code) & 0xff))\n#define PROC_UIO(proc) ((struct uio){.cwd = (proc)->cwd, .uid = (proc)->uid, .gid = (proc)->gid, .mask = (proc)->mask})\n\nextern struct queue *procs;\nextern struct queue *pgroups;\nextern struct queue *sessions;\n\n#endif /* ! _SYS_PROC_H */\n"
  },
  {
    "path": "kernel/include/sys/sched.h",
    "content": "#ifndef _SYS_SCHED_H\n#define _SYS_SCHED_H\n\n#include <core/system.h>\n#include <sys/proc.h>\n#include <ds/queue.h>\n\nextern struct queue *ready_queue;\nextern struct thread *curthread;\n#define curproc (curthread->owner)\n\nextern int kidle;\nvoid kernel_idle(void);\nvoid scheduler_init(void);\nvoid sched_thread_spawn(struct thread *thread);\nvoid sched_init_spawn(struct proc *init);\nvoid schedule(void);\n\nvoid sched_thread_ready(struct thread *thread);\n\n#endif /* ! _SYS_SCHED_H */\n"
  },
  {
    "path": "kernel/include/sys/signal.h",
    "content": "#ifndef _SYS_SIGNAL_H\n#define _SYS_SIGNAL_H\n\n#include <core/system.h>\n\nstruct sigaction;\n\n#include <sys/proc.h>\n\n/* Signal numbers */\n#define SIGHUP  1   /**< hangup */\n#define SIGINT  2   /**< interrupt */\n#define SIGQUIT 3   /**< quit */\n#define SIGILL  4   /**< illegal instruction (not reset when caught) */\n#define SIGTRAP 5   /**< trace trap (not reset when caught) */\n#define SIGIOT  6   /**< IOT instruction */\n#define SIGABRT 6   /**< used by abort, replace SIGIOT in the future */\n#define SIGEMT  7   /**< EMT instruction */\n#define SIGFPE  8   /**< floating point exception */\n#define SIGKILL 9   /**< kill (cannot be caught or ignored) */\n#define SIGBUS  10  /**< bus error */\n#define SIGSEGV 11  /**< segmentation violation */\n#define SIGSYS  12  /**< bad argument to system call */\n#define SIGPIPE 13  /**< write on a pipe with no one to read it */\n#define SIGALRM 14  /**< alarm clock */\n#define SIGTERM 15  /**< software termination signal from kill */\n#define SIGURG  16  /**< urgent condition on IO channel */\n#define SIGSTOP 17  /**< sendable stop signal not from tty */\n#define SIGTSTP 18  /**< stop signal from tty */\n#define SIGCONT 19  /**< continue a stopped process */\n#define SIGCHLD 20  /**< to parent on child stop or exit */\n#define SIGCLD  20  /**< System V name for SIGCHLD */\n#define SIGTTIN 21  /**< to readers pgrp upon background tty read */\n#define SIGTTOU 22  /**< like TTIN for output if (tp->t_local&LTOSTOP) */\n#define SIGIO   23  /**< input/output possible signal */\n#define SIGPOLL SIGIO   /**< System V name for SIGIO */\n#define SIGWINCH 24 /* window changed */\n#define SIGUSR1 25  /**< user defined signal 1 */\n#define SIGUSR2 26  /**< user defined signal 2 */\n\n#define SIG_MAX 26\n\n#define SIGACT_ABORT        1\n#define SIGACT_TERMINATE    2\n#define SIGACT_IGNORE       3\n#define SIGACT_STOP         4\n#define SIGACT_CONTINUE     5\n\n/* libc bindings */\n#define SIG_DFL ((uintptr_t) 0)  /* Default action */\n#define SIG_IGN ((uintptr_t) 1)  /* Ignore action */\n#define SIG_ERR ((uintptr_t) -1) /* Error return */\n\n/**\n * \\ingroup sys\n * \\brief signal action\n */\nstruct sigaction {\n    uintptr_t sa_handler;\n    sigset_t  sa_mask;\n    int       sa_flags;\n};\n\nextern int sig_default_action[];\n\nint signal_send(int pid, int sig);\nint signal_proc_send(struct proc *proc, int signal);\nint signal_pgrp_send(struct pgroup *pg, int signal);\n\n#endif /* ! _SYS_SIGNAL_H */\n"
  },
  {
    "path": "kernel/include/sys/syscall.h",
    "content": "#ifndef _SYS_SYSCALL_H\n#define _SYS_SYSCALL_H\n\n#include <core/system.h>\n\nextern void (*syscall_table[])();\nextern const size_t syscall_cnt;\n\n#endif /* ! _SYS_SYSCALL_H */\n"
  },
  {
    "path": "kernel/include/sys/thread.h",
    "content": "#ifndef _SYS_THREAD_H\n#define _SYS_THREAD_H\n\n#include <core/system.h>\n\nstruct thread;\n\n#include <sys/proc.h>\n\ntypedef enum {\n    RUNNABLE,\n    ISLEEP, /* Interruptable SLEEP (I/O) */\n    USLEEP, /* Uninterruptable SLEEP (Waiting for event) */\n    ZOMBIE,\n} state_t;\n\n/**\n * \\ingroup sys\n * \\brief thread\n */\nstruct thread {\n    /** Thread ID */\n    tid_t tid;\n\n    /** Thread current state */\n    state_t state;\n\n    /** Thread owner process */\n    struct proc *owner;\n\n    /** Thread stack */\n    uintptr_t stack;\n    uintptr_t stack_base;\n    size_t    stack_size;\n\n    /** Current sleep queue */\n    struct queue *sleep_queue;\n    struct qnode *sleep_node;\n\n    /** Scheduler queue */\n    struct queue *sched_queue;\n    struct qnode *sched_node;\n\n    /** Arch specific data */\n    void *arch;\n\n    /** Thread flags */\n    int spawned;\n};\n\nint thread_queue_sleep(struct queue *queue);\nint thread_queue_wakeup(struct queue *queue);\nint thread_new(struct proc *proc, struct thread **rthread);\nint thread_create(struct thread *thread, uintptr_t stack, uintptr_t entry, uintptr_t uentry, uintptr_t arg, uintptr_t attr, struct thread **new_thread);\nint thread_kill(struct thread *thread);\n\n/* sys/execve.h */\nint thread_execve(struct thread *thread, char * const argp[], char * const envp[]);\n\n#endif /* ! _SYS_THREAD_H */\n"
  },
  {
    "path": "kernel/include/video/vbe.h",
    "content": "#ifndef _VIDEO_VBE_H\n#define _VIDEO_VBE_H\n\n#include <core/system.h>\n\n/* VBE Information Block */\nstruct vbe_info_block {\n    union {\n        uint8_t      sig_chr[4];\n        uint32_t     sig32;\n    }            vbe_signature;\n    uint16_t     vbe_version;\n    uint32_t     oem_string;\n    uint8_t      capabilities[4];\n    uint16_t     video_mode_ptr_off;\n    uint16_t     video_mode_ptr_seg;\n    uint16_t     total_memory;\n    uint16_t     oem_software_rev;\n    uint32_t     oem_vendor_name;\n    uint32_t     oem_product_name;\n    uint32_t     oem_product_rev;\n    uint16_t     reserved[111];\n    uint8_t      oemdata[256];\n} __packed;\n\nstruct mode_info_block {\n/* Mandatory information for all VBE revisions */\n   uint16_t mode_attributes;\n   uint8_t  win_a_attributes;\n   uint8_t  win_b_attributes;\n   uint16_t win_granularity;\n   uint16_t win_size;\n   uint16_t win_a_segment;\n   uint16_t win_b_segment;\n   uint32_t win_func_ptr;\n   uint16_t bytes_per_scanline;\n/* Mandatory information for VBE 1.2 and above */\n   uint16_t x_resolution;\n   uint16_t y_resolution;\n   uint8_t  x_char_size;\n   uint8_t  y_char_size;\n   uint8_t  number_of_planes;\n   uint8_t  bits_per_pixel;\n   uint8_t  number_of_banks;\n   uint8_t  memory_model;\n   uint8_t  bank_size;\n   uint8_t  number_of_image_pages;\n   uint8_t  reserved_page;\n/* Direct Color fields (required for direct/6 and YUV/7 memory models) */\n   uint8_t  red_mask_size;\n   uint8_t  red_field_position;\n   uint8_t  green_mask_size;\n   uint8_t  green_field_position;\n   uint8_t  blue_mask_size;\n   uint8_t  blue_field_position;\n   uint8_t  rsvd_mask_size;\n   uint8_t  rsvd_field_position;\n   uint8_t  direct_color_mode_info;\n/* Mandatory information for VBE 2.0 and above */\n   uint32_t phys_base_ptr;\n   uint32_t off_screen_mem_offset;\n   uint16_t off_screen_mem_size;\n/* Mandatory information for VBE 3.0 and above */\n   uint16_t lin_bytes_per_scanline;\n   uint8_t  bnk_number_of_pages;\n   uint8_t  lin_number_of_pages;\n   uint8_t  lin_red_mask_size;\n   uint8_t  lin_red_field_position;\n   uint8_t  lin_green_mask_size;\n   uint8_t  lin_green_field_position;\n   uint8_t  lin_blue_mask_size;\n   uint8_t  lin_blue_field_position;\n   uint8_t  lin_rsvd_mask_size;\n   uint8_t  lin_rsvd_field_position;\n   uint32_t max_pixel_clock;\n   uint8_t  reserved[189];\n} __packed;\n\n/* VBE Mode Numbers */\n#define VBE_MODE_VESA_DEFINED                            0x0100\n#define VBE_MODE_REFRESH_RATE_USE_CRTC                   0x0800\n#define VBE_MODE_LINEAR_FRAME_BUFFER                     0x4000\n#define VBE_MODE_PRESERVE_DISPLAY_MEMORY                 0x8000\n\n/* VBE GFX Mode Number */\n#define VBE_VESA_MODE_640X400X8                          0x100\n#define VBE_VESA_MODE_640X480X8                          0x101\n#define VBE_VESA_MODE_800X600X4                          0x102\n#define VBE_VESA_MODE_800X600X8                          0x103\n#define VBE_VESA_MODE_1024X768X4                         0x104\n#define VBE_VESA_MODE_1024X768X8                         0x105\n#define VBE_VESA_MODE_1280X1024X4                        0x106\n#define VBE_VESA_MODE_1280X1024X8                        0x107\n#define VBE_VESA_MODE_320X200X1555                       0x10D\n#define VBE_VESA_MODE_320X200X565                        0x10E\n#define VBE_VESA_MODE_320X200X888                        0x10F\n#define VBE_VESA_MODE_640X480X1555                       0x110\n#define VBE_VESA_MODE_640X480X565                        0x111\n#define VBE_VESA_MODE_640X480X888                        0x112\n#define VBE_VESA_MODE_800X600X1555                       0x113\n#define VBE_VESA_MODE_800X600X565                        0x114\n#define VBE_VESA_MODE_800X600X888                        0x115\n#define VBE_VESA_MODE_1024X768X1555                      0x116\n#define VBE_VESA_MODE_1024X768X565                       0x117\n#define VBE_VESA_MODE_1024X768X888                       0x118\n#define VBE_VESA_MODE_1280X1024X1555                     0x119\n#define VBE_VESA_MODE_1280X1024X565                      0x11A\n#define VBE_VESA_MODE_1280X1024X888                      0x11B\n#define VBE_VESA_MODE_1600X1200X8                        0x11C\n#define VBE_VESA_MODE_1600X1200X1555                     0x11D\n#define VBE_VESA_MODE_1600X1200X565                      0x11E\n#define VBE_VESA_MODE_1600X1200X888                      0x11F\n\n/* BOCHS/PLEX86 'own' mode numbers */\n#define VBE_OWN_MODE_320X200X8888                        0x140\n#define VBE_OWN_MODE_640X400X8888                        0x141\n#define VBE_OWN_MODE_640X480X8888                        0x142\n#define VBE_OWN_MODE_800X600X8888                        0x143\n#define VBE_OWN_MODE_1024X768X8888                       0x144\n#define VBE_OWN_MODE_1280X1024X8888                      0x145\n#define VBE_OWN_MODE_320X200X8                           0x146\n#define VBE_OWN_MODE_1600X1200X8888                      0x147\n#define VBE_OWN_MODE_1152X864X8                          0x148\n#define VBE_OWN_MODE_1152X864X1555                       0x149\n#define VBE_OWN_MODE_1152X864X565                        0x14a\n#define VBE_OWN_MODE_1152X864X888                        0x14b\n#define VBE_OWN_MODE_1152X864X8888                       0x14c\n\n#define VBE_VESA_MODE_END_OF_LIST                        0xFFFF\n\n/* Capabilities */\n#define VBE_CAPABILITY_8BIT_DAC                          0x0001\n#define VBE_CAPABILITY_NOT_VGA_COMPATIBLE                0x0002\n#define VBE_CAPABILITY_RAMDAC_USE_BLANK_BIT              0x0004\n#define VBE_CAPABILITY_STEREOSCOPIC_SUPPORT              0x0008\n#define VBE_CAPABILITY_STEREO_VIA_VESA_EVC               0x0010\n\n/* Mode Attributes */\n#define VBE_MODE_ATTRIBUTE_SUPPORTED                     0x0001\n#define VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE  0x0002\n#define VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT              0x0004\n#define VBE_MODE_ATTRIBUTE_COLOR_MODE                    0x0008\n#define VBE_MODE_ATTRIBUTE_GRAPHICS_MODE                 0x0010\n#define VBE_MODE_ATTRIBUTE_NOT_VGA_COMPATIBLE            0x0020\n#define VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW      0x0040\n#define VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE      0x0080\n#define VBE_MODE_ATTRIBUTE_DOUBLE_SCAN_MODE              0x0100\n#define VBE_MODE_ATTRIBUTE_INTERLACE_MODE                0x0200\n#define VBE_MODE_ATTRIBUTE_HARDWARE_TRIPLE_BUFFER        0x0400\n#define VBE_MODE_ATTRIBUTE_HARDWARE_STEREOSCOPIC_DISPLAY 0x0800\n#define VBE_MODE_ATTRIBUTE_DUAL_DISPLAY_START_ADDRESS    0x1000\n\n#define VBE_MODE_ATTTRIBUTE_LFB_ONLY                     ( VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE )\n\n/* Window attributes */\n#define VBE_WINDOW_ATTRIBUTE_RELOCATABLE                 0x01\n#define VBE_WINDOW_ATTRIBUTE_READABLE                    0x02\n#define VBE_WINDOW_ATTRIBUTE_WRITEABLE                   0x04\n\n/* Memory model */\n#define VBE_MEMORYMODEL_TEXT_MODE                        0x00\n#define VBE_MEMORYMODEL_CGA_GRAPHICS                     0x01\n#define VBE_MEMORYMODEL_HERCULES_GRAPHICS                0x02\n#define VBE_MEMORYMODEL_PLANAR                           0x03\n#define VBE_MEMORYMODEL_PACKED_PIXEL                     0x04\n#define VBE_MEMORYMODEL_NON_CHAIN_4_256                  0x05\n#define VBE_MEMORYMODEL_DIRECT_COLOR                     0x06\n#define VBE_MEMORYMODEL_YUV                              0x07\n\n/* DirectColorModeInfo */\n#define VBE_DIRECTCOLOR_COLOR_RAMP_PROGRAMMABLE          0x01\n#define VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE          0x02\n\nstruct pm_info_block {\n    char        signature[4];\n    uint16_t    entry_point;\n    uint16_t    pm_initalize;\n    uint16_t    bios_data_sel;\n    uint16_t    a000h;\n    uint16_t    b000h;\n    uint16_t    b800h;\n    uint16_t    code_seg_sel;\n    uint8_t     in_protect_mode;\n    uint8_t     checksum;\n} __packed;\n\n#endif /* _VIDEO_VBE_H */\n"
  },
  {
    "path": "kernel/include/video/vesa.h",
    "content": "#ifndef _VIDEO_VESA\n#define _VIDEO_VESA\n\n#include <video/vbe.h>\n\nstruct fbdev_vesa {\n    struct vbe_info_block *vbe_info;\n    struct mode_info_block *mode_info;\n};\n\n#endif /* ! _VIDEO_VESA */\n"
  },
  {
    "path": "kernel/mm/Build.mk",
    "content": "obj-y += mm.o\nobj-y += vmm.o\nobj-y += vm_space.o\nobj-y += vm_entry.o\nobj-y += vm_anon.o\nobj-y += vm_object.o\nobj-y += fault.o\nobj-y += buddy.o\nobj-y += kvmem.o\n"
  },
  {
    "path": "kernel/mm/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" kernel/$(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" kernel/$(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" kernel/$(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" kernel/$(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/mm/buddy.c",
    "content": "/*\n *                  Buddy Memory Allocator \n *\n *\n *  This file is part of AquilaOS and is released under the terms of\n *  GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar\n */\n\n#include <core/system.h>\n#include <core/panic.h>\n#include <ds/bitmap.h>\n#include <ds/buddy.h>\n#include <mm/buddy.h>\n#include <boot/boot.h>\n\nsize_t k_total_mem, k_used_mem;\nstatic uintptr_t kstart = 0, kend = 0;\n\nstatic char alloc_area[1024 * 1024]; /* 1 MiB heap area */\nstatic char *alloc_mark = alloc_area;\n\nstatic inline void *alloc(size_t size, size_t align)\n{\n    char *ret = (char *)((uintptr_t)(alloc_mark + align - 1) & (~(align - 1)));\n    alloc_mark = ret + size;\n    memset(ret, 0, size);\n    return ret;\n}\n\nstruct buddy buddies[BUDDY_ZONE_NR][BUDDY_MAX_ORDER+1];\nuintptr_t buddy_zone_offset[BUDDY_ZONE_NR+1] = {\n    [BUDDY_ZONE_DMA]     = 0,           /* 0 - 16 MiB */\n    [BUDDY_ZONE_NORMAL]  = 0x1000000,   /* 16 MiB -  */\n    [BUDDY_ZONE_NR]      = (uintptr_t) -1,\n};\n\nstatic size_t buddy_recursive_alloc(int zone, size_t order)\n{\n    if (order > BUDDY_MAX_ORDER)\n        return -1;\n\n    /* Check if there is a free bit in current order */\n    if (buddies[zone][order].usable) {\n        /* Search for a free bit in current order */\n        for (size_t i = buddies[zone][order].first_free_idx; i <= buddies[zone][order].bitmap.max_idx; ++i) {\n\n            /* If bit at i is not checked */\n            if (!bitmap_check(&buddies[zone][order].bitmap, i)) {\n\n                /* Mark the bit as used */\n                bitmap_set(&buddies[zone][order].bitmap, i);\n                buddies[zone][order].usable--;\n\n                /* Shift first_free_idx to search after child_idx */\n                buddies[zone][order].first_free_idx = i + 1;\n\n                return i;\n            }                \n        }\n\n        return -1;\n    } else {\n        /* Search for a buddy in higher order to split */\n        size_t idx = buddy_recursive_alloc(zone, order + 1);\n\n        /* Could not find a free budy */\n        if (idx == (size_t) -1) return -1;\n\n        /* Select the left child of the selected bit */\n        size_t child_idx = idx << 1;\n\n        /* Mark the selected bit as used */\n        bitmap_set(&buddies[zone][order].bitmap, child_idx);\n\n        /* Mark it's buddy as free */\n        bitmap_clear(&buddies[zone][order].bitmap, BUDDY_IDX(child_idx));\n        buddies[zone][order].usable++;\n\n        /* Shift first_free_idx to search after child_idx */\n        buddies[zone][order].first_free_idx = child_idx + 1;\n\n        return child_idx;\n    }\n}\n\nstatic void buddy_recursive_free(int zone, size_t order, size_t idx)\n{\n    if (order > BUDDY_MAX_ORDER) return;\n    if (idx > buddies[zone][order].bitmap.max_idx) return;\n\n    /* Can't free an already free bit */\n    if (!bitmap_check(&buddies[zone][order].bitmap, idx)) return;\n\n    /* Check if buddy bit is free, then combine */\n    if (order < BUDDY_MAX_ORDER && !bitmap_check(&buddies[zone][order].bitmap, BUDDY_IDX(idx))) {\n        bitmap_set(&buddies[zone][order].bitmap, BUDDY_IDX(idx));\n        buddies[zone][order].usable--;\n\n        buddy_recursive_free(zone, order + 1, idx >> 1);\n    } else {\n        bitmap_clear(&buddies[zone][order].bitmap, idx);\n        buddies[zone][order].usable++;\n\n        /* Update first_free_idx */\n        if (buddies[zone][order].first_free_idx > idx)\n            buddies[zone][order].first_free_idx = idx;\n    }\n}\n\n/** allocate new buddy\n * @param zone zone index\n * @param _sz chunk size\n */\npaddr_t buddy_alloc(int zone, size_t _sz)\n{\n    if (_sz > BUDDY_MAX_BS)\n        panic(\"Cannot allocate buddy\");\n\n    size_t sz = BUDDY_MIN_BS;\n\n    /* FIXME */\n    size_t order = 0;\n    for (; order <= BUDDY_MAX_ORDER; ++order) {\n        if (sz >= _sz)\n            break;\n        sz <<= 1;\n    }\n\n    k_used_mem += sz;\n\n    size_t idx = buddy_recursive_alloc(zone, order);\n\n    if (idx != (size_t) -1) {\n        return buddy_zone_offset[zone] + (uintptr_t) (idx * (BUDDY_MIN_BS << order));\n    } else {\n        panic(\"Cannot find free buddy\");\n        //return (uintptr_t) NULL;\n    }\n}\n\nvoid buddy_free(int zone, paddr_t addr, size_t size)\n{\n    if (addr >= kstart && addr < kend)\n        panic(\"trying to free from kernel code\");\n\n    size_t sz = BUDDY_MIN_BS;\n\n    /* FIXME */\n    size_t order = 0;\n    for (; order < BUDDY_MAX_ORDER; ++order) {\n        if (sz >= size)\n            break;\n        sz <<= 1;\n    }\n\n    k_used_mem -= sz;\n\n    addr -= buddy_zone_offset[zone];\n    size_t idx = (addr / (BUDDY_MIN_BS << order));  // & (sz - 1);\n    buddy_recursive_free(zone, order, idx);\n}\n\nvoid buddy_set_unusable(paddr_t addr, size_t size)\n{\n\n    printk(\"buddy: set unusable: %p-%p\\n\", addr, addr+size-1);\n\n    for (int zone = 0; size && zone < BUDDY_ZONE_NR; ++zone) {\n\n        uintptr_t zone_start = buddy_zone_offset[zone];\n        uintptr_t zone_end   = buddy_zone_offset[zone+1];\n\n        if (addr + size < zone_start || addr >= zone_end)\n            continue;\n\n        uintptr_t zone_addr = MAX(addr, zone_start) - zone_start;\n        uintptr_t zone_size = MIN(addr + size, zone_end) - zone_start - zone_addr;\n\n        size_t start_idx = zone_addr / BUDDY_MAX_BS;\n        size_t end_idx   = (zone_addr + zone_size + BUDDY_MAX_BS - 1) / BUDDY_MAX_BS;\n\n        if (end_idx > buddies[zone][BUDDY_MAX_ORDER].bitmap.max_idx)\n            end_idx = buddies[zone][BUDDY_MAX_ORDER].bitmap.max_idx;\n\n        bitmap_set_range(&buddies[zone][BUDDY_MAX_ORDER].bitmap, start_idx, end_idx);\n\n        size_t ffidx = buddies[zone][BUDDY_MAX_ORDER].first_free_idx;\n\n        if (ffidx >= start_idx && ffidx <= end_idx)\n            buddies[zone][BUDDY_MAX_ORDER].first_free_idx = end_idx + 1;\n\n        buddies[zone][BUDDY_MAX_ORDER].usable -= (end_idx - start_idx + 1);\n\n        k_used_mem += size;\n    }\n}\n\nint buddy_setup(size_t total_mem)\n{\n    printk(\"buddy: Setting up buddy allocator (total memory %p)\\n\", total_mem);\n\n    k_total_mem = total_mem;\n    k_used_mem  = 0;\n\n    for (int zone = 0; zone < BUDDY_ZONE_NR; ++zone) {\n        size_t bits_cnt = 0;\n\n        if (zone < BUDDY_ZONE_NR - 1) {\n            bits_cnt = (buddy_zone_offset[zone+1] - buddy_zone_offset[zone]) / BUDDY_MAX_BS;\n        } else {\n            /* Last zone */\n            bits_cnt = (total_mem - buddy_zone_offset[zone]) / BUDDY_MAX_BS;\n        }\n\n        for (int i = BUDDY_MAX_ORDER; i >= 0; --i) {\n            size_t bmsize = bitmap_size(bits_cnt);\n\n            buddies[zone][i].bitmap.map = alloc(bmsize, 4);\n            buddies[zone][i].bitmap.max_idx = bits_cnt - 1;\n\n            bits_cnt <<= 1;\n        }\n\n        /* Set the heighst order as free and the rest as unusable */\n        bitmap_clear_range(&buddies[zone][BUDDY_MAX_ORDER].bitmap, 0, buddies[zone][BUDDY_MAX_ORDER].bitmap.max_idx);\n        buddies[zone][BUDDY_MAX_ORDER].first_free_idx = 0;\n        buddies[zone][BUDDY_MAX_ORDER].usable = buddies[zone][BUDDY_MAX_ORDER].bitmap.max_idx + 1;\n\n        for (int i = 0; i < BUDDY_MAX_ORDER; ++i) {\n            bitmap_set_range(&buddies[zone][i].bitmap, 0, buddies[zone][i].bitmap.max_idx);\n            buddies[zone][i].first_free_idx = -1;\n            buddies[zone][i].usable = 0;\n        }\n    }\n\n    /* FIXME */\n    extern char kernel_start;\n    extern char kernel_end;\n\n    kstart = (uintptr_t) &kernel_start;\n    kend   = (uintptr_t) &kernel_end;\n\n    buddy_set_unusable(kstart, kend - kstart);\n\n    extern struct boot *__kboot;\n\n    if (__kboot->symtab) {\n        struct elf32_shdr *shdr = __kboot->symtab;\n        buddy_set_unusable(LMA((uintptr_t) shdr->sh_addr), shdr->sh_size);\n    }\n\n    if (__kboot->strtab) {\n        struct elf32_shdr *shdr = __kboot->strtab;\n        buddy_set_unusable(LMA((uintptr_t) shdr->sh_addr), shdr->sh_size);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "kernel/mm/fault.c",
    "content": "#include <core/system.h>\n#include <core/panic.h>\n#include <core/arch.h>\n\n#include <mm/pmap.h>\n#include <mm/vm.h>\n\n#include <sys/sched.h>\n\n/**\n * \\ingroup mm\n * \\brief a structure holding parameters relevant to a page fault\n */\nstruct pf {\n    int flags;\n    vaddr_t addr;\n\n    struct vm_space *vm_space;\n    struct vm_entry *vm_entry;\n\n    size_t off;\n    hash_t hash;\n};\n\nstatic inline int check_violation(int flags, int vm_flags)\n{\n    /* returns 1 on violation, 0 otherwise */\n    return\n    ((flags & PF_READ)  && !(vm_flags & VM_UR)) ||\n    ((flags & PF_WRITE) && !(vm_flags & VM_UW)) ||\n    ((flags & PF_EXEC)  && !(vm_flags & VM_UX));\n}\n\n/**\n * \\ingroup mm\n * \\brief handle the page fault if the page is already present\n * in virtual memory mapping\n */\nstatic inline int pf_present(struct pf *pf)\n{\n    /* page is already present but with incorrect permissions */\n    struct vm_entry *vm_entry = pf->vm_entry;\n    struct vm_anon  *vm_anon  = vm_entry->vm_anon;\n\n    struct pmap *pmap = pf->vm_space->pmap;\n\n    /* if there is no anon or the anon is shared\n     * we can't handle it here and have to fallthrough to \n     * other handlers\n     */\n    if (!vm_anon || vm_anon->ref != 1)\n        return 0;\n\n    /* we own the anon */\n    struct hashmap_node *hash_node = hashmap_lookup(vm_anon->arefs, pf->hash, &pf->off);\n    struct vm_aref *vm_aref = (struct vm_aref *) (hash_node? hash_node->entry : NULL);\n\n    if (!vm_aref || vm_aref->ref != 1)\n        return 0;\n\n    if (vm_aref->flags & VM_COPY) {\n        /* copy page */\n        struct vm_page *new_page = mm_page_alloc();\n        new_page->off = vm_aref->vm_page->off;\n        new_page->ref = 1;\n        new_page->vm_object = NULL;\n\n        pmap_page_copy(vm_aref->vm_page->paddr, new_page->paddr);\n\n        mm_page_decref(vm_aref->vm_page->paddr);\n\n        vm_aref->vm_page = new_page;\n        vm_aref->flags &= ~VM_COPY;\n\n        mm_page_map(pmap, pf->addr, new_page->paddr, pf->vm_entry->flags & VM_PERM);\n    } else {\n        /* we own the aref, just change permissions */\n        pmap_protect(pmap, pf->addr, pf->addr+PAGE_SIZE, pf->vm_entry->flags & VM_PERM);\n    }\n\n    return 1;\n}\n\nstatic inline int pf_anon(struct pf *pf)\n{\n    struct vm_entry *vm_entry = pf->vm_entry;\n    struct vm_anon  *vm_anon  = vm_entry->vm_anon;\n\n    struct pmap *pmap = pf->vm_space->pmap;\n\n    if (vm_anon->flags & VM_COPY) {\n\n        if (vm_anon->ref > 1) {\n            struct vm_anon *new_anon = vm_anon_copy(vm_anon);\n            vm_anon_decref(vm_anon);\n            vm_entry->vm_anon = new_anon;\n            vm_anon = new_anon;\n        }\n\n        vm_anon->flags &= ~VM_COPY;\n    }\n\n    struct hashmap_node *aref_node = hashmap_lookup(vm_anon->arefs, pf->hash, &pf->off);\n\n    if (!aref_node || !aref_node->entry)\n        return 0;\n\n    struct vm_aref *aref = (struct vm_aref *) aref_node->entry;\n\n    if (!aref->vm_page)\n        panic(\"aref has no page\");\n\n    if (!(pf->flags & PF_WRITE)) {\n        /* map read-only */\n        struct vm_page *vm_page = aref->vm_page;\n\n        uint32_t perm = (vm_entry->flags & VM_PERM) & ~(VM_UW|VM_KW);\n        mm_page_map(pmap, pf->addr, vm_page->paddr, perm);\n        mm_page_incref(vm_page->paddr);\n\n        return 1;\n    }\n\n    /* we have PF_WRITE */\n\n    if (aref->ref == 1) {\n        /* we own the aref, just map */\n\n        struct vm_page *vm_page = aref->vm_page;\n\n        uint32_t perm = vm_entry->flags & VM_PERM;\n        mm_page_map(pmap, pf->addr, vm_page->paddr, perm);\n\n        mm_page_incref(vm_page->paddr);\n\n        return 1;\n    }\n\n    /* copy, map read-write */\n\n    struct vm_aref *new_aref = kmalloc(sizeof(struct vm_aref), &M_VM_AREF, M_ZERO);\n\n    if (!new_aref) {\n        /* TODO */\n    }\n\n    new_aref->ref = 1;\n    new_aref->flags = aref->flags;\n\n    aref->ref--;\n\n    struct vm_page *vm_page = aref->vm_page;\n\n    struct vm_page *new_page = mm_page_alloc();\n    new_page->off = vm_page->off;\n    new_page->ref = 1;\n    new_page->vm_object = NULL;\n\n    pmap_page_copy(vm_page->paddr, new_page->paddr);\n\n    new_aref->vm_page = new_page;\n\n    hashmap_node_remove(vm_entry->vm_anon->arefs, aref_node);\n    hashmap_insert(vm_entry->vm_anon->arefs, pf->hash, new_aref);\n\n    mm_page_map(pmap, pf->addr, new_page->paddr, vm_entry->flags & VM_PERM);\n\n    return 1;\n}\n\nstatic inline struct vm_page *vm_object_page(struct vm_object *vm_object, hash_t hash, size_t off)\n{\n    struct hashmap_node *hash_node = hashmap_lookup(vm_object->pages, hash, &off);\n    struct vm_page *vm_page = NULL;\n\n    if (hash_node) {\n        /* page was found in the vm object */\n        vm_page = (struct vm_page *) hash_node->entry;\n    } else {\n        /* page was not found, page in */\n        if (vm_object->pager && vm_object->pager->in) {\n            vm_page = vm_object->pager->in(vm_object, off);\n        } else {\n            /* what should we do now? */\n            panic(\"Shit\");\n        }\n    }\n\n    return vm_page;\n}\n\nstatic inline int pf_object(struct pf *pf)\n{\n    struct vm_entry *vm_entry = pf->vm_entry;\n\n    struct vm_object *vm_object = vm_entry->vm_object;\n    struct vm_page *vm_page = NULL;\n    struct pmap *pmap = pf->vm_space->pmap;\n\n    /* look for page in the object pages hashmap */\n    vm_page = vm_object_page(vm_object, pf->hash, pf->off);\n\n    if (!(vm_entry->flags & VM_UW)) {\n        /* read only page -- just map */\n        mm_page_incref(vm_page->paddr);\n        mm_page_map(pmap, pf->addr, vm_page->paddr, vm_entry->flags & VM_PERM);\n        return 1;\n    }\n\n    /* read-write page -- promote */\n\n    /* allocate a new anon if we don't have one */\n    if (!vm_entry->vm_anon) {\n        vm_entry->vm_anon = vm_anon_new();\n        vm_entry->vm_anon->ref = 1;\n    }\n\n    struct vm_aref *vm_aref = kmalloc(sizeof(struct vm_aref), &M_VM_AREF, M_ZERO);\n\n    if (!vm_aref) {\n        /* TODO */\n    }\n\n    vm_aref->vm_page = vm_page;\n    vm_aref->ref = 1;\n\n    //if (!(pf->flags & PF_WRITE)) {\n    //    /* just mark for copying */\n    //    vm_aref->flags |= VM_COPY;\n    //    hashmap_insert(vm_entry->vm_anon->arefs, pf->hash, vm_aref);\n    //    uint32_t perms = (vm_entry->flags & VM_PERM) & ~(VM_UW|VM_KW);\n    //    mm_page_map(pmap, pf->addr, vm_page->paddr, perms);\n    //    return 1;\n    //}\n\n    /* copy page */\n    struct vm_page *new_page = mm_page_alloc();\n    new_page->off = vm_page->off;\n    new_page->ref = 1;\n    new_page->vm_object = NULL;\n\n    pmap_page_copy(vm_page->paddr, new_page->paddr);\n\n    vm_aref->vm_page = new_page;\n    hashmap_insert(vm_entry->vm_anon->arefs, pf->hash, vm_aref);\n\n    mm_page_map(pmap, pf->addr, new_page->paddr, vm_entry->flags & VM_PERM);\n\n\n    return 1;\n}\n\nstatic inline int pf_zero(struct pf *pf)\n{\n    struct vm_entry *vm_entry = pf->vm_entry;\n    struct pmap *pmap = pf->vm_space->pmap;\n\n    if (!vm_entry->vm_anon) {\n        vm_entry->vm_anon = vm_anon_new();\n        vm_entry->vm_anon->ref = 1;\n    }\n\n    struct vm_aref *vm_aref = kmalloc(sizeof(struct vm_aref), &M_VM_AREF, M_ZERO);\n    if (!vm_aref) {\n        /* TODO */\n    }\n\n    struct vm_page *new_page = mm_page_alloc();\n    new_page->off = pf->off;\n    new_page->ref = 1;\n    //new_page->vm_object = vm_object;\n    \n    vm_aref->vm_page = new_page;\n    vm_aref->ref = 1;\n\n    hashmap_insert(vm_entry->vm_anon->arefs, pf->hash, vm_aref);\n\n    mm_page_map(pmap, pf->addr, new_page->paddr, VM_KW); //vm_entry->flags & VM_PERM);\n    memset((void *) pf->addr, 0, PAGE_SIZE);\n    pmap_protect(pmap, pf->addr, pf->addr+PAGE_SIZE, vm_entry->flags & VM_PERM);\n\n    return 1;\n}\n\n/**\n * \\ingroup mm\n * \\brief handle a page fault\n *\n * This function is called from the arch subsystem to handle\n * a page fault\n *\n * \\param vaddr the virtual address that triggered the page fault\n * \\param flags the flags associated with page fault\n */\nvoid mm_page_fault(vaddr_t vaddr, int flags)\n{\n    vaddr_t addr = PAGE_ALIGN(vaddr);\n\n    struct vm_space *vm_space = &curproc->vm_space;\n    struct pmap *pmap = vm_space->pmap;\n    struct vm_entry *vm_entry = NULL;\n\n    /* look for vm_entry that contains the page */\n    vm_entry = vm_space_find(vm_space, addr);\n\n    /* segfault if there is no entry or the permissions are incorrect */\n    if (!vm_entry || check_violation(flags, vm_entry->flags))\n        goto sigsegv;\n\n    /* get page offset in object */\n    size_t off = addr - vm_entry->base + vm_entry->off;\n\n    /* hash the offset */\n    hash_t hash = hashmap_digest(&off, sizeof(off));\n\n    /* construct page fault structure */\n    struct pf pf = {\n        .flags = flags,\n        .addr = addr,\n        .vm_space = vm_space,\n        .vm_entry = vm_entry,\n        .off = off,\n        .hash = hash,\n    };\n\n    /* try to handle page present case */\n    if (flags & PF_PRESENT && pf_present(&pf))\n        return;\n\n    /* check the anon layer for the page and handle if present */\n    if (vm_entry->vm_anon && pf_anon(&pf))\n        return;\n\n    /* check the backening object for the page and handle if present */\n    if (vm_entry->vm_object && pf_object(&pf))\n        return;\n\n    /* just zero out the page */\n    if (pf_zero(&pf))\n        return;\n\nsigsegv:\n    signal_proc_send(curproc, SIGSEGV);\n    return;\n}\n"
  },
  {
    "path": "kernel/mm/kvmem.c",
    "content": "#include <core/system.h>\n#include <core/panic.h>\n#include <core/assert.h>\n\n#include <mm/pmap.h>\n#include <mm/mm.h>\n#include <mm/buddy.h> /* XXX */\n#include <mm/vm.h>\n\nuintptr_t __stack_chk_guard = 0xDEADBEEF;\nvoid __stack_chk_fail(void)\n{\n    panic(\"stack smashing detected\");\n}\n\nstruct queue *malloc_types = QUEUE_NEW();\n\nMALLOC_DEFINE(M_BUFFER, \"buffer\", \"generic buffer\");\nMALLOC_DEFINE(M_RINGBUF, \"ring-buffer\", \"ringbuffer structure\");\nMALLOC_DEFINE(M_QUEUE, \"queue\", \"queue structure\");\nMALLOC_DEFINE(M_QNODE, \"queue-node\", \"queue node structure\");\nMALLOC_DEFINE(M_HASHMAP, \"hashmap\", \"hashmap structure\");\nMALLOC_DEFINE(M_HASHMAP_NODE, \"hashmap-node\", \"hashmap node structure\");\n\nint debug_kmalloc = 0;\n\nstruct kvmem_node {\n    uint32_t addr : 28; /* Offseting (1GiB), 4-bytes aligned objects */\n    uint32_t free : 1;  /* Free or not flag */\n    uint32_t size : 26; /* Size of one object can be up to 256MiB */\n    uint32_t next : 25; /* Index of the next node */\n    struct malloc_type *type;\n};\n\nsize_t kvmem_used;\nsize_t kvmem_obj_cnt;\n\n#define KVMEM_BASE       ARCH_KVMEM_BASE\n\n#define NODE_ADDR(node) (KVMEM_BASE + ((node).addr) * 4U)\n#define NODE_SIZE(node) (((node).size) * 4U)\n#define LAST_NODE_INDEX (100000)\n#define MAX_NODE_SIZE   ((1UL << 26) - 1)\n\n#if 0\nstruct vm_entry kvmem_nodes = {\n    .base  = KVMEM_NODES,\n    .size  = KVMEM_NODES_SIZE,\n    .flags = VM_KRW,\n};\n#endif\n\n//struct kvmem_node *nodes = (struct kvmem_node *) KVMEM_NODES;\nstruct kvmem_node nodes[LAST_NODE_INDEX];\n\nvoid kvmem_setup(void)\n{\n    /* Setting up initial node */\n    nodes[0].addr = 0;\n    nodes[0].free = 1;\n    nodes[0].size = -1;\n    nodes[0].next = LAST_NODE_INDEX;\n\n    /* We have to set qnode to an arbitrary value since\n     * enqueue will use kmalloc which would try to enqueue\n     * M_QNODE type if qnode == NULL, gettings us in an\n     * infinite loop\n     */\n    M_QNODE.qnode = (void *) 0xDEADBEEF;\n    M_QNODE.qnode = enqueue(malloc_types, &M_QNODE);\n}\n\nuint32_t first_free_node = 0;\nstatic uint32_t get_node(void)\n{\n    for (unsigned i = first_free_node; i < LAST_NODE_INDEX; ++i) {\n        if (!nodes[i].size) {\n            return i;\n        }\n    }\n\n    panic(\"Can't find an unused node\");\n}\n\nvoid release_node(uint32_t i)\n{\n    if (nodes[i].type)\n        nodes[i].type->nr--;\n\n    memset(&nodes[i], 0, sizeof(struct kvmem_node));\n    nodes[i].free = 1;\n}\n\nuint32_t get_first_fit_free_node(uint32_t size)\n{\n    unsigned i = first_free_node;\n\n    while (!(nodes[i].free && nodes[i].size >= size)) {\n        if (nodes[i].next == LAST_NODE_INDEX)\n            panic(\"Can't find a free node\");\n        i = nodes[i].next;\n    }\n\n    return i;\n}\n\nvoid print_node(unsigned i)\n{\n    printk(\"Node[%d]\\n\", i);\n    printk(\"   |_ Addr   : %x\\n\", NODE_ADDR(nodes[i]));\n    printk(\"   |_ free?  : %s\\n\", nodes[i].free?\"yes\":\"no\");\n    printk(\"   |_ Size   : %d B [ %d KiB ]\\n\",\n        NODE_SIZE(nodes[i]), NODE_SIZE(nodes[i])/1024);\n    printk(\"   |_ Next   : %d\\n\", nodes[i].next );\n}\n\nvoid *kmalloc(size_t size, struct malloc_type *type, int flags)\n{\n    /* round size to 4-byte units */\n    size = (size + 3)/4;\n\n    /* Look for a first fit free node */\n    unsigned i = get_first_fit_free_node(size);\n\n    /* Mark it as used */\n    nodes[i].free = 0;\n\n    /* Split the node if necessary */\n    if (nodes[i].size > size) {\n        unsigned n = get_node();\n\n        nodes[n].addr = nodes[i].addr + size;\n        nodes[n].free = 1;\n        nodes[n].size = nodes[i].size - size;\n        nodes[n].next = nodes[i].next;\n\n        nodes[i].next = n;\n        nodes[i].size = size;\n    }\n\n    nodes[i].type = type;\n    type->nr++;\n\n    type->total += NODE_SIZE(nodes[i]);\n    kvmem_used += NODE_SIZE(nodes[i]);\n    kvmem_obj_cnt++;\n\n    vaddr_t map_base = PAGE_ALIGN(NODE_ADDR(nodes[i]));\n    vaddr_t map_end  = PAGE_ROUND(NODE_ADDR(nodes[i]) + NODE_SIZE(nodes[i]));\n    size_t  map_size = (map_end - map_base)/PAGE_SIZE;\n\n    if (map_size) {\n        struct vm_entry vm_entry;\n\n        vm_entry.paddr = 0,\n        vm_entry.base  = map_base,\n        vm_entry.size  = map_size * PAGE_SIZE,\n        vm_entry.flags = VM_KRW,\n\n        vm_map(&kvm_space, &vm_entry);\n    }\n\n    if (type->qnode == NULL) {\n        type->qnode = enqueue(malloc_types, type);\n    }\n\n    void *obj = (void *) NODE_ADDR(nodes[i]);\n\n    if (flags & M_ZERO) {\n        memset(obj, 0, size * 4);\n    }\n\n    return obj;\n}\n\nvoid kfree(void *_ptr)\n{\n    //printk(\"kfree(%p)\\n\", _ptr);\n    uintptr_t ptr = (uintptr_t) _ptr;\n\n    if (ptr < KVMEM_BASE)  /* That's not even allocatable */\n        return;\n\n    /* Look for the node containing _ptr -- merge sequential free nodes */\n    size_t cur_node = 0, prev_node = 0;\n\n    while (ptr != NODE_ADDR(nodes[cur_node])) {\n        /* check if current and previous node are free */\n        if (cur_node && nodes[cur_node].free && nodes[prev_node].free) {\n            /* check for overflow */\n            if ((uintptr_t) (nodes[cur_node].size + nodes[prev_node].size) <= MAX_NODE_SIZE) {\n                nodes[prev_node].size += nodes[cur_node].size;\n                nodes[prev_node].next  = nodes[cur_node].next;\n                release_node(cur_node);\n                cur_node = nodes[prev_node].next;\n                continue;\n            }\n        }\n\n        prev_node = cur_node;\n        cur_node = nodes[cur_node].next;\n\n        if (cur_node == LAST_NODE_INDEX)  /* Trying to free unallocated node */\n            goto done;\n    }\n\n    if (nodes[cur_node].free)  { /* Node is already free, dangling pointer? */\n        printk(\"double free detected at %p\\n\", ptr);\n        if (nodes[cur_node].type)\n            printk(\"object type: %s\\n\", nodes[cur_node].type->name);\n        panic(\"double free\");\n        //goto done;\n    }\n\n    /* First we mark our node as free */\n    nodes[cur_node].free = 1;\n    \n    if (nodes[cur_node].type) {\n        nodes[cur_node].type->total -= NODE_SIZE(nodes[cur_node]);\n        nodes[cur_node].type->nr--;\n        nodes[cur_node].type = NULL;\n    }\n\n    if (debug_kmalloc)\n        printk(\"NODE_SIZE %d\\n\", NODE_SIZE(nodes[cur_node]));\n\n    kvmem_used -= NODE_SIZE(nodes[cur_node]);\n    kvmem_obj_cnt--;\n\n    /* Now we merge all free nodes ahead -- except the last node */\n    while (nodes[cur_node].next < LAST_NODE_INDEX && nodes[cur_node].free) {\n        /* check if current and previous node are free */\n        if (cur_node && nodes[cur_node].free && nodes[prev_node].free) {\n            /* check for overflow */\n            if ((uintptr_t) (nodes[cur_node].size + nodes[prev_node].size) <= MAX_NODE_SIZE) {\n                nodes[prev_node].size += nodes[cur_node].size;\n                nodes[prev_node].next  = nodes[cur_node].next;\n                release_node(cur_node);\n                cur_node = nodes[prev_node].next;\n                continue;\n            }\n        }\n\n        prev_node = cur_node;\n        cur_node = nodes[cur_node].next;\n    }\n\n    cur_node = 0;\n    while (nodes[cur_node].next < LAST_NODE_INDEX) {\n        if (nodes[cur_node].free) {\n            //struct vm_entry vm_entry = {0};\n\n            //vm_entry.paddr = 0;\n            //vm_entry.base  = NODE_ADDR(nodes[cur_node]);\n            //vm_entry.size  = NODE_SIZE(nodes[cur_node]);\n            //vm_entry.flags = VM_KRW;\n\n            vaddr_t vaddr = NODE_ADDR(nodes[cur_node]);\n            size_t  size  = NODE_SIZE(nodes[cur_node]);\n\n            //vm_unmap(&kvm_space, &vm_entry);\n\n            /* XXX */\n            if (size < PAGE_SIZE) goto next;\n\n            vaddr_t sva = PAGE_ROUND(vaddr);\n            vaddr_t eva = PAGE_ALIGN(vaddr + size);\n\n            size_t nr = (eva - sva)/PAGE_SIZE;\n\n            while (nr--) {\n                paddr_t paddr = arch_page_get_mapping(kvm_space.pmap, sva);\n\n                if (paddr) {\n                    pmap_remove(kvm_space.pmap, sva, sva + PAGE_SIZE);\n                    buddy_free(BUDDY_ZONE_NORMAL, paddr, PAGE_SIZE);\n                }\n\n                sva += PAGE_SIZE;\n            }\n        }\n\nnext:\n        cur_node = nodes[cur_node].next;\n    }\n\ndone:\n    return;\n}\n\nvoid dump_nodes(void)\n{\n    printk(\"Nodes dump\\n\");\n    unsigned i = 0;\n    while (i < LAST_NODE_INDEX) {\n        print_node(i);\n        if (nodes[i].next == LAST_NODE_INDEX) break;\n        i = nodes[i].next;\n    }\n}\n"
  },
  {
    "path": "kernel/mm/mm.c",
    "content": "/**\n * \\defgroup mm kernel/mm\n * \\brief Memory Management\n *\n * The memory management subsystem is responsible for the allocation\n * of physical memory pages, management of virtual memory of processes\n * and caching of virtual memory objects.\n */\n\n#include <core/system.h>\n#include <core/panic.h>\n#include <core/arch.h>\n\n#include <boot/boot.h>\n\n#include <mm/pmap.h>\n#include <mm/mm.h>\n#include <mm/vm.h>\n#include <mm/buddy.h>\n\n#include <sys/sched.h>\n\n/* FIXME use boot time allocation scheme */\nstruct vm_page pages[768*1024];\n#define PAGE(addr)    (pages[(addr)/PAGE_SIZE])\n\n/** \n * \\ingroup mm\n * \\brief increment references count of a physical page\n */\nvoid mm_page_incref(paddr_t paddr)\n{\n    PAGE(paddr).ref++;\n}\n\n/**\n * \\ingroup mm\n * \\brief decrement references count of a physical page\n */\nvoid mm_page_decref(paddr_t paddr)\n{\n    PAGE(paddr).ref--;\n}\n\n/**\n * \\ingroup mm\n * \\brief get reference counts of a physical page\n */\nsize_t mm_page_ref(paddr_t paddr)\n{\n    return PAGE(paddr).ref;\n}\n\n/**\n * \\ingroup mm\n * \\brief get the virtual memory structure associated with a physical page\n */\nstruct vm_page *mm_page(paddr_t paddr)\n{\n    return &PAGE(paddr);\n}\n\n/**\n * \\ingroup mm\n * \\brief allocate an unused page from physical memory\n */\nstruct vm_page *mm_page_alloc(void)\n{\n    /* Get new frame */\n    paddr_t paddr = buddy_alloc(BUDDY_ZONE_NORMAL, PAGE_SIZE);\n    struct vm_page *vm_page = &PAGE(paddr);\n\n    memset(vm_page, 0, sizeof(struct vm_page));\n    vm_page->paddr = paddr;\n\n    return vm_page;\n}\n\n/**\n * \\ingroup mm\n * \\brief deallocate a page\n */\nvoid mm_page_dealloc(paddr_t paddr)\n{\n    /* TODO: Check out of bounds */\n    buddy_free(BUDDY_ZONE_NORMAL, paddr, PAGE_SIZE);\n\n    /* Release frame if it is no longer referenced */\n    //if (mm_page_ref(paddr) == 0)\n    //    buddy_free(BUDDY_ZONE_NORMAL, paddr, PAGE_SIZE);\n}\n\nint mm_page_map(struct pmap *pmap, vaddr_t vaddr, paddr_t paddr, int flags)\n{\n    /* TODO: Check out of bounds */\n\n    /* Increment references count to physical page */\n    //mm_page_incref(paddr);\n\n    return pmap_add(pmap, vaddr, paddr, flags);\n}\n\nint mm_page_unmap(struct pmap *pmap, vaddr_t vaddr)\n{\n    //printk(\"mm_page_unmap(pmap=%p, vaddr=%p)\\n\", pmap, vaddr);\n\n    /* TODO: Check out of bounds */\n\n    /* Check if page is mapped */\n    paddr_t paddr = arch_page_get_mapping(pmap, vaddr);\n\n    if (paddr) {\n        /* Decrement references count to physical page */\n        //mm_page_decref(paddr);\n\n        /* Call arch specific page unmapper */\n        pmap_remove(pmap, vaddr, vaddr + PAGE_SIZE);\n\n        /* Release page -- checks ref count */\n        //mm_page_dealloc(paddr);\n\n        return 0;\n    }\n\n    return -EINVAL;\n}\n\nint mm_map(struct pmap *pmap, paddr_t paddr, vaddr_t vaddr, size_t size, int flags)\n{\n    //printk(\"mm_map(pmap=%p, paddr=%p, vaddr=%p, size=%d, flags=%x)\\n\", pmap, paddr, vaddr, size, flags);\n\n    /* TODO: Check out of bounds */\n\n    int alloc = !paddr;\n\n    vaddr_t endaddr = PAGE_ROUND(vaddr + size);\n    vaddr = PAGE_ALIGN(vaddr);\n    paddr = PAGE_ALIGN(paddr);\n\n    size_t nr = (endaddr - vaddr) / PAGE_SIZE;\n\n    while (nr--) {\n        paddr_t phys = arch_page_get_mapping(pmap, vaddr);\n\n        if (!phys) {\n            if (alloc) {\n                paddr = mm_page_alloc()->paddr;\n                //printk(\"paddr = %p\\n\", paddr);\n            }\n            mm_page_map(pmap, vaddr, paddr, flags);\n        }\n\n        vaddr += PAGE_SIZE;\n        paddr += PAGE_SIZE;\n    }\n\n    return 0;\n}\n\nvoid mm_unmap(struct pmap *pmap, vaddr_t vaddr, size_t size)\n{\n    //printk(\"mm_unmap(pmap=%p, vaddr=%p, size=%ld)\\n\", pmap, vaddr, size);\n    /* TODO: Check out of bounds */\n\n    if (size < PAGE_SIZE) return;\n\n    vaddr_t sva = PAGE_ROUND(vaddr);\n    vaddr_t eva = PAGE_ALIGN(vaddr + size);\n\n    //pmap_remove(pmap, sva, eva);\n\n#if 1\n    size_t nr = (eva - sva)/PAGE_SIZE;\n\n    while (nr--) {\n        mm_page_unmap(pmap, sva);\n        sva += PAGE_SIZE;\n    }\n#endif\n}\n\nvoid mm_unmap_full(struct pmap *pmap, vaddr_t vaddr, size_t size)\n{\n    //printk(\"mm_unmap_full(pmap=%p, vaddr=%p, size=%ld)\\n\", pmap, vaddr, size);\n\n    /* TODO: Check out of bounds */\n\n    vaddr_t start = PAGE_ALIGN(vaddr);\n    vaddr_t end   = PAGE_ROUND(vaddr + size);\n\n    size_t nr = (end - start)/PAGE_SIZE;\n\n    while (nr--) {\n        mm_page_unmap(pmap, start);\n        start += PAGE_SIZE;\n    }\n}\n\nvoid mm_setup(struct boot *boot)\n{\n    printk(\"kernel: total memory: %d KiB, %d MiB\\n\", boot->total_mem, boot->total_mem / 1024);\n\n    buddy_setup(boot->total_mem * 1024);\n\n    /* Setup memory regions */\n    for (int i = 0; i < boot->mmap_count; ++i) {\n        if (boot->mmap[i].type == MMAP_RESERVED) {\n            size_t size = boot->mmap[i].end - boot->mmap[i].start;\n            buddy_set_unusable(boot->mmap[i].start, size);\n        }\n    }\n\n    /* Mark modules space as unusable */\n    for (int i = 0; i < boot->modules_count; ++i) {\n        module_t *mod = &boot->modules[i];\n        buddy_set_unusable(LMA((uintptr_t) mod->addr), mod->size);\n    }\n\n    arch_mm_setup();\n}\n"
  },
  {
    "path": "kernel/mm/vm_anon.c",
    "content": "#include <core/system.h>\n#include <core/panic.h>\n#include <mm/vm.h>\n\nMALLOC_DEFINE(M_VM_ANON, \"vm-anon\", \"anonymous virtual memory object\");\n\n/**\n * \\ingroup mm\n * \\brief check if two arefs are equal in a hashmap\n */\nstatic int vm_aref_eq(void *_a, void *_b)\n{\n    struct vm_aref *a = (struct vm_aref *) _a;\n\n    if (!a->vm_page)\n        return -1;\n\n    size_t *b = (size_t *) _b;\n\n    return a->vm_page->off == *b;\n}\n\n/**\n * \\ingroup mm\n * \\brief create new anon structure\n */\nstruct vm_anon *vm_anon_new(void)\n{\n    struct vm_anon *vm_anon = kmalloc(sizeof(struct vm_anon), &M_VM_ANON, M_ZERO);\n    if (!vm_anon) goto error;\n\n    vm_anon->arefs = hashmap_new(0, vm_aref_eq);\n\n    if (!vm_anon->arefs)\n        goto error;\n\n    return vm_anon;\n\nerror:\n    //panic(\"failed to allocate vm_anon\");\n\n    if (vm_anon) {\n        if (vm_anon->arefs)\n            hashmap_free(vm_anon->arefs);\n        kfree(vm_anon);\n    }\n\n    return NULL;\n}\n\n/**\n * \\ingroup mm\n * \\brief destroy all resources associated with an aref\n */\nvoid vm_aref_destroy(struct vm_aref *vm_aref)\n{\n    /* nothing to do */\n}\n\n/**\n * \\ingroup mm\n * \\brief decrement references to an aref\n */\nvoid vm_aref_decref(struct vm_aref *vm_aref)\n{\n    vm_aref->ref--;\n}\n\n/**\n * \\ingroup mm\n * \\brief destroy all resources associated with an anon\n */\nvoid vm_anon_destroy(struct vm_anon *vm_anon)\n{\n    if (!vm_anon) return;\n\n    struct hashmap *arefs = vm_anon->arefs;\n\n    if (!arefs)\n        return;\n\n    hashmap_for (qnode, vm_anon->arefs) {\n        struct hashmap_node *hnode = (struct hashmap_node *) qnode->value;\n        struct vm_aref *aref = (struct vm_aref *) hnode->entry;\n\n        vm_aref_decref(aref);\n\n        if (!aref->ref) {\n            if (aref->vm_page) {\n                mm_page_dealloc(aref->vm_page->paddr);\n            }\n\n            kfree(aref);\n        }\n    }\n\n    hashmap_free(vm_anon->arefs);\n}\n\n/**\n * \\ingroup mm\n * \\brief increment number of references to a vm anon\n */\nvoid vm_anon_incref(struct vm_anon *vm_anon)\n{\n    if (!vm_anon)\n        return;\n\n    vm_anon->ref++;\n}\n\n/**\n * \\ingroup mm\n * \\brief decrement number of references to a vm anon\n * and destroy it when it reaches zero\n */\nvoid vm_anon_decref(struct vm_anon *vm_anon)\n{\n    if (!vm_anon)\n        return;\n\n    vm_anon->ref--;\n\n    if (!vm_anon->ref) {\n        vm_anon_destroy(vm_anon);\n        kfree(vm_anon);\n    }\n}\n\n/**\n * \\ingroup mm\n * \\brief copy all aref structures from `src` to `dst`\n */\nstatic int vm_anon_copy_arefs(struct vm_anon *src, struct vm_anon *dst)\n{\n    if (!src || !dst || !src->arefs || !dst->arefs)\n        return -EINVAL;\n\n    /* copy all arefs */\n    hashmap_for (qnode, src->arefs) {\n        struct hashmap_node *node = (struct hashmap_node *) qnode->value;\n        struct vm_aref *aref = (struct vm_aref *) node->entry;\n\n        hashmap_insert(dst->arefs, node->hash, aref);\n        aref->ref++;\n    }\n\n    return 0;\n}\n\n/**\n * \\ingroup mm\n * \\brief clone an existing anon into a new anon\n */\nstruct vm_anon *vm_anon_copy(struct vm_anon *vm_anon)\n{\n    if (!vm_anon)\n        return NULL;\n\n    struct vm_anon *new_anon = vm_anon_new();\n\n    if (!new_anon)\n        return NULL;\n\n    new_anon->flags = vm_anon->flags & ~VM_COPY;\n    new_anon->ref   = 1;\n\n    /* copy all arefs */\n    if (vm_anon_copy_arefs(vm_anon, new_anon)) {\n        kfree(new_anon);\n        return NULL;\n    }\n\n    return new_anon;\n}\n"
  },
  {
    "path": "kernel/mm/vm_entry.c",
    "content": "#include <core/system.h>\n#include <mm/vm.h>\n\nMALLOC_DEFINE(M_VM_ENTRY, \"vm-entry\", \"virtual memory map entry\");\n\n/** create new vm entry\n */\nstruct vm_entry *vm_entry_new(void)\n{\n    struct vm_entry *vm_entry = kmalloc(sizeof(struct vm_entry), &M_VM_ENTRY, M_ZERO);\n    if (!vm_entry) return NULL;\n\n    return vm_entry;\n}\n\n/** destroy all resources associated with a vm entry\n */\nvoid vm_entry_destroy(struct vm_entry *vm_entry)\n{\n    if (!vm_entry)\n        return;\n\n    if (vm_entry->vm_anon)\n        vm_anon_decref(vm_entry->vm_anon);\n\n    if (vm_entry->vm_object)\n        vm_object_decref(vm_entry->vm_object);\n}\n"
  },
  {
    "path": "kernel/mm/vm_object.c",
    "content": "#include <core/system.h>\n#include <core/arch.h>\n#include <core/panic.h>\n#include <mm/mm.h>\n#include <mm/vm.h>\n#include <ds/queue.h>\n#include <ds/hashmap.h>\n\nMALLOC_DEFINE(M_VM_OBJECT, \"vm-object\", \"virtual memory object\");\n\nvoid vm_object_incref(struct vm_object *vm_object)\n{\n    vm_object->ref++;\n}\n\nvoid vm_object_decref(struct vm_object *vm_object)\n{\n    vm_object->ref--;\n    return;\n\n    /*\n    if (vm_object->ref == 0) {\n        hashmap_free(vm_object->pages);\n        kfree(vm_object);\n    }\n    */\n}\n\nvoid vm_object_page_insert(struct vm_object *vm_object, struct vm_page *vm_page)\n{\n    size_t off = vm_page->off;\n    hash_t hash = hashmap_digest(&off, sizeof(off));\n    hashmap_insert(vm_object->pages, hash, vm_page);\n}\n"
  },
  {
    "path": "kernel/mm/vm_space.c",
    "content": "#include <core/system.h>\n#include <core/arch.h>\n\n#include <mm/pmap.h>\n#include <mm/vm.h>\n\n#include <ds/queue.h>\n\n/**\n * \\ingroup mm\n * \\brief insert a new vm entry into a vm space\n */\nint vm_space_insert(struct vm_space *vm_space, struct vm_entry *vm_entry)\n{\n    if (!vm_space || !vm_entry)\n        return -EINVAL;\n\n    struct queue *queue = &vm_space->vm_entries;\n\n    int alloc = !vm_entry->base;\n\n    uintptr_t end = vm_entry->base + vm_entry->size;\n\n    struct qnode *cur = NULL;\n    uintptr_t prev_end = 0;\n\n    if (alloc) {\n        /* look for the last valid entry */\n        queue_for (node, queue) {\n            struct vm_entry *cur_vm_entry = (struct vm_entry *) node->value;\n\n            if (cur_vm_entry->base - prev_end >= vm_entry->size) {\n                vm_entry->base = cur_vm_entry->base - vm_entry->size;\n                end = vm_entry->base + vm_entry->size;\n            }\n\n            prev_end = cur_vm_entry->base + cur_vm_entry->size;\n        }\n    }\n\n    queue_for (node, queue) {\n        struct vm_entry *cur_vm_entry = (struct vm_entry *) node->value;\n\n        if (vm_entry->base && cur_vm_entry->base >= end && prev_end <= vm_entry->base) {\n            cur = node;\n            break;\n        }\n\n        prev_end = cur_vm_entry->base + cur_vm_entry->size;\n    }\n\n    if (!cur)\n        return -ENOMEM;\n\n    struct qnode *node = kmalloc(sizeof(struct qnode), &M_QNODE, M_ZERO);\n    if (!node) {\n        /* TODO */\n    }\n\n    node->value = vm_entry;\n    node->next = cur;\n    node->prev = cur->prev;\n\n    if (cur->prev)\n        cur->prev->next = node;\n\n    cur->prev  = node;\n    vm_entry->qnode = node;\n    ++queue->count;\n\n    return 0;\n}\n\n/**\n * \\ingroup mm\n * \\brief lookup the vm entry containing `vaddr` inside a vm space\n */\nstruct vm_entry *vm_space_find(struct vm_space *vm_space, vaddr_t vaddr)\n{\n    if (!vm_space) return NULL;\n\n    vaddr = PAGE_ALIGN(vaddr);\n\n    struct queue *vm_entries = &vm_space->vm_entries;\n\n    queue_for (node, vm_entries) {\n        struct vm_entry *vm_entry = node->value;\n        vaddr_t vm_end = vm_entry->base + vm_entry->size;\n\n        if (vaddr >= vm_entry->base && vaddr < vm_end)\n            return vm_entry;\n    }\n\n    return NULL;\n}\n\n/**\n * \\ingroup mm\n * \\brief destroy all resources associated with a vm space\n */\nvoid vm_space_destroy(struct vm_space *vm_space)\n{\n    if (!vm_space)\n        return;\n\n    struct vm_entry *vm_entry = NULL;\n\n    while ((vm_entry = dequeue(&vm_space->vm_entries))) {\n        vm_entry_destroy(vm_entry);\n        kfree(vm_entry);\n    }\n\n    pmap_remove_all(vm_space->pmap);\n}\n\n/**\n * \\ingroup mm\n * \\brief fork a vm space into another vm space\n */\nint vm_space_fork(struct vm_space *src, struct vm_space *dst)\n{\n    if (!src || !dst)\n        return -EINVAL;\n\n    /* copy vm entries */\n    queue_for (node, &src->vm_entries) {\n        struct vm_entry *s_entry = node->value;\n        struct vm_entry *d_entry = kmalloc(sizeof(struct vm_entry), &M_VM_ENTRY, 0);\n\n        if (!d_entry) {\n            /* TODO */\n        }\n\n        memcpy(d_entry, s_entry, sizeof(struct vm_entry));\n        d_entry->qnode = enqueue(&dst->vm_entries, d_entry);\n\n        if (s_entry->vm_anon) {\n            s_entry->vm_anon->flags |= VM_COPY;\n            vm_anon_incref(s_entry->vm_anon);\n            //s_entry->vm_anon->ref++;\n        }\n\n        if (s_entry->vm_object) {\n            s_entry->vm_object->ref++;\n        }\n\n        if (s_entry->flags & (VM_UW|VM_KW) && !(s_entry->flags & VM_SHARED)) {\n            /* remove write permission from all pages */\n            vaddr_t sva = s_entry->base;\n            vaddr_t eva = sva + s_entry->size;\n            unsigned flags = s_entry->flags & ~(VM_UW|VM_KW);\n            pmap_protect(src->pmap, sva, eva, flags);\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "kernel/mm/vmm.c",
    "content": "#include <core/system.h>\n#include <core/arch.h>\n#include <core/panic.h>\n#include <mm/mm.h>\n#include <mm/vm.h>\n#include <ds/queue.h>\n#include <ds/hashmap.h>\n\nMALLOC_DEFINE(M_VM_AREF, \"vm-aref\", \"anonymous virtual memory object reference\");\n\nstruct vm_space kvm_space;\n\nint vm_map(struct vm_space *vm_space, struct vm_entry *vm_entry)\n{\n    //printk(\"vm_map(vm_space=%p, vm_entry=%p)\\n\", vm_space, vm_entry);\n    return mm_map(vm_space->pmap, vm_entry->paddr, vm_entry->base, vm_entry->size, vm_entry->flags);\n}\n\nvoid vm_unmap(struct vm_space *vm_space, struct vm_entry *vm_entry)\n{\n    printk(\"vm_unmap(vm_space=%p, vm_entry=%p)\\n\", vm_space, vm_entry);\n\n    if (vm_entry->flags & VM_SHARED) {\n        /* TODO */\n    } else {\n        mm_unmap(vm_space->pmap, vm_entry->base, vm_entry->size);\n    }\n}\n\nvoid vm_unmap_full(struct vm_space *vm_space, struct vm_entry *vm_entry)\n{\n    printk(\"vm_unmap(vm_space=%p, vm_entry=%p)\\n\", vm_space, vm_entry);\n\n    if (vm_entry->flags & VM_SHARED) {\n        /* TODO */\n    } else {\n        mm_unmap_full(vm_space->pmap, vm_entry->base, vm_entry->size);\n    }\n}\n\n"
  },
  {
    "path": "kernel/net/Build.mk",
    "content": "dirs-$(NET_UNIX) += unix/\nobj-y  += socket.o\n"
  },
  {
    "path": "kernel/net/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/net/socket.c",
    "content": "/**\n * \\defgroup net kernel/net\n * \\brief networking subsystem\n */\n\n#include <core/system.h>\n#include <core/string.h>\n#include <ds/queue.h>\n#include <bits/errno.h>\n#include <net/socket.h>\n\nint socket_create(struct file *file, int domain, int type, int protocol)\n{\n    switch (domain) {\n        case AF_UNIX:\n            return socket_unix_create(file, domain, type, protocol);\n    }\n\n    return -EAFNOSUPPORT;\n}\n\nint socket_accept(struct file *file, struct file *conn, const struct sockaddr *addr, socklen_t *len)\n{\n    if (!(file->flags & FILE_SOCKET))\n        return -ENOTSOCK;\n\n    if (!file->socket->ops || !file->socket->ops->accept)\n        return -EOPNOTSUPP;\n\n    return file->socket->ops->accept(file, conn, addr, len);\n}\n\nint socket_bind(struct file *file, const struct sockaddr *addr, uint32_t len)\n{\n    if (!(file->flags & FILE_SOCKET))\n        return -ENOTSOCK;\n\n    if (!file->socket->ops || !file->socket->ops->bind)\n        return -EOPNOTSUPP;\n\n    return file->socket->ops->bind(file, addr, len);\n}\n\nint socket_connect(struct file *file, const struct sockaddr *addr, uint32_t len)\n{\n    if (!(file->flags & FILE_SOCKET))\n        return -ENOTSOCK;\n\n    if (!file->socket->ops || !file->socket->ops->connect)\n        return -EOPNOTSUPP;\n\n    return file->socket->ops->connect(file, addr, len);\n}\n\nint socket_listen(struct file *file, int backlog)\n{\n    if (!(file->flags & FILE_SOCKET))\n        return -ENOTSOCK;\n\n    if (!file->socket->ops || !file->socket->ops->listen)\n        return -EOPNOTSUPP;\n\n    return file->socket->ops->listen(file, backlog);\n}\n\nint socket_send(struct file *file, void *buf, size_t len, int flags)\n{\n    if (!file)\n        return -EINVAL;\n\n    if (!(file->flags & FILE_SOCKET))\n        return -ENOTSOCK;\n\n    if (!(file->socket))\n        return -EINVAL;\n\n    if (!file->socket->ops || !file->socket->ops->send)\n        return -EOPNOTSUPP;\n\n    return file->socket->ops->send(file, buf, len, flags);\n}\n\nint socket_recv(struct file *file, void *buf, size_t len, int flags)\n{\n    if (!(file->flags & FILE_SOCKET))\n        return -ENOTSOCK;\n\n    if (!file->socket->ops || !file->socket->ops->recv)\n        return -EOPNOTSUPP;\n\n    return file->socket->ops->recv(file, buf, len, flags);\n}\n\nint socket_can_read(struct file *file, size_t len)\n{\n    if (!(file->flags & FILE_SOCKET))\n        return -ENOTSOCK;\n\n    if (!file->socket->ops || !file->socket->ops->can_read)\n        return -EOPNOTSUPP;\n\n    return file->socket->ops->can_read(file, len);\n}\n\nint socket_can_write(struct file *file, size_t len)\n{\n    if (!(file->flags & FILE_SOCKET))\n        return -ENOTSOCK;\n\n    if (!file->socket->ops || !file->socket->ops->can_write)\n        return -EOPNOTSUPP;\n\n    return file->socket->ops->can_write(file, len);\n}\n\nint socket_shutdown(struct file *file, int how)\n{\n    if (!(file->flags & FILE_SOCKET))\n        return -ENOTSOCK;\n\n    if (!file->socket->ops || !file->socket->ops->shutdown)\n        return -EOPNOTSUPP;\n\n    file->socket->ref--;\n\n    if (!file->socket->ref)\n        return file->socket->ops->shutdown(file, how);\n\n    return 0;\n}\n"
  },
  {
    "path": "kernel/net/unix/Build.mk",
    "content": "obj-y += unix.o\n"
  },
  {
    "path": "kernel/net/unix/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/net/unix/unix.c",
    "content": "#include <core/system.h>\n#include <sys/sched.h>\n#include <fs/vfs.h>\n#include <ds/ringbuf.h>\n#include <net/socket.h>\n#include <unix.h>\n\n#define SOCKBUF 8192\n\nMALLOC_DEFINE(M_SOCKET, \"socket\", \"socket struct\");\nMALLOC_DEFINE(M_UN_SOCKET, \"unix socket\", \"unix socket struct\");\nMALLOC_DEFINE(M_UN_CONN, \"unix conn\", \"unix connection struct\");\n\nstatic struct sock_ops socket_unix_ops;\n\nstatic struct queue *sockets = QUEUE_NEW();  /* Open sockets */\n\nint socket_unix_create(struct file *file, int domain, int type, int protocol)\n{\n    //printk(\"socket_unix_create(file=%p, domain=%d, type=%d, protocol=%d)\\n\", file, domain, type, protocol);\n    struct socket *socket = kmalloc(sizeof(struct socket), &M_SOCKET, M_ZERO);\n    if (!socket) return -ENOMEM;\n\n    socket->domain   = domain;\n    socket->type     = type;\n    socket->protocol = protocol;\n    socket->ops      = &socket_unix_ops;\n    socket->p        = NULL;\n    socket->ref      = 1;\n\n    file->flags     |= FILE_SOCKET;\n    file->socket     = socket;\n    return 0;\n}\n\nstatic int socket_unix_accept(struct file *file, struct file *conn, const struct sockaddr *addr, socklen_t *len)\n{\n    //printk(\"%d:%d socket_unix_accept(socket=%p, conn=%p, addr=%p, len=%p)\\n\", curthread->tid, curproc->pid, file, conn, addr, len);\n    \n    if (!file || !file->socket)\n        return -EINVAL;\n\n    struct un_socket *socket = file->socket->p;\n\n    if (!socket)\n        return -EINVAL;\n\n    if (!socket->requests.count) {\n        /* Sleep until a connection request is present */\n        if (thread_queue_sleep(&socket->accept))\n            return -EINTR;\n    }\n\n    struct un_conn *request = dequeue(&socket->requests);\n\n    /* Initialize connection */\n    conn->flags  |= FILE_SOCKET;\n    conn->socket  = kmalloc(sizeof(struct socket), &M_SOCKET, 0);\n    if (!conn->socket) {\n        /* TODO */\n    }\n\n    memcpy(conn->socket, file->socket, sizeof(struct socket));\n\n    conn->socket->domain = AF_UNIX_CONN;\n    conn->socket->p      = request;\n\n    /* Initialize buffers */\n    request->soci = ringbuf_new(SOCKBUF);\n    request->sico = ringbuf_new(SOCKBUF);\n\n    /* Connection established */\n    request->connected = 1;\n\n    /* Wakeup client if waiting for connection */\n    thread_queue_wakeup(&request->connect);\n\n    return 0;\n}\n\nstatic int socket_unix_bind(struct file *file, const struct sockaddr *addr, socklen_t len)\n{\n    //printk(\"socket_unix_bind(file=%p, addr=%p, len=%d)\\n\", file, addr, len);\n    struct sockaddr_un *addr_un = (struct sockaddr_un *) addr;\n\n    /* Get path vnode */\n    int err = 0;\n    struct uio uio = PROC_UIO(curproc);\n\n    struct vnode *vnode = NULL;\n    err = vfs_lookup(addr_un->sun_path, &uio, &vnode, NULL);\n\n    if (err && err != -ENOENT)\n        return err;\n\n    if (!err)\n        return -EEXIST;\n\n    /* Create socket */\n    if ((err = vfs_mknod(addr_un->sun_path, S_IFSOCK, 0, &uio, NULL)))\n        return err;\n\n    /* Get vnode -- FIXME */\n    if ((err = vfs_lookup(addr_un->sun_path, &uio, &vnode, NULL)))\n        return err;\n\n    struct un_socket *socket = kmalloc(sizeof(struct un_socket), &M_UN_SOCKET, M_ZERO);\n    if (!socket) return -ENOMEM;\n\n    socket->vnode = vnode;\n    enqueue(sockets, socket);\n\n    file->socket->p = socket;\n\n    return 0;\n}\n\nstatic int socket_unix_connect(struct file *file, const struct sockaddr *addr, socklen_t len)\n{\n    //printk(\"socket_unix_connect(socket=%p, addr=%p, len=%d)\\n\", file, addr, len);\n\n    struct sockaddr_un *addr_un = (struct sockaddr_un *) addr;\n\n    /* Get path vnode */\n    int err = 0;\n    struct vnode *vnode = NULL;\n    struct uio uio = PROC_UIO(curproc);\n\n    /* Open socket */\n    if ((err = vfs_lookup(addr_un->sun_path, &uio, &vnode, NULL))) {\n        return err;\n    }\n\n    struct un_socket *socket = NULL;\n\n    queue_for (node, sockets) {\n        struct un_socket *_socket = (struct un_socket *) node->value;\n        if (_socket->vnode == vnode) {\n            socket = _socket;\n            break;\n        }\n    }\n\n    if ((!socket->listening) || socket->requests.count > socket->backlog)\n        return -ECONNREFUSED;\n\n    struct un_conn *request = kmalloc(sizeof(struct un_conn), &M_UN_CONN, M_ZERO);\n    if (!request) return -ENOMEM;\n\n    enqueue(&socket->requests, request);\n\n    /* Wake up server if waiting for connections */\n    thread_queue_wakeup(&socket->accept);\n\n    /* Sleep until the connection is established */\n    if (!request->connected && thread_queue_sleep(&request->connect))\n        return -EINTR;\n\n    /* Initialize connection */\n    file->socket->domain = AF_UNIX_CONN;\n    file->socket->p = request;\n    file->offset    = 1;   /* FIXME */\n\n    return 0;\n}\n\nstatic int socket_unix_listen(struct file *file, int backlog)\n{\n    //printk(\"socket_unix_listen(file=%p, backlog=%d)\\n\", file, backlog);\n\n    struct un_socket *socket = (struct un_socket *) file->socket->p;\n\n    socket->backlog = backlog;\n    socket->listening = 1;\n\n    return 0;\n}\n\nstatic ssize_t socket_unix_send(struct file *file, void *buf, size_t len, int flags)\n{\n    //printk(\"socket_unix_send(file=%p, buf=%p, len=%d, flags=%x)\\n\", file, buf, len, flags);\n\n    if (file->socket->domain != AF_UNIX_CONN)\n        return -ENOTCONN;\n\n    struct un_conn *conn = file->socket->p;\n\n    struct ringbuf *ring = NULL;\n\n    struct queue *recv_queue = NULL;\n    struct queue *send_queue = NULL;\n\n    if (file->offset == 0) {  /* Server */\n        ring       = conn->soci;\n        recv_queue = &conn->client_recv;\n        send_queue = &conn->server_send;\n    } else {    /* Client */\n        ring       = conn->sico;\n        recv_queue = &conn->server_recv;\n        send_queue = &conn->client_send;\n    }\n\n    ssize_t retval = 0;\n    ssize_t incr   = 0;\n\n    for (;;) {\n        if (!ring)  /* Connection closed */\n            return retval;\n\n        size_t wlen = MIN(len - retval, SOCKBUF - ringbuf_available(ring));\n\n        incr = ringbuf_write(ring, wlen, (char *) buf + retval);\n\n        if (incr > 0)\n            thread_queue_wakeup(recv_queue);\n\n        if (incr > 0 && !(flags & MSG_WAITALL))\n            return incr;\n\n        retval += incr;\n\n        if ((size_t) retval == len)\n            return retval;\n\n        if (thread_queue_sleep(send_queue))\n            return -EINTR;\n    }\n}\n\nstatic ssize_t socket_unix_recv(struct file *file, void *buf, size_t len, int flags)\n{\n    //printk(\"socket_unix_recv(file=%p, buf=%p, len=%d, flags=%x)\\n\", file, buf, len, flags);\n\n    if (file->socket->domain != AF_UNIX_CONN)\n        return -ENOTCONN;\n\n    struct un_conn *conn = file->socket->p;\n\n    struct ringbuf *ring = NULL;\n\n    struct queue *recv_queue = NULL;\n    struct queue *send_queue = NULL;\n\n    if (file->offset == 0) {  /* Server */\n        ring       = conn->sico;\n        recv_queue = &conn->server_recv;\n        send_queue = &conn->client_send;\n    } else {    /* Client */\n        ring       = conn->soci;\n        recv_queue = &conn->client_recv;\n        send_queue = &conn->server_send;\n    }\n\n    ssize_t retval = 0;\n    ssize_t incr   = 0;\n\n    for (;;) {\n        if (!ring)  /* Connection closed */\n            return retval;\n\n        incr = ringbuf_read(ring, len - retval, (char *) buf + retval);\n\n        if (incr > 0)\n            thread_queue_wakeup(send_queue);\n\n        if (incr > 0 && !(flags & MSG_WAITALL))\n            return incr;\n\n        retval += incr;\n\n        if ((size_t) retval == len)\n            return retval;\n\n        if (thread_queue_sleep(recv_queue))\n            return -EINTR;\n    }\n}\n\nstatic int socket_unix_can_read(struct file *file, size_t len)\n{\n    //printk(\"socket_unix_can_read(file=%p, len=%d)\\n\", file, len);\n\n    if (!file || !file->socket)\n        return -EINVAL;\n\n    if (file->socket->domain == AF_UNIX) {\n        struct un_socket *socket = file->socket->p;\n        return socket->requests.count;\n    }\n\n    if (file->socket->domain != AF_UNIX_CONN)\n        return -ENOTCONN;\n\n    struct un_conn *conn = file->socket->p;\n\n    struct ringbuf *ring = NULL;\n\n    if (file->offset == 0) {\n        /* Server */\n        ring = conn->sico;\n    } else {\n        /* Client */\n        ring = conn->soci;\n    }\n\n    if (!ring)\n        return -ENOTCONN; /* ??? */\n\n    return ringbuf_available(ring);\n}\n\nstatic int socket_unix_can_write(struct file *file, size_t len)\n{\n    //printk(\"socket_unix_can_write(file=%p, len=%d)\\n\", file, len);\n\n    if (file->socket->domain != AF_UNIX_CONN)\n        return -ENOTCONN;\n\n    struct un_conn *conn = file->socket->p;\n\n    struct ringbuf *ring = NULL;\n\n    if (file->offset == 0) {\n        /* Server */\n        ring = conn->soci;\n    } else {\n        /* Client */\n        ring = conn->sico;\n    }\n\n    return ring->size - ringbuf_available(ring);\n}\n\n\nstatic int socket_unix_shutdown(struct file *file, int how)\n{\n    //printk(\"socket_unix_shutdown(file=%p, how=%d)\\n\", file, how);\n    \n    if (!file || !file->socket)\n        return -EINVAL;\n    \n    if (file->socket->domain == AF_UNIX_CONN) {\n        /* Connected socket */\n        struct un_conn *conn = file->socket->p;\n\n        int client = file->offset;\n\n        if ((client && (how & SHUT_RD)) || (!client && (how & SHUT_WR))) {\n            if (conn->soci) {\n                ringbuf_free(conn->soci);\n                conn->soci = NULL;\n            }\n        }\n\n        if ((client && (how & SHUT_WR)) || (!client && (how & SHUT_RD))) {\n            if (conn->sico) {\n                ringbuf_free(conn->sico);\n                conn->sico = NULL;\n            }\n        }\n\n        if (!conn->soci && !conn->sico) {\n            /* Free resources */\n            //kfree(conn);  /* FIXME */\n            kfree(file->socket);\n            file->socket = NULL;\n        }\n\n        return 0;\n    } else {\n        /* TODO */\n    }\n\n    return -ENOTCONN;\n}\n\nstatic struct sock_ops socket_unix_ops = {\n    .accept    = socket_unix_accept,\n    .bind      = socket_unix_bind,\n    .connect   = socket_unix_connect,\n    .listen    = socket_unix_listen,\n    .recv      = socket_unix_recv,\n    .send      = socket_unix_send,\n    .can_read  = socket_unix_can_read,\n    .can_write = socket_unix_can_write,\n    .shutdown  = socket_unix_shutdown,\n};\n"
  },
  {
    "path": "kernel/net/unix/unix.h",
    "content": "#ifndef _NET_UNIX_H\n#define _NET_UNIX_H\n\n#define AF_UNIX_CONN    255\n\nstruct un_conn {\n    struct ringbuf *soci;   /* Server Out, Client In */\n    struct ringbuf *sico;   /* Server In, Client Out */\n\n    struct queue server_recv;\n    struct queue server_send;\n    struct queue client_recv;\n    struct queue client_send;\n    struct queue connect;\n\n    int connected;\n};\n\nstruct un_socket {\n    struct vnode *vnode;\n\n    size_t backlog;    /* Number of connections to keep in queue */\n\n    struct queue requests;\n    struct queue accept;\n\n    /* Flags */\n    int listening;\n};\n\nstruct sockaddr_un {\n    sa_family_t sun_family;\n    char        sun_path[128];\n};\n\n#endif /* ! _NET_UNIX_H */\n"
  },
  {
    "path": "kernel/sys/Build.mk",
    "content": "obj-y += proc.o\nobj-y += thread.o\nobj-y += sched.o\nobj-y += syscall.o\nobj-y += fork.o\ndirs-y += binfmt/\nobj-y += execve.o\nobj-y += signal.o\n"
  },
  {
    "path": "kernel/sys/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/sys/binfmt/Build.mk",
    "content": "obj-y += elf.o\nobj-y += binfmt.o\n"
  },
  {
    "path": "kernel/sys/binfmt/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o $(elf)\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  LD      \" $(CWD)/builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@;\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  CC      \" $(CWD)/$@;\n\t@$(CC) $(CFLAGS) -c $< -o $@\n\n%.o:%.S\n\t@$(ECHO) \"  AS      \" $(CWD)/$@;\n\t@$(AS) $(ASFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) $(elf) builtin.o\n\t@$(RM) $(obj-y) $(elf) builtin.o\n"
  },
  {
    "path": "kernel/sys/binfmt/binfmt.c",
    "content": "#include <core/arch.h>\n#include <sys/binfmt.h>\n#include <sys/elf.h>\n#include <mm/vm.h>\n\nstatic struct binfmt binfmt_list[] = {\n    {binfmt_elf_check, binfmt_elf_load},\n};\n\n#define NR_BINFMT   ((sizeof(binfmt_list)/sizeof(binfmt_list[0])))\n\nstatic int binfmt_fmt_load(struct proc *proc, const char *path, struct vnode *vnode, struct binfmt *binfmt, struct proc **ref)\n{\n    int err = 0;\n\n    vm_space_destroy(&proc->vm_space);\n\n    if ((err = binfmt->load(proc, path, vnode)))\n        goto error;\n\n    kfree(proc->name);\n    proc->name = strdup(path);\n\n    /* Align heap */\n    proc->heap_start = PAGE_ROUND(proc->heap_start);\n    proc->heap = proc->heap_start;\n\n    /* Create heap vm_entry */\n    struct vm_entry *heap_vm = kmalloc(sizeof(struct vm_entry), &M_VM_ENTRY, M_ZERO);\n    if (!heap_vm) {\n        /* TODO */\n    }\n\n    heap_vm->base  = proc->heap_start;\n    heap_vm->size  = 0;\n    heap_vm->flags = VM_URW;\n    heap_vm->qnode = enqueue(&proc->vm_space.vm_entries, heap_vm);\n\n    heap_vm->vm_object = NULL; //vm_object_anon();\n    //vm_object_incref(heap_vm->vm_object);\n    \n    proc->heap_vm  = heap_vm;\n\n    /* Create stack vm_entry */\n    struct vm_entry *stack_vm = kmalloc(sizeof(struct vm_entry), &M_VM_ENTRY, M_ZERO);\n    if (!stack_vm) {\n        /* TODO */\n    }\n\n    stack_vm->base  = USER_STACK_BASE;\n    stack_vm->size  = USER_STACK_SIZE;\n    stack_vm->flags = VM_URW;\n    stack_vm->qnode = enqueue(&proc->vm_space.vm_entries, stack_vm);\n\n    stack_vm->vm_object = NULL; //vm_object_anon();\n    //vm_object_incref(stack_vm->vm_object);\n\n    proc->stack_vm  = stack_vm;\n\n    struct thread *thread = (struct thread *) proc->threads.head->value;\n    thread->stack_base = USER_STACK_BASE;\n    thread->stack_size = USER_STACK_BASE;\n\n    return 0;\n\nerror:\n    return err;\n}\n\nint binfmt_load(struct proc *proc, const char *path, struct proc **ref)\n{\n    struct vnode *vnode = NULL;\n    int err = 0;\n\n    struct uio uio;\n    memset(&uio, 0, sizeof(struct uio));\n\n    if (proc) {\n        uio = PROC_UIO(proc);\n    }\n\n    if ((err = vfs_lookup(path, &uio, &vnode, NULL)))\n        return err;\n\n    for (size_t i = 0; i < NR_BINFMT; ++i) {\n        if (!binfmt_list[i].check(vnode)) {\n            binfmt_fmt_load(proc, path, vnode, &binfmt_list[i], ref);\n            //vfs_close(vnode);\n            return 0;\n        }\n    }\n\n    //vfs_close(vnode);\n    return -ENOEXEC;\n}\n"
  },
  {
    "path": "kernel/sys/binfmt/elf.c",
    "content": "/*\n *          ELF format loader\n *\n *\n *  This file is part of Aquila OS and is released under\n *  the terms of GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) 2016 Mohamed Anwar <mohamed_anwar@opmbx.org>\n */\n\n\n#include <core/system.h>\n#include <core/panic.h>\n\n#include <sys/proc.h>\n#include <sys/sched.h>\n#include <sys/elf.h>\n#include <mm/vm.h>\n\nstatic int binfmt_elf32_load(struct proc *proc, struct vnode *vnode)\n{\n    int err = 0;\n\n    struct vm_space *vm_space = &proc->vm_space;\n\n    struct elf32_hdr hdr;\n\n    if (vfs_read(vnode, 0, sizeof(hdr), &hdr) != sizeof(hdr))\n        goto e_inval;\n\n    uintptr_t proc_heap = 0;\n    size_t offset = hdr.e_phoff;\n    \n    for (int i = 0; i < hdr.e_phnum; ++i) {\n        struct elf32_phdr phdr;\n        \n        if (vfs_read(vnode, offset, sizeof(phdr), &phdr) != sizeof(phdr))\n            goto e_inval;\n\n        if (phdr.p_type == PT_LOAD) {\n            vaddr_t base  = phdr.p_vaddr;\n            size_t filesz = phdr.p_filesz;\n            size_t memsz  = phdr.p_memsz;\n            size_t off    = phdr.p_offset;\n\n            /* make sure vaddr is aligned */\n            if (base & PAGE_MASK) {\n                memsz  += base & PAGE_MASK;\n                filesz += base & PAGE_MASK;\n                off    -= base & PAGE_MASK;\n                base    = PAGE_ALIGN(base);\n            }\n\n            /* page align size */\n            memsz = PAGE_ROUND(memsz);\n\n            struct vm_entry *vm_entry = vm_entry_new();\n            if (!vm_entry) goto e_nomem;\n\n            vm_entry->base = base;\n            vm_entry->size = memsz;\n            vm_entry->off  = off;\n\n            /* access flags */\n            vm_entry->flags |= phdr.p_flags & PF_R? VM_UR : 0;\n            vm_entry->flags |= phdr.p_flags & PF_W? VM_UW : 0;\n            vm_entry->flags |= phdr.p_flags & PF_X? VM_UX : 0;\n\n            /* TODO use W^X */\n\n            vm_entry->qnode = enqueue(&vm_space->vm_entries, vm_entry);\n\n            if (!vm_entry->qnode)\n                goto e_nomem;\n\n            vm_entry->vm_object = vm_object_vnode(vnode);\n\n            if (!vm_entry->vm_object)\n                goto e_nomem;\n\n            if (vm_entry->flags & VM_UW)\n                vm_entry->flags |= VM_COPY;\n\n            vm_object_incref(vm_entry->vm_object);\n\n            if (base + memsz > proc_heap)\n                proc_heap = base + memsz;\n\n            /* handle bss */\n            if (phdr.p_memsz != phdr.p_filesz) {\n                vaddr_t bss = base + filesz;\n\n                vaddr_t bss_init_end = PAGE_ROUND(base + filesz);\n\n                if (vm_entry->base + vm_entry->size > bss_init_end) {\n                    size_t sz = bss_init_end - vm_entry->base;\n\n                    struct vm_entry *split = vm_entry_new();\n\n                    split->base = bss_init_end;\n                    split->size = vm_entry->size - sz;\n                    split->flags = vm_entry->flags;\n                    split->off = 0;\n\n                    split->qnode = enqueue(&vm_space->vm_entries, split);\n\n                    vm_entry->size = sz;\n                }\n\n                /* fault in the page */\n                memset((void *) bss, 0, bss_init_end-bss);\n            }\n        }\n\n        offset += hdr.e_phentsize;\n    }\n\n    proc->heap_start = proc_heap;\n    proc->heap       = proc_heap;\n    proc->entry      = hdr.e_entry;\n\n    return err;\n\ne_nomem:\n    err = -ENOMEM;\n    goto error;\n\ne_inval:\n    err = -EINVAL;\n    goto error;\n\nerror:\n    printk(\"err %d\\n\", -err);\n    panic(\"TODO\");\n}\n\n#if 0\nstatic int binfmt_elf64_load(struct proc *proc, struct vnode *file)\n{\n    int err = 0;\n\n    struct elf64_hdr hdr;\n    vfs_read(file, 0, sizeof(hdr), &hdr);\n\n    uintptr_t proc_heap = 0;\n    size_t offset = hdr.shoff;\n    \n    for (int i = 0; i < hdr.shnum; ++i) {\n        struct elf64_section_hdr shdr;\n        vfs_read(file, offset, sizeof(shdr), &shdr);\n        \n        if (shdr.flags & SHF_ALLOC) {\n            struct vmr *vmr = kmalloc(sizeof(struct vmr));\n            memset(vmr, 0, sizeof(struct vmr));\n\n            vmr->base  = shdr.addr;\n            vmr->size  = shdr.size;\n\n            /* access flags */\n            vmr->flags |= VM_UR;\n            vmr->flags |= shdr.flags & SHF_WRITE ? VM_UW : 0;\n            vmr->flags |= shdr.flags & SHF_EXEC ? VM_UX : 0;\n            //vmr->flags = VM_URWX;   /* FIXME */\n\n            vmr->qnode = enqueue(&proc->vmr, vmr);\n\n            if (shdr.type == SHT_PROGBITS) {\n                vmr->flags |= VM_FILE;\n                vmr->off   = shdr.off;\n                vmr->vnode = file;\n                //vfs_read(vmr->vnode, vmr->off, vmr->size, (void *) vmr->base);\n            } else {\n                vmr->flags |= VM_ZERO;\n                //memset((void *) vmr->base, 0, vmr->size);\n            }\n\n            if (shdr.addr + shdr.size > proc_heap)\n                proc_heap = shdr.addr + shdr.size;\n        }\n\n        offset += hdr.shentsize;\n    }\n\n    proc->heap_start = proc_heap;\n    proc->heap = proc_heap;\n    proc->entry = hdr.entry;\n\n    return err;\n}\n#endif\n\nint binfmt_elf_check(struct vnode *vnode)\n{\n    struct elf32_hdr hdr;\n    vfs_read(vnode, 0, sizeof(hdr), &hdr);\n\n    /* Check header */\n    if (hdr.e_ident[EI_MAG0] == ELFMAG0 &&\n        hdr.e_ident[EI_MAG1] == ELFMAG1 &&\n        hdr.e_ident[EI_MAG2] == ELFMAG2 &&\n        hdr.e_ident[EI_MAG3] == ELFMAG3)\n        return 0;\n\n    return -ENOEXEC;\n}\n\nint binfmt_elf_load(struct proc *proc, const char *path __unused, struct vnode *vnode)\n{\n    int err = 0;\n\n    struct elf32_hdr hdr;\n\n    if (vfs_read(vnode, 0, sizeof(hdr), &hdr) != sizeof(hdr))\n        return -EINVAL;\n\n    switch (hdr.e_ident[EI_CLASS]) {\n        case ELFCLASS32:\n            return binfmt_elf32_load(proc, vnode);\n    }\n\n    return -EINVAL;\n}\n"
  },
  {
    "path": "kernel/sys/execve.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n#include <core/arch.h>\n#include <sys/proc.h>\n#include <sys/binfmt.h>\n#include <mm/mm.h>\n\nint proc_execve(struct thread *thread, const char *fn, char * const _argp[], char * const _envp[])\n{\n    struct proc *proc = thread->owner;\n    char **u_argp = (char **) _argp;\n    char **u_envp = (char **) _envp;\n\n    int argc = 0, envc = 0;\n    \n    if (u_argp)\n        for (char **arg_p = u_argp; *arg_p; ++arg_p)\n            ++argc;\n\n    if (u_envp)\n        for (char **env_p = u_envp; *env_p; ++env_p)\n            ++envc;\n\n    char **argp = kmalloc((argc + 1) * sizeof(char *), &M_BUFFER, 0);\n    char **envp = kmalloc((envc + 1) * sizeof(char *), &M_BUFFER, 0);\n\n    argp[argc] = NULL;\n    envp[envc] = NULL;\n\n    for (int i = 0; i < argc; ++i)\n        argp[i] = strdup(u_argp[i]);\n\n    for (int i = 0; i < envc; ++i)\n        envp[i] = strdup(u_envp[i]);\n\n    int err;\n    if ((err = binfmt_load(proc, fn, NULL))) {\n        /* Free used resources */\n        for (int i = 0; i < argc + 1; ++i)\n            kfree(argp[i]);\n        kfree(argp);\n\n        for (int i = 0; i < envc + 1; ++i)\n            kfree(envp[i]);\n        kfree(envp);\n\n        return err;\n    }\n\n    thread->spawned = 0;\n    \n    arch_sys_execve(proc, argc + 1, argp, envc + 1, envp);\n    memset(proc->sigaction, 0, sizeof(proc->sigaction));\n\n    /* Free used resources */\n    for (int i = 0; i < argc + 1; ++i)\n        kfree(argp[i]);\n    kfree(argp);\n\n    for (int i = 0; i < envc + 1; ++i)\n        kfree(envp[i]);\n    kfree(envp);\n    \n    return 0;\n}\n\nint thread_execve(struct thread *thread, char * const _argp[], char * const _envp[])\n{\n    struct proc *proc = thread->owner;\n\n    char **argp = (char **) _argp;\n    char **envp = (char **) _envp;\n\n    /* Start at the top of user stack */\n    char *stack = (char *) thread->stack_base;\n\n    int argc = 0, envc = 0;\n    \n    if (envp)\n        for (char **env_p = envp; *env_p; ++env_p)\n            ++envc;\n\n    if (argp)\n        for (char **arg_p = argp; *arg_p; ++arg_p)\n            ++argc;\n\n    char *u_envp[envc+1];\n    char *u_argp[argc+1];\n\n    /* TODO support upward growing stacks */\n\n    /* Push envp strings */\n    u_envp[envc] = NULL;\n    for (int i = envc - 1; i >= 0; --i) {\n        stack -= strlen(envp[i]) + 1;\n        strcpy((char *) stack, envp[i]);\n        u_envp[i] = (char *) stack;\n    }\n\n    /* Push argp strings */\n    u_argp[argc] = NULL;\n    for (int i = argc - 1; i >= 0; --i) {\n        stack -= strlen(argp[i]) + 1;\n        strcpy((char *) stack, argp[i]);\n        u_argp[i] = (char *) stack;\n    }\n\n    /* Push envp array */\n    stack -= (envc+1) * sizeof(char *);\n    memcpy((void *) stack, u_envp, (envc+1) * sizeof(char *));\n\n    uintptr_t env_ptr = (uintptr_t) stack;\n\n    stack -= (argc+1) * sizeof(char *);\n    memcpy((void *) stack, u_argp, (argc+1) * sizeof(char *));\n\n    uintptr_t arg_ptr = (uintptr_t) stack;\n\n    /* main(int argc, char **argv, char **envp) */\n    stack -= sizeof(uintptr_t);\n    *(uintptr_t *) stack = env_ptr;\n\n    stack -= sizeof(uintptr_t);\n    *(uintptr_t *) stack = arg_ptr;\n\n#if ARCH_BITS==32\n    stack -= sizeof(int32_t);\n    *(int32_t *) stack = argc;\n#else\n    stack -= sizeof(int64_t);\n    *(int64_t *) stack = argc;\n#endif\n\n    thread->stack = (uintptr_t) stack;\n    \n    return 0;\n}\n"
  },
  {
    "path": "kernel/sys/fork.c",
    "content": "#include <core/system.h>\n#include <core/string.h>\n#include <core/arch.h>\n#include <mm/mm.h>\n#include <mm/vm.h>\n#include <sys/proc.h>\n#include <ds/queue.h>\n#include <bits/errno.h>\n#include <net/socket.h>\n\nMALLOC_DECLARE(M_FDS);\n\nstatic int copy_fds(struct proc *parent, struct proc *fork)\n{\n    /* copy open files descriptors */\n    fork->fds = kmalloc(FDS_COUNT * sizeof(struct file), &M_FDS, 0);\n\n    if (!fork->fds)\n        return -ENOMEM;\n\n    memcpy(fork->fds, parent->fds, FDS_COUNT * sizeof(struct file));\n\n    for (int i = 0; i < FDS_COUNT; ++i) {\n        struct file *file = &fork->fds[i];\n        if (file->vnode && (file->vnode != (void *) -1)) {\n            if (file->flags & FILE_SOCKET)\n                file->socket->ref++;\n            else\n                file->vnode->ref++;\n        }\n    }\n\n    return 0;\n}\n\nstatic int fork_proc_copy(struct proc *parent, struct proc *fork)\n{\n    fork->pgrp = parent->pgrp;\n    fork->pgrp_node = enqueue(fork->pgrp->procs, fork);\n\n    fork->mask = parent->mask;\n    fork->uid  = parent->uid;\n    fork->gid  = parent->gid;\n\n    fork->heap_start = parent->heap_start;\n    fork->heap  = parent->heap;\n    fork->entry = parent->entry;\n\n    memcpy(fork->sigaction, parent->sigaction, sizeof(parent->sigaction));\n\n    return 0;\n}\n\nint proc_fork(struct thread *thread, struct proc **ref)\n{\n    int err = 0;\n    struct proc *fork = NULL;\n    struct thread *fork_thread = NULL;\n\n    /* Create new process for fork */\n    if ((err = proc_new(&fork)))\n        goto error;\n\n    /* New process main thread */\n    fork_thread = (struct thread *) fork->threads.head->value;\n\n    /* Parent process */\n    struct proc *proc = thread->owner;\n\n    /* Copy process structure */\n    if ((err = fork_proc_copy(proc, fork)))\n        goto error;\n\n    /* Copy process name */\n    if (!(fork->name = strdup(proc->name))) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    /* Allocate a new PID */\n    fork->pid = proc_pid_alloc();\n\n    /* Set fork parent */\n    fork->parent = proc;\n\n    /* Mark the new thread as spawned\n     * fork continues execution from a spawned thread */\n    fork_thread->spawned = 1;\n\n    /* Copy current working directory */\n    if (!(fork->cwd = strdup(proc->cwd))) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    /* Allocate new signals queue */\n    if (!(fork->sig_queue = queue_new())) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    /* copy file descriptors */\n    if ((err = copy_fds(proc, fork)))\n        goto error;\n\n    /* copy virtual memory space */\n    if ((err = vm_space_fork(&proc->vm_space, &fork->vm_space)))\n        goto error;\n\n    /* Fix heap & stack entry pointers -- XXX yes, we are doing this */\n    struct qnode *pvm_node = proc->vm_space.vm_entries.head;\n    struct qnode *fvm_node = fork->vm_space.vm_entries.head;\n\n    while (pvm_node) {\n        struct vm_entry *pvm_entry = pvm_node->value;\n        struct vm_entry *fvm_entry = fvm_node->value;\n\n        if (pvm_entry == proc->heap_vm)\n            fork->heap_vm = fvm_entry;\n\n        if (pvm_entry == proc->stack_vm)\n            fork->stack_vm = fvm_entry;\n\n        pvm_node = pvm_node->next;\n        fvm_node = fvm_node->next;\n    }\n\n    /* Call arch specific fork handler */\n    err = arch_proc_fork(thread, fork);\n\n    if (!err) {\n        /* Return 0 to child */\n        arch_syscall_return(fork_thread, 0);\n        /* And PID to parent */\n        arch_syscall_return(thread, fork->pid);\n    } else {\n        /* Return error to parent */\n        arch_syscall_return(thread, err);\n        goto error;\n    }\n\n    if (ref)\n        *ref = fork;\n\n    return 0;\n\nerror:\n    if (fork) {\n        if (fork->name)\n            kfree(fork->name);\n        if (fork->cwd)\n            kfree(fork->cwd);\n        if (fork->sig_queue)\n            kfree(fork->sig_queue);\n\n        /* TODO free VMRs */\n\n        kfree(fork);\n    }\n\n    return err;\n}\n"
  },
  {
    "path": "kernel/sys/proc.c",
    "content": "/*\n *          Process managment helpers\n *\n *\n *  This file is part of AquilaOS and is released under\n *  the terms of GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar\n */\n\n\n/** \n * \\defgroup sys kernel/sys\n * \\brief system managment\n */\n\n#include <core/system.h>\n#include <core/panic.h>\n#include <core/string.h>\n#include <core/arch.h>\n\n#include <mm/pmap.h>\n#include <mm/mm.h>\n#include <mm/vm.h>\n\n#include <sys/proc.h>\n#include <sys/sched.h>\n\n#include <fs/vfs.h>\n\n#include <ds/queue.h>\n#include <ds/bitmap.h>\n\nMALLOC_DEFINE(M_PROC, \"proc\", \"process structure\");\nMALLOC_DEFINE(M_SESSION, \"session\", \"session structure\");\nMALLOC_DEFINE(M_PGROUP, \"pgroup\", \"process group structure\");\nMALLOC_DEFINE(M_FDS, \"fds\", \"file descriptor array\"); /* FIXME */\n\n/* all processes */\nstruct queue *procs = QUEUE_NEW();\n\n/* all sessions */\nstruct queue *sessions = QUEUE_NEW();\n\n/* all process groups */\nstruct queue *pgroups = QUEUE_NEW();\n\nstruct bitmap *pid_bitmap = BITMAP_NEW(4096);\nstatic int ff_pid = 1;\n\nint proc_pid_alloc()\n{\n    for (int i = ff_pid; (size_t) i < pid_bitmap->max_idx; ++i) {\n        if (!bitmap_check(pid_bitmap, i)) {\n            bitmap_set(pid_bitmap, i);\n            ff_pid = i;\n            return i;\n        }\n    }\n\n    return -1;\n}\n\nvoid proc_pid_free(int pid)\n{\n    bitmap_clear(pid_bitmap, pid);\n    if (pid < ff_pid)\n        ff_pid = pid;\n}\n\nint proc_new(struct proc **ref)\n{\n    int err = 0;\n    struct proc *proc = NULL;\n    struct thread *thread = NULL;\n    struct pmap *pmap = NULL;\n\n    proc = kmalloc(sizeof(struct proc), &M_PROC, M_ZERO);\n\n    if (!proc) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    err = thread_new(proc, &thread);\n\n    if (err != 0)\n        goto error;\n\n    pmap = pmap_create();\n\n    if (pmap == NULL) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    proc->vm_space.pmap = pmap;\n\n    /* Set all signal handlers to default */\n    for (int i = 0; i < SIG_MAX; ++i)\n        proc->sigaction[i].sa_handler = SIG_DFL;\n\n    proc->running = 1;\n    enqueue(procs, proc);   /* Add process to all processes queue */\n\n    if (ref)\n        *ref = proc;\n\n    return 0;\n\nerror:\n    if (proc)\n        kfree(proc);\n\n    return err;\n}\n\nstruct proc *proc_pid_find(pid_t pid)\n{\n    queue_for (node, procs) {\n        struct proc *proc = node->value;\n        if (proc->pid == pid)\n            return proc;\n    }\n    \n    return NULL;\n}\n\nint proc_init(struct proc *proc)\n{\n    int err = 0;\n\n    if (!proc)\n        return -EINVAL;\n\n    proc->pid = proc_pid_alloc();\n\n    proc->fds = kmalloc(FDS_COUNT * sizeof(struct file), &M_FDS, M_ZERO);\n\n    if (!proc->fds) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    proc->sig_queue = queue_new();  /* Initalize signals queue */\n\n    if (!proc->sig_queue) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    return 0;\n\nerror:\n    if (proc->fds)\n        kfree(proc->fds);\n\n    if (proc->sig_queue)\n        kfree(proc->sig_queue);\n\n    return err;\n}\n\nvoid proc_kill(struct proc *proc)\n{\n    if (proc->pid == 1) {\n        if (proc->exit)\n            panic(\"init killed\");\n\n        printk(\"kernel: reached target reboot\\n\");\n        arch_reboot();\n\n        panic(\"reboot not implemented\\n\");\n    }\n\n    proc->running = 0;\n\n    int kill_curthread = 0;\n\n    /* Kill all threads */\n    while (proc->threads.count) {\n        struct thread *thread = dequeue(&proc->threads);\n\n        if (thread->sleep_node) /* Thread is sleeping on some queue */\n            queue_node_remove(thread->sleep_queue, thread->sleep_node);\n\n        if (thread->sched_node) /* Thread is in the scheduler queue */\n            queue_node_remove(thread->sched_queue, thread->sched_node);\n\n        if (thread == curthread) {\n            kill_curthread = 1;\n            continue;\n        }\n\n        thread_kill(thread);\n        kfree(thread);\n    }\n\n    /* close all file descriptors */\n    for (int i = 0; i < FDS_COUNT; ++i) {\n        struct file *file = &proc->fds[i];\n        if (file->vnode && file->vnode != (void *) -1) {\n            vfs_file_close(file);\n            file->vnode = NULL;\n        }\n    }\n\n    struct vm_space *vm_space = &proc->vm_space;\n    vm_space_destroy(vm_space);\n    pmap_decref(vm_space->pmap);\n\n    /* Free kernel-space resources */\n    kfree(proc->fds);\n    kfree(proc->cwd);\n\n    while (proc->sig_queue->count)\n        dequeue(proc->sig_queue);\n\n    kfree(proc->sig_queue);\n\n    /* Mark all children as orphans */\n    queue_for (node, procs) {\n        struct proc *_proc = node->value;\n\n        if (_proc->parent == proc)\n            _proc->parent = NULL;\n    }\n\n    kfree(proc->name);\n\n    /* XXX */\n    queue_node_remove(proc->pgrp->procs, proc->pgrp_node);\n\n    /* Wakeup parent if it is waiting for children */\n    if (proc->parent) {\n        thread_queue_wakeup(&proc->parent->wait_queue);\n        signal_proc_send(proc->parent, SIGCHLD);\n    } else { \n        /* Orphan zombie, just reap it */\n        proc_reap(proc);\n    }\n\n    if (kill_curthread) {\n        arch_cur_thread_kill();\n        panic(\"How did we get here?\");\n    }\n}\n\nint proc_reap(struct proc *proc)\n{\n    proc_pid_free(proc->pid);\n\n    queue_remove(procs, proc);\n    kfree(proc);\n\n    return 0;\n}\n\nint proc_fd_get(struct proc *proc)\n{\n    for (int i = 0; i < FDS_COUNT; ++i) {\n        if (!proc->fds[i].vnode) {\n            proc->fds[i].vnode = (void *) -1;    \n            return i;\n        }\n    }\n\n    return -1;\n}\n\nvoid proc_fd_release(struct proc *proc, int fd)\n{\n    if (fd < FDS_COUNT) {\n        proc->fds[fd].vnode = NULL;\n    }\n}\n\nint session_new(struct proc *proc)\n{\n    int err = 0;\n    struct session *session = NULL;\n    struct pgroup  *pgrp    = NULL;\n\n    /* allocate a new session structure */\n    session = kmalloc(sizeof(struct session), &M_SESSION, M_ZERO);\n    if (!session) goto e_nomem;\n\n    /* allocate a new process group structure for the session */\n    pgrp = kmalloc(sizeof(struct pgroup), &M_PGROUP, M_ZERO);\n    if (!pgrp) goto e_nomem;\n\n    session->pgps = queue_new();\n    if (!session->pgps) goto e_nomem;\n\n    pgrp->procs = queue_new();\n    if (!pgrp->procs) goto e_nomem;\n\n    pgrp->session_node = enqueue(session->pgps, pgrp);\n    if (!pgrp->session_node) goto e_nomem;\n\n    proc->pgrp_node = enqueue(pgrp->procs, proc);\n    if (!proc->pgrp_node) goto e_nomem;\n\n    session->sid = proc->pid;\n    pgrp->pgid = proc->pid;\n\n    session->leader = proc;\n    pgrp->leader = proc;\n\n    pgrp->session = session;\n    proc->pgrp = pgrp;\n\n    return 0;\n\ne_nomem:\n    err = -ENOMEM;\nerror:\n    if (session) {\n        kfree(session->pgps);\n        kfree(session);\n    }\n\n    if (pgrp) {\n        kfree(pgrp->procs);\n        kfree(pgrp);\n    }\n\n    return err;\n}\n\nint pgrp_new(struct proc *proc, struct pgroup **ref)\n{\n    int err = 0;\n    struct pgroup *pgrp = NULL;\n    \n    pgrp = kmalloc(sizeof(struct pgroup), &M_PGROUP, M_ZERO);\n    if (!pgrp) goto e_nomem;\n\n    pgrp->pgid = proc->pid;\n    pgrp->session = proc->pgrp->session;\n\n    /* remove the process from the old process group */\n    queue_node_remove(proc->pgrp->procs, proc->pgrp_node);\n\n    pgrp->procs = queue_new();\n    if (!pgrp->procs) goto e_nomem;\n\n    proc->pgrp_node = enqueue(pgrp->procs, proc);\n    if (!proc->pgrp_node) goto e_nomem;\n\n    pgrp->session_node = enqueue(proc->pgrp->session->pgps, pgrp);\n    if (!pgrp->session_node) goto e_nomem;\n\n    if (!proc->pgrp->procs->count) {\n        /* TODO */\n    }\n\n    proc->pgrp = pgrp;\n\n    if (ref) *ref = pgrp;\n\n    return 0;\n\ne_nomem:\n    err = -ENOMEM;\n\nerror:\n    if (pgrp)\n        kfree(pgrp);\n\n    return err;\n}\n"
  },
  {
    "path": "kernel/sys/sched.c",
    "content": "#include <core/system.h>\n#include <core/panic.h>\n#include <core/arch.h>\n#include <sys/proc.h>\n#include <sys/sched.h>\n#include <ds/queue.h>\n\nstruct queue *ready_queue = QUEUE_NEW();   /* Ready threads queue */\nstruct thread *curthread = NULL;\n\nvoid sched_thread_ready(struct thread *thread)\n{\n    struct qnode *sched_node = enqueue(ready_queue, thread);\n    thread->sched_queue = ready_queue;\n    thread->sched_node  = sched_node;\n}\n\nint kidle = 0;\nvoid kernel_idle(void)\n{\n    kidle = 1;\n    arch_idle();\n}\n\nvoid sched_thread_spawn(struct thread *thread)   /* Starts thread execution */\n{\n    thread->spawned = 1;\n    arch_thread_spawn(thread);\n}\n\nvoid sched_init_spawn(struct proc *init)\n{\n    proc_init(init);\n\n    /* init defaults */\n    init->mask = 0775;\n    init->cwd = strdup(\"/\");\n\n    arch_sched_init();\n\n    session_new(init);\n\n    curthread = (struct thread *) init->threads.head->value;\n    curthread->state = RUNNABLE;\n    sched_thread_spawn(curthread);\n}\n\nvoid schedule() /* Called from arch-specific timer event handler */\n{\n    if (!ready_queue)    /* How did we even get here? */\n        panic(\"Threads queue is not initialized\");\n\n    if (!kidle)\n        sched_thread_ready(curthread);\n\n    kidle = 0;\n\n    if (!ready_queue->count) /* No ready threads, idle */\n        kernel_idle();\n\n    curthread = dequeue(ready_queue);\n    curthread->sched_node = NULL;\n\n    if (curthread->spawned) {\n        arch_thread_switch(curthread);\n    } else {\n        sched_thread_spawn(curthread);\n    }\n}\n"
  },
  {
    "path": "kernel/sys/signal.c",
    "content": "/**********************************************************************\n *                            Signals\n *\n *\n *  This file is part of AquilaOS and is released under the terms of\n *  GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar\n */\n\n#include <core/system.h>\n#include <core/arch.h>\n\n#include <ds/queue.h>\n\n#include <sys/proc.h>\n#include <sys/signal.h>\n#include <sys/sched.h>\n\n#include <bits/errno.h>\n\nint sig_default_action[] = {\n    [SIGABRT] = SIGACT_ABORT,\n    [SIGALRM] = SIGACT_TERMINATE,\n    [SIGBUS]  = SIGACT_ABORT,\n    [SIGCHLD] = SIGACT_IGNORE,\n    [SIGCONT] = SIGACT_CONTINUE,\n    [SIGFPE]  = SIGACT_ABORT,\n    [SIGHUP]  = SIGACT_TERMINATE,\n    [SIGILL]  = SIGACT_ABORT,\n    [SIGINT]  = SIGACT_TERMINATE,\n    [SIGKILL] = SIGACT_TERMINATE,\n    [SIGPIPE] = SIGACT_TERMINATE,\n    [SIGQUIT] = SIGACT_ABORT,\n    [SIGSEGV] = SIGACT_ABORT,\n    [SIGSTOP] = SIGACT_STOP,\n    [SIGTERM] = SIGACT_TERMINATE,\n    [SIGTSTP] = SIGACT_STOP,\n    [SIGTTIN] = SIGACT_STOP,\n    [SIGTTOU] = SIGACT_STOP,\n    [SIGUSR1] = SIGACT_TERMINATE,\n    [SIGUSR2] = SIGACT_TERMINATE,\n    [SIGPOLL] = SIGACT_TERMINATE,\n    //[SIGPROF] = SIGACT_TERMINATE,\n    [SIGSYS]  = SIGACT_ABORT,\n    [SIGTRAP] = SIGACT_ABORT,\n    [SIGURG]  = SIGACT_IGNORE,\n    //[SIGVTALRM] = SIGACT_TERMINATE,\n    //[SIGXCPU] = SIGACT_ABORT,\n    //[SIGXFSZ] = SIGACT_ABORT,\n};\n\nint signal_proc_send(struct proc *proc, int signal)\n{\n    if (proc == curproc) {\n        arch_handle_signal(signal);\n    } else {\n        enqueue(proc->sig_queue, (void *)(intptr_t) signal);\n\n        /* wake up main thread if sleeping - XXX */\n        struct thread *thread = (struct thread *) proc->threads.head->value;\n        if (thread->state == ISLEEP)\n            thread_queue_wakeup(thread->sleep_queue);\n    }\n\n    return 0;\n}\n\nint signal_pgrp_send(struct pgroup *pg, int signal)\n{\n    queue_for (node, pg->procs) {\n        struct proc *proc = node->value;\n        signal_proc_send(proc, signal);\n    }\n\n    return 0;\n}\n\nint signal_send(pid_t pid, int signal)\n{\n    if (curproc->pid == pid) {\n        arch_handle_signal(signal);\n        return 0;\n    } else {\n        struct proc *proc = proc_pid_find(pid);\n\n        if (!proc)\n            return -ESRCH;\n        else\n            return signal_proc_send(proc, signal);\n    }\n}\n"
  },
  {
    "path": "kernel/sys/syscall.c",
    "content": "/**********************************************************************\n *                          System Calls\n *\n *\n *  This file is part of AquilaOS and is released under the terms of\n *  GNU GPLv3 - See LICENSE.\n *\n *  Copyright (C) Mohamed Anwar\n */\n\n\n#include <core/system.h>\n#include <core/panic.h>\n#include <core/string.h>\n#include <core/arch.h>\n#include <core/time.h>\n\n#include <sys/proc.h>\n#include <sys/sched.h>\n#include <sys/signal.h>\n#include <sys/binfmt.h>\n\n#include <net/socket.h>\n\n#include <bits/errno.h>\n#include <bits/dirent.h>\n#include <bits/utsname.h>\n#include <bits/fcntl.h>\n#include <bits/mman.h>\n\n#include <fs/devpts.h>\n#include <fs/pipe.h>\n#include <fs/stat.h>\n\n#include <mm/vm.h>\n\nstatic int syscall_log_level = LOG_NONE;\nLOGGER_DEFINE(syscall, syscall_log, syscall_log_level)\n\nstatic void sys_exit(int code)\n{\n    syscall_log(LOG_DEBUG, \"exit(code=%d)\\n\", code);\n\n    struct proc *owner = curproc;\n\n    owner->exit = PROC_EXIT(code, 0);  /* Child exited normally */\n\n    proc_kill(owner);\n    arch_sleep();\n\n    /* We should never reach this anyway */\n    for (;;);\n}\n\nstatic void sys_close(int fildes)\n{\n    syscall_log(LOG_DEBUG, \"close(fildes=%d)\\n\", fildes);\n\n    if (fildes < 0 || fildes >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fildes];\n    \n    if (file == (void *) -1 || !file->vnode) {\n        arch_syscall_return(curthread, -EBADFD);\n        return;\n    }\n\n    int ret = vfs_file_close(file);\n    curproc->fds[fildes].vnode = NULL;\n    arch_syscall_return(curthread, ret);\n}\n\nstatic void sys_execve(const char *path, char * const argp[], char * const envp[])\n{\n    syscall_log(LOG_DEBUG, \"execve(path=%s, argp=%p, envp=%p)\\n\", path, argp, envp);\n\n    if (!path || !*path) {\n        arch_syscall_return(curthread, -ENOENT);\n        return;\n    }\n\n    int err = 0;\n    char *fn = strdup(path);\n\n    if (!fn) {\n        arch_syscall_return(curthread, -ENOMEM);\n        return;\n    }\n\n    err = proc_execve(curthread, fn, argp, envp);\n\n    kfree(fn);\n\n    if (err) {\n        arch_syscall_return(curthread, err);\n    } else {\n        sched_thread_spawn(curthread);\n    }\n}\n\nstatic void sys_fork(void)\n{\n    syscall_log(LOG_DEBUG, \"fork()\\n\");\n\n    struct proc *fork = NULL;\n    proc_fork(curthread, &fork);\n\n    /* Returns are handled inside proc_fork */\n    if (fork != NULL) {\n        struct thread *thread = (struct thread *) fork->threads.head->value;\n        sched_thread_ready(thread);\n    }\n}\n\nstatic void sys_fstat(int fildes, struct stat *buf)\n{\n    syscall_log(LOG_DEBUG, \"fstat(fildes=%d, buf=%p)\\n\", fildes, buf);\n\n    if (fildes < 0 || fildes >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fildes];\n    \n    if (!file->vnode) {\n        arch_syscall_return(curthread, -EBADFD);\n        return;\n    }\n\n    struct vnode *vnode = file->vnode;\n\n    int ret = vfs_stat(vnode, buf);\n    arch_syscall_return(curthread, ret);\n}\n\nstatic void sys_getpid(void)\n{\n    syscall_log(LOG_DEBUG, \"getpid()\\n\");\n    arch_syscall_return(curthread, curproc->pid);\n}\n\nstatic void sys_isatty(int fildes)\n{\n    syscall_log(LOG_DEBUG, \"isatty(fildes=%d)\\n\", fildes);\n\n    if (fildes < 0 || fildes >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct vnode *node = curproc->fds[fildes].vnode;\n\n    if (!node) {    /* Invalid File Descriptor */\n        arch_syscall_return(curthread, -EBADFD);\n        return;\n    }\n\n    //arch_syscall_return(curthread, node->rdev & (136 << 8));\n    arch_syscall_return(curthread, 1);\n}\n\nstatic void sys_kill(pid_t pid, int sig)\n{\n    syscall_log(LOG_DEBUG, \"kill(pid=%d, sig=%d)\\n\", pid, sig);\n    int ret = signal_send(pid, sig);\n    arch_syscall_return(curthread, ret);\n}\n\nstatic void sys_link(const char *oldpath, const char *newpath)\n{\n    syscall_log(LOG_DEBUG, \"link(oldpath=%s, newpath=%s)\\n\",\n            oldpath, newpath);\n\n    /* TODO */\n\n    arch_syscall_return(curthread, -ENOSYS);\n}\n\nstatic void sys_lseek(int fildes, off_t offset, int whence)\n{\n    syscall_log(LOG_DEBUG, \"lseek(fildes=%d, offset=%d, whence=%d)\\n\",\n            fildes, offset, whence);\n\n    if (fildes < 0 || fildes >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fildes];\n\n    if (!file->vnode) {    /* Invalid File Descriptor */\n        arch_syscall_return(curthread, -EBADFD);\n        return;\n    }\n\n    int ret = vfs_file_lseek(file, offset, whence);\n    arch_syscall_return(curthread, ret);\n}\n\nstatic void sys_open(const char *path, int oflags, mode_t mode)\n{\n    syscall_log(LOG_DEBUG, \"open(path=%s, oflags=0x%x, mode=0x%x)\\n\", path, oflags, mode);\n    \n    int fd = proc_fd_get(curproc);  /* Find a free file descriptor */\n\n    if (fd == -1) {\n        /* Reached maximum number of open file descriptors */\n        arch_syscall_return(curthread, -EMFILE);\n        return;\n    }\n\n    /* Look up the file */\n    struct vnode *vnode = NULL;\n    struct uio uio = PROC_UIO(curproc);\n    uio.flags = oflags;\n\n    int ret = vfs_lookup(path, &uio, &vnode, NULL);\n\n    if (ret) {   /* Lookup failed */\n        if ((ret == -ENOENT) && (oflags & O_CREAT)) {\n            if ((ret = vfs_creat(path, mode, &uio, &vnode))) {\n                goto done;\n            }\n\n            goto o_creat;\n        }\n\n        goto done;\n    }\n\n    if (ret)\n        goto done;\n\no_creat:\n    curproc->fds[fd] = (struct file) {\n        .vnode  = vnode,\n        .offset = 0,\n        .flags  = oflags,\n    };\n\n    if ((ret = vfs_perms_check(&curproc->fds[fd], &uio)))\n        goto done;\n\n    ret = vfs_file_open(&curproc->fds[fd]);\n\ndone:\n    if (ret < 0) { /* open returned an error code */\n        proc_fd_release(curproc, fd);\n        vfs_close(vnode);\n    } else {\n        ret = fd;\n    }\n\n    arch_syscall_return(curthread, ret);\n    return;\n}\n\nstatic void sys_read(int fildes, void *buf, size_t nbytes)\n{\n    syscall_log(LOG_DEBUG, \"read(fd=%d, buf=%p, count=%d)\\n\", fildes, buf, nbytes);\n    \n    if (fildes < 0 || fildes >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fildes];\n    int ret = vfs_file_read(file, buf, nbytes);\n    arch_syscall_return(curthread, ret);\n    return;\n}\n\nstatic void sys_sbrk(ptrdiff_t incr)\n{\n    syscall_log(LOG_DEBUG, \"sbrk(incr=0x%x)\\n\", incr);\n\n    uintptr_t heap_start = curproc->heap_start;\n    uintptr_t heap = curproc->heap;\n\n    curproc->heap = heap + incr;\n    curproc->heap_vm->size = PAGE_ROUND(heap + incr - heap_start);\n\n    arch_syscall_return(curthread, heap);\n    return;\n}\n\nstatic void sys_stat(const char *path, struct stat *buf)\n{\n    syscall_log(LOG_DEBUG, \"stat(path=%s, buf=%p)\\n\", path, buf);\n\n    struct vnode *vnode = NULL;\n    int ret = 0;\n    struct uio uio = PROC_UIO(curproc);\n\n    if ((ret = vfs_lookup(path, &uio, &vnode, NULL))) {\n        arch_syscall_return(curthread, ret);\n        return;\n    }\n\n    ret = vfs_stat(vnode, buf);\n    arch_syscall_return(curthread, ret);\n}\n\nstatic void sys_times()\n{\n\n}\n\nstatic void sys_unlink(const char *path)\n{\n    syscall_log(LOG_DEBUG, \"unlink(path=%p)\\n\", path);\n\n    struct uio uio = PROC_UIO(curproc);\n    int ret = vfs_unlink(path, &uio);\n    arch_syscall_return(curthread, ret);\n}\n\n#define WNOHANG 1\nstatic void sys_waitpid(int pid, int *stat_loc, int options)\n{\n    syscall_log(LOG_DEBUG, \"waitpid(pid=%d, stat_loc=%p, options=0x%x)\\n\", pid, stat_loc, options);\n\n    int nohang = options & WNOHANG;\n\n    if (pid < -1) {\n        /* wait for any child process whose process group ID\n              is equal to the absolute value of pid */\n        panic(\"unsupported\");\n    } else if (pid == -1) {\n\n        /* wait for any child process */\n        for (;;) {\n            int found = 0;\n\n            queue_for (node, procs) {\n                struct proc *proc = node->value;\n\n                if (proc->parent != curproc)\n                    continue;\n\n                found = 1;\n\n                if (!proc->running) {\n                    if (stat_loc)\n                        *stat_loc = proc->exit;\n\n                    arch_syscall_return(curthread, proc->pid);\n                    proc_reap(proc);\n                    return;\n                }\n            }\n\n            if (nohang) {\n                arch_syscall_return(curthread, found? 0 : -ECHILD);\n                return;\n            }\n\n            if (thread_queue_sleep(&curproc->wait_queue)) {\n                arch_syscall_return(curthread, -EINTR);\n                return;\n            }\n        }\n\n    } else if (pid == 0) {\n        /* wait for any child process whose process group ID\n              is equal to that of the calling process */\n        panic(\"unsupported\");\n    } else {\n        /* wait for the child whose process ID is equal to the\n              value of pid */\n        struct proc *child = proc_pid_find(pid);\n\n        /* If pid is invalid or current process is not parent of child */\n        if (child == NULL || child->parent != curproc) {\n            arch_syscall_return(curthread, -ECHILD);\n            return;\n        }\n\n        if (!(child->running)) {  /* Child is killed */\n            *stat_loc = child->exit;\n            arch_syscall_return(curthread, child->pid);\n            proc_reap(child);\n            return;\n        }\n\n        /*\n        if (options & WNOHANG) {\n            arch_syscall_return(curthread, 0);\n            return;\n        }\n        */\n\n        while (child->running) {\n            if (thread_queue_sleep(&curproc->wait_queue)) {\n                arch_syscall_return(curthread, -EINTR);\n                return;\n            }\n        }\n\n        *stat_loc = child->exit;\n        arch_syscall_return(curthread, child->pid);\n        proc_reap(child);\n    }\n}\n\nstatic void sys_write(int fd, void *buf, size_t nbytes)\n{\n    syscall_log(LOG_DEBUG, \"write(fd=%d, buf=%p, nbytes=%d)\\n\", fd, buf, nbytes);\n    \n    if (fd < 0 || fd >= FDS_COUNT) {   /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fd];\n    int ret = vfs_file_write(file, buf, nbytes);\n    arch_syscall_return(curthread, ret);\n    return;\n}\n\nstatic void sys_ioctl(int fd, int request, void *argp)\n{\n    syscall_log(LOG_DEBUG, \"ioctl(fd=%d, request=0x%x, argp=%p)\\n\",\n            fd, request, argp);\n\n    if (fd < 0 || fd >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fd];\n    int ret = vfs_file_ioctl(file, request, argp);\n    arch_syscall_return(curthread, ret);\n    return;\n}\n\nstatic void sys_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)\n{\n    syscall_log(LOG_DEBUG, \"sigaction(sig=%d, act=%p, oact=%p)\\n\",\n            sig, act, oact);\n\n    if (sig < 1 || sig > SIG_MAX) {\n        arch_syscall_return(curthread, -EINVAL);\n        return;\n    }\n\n    if (oact)\n        memcpy(oact, &curproc->sigaction[sig], sizeof(struct sigaction));\n\n    if (act)\n        memcpy(&curproc->sigaction[sig], act, sizeof(struct sigaction));\n\n    arch_syscall_return(curthread, 0);\n}\n\nstatic void sys_readdir(int fd, struct dirent *dirent)\n{\n    syscall_log(LOG_DEBUG, \"readdir(fd=%d, dirent=%p)\\n\", fd, dirent);\n\n    if (fd < 0 || fd >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fd];\n    int ret = vfs_file_readdir(file, dirent);\n    arch_syscall_return(curthread, ret);\n    return;\n}\n\nstruct mount_struct {\n    const char *type;\n    const char *dir;\n    int flags;\n    void *data;\n} __packed;\n\nstatic void sys_mount(struct mount_struct *args)\n{\n    if (curproc->uid != 0) {\n        arch_syscall_return(curthread, -EACCES);\n        return;\n    }\n\n    const char *type = args->type;\n    const char *dir  = args->dir;\n    int flags = args->flags;\n    void *data = args->data;\n\n    syscall_log(LOG_DEBUG, \"mount(type=%s, dir=%s, flags=%x, data=%p)\\n\",\n            type, dir, flags, data);\n\n    int ret = vfs_mount(type, dir, flags, data, &PROC_UIO(curproc));\n    arch_syscall_return(curthread, ret);\n    return;\n}\n\nstatic void sys_mkdir(const char *path, mode_t mode)\n{\n    syscall_log(LOG_DEBUG, \"mkdir(path=%s, mode=%x)\\n\", path, mode);\n\n    struct uio uio = PROC_UIO(curproc);\n\n    int ret = vfs_mkdir(path, mode, &uio, NULL);\n    arch_syscall_return(curthread, ret);\n    return;\n}\n\nstatic void sys_uname(struct utsname *name)\n{\n    syscall_log(LOG_DEBUG, \"uname(name=%p)\\n\", name);\n\n    /* FIXME: Sanity checking */\n\n    strcpy(name->sysname,  UTSNAME_SYSNAME);\n    strcpy(name->nodename, UTSNAME_NODENAME);\n    strcpy(name->release,  UTSNAME_RELEASE);\n    strcpy(name->version,  UTSNAME_VERSION);\n    strcpy(name->machine,  UTSNAME_MACHINE);\n\n    arch_syscall_return(curthread, 0);\n    return;\n}\n\nstatic void sys_pipe(int fd[2])\n{\n    syscall_log(LOG_DEBUG, \"pipe(fd=%p)\\n\", fd);\n    int fd1 = proc_fd_get(curproc);\n    int fd2 = proc_fd_get(curproc);\n    pipefs_pipe(&curproc->fds[fd1], &curproc->fds[fd2]);\n    fd[0] = fd1;\n    fd[1] = fd2;\n    arch_syscall_return(curthread, 0);\n}\n\nstatic void sys_fcntl(int fd, int cmd, uintptr_t arg)\n{\n    syscall_log(LOG_DEBUG, \"fcntl(fd=%d, cmd=%d, arg=0x%x)\\n\",\n            fd, cmd, arg);\n\n    if (fd < 0 || fd >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fd];\n\n    int dupfd = 0;\n\n    switch (cmd) {\n        case F_DUPFD:\n            if (arg == 0)\n                dupfd = proc_fd_get(curproc);\n            else\n                dupfd = arg;\n            curproc->fds[dupfd] = *file;\n            arch_syscall_return(curthread, dupfd);\n            return;\n        case F_GETFD:\n            arch_syscall_return(curthread, file->flags);\n            return;\n        case F_SETFD:\n            file->flags = (int) arg; /* XXX */\n            arch_syscall_return(curthread, 0);\n            return;\n    }\n\n    arch_syscall_return(curthread, -EINVAL);\n}\n\nstatic void sys_chdir(const char *path)\n{\n    syscall_log(LOG_DEBUG, \"chdir(path=%s)\\n\", path);\n\n    if (!path || !*path) {\n        arch_syscall_return(curthread, -ENOENT);\n        return;\n    }\n\n    int ret = 0;\n    char *abs_path = NULL;\n\n    struct vnode *vnode = NULL;\n    ret = vfs_lookup(path, &PROC_UIO(curproc), &vnode, &abs_path);\n\n    if (ret)\n        goto free_resources;\n\n    if (!S_ISDIR(vnode->mode)) {\n        ret = -ENOTDIR;\n        goto free_resources;\n    }\n\n    kfree(curproc->cwd);\n    curproc->cwd = strdup(abs_path);\n\nfree_resources:\n    kfree(abs_path);\n    arch_syscall_return(curthread, ret);\n}\n\nstatic void sys_getcwd(char *buf, size_t size)\n{\n    syscall_log(LOG_DEBUG, \"getcwd(buf=%p, size=%d)\\n\", buf, size);\n\n    if (!size) {\n        arch_syscall_return(curthread, -EINVAL);\n        return;\n    }\n\n    size_t len = strlen(curproc->cwd);\n\n    if (size < len + 1) {\n        arch_syscall_return(curthread, -ERANGE);\n        return;\n    }\n\n    memcpy(buf, curproc->cwd, len + 1);\n    arch_syscall_return(curthread, 0);\n}\n\nstruct __uthread {\n    uintptr_t stack;\n    uintptr_t entry;    /* Sys entry */\n    uintptr_t uentry;   /* User entry */\n    uintptr_t arg;\n    uintptr_t attr;\n};\n\nstatic void sys_thread_create(struct __uthread *__uthread)\n{\n    syscall_log(LOG_DEBUG,\n            \"thread_create(stack=%p, entry=%p, uentry=%p, arg=%p, attr=%p)\\n\",\n            __uthread->stack, __uthread->entry, __uthread->uentry,\n            __uthread->arg, __uthread->attr);\n\n    struct thread *thread;\n    thread_create(curthread, __uthread->stack, __uthread->entry, __uthread->uentry, __uthread->arg, __uthread->attr, &thread);\n    sched_thread_ready(thread);\n    arch_syscall_return(curthread, thread->tid);\n}\n\nstatic void sys_thread_exit(void *value_ptr)\n{\n    syscall_log(LOG_DEBUG, \"thread_exit(value_ptr=%p)\\n\", value_ptr);\n\n    //curthread->value_ptr = value_ptr;\n    struct proc *owner = curproc;\n\n    thread_kill(curthread);\n\n    /* Wakeup owner if it is waiting for joining */\n    thread_queue_wakeup(&owner->thread_join);\n\n    arch_sleep();\n\n    for (;;);\n}\n\nstatic void sys_thread_join(int tid, void **value_ptr)\n{\n    syscall_log(LOG_DEBUG, \"thread_join(tid=%d, value_ptr=%p)\\n\", tid, value_ptr);\n\n    struct proc *owner = curproc;\n    struct thread *thread = NULL;\n\n    queue_for (node, &owner->threads) {\n        struct thread *_thread = node->value;\n        if (_thread->tid == tid)\n            thread = _thread;\n    }\n\n    /* No such thread */\n    if (!thread) {\n        arch_syscall_return(curthread, -ECHILD);\n        return;\n    }\n\n    if (thread->state == ZOMBIE) {  /* Thread is terminated */\n        //*value_ptr = thread->value_ptr;\n        arch_syscall_return(curthread, thread->tid);\n        return;\n    }\n\n    while (thread->state != ZOMBIE) {\n        if (thread_queue_sleep(&curproc->thread_join)) {\n            arch_syscall_return(curthread, -EINTR);\n            return;\n        }\n    }\n\n    //*value_ptr = thread->value_ptr;\n    arch_syscall_return(curthread, thread->tid);\n}\n\nstatic void sys_setpgid(pid_t pid, pid_t pgid)\n{\n    syscall_log(LOG_DEBUG, \"setpgid(pid=%d, pgid=%d)\\n\", pid, pgid);\n\n    //if (pid == 0 && pgid == 0) {\n        int ret = pgrp_new(curproc, NULL);\n        arch_syscall_return(curthread, ret);\n    //} else {\n    //    panic(\"Unsupported\");\n    //}\n}\n\nstatic void sys_mknod(const char *path, uint32_t mode, uint32_t dev)\n{\n    syscall_log(LOG_DEBUG, \"mknod(path=%s, mode=%x, dev=%x)\\n\", path, mode, dev);\n\n    int ret = vfs_mknod(path, mode, dev, &PROC_UIO(curproc), NULL);\n    arch_syscall_return(curthread, ret);\n}\n\nstatic void sys_lstat(const char *path, struct stat *buf)\n{\n    syscall_log(LOG_DEBUG, \"lstat(path=%s, buf=%p)\\n\", path, buf);\n\n    struct vnode *vnode = NULL;\n    int ret = 0;\n    struct uio uio = PROC_UIO(curproc);\n    uio.flags = O_NOFOLLOW;\n\n    if ((ret = vfs_lookup(path, &uio, &vnode, NULL))) {\n        arch_syscall_return(curthread, ret);\n        return;\n    }\n\n    ret = vfs_stat(vnode, buf);\n    arch_syscall_return(curthread, ret);\n}\n\nstatic void sys_auth(uint32_t uid, const char *pw)\n{\n    syscall_log(LOG_DEBUG, \"auth(uid=%d, pw=%s)\\n\", uid, pw);\n\n    curproc->uid = uid;   /* XXX */\n    arch_syscall_return(curthread, 0);\n}\n\nstatic void sys_getuid(void)\n{\n    syscall_log(LOG_DEBUG, \"getuid()\\n\");\n    arch_syscall_return(curthread, curproc->uid);\n}\n\nstatic void sys_getgid(void)\n{\n    syscall_log(LOG_DEBUG, \"getgid()\\n\");\n    arch_syscall_return(curthread, curproc->gid);\n}\n\nstruct mmap_args {\n    void    *addr;\n    size_t  len;\n    int     prot;\n    int     flags;\n    int     fildes;\n    off_t   off;\n} __packed;\n\nstatic void sys_mmap(struct mmap_args *args, void **ret)\n{\n    syscall_log(LOG_DEBUG, \"mmap(addr=%p, len=%d, prot=%x, flags=%x, fildes=%d, off=%d, ret=%p)\\n\",\n            args->addr, args->len, args->prot, args->flags, args->fildes, args->off, ret);\n\n    int err = 0;\n\n    int fildes = args->fildes;\n    if (fildes < 0 || fildes >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fildes];\n\n    if (!file->vnode) {    /* Invalid File Descriptor */\n        arch_syscall_return(curthread, -EBADFD);\n        return;\n    }\n\n    /* Allocate VMR */\n    struct vm_entry *vm_entry;\n    vm_entry = vm_entry_new();\n\n    if (vm_entry == NULL) {\n        err = -ENOMEM;\n        goto error;\n    }\n\n    /* Initialize VM entry */\n    vm_entry->base   = (uintptr_t) args->addr;\n    vm_entry->size   = args->len;\n    vm_entry->flags  = args->prot & PROT_READ  ? VM_UR : 0;\n    vm_entry->flags |= args->prot & PROT_WRITE ? VM_UW : 0;\n    vm_entry->flags |= args->prot & PROT_EXEC  ? VM_UX : 0;\n    vm_entry->flags |= args->flags & MAP_SHARED ? VM_SHARED : 0;\n    vm_entry->off    = args->off;\n\n    vm_entry->vm_object = vm_object_vnode(file->vnode);\n\n    if (!(args->flags & MAP_FIXED))\n        vm_entry->base = 0;  /* Allocate memory region */\n\n    struct vm_space *vm_space = &curproc->vm_space;\n    if ((err = vm_space_insert(vm_space, vm_entry)))\n        goto error;\n\n    if (!(args->flags & MAP_PRIVATE) && (err = vfs_map(vm_space, vm_entry)))\n        goto error;\n\n    *ret = (void *) vm_entry->base;\n\n    arch_syscall_return(curthread, err);\n    return;\n\nerror:\n    if (vm_entry) {\n        if (vm_entry->qnode)\n            queue_node_remove(&curproc->vm_space.vm_entries, vm_entry->qnode);\n\n        kfree(vm_entry);\n    }\n\n    arch_syscall_return(curthread, err);\n    return;\n}\n\nstatic void sys_munmap(void *addr, size_t len)\n{\n    syscall_log(LOG_DEBUG, \"munmap(addr=%p, len=%d)\\n\", addr, len);\n\n    struct vm_space *vm_space = &curproc->vm_space;\n\n    queue_for (node, &vm_space->vm_entries) {\n        struct vm_entry *vm_entry = node->value;\n\n        if (vm_entry->base == (uintptr_t) addr && vm_entry->size == len) {\n            queue_node_remove(&vm_space->vm_entries, vm_entry->qnode);\n            vm_unmap_full(vm_space, vm_entry);\n            kfree(vm_entry);\n            arch_syscall_return(curthread, 0);\n            return;\n        }\n    }\n\n    /* Not found */\n    arch_syscall_return(curthread, -EINVAL);\n    return;\n}\n\nstatic void sys_socket(int domain, int type, int protocol)\n{\n    syscall_log(LOG_DEBUG, \"socket(domain=%d, type=%d, protocol=%d)\\n\",\n            domain, type, protocol);\n\n    int fd = proc_fd_get(curproc);  /* Find a free file descriptor */\n\n    if (fd == -1) {     /* No free file descriptor */\n        /* Reached maximum number of open file descriptors */\n        arch_syscall_return(curthread, -EMFILE);\n        return;\n    }\n    \n    int err = 0;\n    struct file *file = &curproc->fds[fd];\n\n    if ((err = socket_create(file, domain, type, protocol))) {\n        proc_fd_release(curproc, fd);\n        arch_syscall_return(curthread, err);\n        return;\n    }\n\n    arch_syscall_return(curthread, fd);\n    return;\n}\n\nstatic void sys_accept(int fd, const struct sockaddr *addr, uint32_t *len)\n{\n    syscall_log(LOG_DEBUG, \"accept(fd=%d, addr=%p, len=%p)\\n\",\n            fd, addr, len);\n\n    if (fd < 0 || fd >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    int conn_fd = proc_fd_get(curproc);\n\n    if (conn_fd == -1) {\n        arch_syscall_return(curthread, -EMFILE);\n        return; \n    }\n\n    struct file *socket = &curproc->fds[fd];\n    struct file *conn   = &curproc->fds[conn_fd];\n\n    int err = 0;\n    if ((err = socket_accept(socket, conn, addr, len))) {\n        proc_fd_release(curproc, conn_fd);\n        arch_syscall_return(curthread, err);\n        return; \n    }\n\n    arch_syscall_return(curthread, conn_fd);\n    return;\n}\n\nstatic void sys_bind(int fd, const struct sockaddr *addr, uint32_t len)\n{\n    syscall_log(LOG_DEBUG, \"bind(fd=%d, addr=%p, len=%d)\\n\",\n            fd, addr, len);\n\n    if (fd < 0 || fd >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fd];\n\n    if (!file) {\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    int err = 0;\n\n    if ((err = socket_bind(file, addr, len))) {\n        arch_syscall_return(curthread, err);\n        return; \n    }\n\n    arch_syscall_return(curthread, 0);\n    return;\n}\n\nstatic void sys_connect(int fd, const struct sockaddr *addr, uint32_t len)\n{\n    syscall_log(LOG_DEBUG, \"connect(fd=%d, addr=%p, len=%d)\\n\",\n            fd, addr, len);\n\n    if (fd < 0 || fd >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *socket = &curproc->fds[fd];\n    int err = 0;\n\n    if ((err = socket_connect(socket, addr, len))) {\n        arch_syscall_return(curthread, err);\n        return; \n    }\n\n    arch_syscall_return(curthread, 0);\n    return;\n}\n\nstatic void sys_listen(int fd, int backlog)\n{\n    syscall_log(LOG_DEBUG, \"listen(fd=%d, backlog=%d)\\n\", fd, backlog);\n\n    if (fd < 0 || fd >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fd];\n\n    if (!file) {\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    int err = 0;\n\n    if ((err = socket_listen(file, backlog))) {\n        arch_syscall_return(curthread, err);\n        return; \n    }\n\n    arch_syscall_return(curthread, 0);\n    return;\n}\n\nstruct socket_io_syscall {\n    int fd;\n    void *buf;\n    size_t len;\n    int flags;\n} __attribute__((packed));\n\nstatic void sys_send(struct socket_io_syscall *s)\n{\n    int fd = s->fd;\n    void *buf = s->buf;\n    size_t len = s->len;\n    int flags = s->flags;\n\n    syscall_log(LOG_DEBUG, \"send(fd=%d, buf=%p, len=%d, flags=%x)\\n\",\n            fd, buf, len, flags);\n\n    if (fd < 0 || fd >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fd];\n\n    if (!file) {\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    int err = 0;\n\n    if ((err = socket_send(file, buf, len, flags))) {\n        arch_syscall_return(curthread, err);\n        return; \n    }\n\n    arch_syscall_return(curthread, 0);\n    return;\n}\n\nstatic void sys_recv(struct socket_io_syscall *s)\n{\n    int fd = s->fd;\n    void *buf = s->buf;\n    size_t len = s->len;\n    int flags = s->flags;\n\n    syscall_log(LOG_DEBUG, \"recv(fd=%d, buf=%p, len=%d, flags=%x)\\n\",\n            fd, buf, len, flags);\n\n    if (fd < 0 || fd >= FDS_COUNT) {  /* Out of bounds */\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    struct file *file = &curproc->fds[fd];\n\n    if (!file) {\n        arch_syscall_return(curthread, -EBADFD);\n        return; \n    }\n\n    int err = 0;\n\n    if ((err = socket_recv(file, buf, len, flags))) {\n        arch_syscall_return(curthread, err);\n        return; \n    }\n\n    arch_syscall_return(curthread, 0);\n    return;\n}\n\nstatic void sys_umask(mode_t mask)\n{\n    syscall_log(LOG_DEBUG, \"umask(mask=%d)\\n\", mask);\n\n    mode_t cur_mask = curproc->mask;\n    curproc->mask = mask & 0777;\n\n    arch_syscall_return(curthread, cur_mask);\n    return;\n}\n\nstatic void sys_chmod(const char *path, mode_t mode)\n{\n    syscall_log(LOG_DEBUG, \"chmod(path=%s, mode=%d)\\n\", path, mode);\n    arch_syscall_return(curthread, -ENOSYS);\n}\n\nstatic void sys_sysconf(int name)\n{\n    syscall_log(LOG_DEBUG, \"sysconf(name=%d)\\n\", name);\n    arch_syscall_return(curthread, -ENOSYS);\n}\n\n#define F_OK    0\n#define X_OK    1\n#define W_OK    2\n#define R_OK    4\n\nstatic void sys_access(const char *path, int mode)\n{\n    syscall_log(LOG_DEBUG, \"access(path=%s, mode=%d)\\n\", path, mode);\n\n    int err = 0;\n\n    /* Look up the file */\n    struct vnode *vnode = NULL;\n    struct file  file;\n\n    struct uio uio = PROC_UIO(curproc);\n\n    uio.flags |= mode && R_OK? O_RDONLY : 0;\n    uio.flags |= mode && W_OK? O_WRONLY : 0;\n    uio.flags |= mode && X_OK? O_EXEC   : 0;\n\n    err = vfs_lookup(path, &uio, &vnode, NULL);\n\n    if (err) goto done;\n\n    file = (struct file) {\n        .vnode  = vnode,\n        .offset = 0,\n        .flags  = uio.flags,\n    };\n\n    if ((err = vfs_perms_check(&file, &uio)))\n        goto done;\n\ndone:\n    if (vnode)\n        vfs_close(vnode);\n\n    arch_syscall_return(curthread, err);\n\n    return;\n}\n\nstatic void sys_gettimeofday(struct timeval *tv, struct timezone *tz)\n{\n    syscall_log(LOG_DEBUG, \"gettimeofday(tv=%p, tz=%p)\\n\", tv, tz);\n    arch_syscall_return(curthread, gettimeofday(tv, tz));\n    return;\n}\n\nstatic void sys_sigmask(int how, void *set, void *oldset)\n{\n    syscall_log(LOG_DEBUG, \"sigmask(how=%d, set=%p, oldset=%p)\\n\", how, set, oldset);\n    arch_syscall_return(curthread, -ENOTSUP);\n}\n\ntypedef unsigned long fd_mask;\n\n#define  FD_SETSIZE  64\n#define   NFDBITS (sizeof (fd_mask) * 8)  /* bits per mask */\n#define  _howmany(x,y)   (((x)+((y)-1))/(y))\n\ntypedef struct {\n    fd_mask fds_bits[_howmany(FD_SETSIZE, NFDBITS)];\n} fd_set;\n\nstruct select_args {\n    int nfds;\n    fd_set *readfds;\n    fd_set *writefds;\n    fd_set *exceptfds;\n    struct timeval *timeout;\n};\n\nstatic void sys_select(struct select_args *args)\n{\n    syscall_log(LOG_DEBUG, \"select(args=%p)\\n\", args);\n\n    int nfds = args->nfds;\n    fd_set *readfds = args->readfds;\n    fd_set *writefds = args->writefds;\n    fd_set *exceptfds = args->exceptfds;\n    struct timeval *timeout = args->timeout;\n\n    int count = 0;\n\n    for (int i = 0; i < nfds; ++i) {\n        if (readfds && readfds->fds_bits[i/NFDBITS] & (1 << (i % NFDBITS))) {\n            struct file *file = &curproc->fds[i];\n            if (vfs_file_can_read(file, 1) > 0) {\n                readfds->fds_bits[i/NFDBITS] |= (1 << (i % NFDBITS));\n                ++count;\n            } else {\n                readfds->fds_bits[i/NFDBITS] &= ~(1 << (i % NFDBITS));\n            }\n        }\n\n        if (writefds && writefds->fds_bits[i/NFDBITS] & (1 << (i % NFDBITS))) {\n            struct file *file = &curproc->fds[i];\n            if (vfs_file_can_write(file, 1) > 0) {\n                writefds->fds_bits[i/NFDBITS] |= (1 << (i % NFDBITS));\n                ++count;\n            } else {\n                writefds->fds_bits[i/NFDBITS] &= ~(1 << (i % NFDBITS));\n            }\n        }\n    }\n\n    arch_syscall_return(curthread, count);\n}\n\nstatic void sys_getpgrp(void)\n{\n    syscall_log(LOG_DEBUG, \"getpgrp()\\n\");\n    arch_syscall_return(curthread, curproc->pgrp->pgid);\n}\n\nstatic void sys_chown(const char *path, uid_t owner, gid_t group)\n{\n    syscall_log(LOG_DEBUG, \"chown(path=%s, ownder=%d, group=%d)\\n\", path, owner, group);\n    arch_syscall_return(curthread, -ENOSYS);\n}\n\nstatic void sys_fchown(int fd, uid_t owner, gid_t group)\n{\n    syscall_log(LOG_DEBUG, \"fchown(fd=%d, owner=%d, group=%d)\\n\", fd, owner, group);\n    arch_syscall_return(curthread, -ENOSYS);\n}\n\nstatic void sys_lchown(const char *path, uid_t owner, gid_t group)\n{\n    syscall_log(LOG_DEBUG, \"lchown(path=%s, owner=%d, group=%d)\\n\", path, owner, group);\n    arch_syscall_return(curthread, -ENOSYS);\n}\n\nstatic void sys_utime(const char *path, const struct utimbuf *times)\n{\n    syscall_log(LOG_DEBUG, \"utime(path=%s, times=%p)\\n\", path, times);\n    arch_syscall_return(curthread, -ENOSYS);\n}\n\nstatic void sys_rmdir(const char *path)\n{\n    syscall_log(LOG_DEBUG, \"rmdir(path=%s)\\n\", path);\n    arch_syscall_return(curthread, -ENOSYS);\n}\n\nvoid (*syscall_table[])() =  {\n    /* 00 */    NULL,\n    /* 01 */    sys_exit,\n    /* 02 */    sys_close,\n    /* 03 */    sys_execve,\n    /* 04 */    sys_fork,\n    /* 05 */    sys_fstat,\n    /* 06 */    sys_getpid,\n    /* 07 */    sys_isatty,\n    /* 08 */    sys_kill,\n    /* 09 */    sys_link,\n    /* 10 */    sys_lseek,\n    /* 11 */    sys_open,\n    /* 12 */    sys_read,\n    /* 13 */    sys_sbrk,\n    /* 14 */    sys_stat,\n    /* 15 */    sys_times,\n    /* 16 */    sys_unlink,\n    /* 17 */    sys_waitpid,\n    /* 18 */    sys_write,\n    /* 19 */    sys_ioctl,\n    /* 20 */    sys_sigaction,\n    /* 21 */    sys_readdir,\n    /* 22 */    sys_mount,\n    /* 23 */    sys_mkdir,\n    /* 24 */    sys_uname,\n    /* 25 */    sys_pipe,\n    /* 26 */    sys_fcntl,\n    /* 27 */    sys_chdir,\n    /* 28 */    sys_getcwd,\n    /* 29 */    sys_thread_create,\n    /* 30 */    sys_thread_exit,\n    /* 31 */    sys_thread_join,\n    /* 32 */    sys_setpgid,\n    /* 33 */    sys_mknod,\n    /* 34 */    sys_lstat,\n    /* 35 */    sys_auth, /* deprecated */\n    /* 36 */    sys_getuid,\n    /* 37 */    sys_getgid,\n    /* 38 */    sys_mmap,\n    /* 39 */    sys_munmap,\n    /* 40 */    sys_socket,\n    /* 41 */    sys_accept,\n    /* 42 */    sys_bind,\n    /* 43 */    sys_connect,\n    /* 44 */    sys_listen,\n    /* 45 */    sys_send,\n    /* 46 */    sys_recv,\n    /* 47 */    sys_umask,\n    /* 48 */    sys_chmod,\n    /* 49 */    sys_sysconf,\n    /* 50 */    sys_gettimeofday,\n    /* 51 */    sys_access,\n    /* 52 */    sys_sigmask,\n    /* 53 */    sys_select,\n    /* 54 */    sys_getpgrp,\n    /* 55 */    sys_chown,\n    /* 56 */    sys_fchown,\n    /* 57 */    sys_lchown,\n    /* 58 */    sys_utime,\n    /* 59 */    sys_rmdir,\n};\n\nconst size_t syscall_cnt = sizeof(syscall_table)/sizeof(syscall_table[0]);\n"
  },
  {
    "path": "kernel/sys/thread.c",
    "content": "#include <core/system.h>\n#include <core/arch.h>\n#include <core/panic.h>\n#include <sys/proc.h>\n#include <sys/sched.h>\n#include <ds/queue.h>\n\nMALLOC_DEFINE(M_THREAD, \"thread\", \"thread structure\");\n\nint thread_new(struct proc *proc, struct thread **ref)\n{\n    struct thread *thread = NULL;\n\n    if (!proc)\n        return -EINVAL;\n\n    thread = kmalloc(sizeof(struct thread), &M_THREAD, M_ZERO);\n    if (!thread) return -ENOMEM;\n\n    thread->owner = proc;\n    thread->tid = proc->threads.count + 1;\n\n    enqueue(&proc->threads, thread);\n\n    if (ref)\n        *ref = thread;\n\n    return 0;\n}\n\nint thread_kill(struct thread *thread)\n{\n    if (!thread)\n        return -EINVAL;\n\n    /* Free resources */\n    arch_thread_kill(thread);\n    thread->state = ZOMBIE;\n    return 0;\n}\n\nint thread_queue_sleep(struct queue *queue)\n{\n    if (!queue)\n        panic(\"sleeping in a blackhole?\");\n\n#ifdef DEBUG_SLEEP_QUEUE\n    printk(\"[%d:%d] %s: Sleeping on queue %p\\n\", curproc->pid, curthread->tid, curproc->name, queue);\n#endif\n\n    struct qnode *sleep_node = enqueue(queue, curthread);\n\n    curthread->sleep_queue = queue;\n    curthread->sleep_node  = sleep_node;\n    curthread->state = ISLEEP;\n    arch_sleep();\n\n    /* Woke up */\n    if (curthread->state != ISLEEP) {\n        /* A signal interrupted the sleep */\n#ifdef DEBUG_SLEEP_QUEUE\n        printk(\"[%d:%d] %s: Sleeping was interrupted by a signal\\n\", curproc->pid, curthread->tid, curproc->name);\n#endif\n        return -EINTR;\n    } else {\n        curthread->state = RUNNABLE;\n        return 0;\n    }\n}\n\nint thread_queue_wakeup(struct queue *queue)\n{\n    if (!queue)\n        return -EINVAL;\n\n    while (queue->count) {\n        struct thread *thread = dequeue(queue);\n        thread->sleep_node = NULL;\n#ifdef DEBUG_SLEEP_QUEUE\n        printk(\"[%d:%d] %s: Waking up from queue %p\\n\", thread->owner->pid, thread->tid, thread->owner->name, queue);\n#endif\n        sched_thread_ready(thread);\n    }\n\n    return 0;\n}\n\nint thread_create(struct thread *thread, uintptr_t stack, uintptr_t entry, uintptr_t uentry, uintptr_t arg, uintptr_t attr __unused, struct thread **new_thread)\n{\n    struct thread *t = NULL;\n    thread_new(thread->owner, &t);\n\n    arch_thread_create(t, stack, entry, uentry, arg);\n\n    if (new_thread)\n        *new_thread = t;\n\n    return 0;\n}\n"
  },
  {
    "path": "loader/grub-legacy/boot/grub/menu.lst",
    "content": "default=0\ntimeout=5\n\ntitle AquilaOS\n\tkernel /boot/kernel.elf\n\tmodule /boot/initrd.img\n\tvbeset 0x142\n"
  },
  {
    "path": "loader/grub2/boot/grub/grub.cfg",
    "content": "set timeout=3\nset default=0\n\nmenuentry \"AquilaOS\" {\n\tmultiboot /kernel.elf\n\tmodule /initrd.img --fbterm\n\tboot\n}\n"
  },
  {
    "path": "system/Makefile",
    "content": "export\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\ndirs-y = aqbox/ fbterm/\n\nall: $(dirs-y)\n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@echo -e \"  MK      \" $(CWD)/$@\n\t@$(MAKE) -C $@ $(param)\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n"
  },
  {
    "path": "system/aqbox/Build.mk",
    "content": "dirs-y += posix/\ndirs-y += extra/\ndirs-y += sys/\nobj-y  += aqbox.o\n"
  },
  {
    "path": "system/aqbox/Makefile",
    "content": "export\n\nCWD != realpath --relative-to=$(SRCDIR) .\nPDIR = $(SRCDIR)/system/aqbox\nSYSCFLAGS += -I$(PDIR)/include\n\ninclude Build.mk\n\nall: builtin.o aqbox\n\naqbox: builtin.o aqbox.o\n\t@$(ECHO) \"  ELF     \" $(CWD)/$@\n\t@$(SYSCC) $(SYSLDFLAGS) -lm $< $(SYSLDLIBS) -o $@\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  SYSLD   \" $(CWD)/builtin.o\n\t@$(SYSLD) $(SYSLDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o\n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  SYSCC   \" $(CWD)/$@\n\t@$(SYSCC) $(SYSCFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) builtin.o aqbox\n\t@$(RM) $(obj-y) builtin.o aqbox\n"
  },
  {
    "path": "system/aqbox/aqbox.c",
    "content": "#include <aqbox.h>\n#include <aq_applets.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <libgen.h>\n\n#define AQBOX_VERSION \"0.0.1\"\n\nstatic void usage()\n{\n    printf(\"aqbox v\" AQBOX_VERSION \" (Swiss-Army-Knife of AquilaOS)\\n\\n\");\n    printf(\"Built-in commands:\\n\");\n    for (unsigned i = 0; i < APPLETS_NR; ++i) {\n        printf(\"%s \", applets[i].name);\n    }\n\n    printf(\"\\n\");\n}\n\nstatic int bsearch_helper(const void *a, const void *b)\n{\n    struct applet *_a = (struct applet *) a;\n    struct applet *_b = (struct applet *) b;\n    return strcmp(_a->name, _b->name);\n}\n\nint (*aqbox_get_applet(char *name))()\n{\n    /* Perform binary search on applets */\n    struct applet *applet = (struct applet *) \n        bsearch(&(struct applet){.name=name}, applets, APPLETS_NR, sizeof(*applets), bsearch_helper);\n\n    return applet? applet->f : NULL;\n}\n\nint aqbox_run(int argc, char **argv)\n{\n    int (*f)() = aqbox_get_applet(argv[0]);\n\n    if (f) {\n        return f(argc, argv);\n    } else {\n        printf(\"%s: applet not found\\n\", argv[0]);\n        return -1;\n    }\n}\n\nint main(int argc, char *argv[])\n{\n    char *applet = basename(argv[0]);\n\n    /* We were launched with a different name */\n    if (strcmp(applet, \"aqbox\")) {\n        argv[0] = applet;\n        return aqbox_run(argc, argv);\n    }\n\n    if (argc < 2) {\n        usage();\n        return 0;\n    } else {\n        return aqbox_run(argc-1, argv+1);\n    }\n}\n"
  },
  {
    "path": "system/aqbox/extra/Build.mk",
    "content": "obj-y += clear.o\nobj-y += stat.o\nobj-y += mknod.o\nobj-y += readmbr.o\nobj-y += bim.o\nobj-y += truncate.o\nobj-y += mktemp.o\nobj-y += vmstat.o\n"
  },
  {
    "path": "system/aqbox/extra/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  SYSLD   \" $(CWD)/builtin.o\n\t@$(SYSLD) $(SYSLDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  SYSCC   \" $(CWD)/$@\n\t@$(SYSCC) $(SYSCFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) builtin.o\n\t@$(RM) $(obj-y) builtin.o\n"
  },
  {
    "path": "system/aqbox/extra/bim.c",
    "content": "/* vim: tabstop=4 shiftwidth=4 noexpandtab\n *\n * Copyright (C) 2012-2018 K. Lange\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n *\n * bim - Text editor\n *\n * Bim is inspired by vim, and its name is short for \"Bad IMitation\".\n *\n * Bim supports syntax highlighting, extensive editing, line selection\n * and copy-paste, undo/redo stack, forward and backward search, and can\n * be built for ToaruOS, Sortix, Linux, macOS, and BSDs.\n */\n#define _XOPEN_SOURCE\n#define _DEFAULT_SOURCE\n#include <aqbox.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <unistd.h>\n#include <termios.h>\n#include <signal.h>\n#include <locale.h>\n#include <wchar.h>\n#include <ctype.h>\n#include <dirent.h>\n//#include <poll.h>\n#include <sys/select.h>\n#include <fcntl.h>\n#include <sys/types.h>\n#include <sys/ioctl.h>\n#include <sys/stat.h>\n\n#define BIM_VERSION   \"1.1.6\"\n#define BIM_COPYRIGHT \"Copyright 2012-2018 K. Lange <\\033[3mklange@toaruos.org\\033[23m>\"\n\n#define BLOCK_SIZE 4096\n#define ENTER_KEY     '\\r'\n#define LINE_FEED     '\\n'\n#define BACKSPACE_KEY 0x08\n#define DELETE_KEY    0x7F\n\n/**\n * Theming data\n *\n * This is all overridden by a load_colorscheme_ method.\n * The default is to load_colorscheme_ansi, but config\n * files can be used to set a different default theme.\n */\nconst char * COLOR_FG        = \"@17\";\nconst char * COLOR_BG        = \"@0\";\nconst char * COLOR_ALT_FG    = \"@17\";\nconst char * COLOR_ALT_BG    = \"@0\";\nconst char * COLOR_NUMBER_FG = \"@17\";\nconst char * COLOR_NUMBER_BG = \"@0\";\nconst char * COLOR_STATUS_FG = \"@17\";\nconst char * COLOR_STATUS_BG = \"@0\";\nconst char * COLOR_TABBAR_BG = \"@0\";\nconst char * COLOR_TAB_BG    = \"@0\";\nconst char * COLOR_ERROR_FG  = \"@17\";\nconst char * COLOR_ERROR_BG  = \"@0\";\nconst char * COLOR_SEARCH_FG = \"@17\";\nconst char * COLOR_SEARCH_BG = \"@0\";\nconst char * COLOR_KEYWORD   = \"@17\";\nconst char * COLOR_STRING    = \"@17\";\nconst char * COLOR_COMMENT   = \"@17\";\nconst char * COLOR_TYPE      = \"@17\";\nconst char * COLOR_PRAGMA    = \"@17\";\nconst char * COLOR_NUMERAL   = \"@17\";\nconst char * COLOR_SELECTFG  = \"@0\";\nconst char * COLOR_SELECTBG  = \"@17\";\nconst char * COLOR_RED       = \"@1\";\nconst char * COLOR_GREEN     = \"@2\";\nconst char * current_theme = \"none\";\n\n/**\n * Syntax highlighting flags.\n */\n#define FLAG_NONE      0\n#define FLAG_KEYWORD   1\n#define FLAG_STRING    2\n#define FLAG_COMMENT   3\n#define FLAG_TYPE      4\n#define FLAG_PRAGMA    5\n#define FLAG_NUMERAL   6\n#define FLAG_STRING2   7\n#define FLAG_DIFFPLUS  8\n#define FLAG_DIFFMINUS 9\n\n#define FLAG_SELECT    (1 << 4)\n#define FLAG_SEARCH    (1 << 5)\n#define FLAG_CONTINUES (1 << 6)\n\n/**\n * Convert syntax hilighting flag to color code\n */\nconst char * flag_to_color(int _flag) {\n\tint flag = _flag & 0xF;\n\tswitch (flag) {\n\t\tcase FLAG_KEYWORD:\n\t\t\treturn COLOR_KEYWORD;\n\t\tcase FLAG_STRING:\n\t\tcase FLAG_STRING2: /* allows python to differentiate \" and ' */\n\t\t\treturn COLOR_STRING;\n\t\tcase FLAG_COMMENT:\n\t\t\treturn COLOR_COMMENT;\n\t\tcase FLAG_TYPE:\n\t\t\treturn COLOR_TYPE;\n\t\tcase FLAG_NUMERAL:\n\t\t\treturn COLOR_NUMERAL;\n\t\tcase FLAG_PRAGMA:\n\t\t\treturn COLOR_PRAGMA;\n\t\tcase FLAG_DIFFPLUS:\n\t\t\treturn COLOR_GREEN;\n\t\tcase FLAG_DIFFMINUS:\n\t\t\treturn COLOR_RED;\n\t\tcase FLAG_SELECT:\n\t\t\treturn COLOR_FG;\n\t\tdefault:\n\t\t\treturn COLOR_FG;\n\t}\n}\n\n/**\n * Line buffer definitions\n *\n * Lines are essentially resizable vectors of char_t structs,\n * which represent single codepoints in the file.\n */\ntypedef struct {\n\tuint32_t display_width:4;\n\tuint32_t flags:7;\n\tuint32_t codepoint:21;\n} __attribute__((packed)) char_t;\n\n/**\n * Lines have available and actual lengths, describing\n * how much space was allocated vs. how much is being\n * used at the moment.\n */\ntypedef struct {\n\tint available;\n\tint actual;\n\tint istate;\n\tchar_t   text[];\n} line_t;\n\n/**\n * Global configuration state\n */\nstruct {\n\t/* Terminal size */\n\tint term_width, term_height;\n\tint bottom_size;\n\n\t/* Command-line parameters */\n\tint hilight_on_open;\n\tint initial_file_is_read_only;\n\n\tline_t ** yanks;\n\tsize_t    yank_count;\n\tint       yank_is_full_lines;\n\n\tint tty_in;\n\n\tconst char * bimrc_path;\n\n\tint can_scroll;\n\tint can_hideshow;\n\tint can_altscreen;\n\tint can_mouse;\n\tint can_unicode;\n\tint can_bright;\n\tint can_title;\n\tint can_bce;\n\tint history_enabled;\n\n\tint cursor_padding;\n\tint highlight_parens;\n\tint smart_case;\n\tint can_24bit;\n\tint can_256color;\n\tint can_italic;\n\n\tint go_to_line;\n} global_config = {\n\t0, /* term_width */\n\t0, /* term_height */\n\t2, /* bottom_size */\n\t1, /* hilight_on_open */\n\t0, /* initial_file_is_read_only */\n\tNULL, /* yanks */\n\t0, /* yank_count */\n\t0,\n\tSTDIN_FILENO, /* tty_in */\n\t\"~/.bimrc\", /* bimrc_path */\n\t0, /* can scroll */\n\t1, /* can hide/show cursor */\n\t0, /* can use alternate screen */\n\t0, /* can mouse */\n\t0, /* can unicode */\n\t1, /* can use bright colors */\n\t1, /* can set title */\n\t1, /* can bce */\n\t1, /* history enabled */\n\t4, /* cursor padding */\n\t1, /* highlight parens/braces when cursor moves */\n\t1, /* smart case */\n\t0, /* can use 24-bit color */\n\t0, /* can use 265 colors */\n\t0, /* can use italics (without inverting) */\n\t1, /* should go to line when opening file */\n};\n\nvoid redraw_line(int j, int x);\n\n/**\n * Special implementation of getch with a timeout\n */\nint _bim_unget = -1;\n\nvoid bim_unget(int c) {\n\t_bim_unget = c;\n}\n\n#define bim_getch() bim_getch_timeout(200)\nint bim_getch_timeout(int timeout) {\n\tif (_bim_unget != -1) {\n\t\tint out = _bim_unget;\n\t\t_bim_unget = -1;\n\t\treturn out;\n\t}\n\n\t//struct pollfd fds[1];\n\t//fds[0].fd = global_config.tty_in;\n\t//fds[0].events = POLLIN;\n\t//int ret = poll(fds,1,timeout);\n\n\tint fd = global_config.tty_in;\n\n\tstruct fd_set fdset;\n\tFD_ZERO(&fdset);\n\tFD_SET(fd, &fdset);\n\n\tint ret = select(1, &fdset, NULL, NULL, NULL);\n\t//if (ret > 0 && fds[0].revents & POLLIN) {\n\tif (ret > 0 && FD_ISSET(fd, &fdset)) {\n\t\tunsigned char buf[1];\n\t\tif (read(global_config.tty_in, buf, 1) > 0)\n\t\t\treturn buf[0];\n\t\treturn -1;\n\t} else {\n\t\treturn -1;\n\t}\n}\n\n#define HISTORY_SENTINEL     0\n#define HISTORY_INSERT       1\n#define HISTORY_DELETE       2\n#define HISTORY_REPLACE      3\n#define HISTORY_REMOVE_LINE  4\n#define HISTORY_ADD_LINE     5\n#define HISTORY_REPLACE_LINE 6\n#define HISTORY_MERGE_LINES  7\n#define HISTORY_SPLIT_LINE   8\n\n#define HISTORY_BREAK        10\n\ntypedef struct history {\n\tstruct history * previous;\n\tstruct history * next;\n\tint type;\n\tunion {\n\t\tstruct {\n\t\t\tint lineno;\n\t\t\tint offset;\n\t\t\tint codepoint;\n\t\t\tint old_codepoint;\n\t\t} insert_delete_replace;\n\n\t\tstruct {\n\t\t\tint lineno;\n\t\t\tline_t * contents;\n\t\t\tline_t * old_contents;\n\t\t} remove_replace_line;\n\n\t\tstruct {\n\t\t\tint lineno;\n\t\t\tint split;\n\t\t} add_merge_split_lines;\n\t} contents;\n} history_t;\n\n/**\n * Buffer data\n *\n * A buffer describes a file, and stores\n * its name as well as the editor state\n * (cursor offsets, etc.) and the actual\n * line buffers.\n */\ntypedef struct _env {\n\tunsigned short loading:1;\n\tunsigned short tabs:1;\n\tunsigned short modified:1;\n\tunsigned short readonly:1;\n\tunsigned short indent:1;\n\tunsigned short highlighting_paren:1;\n\n\tshort  mode;\n\tshort  tabstop;\n\n\tchar * file_name;\n\tint    offset;\n\tint    coffset;\n\tint    line_no;\n\tint    line_count;\n\tint    line_avail;\n\tint    col_no;\n\tint    preferred_column;\n\tuint32_t * search;\n\tstruct syntax_definition * syntax;\n\tline_t ** lines;\n\n\thistory_t * history;\n\thistory_t * last_save_history;\n} buffer_t;\n\n/**\n * Pointer to current active buffer\n */\nbuffer_t * env;\n\n/**\n * Editor modes (like in vim)\n */\n#define MODE_NORMAL 0\n#define MODE_INSERT 1\n#define MODE_LINE_SELECTION 2\n#define MODE_REPLACE 3\n#define MODE_CHAR_SELECTION 4\n\n/**\n * Available buffers\n */\nint    buffers_len;\nint    buffers_avail;\nbuffer_t ** buffers;\n\n/**\n * Create a new buffer\n */\nbuffer_t * buffer_new(void) {\n\tif (buffers_len == buffers_avail) {\n\t\t/* If we are out of buffer space, expand the buffers vector */\n\t\tbuffers_avail *= 2;\n\t\tbuffers = realloc(buffers, sizeof(buffer_t *) * buffers_avail);\n\t}\n\n\t/* Allocate a new buffer */\n\tbuffers[buffers_len] = malloc(sizeof(buffer_t));\n\tmemset(buffers[buffers_len], 0x00, sizeof(buffer_t));\n\tbuffers_len++;\n\n\treturn buffers[buffers_len-1];\n}\n\n/**\n * Close a buffer\n */\nbuffer_t * buffer_close(buffer_t * buf) {\n\tint i;\n\n\t/* Locate the buffer in the buffer pointer vector */\n\tfor (i = 0; i < buffers_len; i++) {\n\t\tif (buf == buffers[i])\n\t\t\tbreak;\n\t}\n\n\t/* Invalid buffer? */\n\tif (i == buffers_len) {\n\t\treturn env; /* wtf */\n\t}\n\n\t/* Remove the buffer from the vector, moving others up */\n\tif (i != buffers_len - 1) {\n\t\tmemmove(&buffers[i], &buffers[i+1], sizeof(*buffers) * (buffers_len - i));\n\t}\n\n\t/* There is one less buffer */\n\tbuffers_len--;\n\tif (!buffers_len) { \n\t\t/* There are no more buffers. */\n\t\treturn NULL;\n\t}\n\n\t/* If this was the last buffer, return the previous last buffer */\n\tif (i == buffers_len) {\n\t\treturn buffers[buffers_len-1];\n\t}\n\n\t/* Otherwise return the new last buffer */\n\treturn buffers[i];\n}\n\n/**\n * Themes\n */\n\n/* 16-color theme, default */\nvoid load_colorscheme_ansi(void) {\n\tCOLOR_FG        = global_config.can_bright ? \"@17\" : \"@7\";\n\tCOLOR_BG        = global_config.can_bright ? \"@9\"  : \"@0\";\n\tCOLOR_ALT_FG    = global_config.can_bright ? \"@10\" : \"@5\";\n\tCOLOR_ALT_BG    = \"@9\";\n\tCOLOR_NUMBER_FG = \"@3\";\n\tCOLOR_NUMBER_BG = \"@9\";\n\tCOLOR_STATUS_FG = global_config.can_bright ? \"@17\" : \"@7\";\n\tCOLOR_STATUS_BG = \"@4\";\n\tCOLOR_TABBAR_BG = \"@4\";\n\tCOLOR_TAB_BG    = \"@4\";\n\tCOLOR_KEYWORD   = global_config.can_bright ? \"@14\" : \"@4\";\n\tCOLOR_STRING    = \"@2\";\n\tCOLOR_COMMENT   = global_config.can_bright ? \"@10\" : \"@5\";\n\tCOLOR_TYPE      = \"@3\";\n\tCOLOR_PRAGMA    = \"@1\";\n\tCOLOR_NUMERAL   = \"@1\";\n\n\tCOLOR_ERROR_FG  = global_config.can_bright ? \"@17\" : \"@7\";\n\tCOLOR_ERROR_BG  = \"@1\";\n\tCOLOR_SEARCH_FG = \"@0\";\n\tCOLOR_SEARCH_BG = global_config.can_bright ? \"@13\" : \"@3\";\n\n\tCOLOR_SELECTBG  = global_config.can_bright ? \"@17\" : \"@7\";\n\tCOLOR_SELECTFG  = \"@0\";\n\n\tCOLOR_RED       = \"@1\";\n\tCOLOR_GREEN     = \"@2\";\n\n\tcurrent_theme = \"ansi\";\n}\n\n/* Based on the wombat256 theme for vim */\nvoid load_colorscheme_wombat(void) {\n\tif (!global_config.can_256color) return;\n\tCOLOR_FG        = \"5;230\";\n\tCOLOR_BG        = \"5;235\";\n\tCOLOR_ALT_FG    = \"5;244\";\n\tCOLOR_ALT_BG    = \"5;236\";\n\tCOLOR_NUMBER_BG = \"5;232\";\n\tCOLOR_NUMBER_FG = \"5;101\";\n\tCOLOR_STATUS_FG = \"5;230\";\n\tCOLOR_STATUS_BG = \"5;238\";\n\tCOLOR_TABBAR_BG = \"5;230\";\n\tCOLOR_TAB_BG    = \"5;248\";\n\tCOLOR_KEYWORD   = \"5;117\";\n\tCOLOR_STRING    = \"5;113\";\n\tCOLOR_COMMENT   = global_config.can_italic ? \"5;102;3\" : \"5;102\";\n\tCOLOR_TYPE      = \"5;186\";\n\tCOLOR_PRAGMA    = \"5;173\";\n\tCOLOR_NUMERAL   = COLOR_PRAGMA;\n\n\tCOLOR_ERROR_FG  = \"5;15\";\n\tCOLOR_ERROR_BG  = \"5;196\";\n\tCOLOR_SEARCH_FG = \"5;234\";\n\tCOLOR_SEARCH_BG = \"5;226\";\n\n\tCOLOR_SELECTFG  = \"5;235\";\n\tCOLOR_SELECTBG  = \"5;230\";\n\n\tCOLOR_RED       = \"@1\";\n\tCOLOR_GREEN     = \"@2\";\n\n\tcurrent_theme = \"wombat\";\n}\n\n/* \"City Lights\" based on citylights.xyz */\nvoid load_colorscheme_citylights(void) {\n\tif (!global_config.can_24bit) return;\n\tCOLOR_FG        = \"2;151;178;198\";\n\tCOLOR_BG        = \"2;29;37;44\";\n\tCOLOR_ALT_FG    = \"2;45;55;65\";\n\tCOLOR_ALT_BG    = \"2;33;42;50\";\n\tCOLOR_NUMBER_FG = \"2;71;89;103\";\n\tCOLOR_NUMBER_BG = \"2;37;47;56\";\n\tCOLOR_STATUS_FG = \"2;116;144;166\";\n\tCOLOR_STATUS_BG = \"2;53;67;78\";\n\tCOLOR_TABBAR_BG = \"2;37;47;56\";\n\tCOLOR_TAB_BG    = \"2;29;37;44\";\n\tCOLOR_KEYWORD   = \"2;94;196;255\";\n\tCOLOR_STRING    = \"2;83;154;252\";\n\tCOLOR_COMMENT   = \"2;107;133;153;3\";\n\tCOLOR_TYPE      = \"2;139;212;156\";\n\tCOLOR_PRAGMA    = \"2;0;139;148\";\n\tCOLOR_NUMERAL   = \"2;207;118;132\";\n\n\tCOLOR_ERROR_FG  = \"5;15\";\n\tCOLOR_ERROR_BG  = \"5;196\";\n\tCOLOR_SEARCH_FG = \"5;234\";\n\tCOLOR_SEARCH_BG = \"5;226\";\n\n\tCOLOR_SELECTFG  = \"2;29;37;44\";\n\tCOLOR_SELECTBG  = \"2;151;178;198\";\n\n\tCOLOR_RED       = \"2;222;53;53\";\n\tCOLOR_GREEN     = \"2;55;167;0\";\n\n\tcurrent_theme = \"citylights\";\n}\n\n/* Solarized Dark, popular theme */\nvoid load_colorscheme_solarized_dark(void) {\n\tif (!global_config.can_24bit) return;\n\tCOLOR_FG        = \"2;147;161;161\";\n\tCOLOR_BG        = \"2;0;43;54\";\n\tCOLOR_ALT_FG    = \"2;147;161;161\";\n\tCOLOR_ALT_BG    = \"2;7;54;66\";\n\tCOLOR_NUMBER_FG = \"2;131;148;149\";\n\tCOLOR_NUMBER_BG = \"2;7;54;66\";\n\tCOLOR_STATUS_FG = \"2;131;148;150\";\n\tCOLOR_STATUS_BG = \"2;7;54;66\";\n\tCOLOR_TABBAR_BG = \"2;7;54;66\";\n\tCOLOR_TAB_BG    = \"2;131;148;150\";\n\tCOLOR_KEYWORD   = \"2;133;153;0\";\n\tCOLOR_STRING    = \"2;42;161;152\";\n\tCOLOR_COMMENT   = \"2;101;123;131\";\n\tCOLOR_TYPE      = \"2;181;137;0\";\n\tCOLOR_PRAGMA    = \"2;203;75;22\";\n\tCOLOR_NUMERAL   = \"2;220;50;47\";\n\n\tCOLOR_ERROR_FG  = \"5;15\";\n\tCOLOR_ERROR_BG  = \"5;196\";\n\tCOLOR_SEARCH_FG = \"5;234\";\n\tCOLOR_SEARCH_BG = \"5;226\";\n\n\tCOLOR_SELECTFG  = \"2;0;43;54\";\n\tCOLOR_SELECTBG  = \"2;147;161;161\";\n\n\tCOLOR_RED       = \"2;222;53;53\";\n\tCOLOR_GREEN     = \"2;55;167;0\";\n\n\tcurrent_theme = \"solarized-dark\";\n}\n\n\nvoid load_colorscheme_sunsmoke256(void) {\n\tif (!global_config.can_256color) return;\n\tCOLOR_FG        = \"5;188\";\n\tCOLOR_BG        = \"5;234\";\n\tCOLOR_ALT_FG    = \"5;244\";\n\tCOLOR_ALT_BG    = \"5;236\";\n\tCOLOR_NUMBER_FG = \"5;101\";\n\tCOLOR_NUMBER_BG = \"5;232\";\n\tCOLOR_STATUS_FG = \"5;188\";\n\tCOLOR_STATUS_BG = \"5;59\";\n\tCOLOR_TABBAR_BG = \"5;59\";\n\tCOLOR_TAB_BG    = \"5;59\";\n\tCOLOR_KEYWORD   = \"5;74\";\n\tCOLOR_STRING    = \"5;71\";\n\tCOLOR_COMMENT   = global_config.can_italic ? \"5;102;3\" : \"5;102\";\n\tCOLOR_TYPE      = \"5;221\";\n\tCOLOR_PRAGMA    = \"5;160\";\n\tCOLOR_NUMERAL   = \"5;161\";\n\n\tCOLOR_ERROR_FG  = \"5;15\";\n\tCOLOR_ERROR_BG  = \"5;196\";\n\tCOLOR_SEARCH_FG = \"5;234\";\n\tCOLOR_SEARCH_BG = \"5;226\";\n\n\tCOLOR_SELECTFG  = \"5;17\";\n\tCOLOR_SELECTBG  = \"5;109\";\n\n\tCOLOR_RED       = \"@1\";\n\tCOLOR_GREEN     = \"@2\";\n\tcurrent_theme = \"sunsmoke256\";\n}\n\n/* Custom theme */\nvoid load_colorscheme_sunsmoke(void) {\n\tif (!global_config.can_24bit) {\n\t\tload_colorscheme_sunsmoke256();\n\t\treturn;\n\t}\n\tCOLOR_FG        = \"2;230;230;230\";\n\tCOLOR_BG        = \"2;31;31;31\";\n\tCOLOR_ALT_FG    = \"2;122;122;122\";\n\tCOLOR_ALT_BG    = \"2;46;43;46\";\n\tCOLOR_NUMBER_FG = \"2;150;139;57\";\n\tCOLOR_NUMBER_BG = \"2;0;0;0\";\n\tCOLOR_STATUS_FG = \"2;230;230;230\";\n\tCOLOR_STATUS_BG = \"2;71;64;58\";\n\tCOLOR_TABBAR_BG = \"2;71;64;58\";\n\tCOLOR_TAB_BG    = \"2;71;64;58\";\n\tCOLOR_KEYWORD   = \"2;51;162;230\";\n\tCOLOR_STRING    = \"2;72;176;72\";\n\tCOLOR_COMMENT   = \"2;158;153;129;3\";\n\tCOLOR_TYPE      = \"2;230;206;110\";\n\tCOLOR_PRAGMA    = \"2;194;70;54\";\n\tCOLOR_NUMERAL   = \"2;230;43;127\";\n\n\tCOLOR_ERROR_FG  = \"5;15\";\n\tCOLOR_ERROR_BG  = \"5;196\";\n\tCOLOR_SEARCH_FG = \"5;234\";\n\tCOLOR_SEARCH_BG = \"5;226\";\n\n\tCOLOR_SELECTFG  = \"2;0;43;54\";\n\tCOLOR_SELECTBG  = \"2;147;161;161\";\n\n\tCOLOR_RED       = \"2;222;53;53\";\n\tCOLOR_GREEN     = \"2;55;167;0\";\n\n\tcurrent_theme = \"sunsmoke\";\n}\n\nstruct theme_def {\n\tconst char * name;\n\tvoid (*load)(void);\n} themes[] = {\n\t{\"wombat\", load_colorscheme_wombat},\n\t{\"citylights\", load_colorscheme_citylights},\n\t{\"solarized-dark\", load_colorscheme_solarized_dark},\n\t{\"ansi\", load_colorscheme_ansi},\n\t{\"sunsmoke\", load_colorscheme_sunsmoke},\n\t{\"sunsmoke256\", load_colorscheme_sunsmoke256},\n\t{NULL, NULL}\n};\n\n\n/**\n * Syntax definition for C\n */\nint syn_c_iskeywordchar(int c) {\n\tif (isalnum(c)) return 1;\n\tif (c == '_') return 1;\n\treturn 0;\n}\n\nstatic char * syn_c_keywords[] = {\n\t\"while\",\"if\",\"for\",\"continue\",\"return\",\"break\",\"switch\",\"case\",\"sizeof\",\n\t\"struct\",\"union\",\"typedef\",\"do\",\"default\",\"else\",\"goto\",\n\t\"alignas\",\"alignof\",\"offsetof\",\"asm\",\"__asm__\",\n\t/* C++ stuff */\n\t\"public\",\"private\",\"class\",\"using\",\"namespace\",\"virtual\",\"override\",\"protected\",\n\tNULL\n};\n\nstatic char * syn_c_types[] = {\n\t\"static\",\"int\",\"char\",\"short\",\"float\",\"double\",\"void\",\"unsigned\",\"volatile\",\"const\",\n\t\"register\",\"long\",\"inline\",\"restrict\",\"enum\",\"auto\",\"extern\",\"bool\",\"complex\",\n\t\"uint8_t\",\"uint16_t\",\"uint32_t\",\"uint64_t\",\n\t\"int8_t\",\"int16_t\",\"int32_t\",\"int64_t\",\"FILE\",\n\t\"ssize_t\",\"size_t\",\"uintptr_t\",\"intptr_t\",\"__volatile__\",\n\tNULL\n};\n\nstatic char * syn_c_special[] = {\n\t\"NULL\",\n\t\"stdin\",\"stdout\",\"stderr\",\n\t\"STDIN_FILENO\",\"STDOUT_FILENO\",\"STDERR_FILENO\",\n\tNULL\n};\n\nstatic int syn_c_extended(line_t * line, int i, int c, int last, int * out_left) {\n\tif (i == 0 && c == '#') {\n\t\t*out_left = line->actual+1;\n\t\tif (line->text[line->actual-1].codepoint == '\\\\') {\n\t\t\treturn FLAG_PRAGMA | FLAG_CONTINUES;\n\t\t}\n\t\treturn FLAG_PRAGMA;\n\t}\n\t\n\tif ((!last || !syn_c_iskeywordchar(last)) && syn_c_iskeywordchar(c)) {\n\t\tint j = i;\n\t\tfor (int s = 0; syn_c_special[s]; ++s) {\n\t\t\tint d = 0;\n\t\t\twhile (j + d < line->actual - 1 && line->text[j+d].codepoint == syn_c_special[s][d]) d++;\n\t\t\tif (syn_c_special[s][d] == '\\0' && (j+d > line->actual || !syn_c_iskeywordchar(line->text[j+d].codepoint))) {\n\t\t\t\t*out_left = d-1;\n\t\t\t\treturn FLAG_NUMERAL;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ((!last || !syn_c_iskeywordchar(last)) && isdigit(c)) {\n\t\tif (c == '0' && i < line->actual - 1 && line->text[i+1].codepoint == 'x') {\n\t\t\tint j = 2;\n\t\t\tfor (; i + j < line->actual && isxdigit(line->text[i+j].codepoint); ++j);\n\t\t\tif (i + j < line->actual && syn_c_iskeywordchar(line->text[i+j].codepoint)) {\n\t\t\t\treturn FLAG_NONE;\n\t\t\t}\n\t\t\t*out_left = j - 1;\n\t\t\treturn FLAG_NUMERAL;\n\t\t} else {\n\t\t\tint j = 1;\n\t\t\twhile (i + j < line->actual && isdigit(line->text[i+j].codepoint)) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\tif (i + j < line->actual && syn_c_iskeywordchar(line->text[i+j].codepoint)) {\n\t\t\t\treturn FLAG_NONE;\n\t\t\t}\n\t\t\t*out_left = j - 1;\n\t\t\treturn FLAG_NUMERAL;\n\t\t}\n\t}\n\n\tif (c == '/') {\n\t\tif (i < line->actual - 1 && line->text[i+1].codepoint == '/') {\n\t\t\t*out_left = (line->actual + 1) - i;\n\t\t\treturn FLAG_COMMENT;\n\t\t}\n\n\t\tif (i < line->actual - 1 && line->text[i+1].codepoint == '*') {\n\t\t\tint last = 0;\n\t\t\tfor (int j = i + 2; j < line->actual; ++j) {\n\t\t\t\tint c = line->text[j].codepoint;\n\t\t\t\tif (c == '/' && last == '*') {\n\t\t\t\t\t*out_left = j - i;\n\t\t\t\t\treturn FLAG_COMMENT;\n\t\t\t\t}\n\t\t\t\tlast = c;\n\t\t\t}\n\t\t\t/* TODO multiline - update next */\n\t\t\t*out_left = (line->actual + 1) - i;\n\t\t\treturn FLAG_COMMENT | FLAG_CONTINUES;\n\t\t}\n\t}\n\n\tif (c == '\\'') {\n\t\tif (i < line->actual - 3 && line->text[i+1].codepoint == '\\\\' &&\n\t\t\tline->text[i+3].codepoint == '\\'') {\n\t\t\t*out_left = 3;\n\t\t\treturn FLAG_NUMERAL;\n\t\t}\n\t\tif (i < line->actual - 2 && line->text[i+2].codepoint == '\\'') {\n\t\t\t*out_left = 2;\n\t\t\treturn FLAG_NUMERAL;\n\t\t}\n\t}\n\n\tif (c == '\"') {\n\t\tint last = 0;\n\t\tfor (int j = i+1; j < line->actual; ++j) {\n\t\t\tint c = line->text[j].codepoint;\n\t\t\tif (last != '\\\\' && c == '\"') {\n\t\t\t\t*out_left = j - i;\n\t\t\t\treturn FLAG_STRING;\n\t\t\t}\n\t\t\tif (last == '\\\\' && c == '\\\\') {\n\t\t\t\tlast = 0;\n\t\t\t}\n\t\t\tlast = c;\n\t\t}\n\t\t*out_left = (line->actual + 1) - i; /* unterminated string */\n\t\treturn FLAG_STRING;\n\t}\n\n\treturn 0;\n}\n\nchar * syn_c_ext[] = {\".c\",\".h\",\".cpp\",\".hpp\",\".c++\",\".h++\",NULL};\n\nstatic int syn_c_finish(line_t * line, int * left, int state) {\n\tif (state == (FLAG_COMMENT | FLAG_CONTINUES)) {\n\t\tint last = 0;\n\t\tfor (int i = 0; i < line->actual; ++i) {\n\t\t\tif (line->text[i].codepoint == '/' && last == '*') {\n\t\t\t\t*left = i+2;\n\t\t\t\treturn FLAG_COMMENT;\n\t\t\t}\n\t\t\tlast = line->text[i].codepoint;\n\t\t}\n\t\treturn FLAG_COMMENT | FLAG_CONTINUES;\n\t}\n\tif (state == (FLAG_PRAGMA | FLAG_CONTINUES)) {\n\t\t*left = line->actual + 1;\n\t\tif (line->text[line->actual-1].codepoint == '\\\\') {\n\t\t\treturn FLAG_PRAGMA | FLAG_CONTINUES;\n\t\t}\n\t\treturn FLAG_PRAGMA;\n\t}\n\treturn 0;\n}\n\n/**\n * Syntax definition for Python\n */\nstatic char * syn_py_keywords[] = {\n\t\"class\",\"def\",\"return\",\"del\",\"if\",\"else\",\"elif\",\n\t\"for\",\"while\",\"continue\",\"break\",\"assert\",\n\t\"as\",\"and\",\"or\",\"except\",\"finally\",\"from\",\n\t\"global\",\"import\",\"in\",\"is\",\"lambda\",\"with\",\n\t\"nonlocal\",\"not\",\"pass\",\"raise\",\"try\",\"yield\",\n\tNULL\n};\n\nstatic char * syn_py_types[] = {\n\t\"True\",\"False\",\"None\",\n\t\"object\",\"set\",\"dict\",\"int\",\"str\",\"bytes\",\n\tNULL\n};\n\nstatic int syn_py_extended(line_t * line, int i, int c, int last, int * out_left) {\n\n\tif (i == 0 && c == 'i') {\n\t\t/* Check for import */\n\t\tchar * import = \"import \";\n\t\tfor (int j = 0; j < line->actual + 1; ++j) {\n\t\t\tif (import[j] == '\\0') {\n\t\t\t\t*out_left = j - 2;\n\t\t\t\treturn FLAG_PRAGMA;\n\t\t\t}\n\t\t\tif (line->text[j].codepoint != import[j]) break;\n\t\t}\n\t}\n\n\tif (c == '#') {\n\t\t*out_left = (line->actual + 1) - i;\n\t\treturn FLAG_COMMENT;\n\t}\n\n\tif (c == '@') {\n\t\tfor (int j = i+1; j < line->actual + 1; ++j) {\n\t\t\tif (!syn_c_iskeywordchar(line->text[j].codepoint)) {\n\t\t\t\t*out_left = j - i - 1;\n\t\t\t\treturn FLAG_PRAGMA;\n\t\t\t}\n\t\t\t*out_left = (line->actual + 1) - i;\n\t\t\treturn FLAG_PRAGMA;\n\t\t}\n\t}\n\n\tif ((!last || !syn_c_iskeywordchar(last)) && isdigit(c)) {\n\t\tif (c == '0' && i < line->actual - 1 && line->text[i+1].codepoint == 'x') {\n\t\t\tint j = 2;\n\t\t\tfor (; i + j < line->actual && isxdigit(line->text[i+j].codepoint); ++j);\n\t\t\tif (i + j < line->actual && syn_c_iskeywordchar(line->text[i+j].codepoint)) {\n\t\t\t\treturn FLAG_NONE;\n\t\t\t}\n\t\t\t*out_left = j - 1;\n\t\t\treturn FLAG_NUMERAL;\n\t\t} else {\n\t\t\tint j = 1;\n\t\t\twhile (i + j < line->actual && isdigit(line->text[i+j].codepoint)) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\tif (i + j < line->actual && syn_c_iskeywordchar(line->text[i+j].codepoint)) {\n\t\t\t\treturn FLAG_NONE;\n\t\t\t}\n\t\t\t*out_left = j - 1;\n\t\t\treturn FLAG_NUMERAL;\n\t\t}\n\t}\n\n\tif (line->text[i].codepoint == '\\'') {\n\t\tif (i + 2 < line->actual && line->text[i+1].codepoint == '\\'' && line->text[i+2].codepoint == '\\'') {\n\t\t\t/* Begin multiline */\n\t\t\tfor (int j = i + 3; j < line->actual - 2; ++j) {\n\t\t\t\tif (line->text[j].codepoint == '\\'' &&\n\t\t\t\t\tline->text[j+1].codepoint == '\\'' &&\n\t\t\t\t\tline->text[j+2].codepoint == '\\'') {\n\t\t\t\t\t*out_left = (j+2) - i;\n\t\t\t\t\treturn FLAG_STRING;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn FLAG_STRING | FLAG_CONTINUES;\n\t\t}\n\n\t\tint last = 0;\n\t\tfor (int j = i+1; j < line->actual; ++j) {\n\t\t\tint c = line->text[j].codepoint;\n\t\t\tif (last != '\\\\' && c == '\\'') {\n\t\t\t\t*out_left = j - i;\n\t\t\t\treturn FLAG_STRING;\n\t\t\t}\n\t\t\tif (last == '\\\\' && c == '\\\\') {\n\t\t\t\tlast = 0;\n\t\t\t}\n\t\t\tlast = c;\n\t\t}\n\t\t*out_left = (line->actual + 1) - i; /* unterminated string */\n\t\treturn FLAG_STRING;\n\t}\n\n\tif (line->text[i].codepoint == '\"') {\n\t\tif (i + 2 < line->actual && line->text[i+1].codepoint == '\"' && line->text[i+2].codepoint == '\"') {\n\t\t\t/* Begin multiline */\n\t\t\tfor (int j = i + 3; j < line->actual - 2; ++j) {\n\t\t\t\tif (line->text[j].codepoint == '\"' &&\n\t\t\t\t\tline->text[j+1].codepoint == '\"' &&\n\t\t\t\t\tline->text[j+2].codepoint == '\"') {\n\t\t\t\t\t*out_left = (j+2) - i;\n\t\t\t\t\treturn FLAG_STRING;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn FLAG_STRING2 | FLAG_CONTINUES;\n\t\t}\n\n\t\tint last = 0;\n\t\tfor (int j = i+1; j < line->actual; ++j) {\n\t\t\tint c = line->text[j].codepoint;\n\t\t\tif (last != '\\\\' && c == '\"') {\n\t\t\t\t*out_left = j - i;\n\t\t\t\treturn FLAG_STRING;\n\t\t\t}\n\t\t\tif (last == '\\\\' && c == '\\\\') {\n\t\t\t\tlast = 0;\n\t\t\t}\n\t\t\tlast = c;\n\t\t}\n\t\t*out_left = (line->actual + 1) - i; /* unterminated string */\n\t\treturn FLAG_STRING;\n\t}\n\n\treturn 0;\n}\n\nstatic int syn_py_finish(line_t * line, int * left, int state) {\n\t/* TODO support multiline quotes */\n\tif (state == (FLAG_STRING | FLAG_CONTINUES)) {\n\t\tfor (int j = 0; j < line->actual - 2; ++j) {\n\t\t\tif (line->text[j].codepoint == '\\'' &&\n\t\t\t\tline->text[j+1].codepoint == '\\'' &&\n\t\t\t\tline->text[j+2].codepoint == '\\'') {\n\t\t\t\t*left = (j+3);\n\t\t\t\treturn FLAG_STRING;\n\t\t\t}\n\t\t}\n\t\treturn FLAG_STRING | FLAG_CONTINUES;\n\t}\n\tif (state == (FLAG_STRING2 | FLAG_CONTINUES)) {\n\t\tfor (int j = 0; j < line->actual - 2; ++j) {\n\t\t\tif (line->text[j].codepoint == '\"' &&\n\t\t\t\tline->text[j+1].codepoint == '\"' &&\n\t\t\t\tline->text[j+2].codepoint == '\"') {\n\t\t\t\t*left = (j+3);\n\t\t\t\treturn FLAG_STRING2;\n\t\t\t}\n\t\t}\n\t\treturn FLAG_STRING2 | FLAG_CONTINUES;\n\t}\n\treturn 0;\n}\n\nchar * syn_py_ext[] = {\".py\",NULL};\n\n/**\n * Syntax definition for ToaruOS shell\n */\nstatic char * syn_sh_keywords[] = {\n\t\"cd\",\"exit\",\"export\",\"help\",\"history\",\"if\",\n\t\"empty?\",\"equals?\",\"return\",\"export-cmd\",\"read\",\n\t\"source\",\"exec\",\"not\",\"while\",\"then\",\"else\",\n\t/* Command commands */\n\t\"echo\",\"cd\",\"ln\",\"tar\",\"rm\",\"cp\",\"chmod\",\n\tNULL,\n};\n\nstatic int variable_char(uint8_t c) {\n\tif (c >= 'A' && c <= 'Z')  return 1;\n\tif (c >= 'a' && c <= 'z') return 1;\n\tif (c >= '0' && c <= '9')  return 1;\n\tif (c == '_') return 1;\n\tif (c == '?') return 1;\n\treturn 0;\n}\n\nstatic int syn_sh_extended(line_t * line, int i, int c, int last, int * out_left) {\n\t(void)last;\n\n\tif (c == '#' && last != '\\\\') {\n\t\t*out_left = (line->actual + 1) - i;\n\t\treturn FLAG_COMMENT;\n\t}\n\n\tif (line->text[i].codepoint == '\\'' && last != '\\\\') {\n\t\tint last = 0;\n\t\tfor (int j = i+1; j < line->actual + 1; ++j) {\n\t\t\tint c = line->text[j].codepoint;\n\t\t\tif (last != '\\\\' && c == '\\'') {\n\t\t\t\t*out_left = j - i;\n\t\t\t\treturn FLAG_STRING;\n\t\t\t}\n\t\t\tif (last == '\\\\' && c == '\\\\') {\n\t\t\t\tlast = 0;\n\t\t\t}\n\t\t\tlast = c;\n\t\t}\n\t\t*out_left = (line->actual + 1) - i; /* unterminated string */\n\t\treturn FLAG_STRING;\n\t}\n\n\tif (line->text[i].codepoint == '$' && last != '\\\\') {\n\t\tif (i < line->actual - 1 && line->text[i+1].codepoint == '{') {\n\t\t\tint j = i + 2;\n\t\t\tfor (; j < line->actual+1; ++j) {\n\t\t\t\tif (line->text[j].codepoint == '}') break;\n\t\t\t}\n\t\t\t*out_left = (j - i);\n\t\t\treturn FLAG_NUMERAL;\n\t\t}\n\t\tint j = i + 1;\n\t\tfor (; j < line->actual + 1; ++j) {\n\t\t\tif (!variable_char(line->text[j].codepoint)) break;\n\t\t}\n\t\t*out_left = (j - i) - 1;\n\t\treturn FLAG_NUMERAL;\n\t}\n\n\tif (line->text[i].codepoint == '\"' && last != '\\\\') {\n\t\tint last = 0;\n\t\tfor (int j = i+1; j < line->actual + 1; ++j) {\n\t\t\tint c = line->text[j].codepoint;\n\t\t\tif (last != '\\\\' && c == '\"') {\n\t\t\t\t*out_left = j - i;\n\t\t\t\treturn FLAG_STRING;\n\t\t\t}\n\t\t\tif (last == '\\\\' && c == '\\\\') {\n\t\t\t\tlast = 0;\n\t\t\t}\n\t\t\tlast = c;\n\t\t}\n\t\t*out_left = (line->actual + 1) - i; /* unterminated string */\n\t\treturn FLAG_STRING;\n\t}\n\n\treturn 0;\n}\n\nstatic int syn_sh_iskeywordchar(int c) {\n\tif (isalnum(c)) return 1;\n\tif (c == '-') return 1;\n\tif (c == '_') return 1;\n\tif (c == '?') return 1;\n\treturn 0;\n}\n\nstatic char * syn_sh_ext[] = {\".sh\",\".eshrc\",\".esh\",NULL};\n\nstatic char * syn_make_ext[] = {\"Makefile\",\"makefile\",\"GNUmakefile\",\".mak\",NULL};\n\nstatic char * syn_make_commands[] = {\n\t\"define\",\"endef\",\"undefine\",\"ifdef\",\"ifndef\",\"ifeq\",\"ifneq\",\"else\",\"endif\",\n\t\"include\",\"sinclude\",\"override\",\"export\",\"unexport\",\"private\",\"vpath\",\n\t\"-include\",\n\tNULL\n};\n\nstatic char * syn_make_functions[] = {\n\t\"subst\",\"patsubst\",\"findstring\",\"filter\",\"filter-out\",\n\t\"sort\",\"word\",\"words\",\"wordlist\",\"firstword\",\"lastword\",\n\t\"dir\",\"notdir\",\"suffix\",\"basename\",\"addsuffix\",\"addprefix\",\n\t\"join\",\"wildcard\",\"realpath\",\"abspath\",\"error\",\"warning\",\n\t\"shell\",\"origin\",\"flavor\",\"foreach\",\"if\",\"or\",\"and\",\n\t\"call\",\"eval\",\"file\",\"value\",\n\tNULL\n};\n\nstatic int syn_make_extended(line_t * line, int i, int c, int last, int * out_left) {\n\t(void)last;\n\n\tif (c == '#') {\n\t\t*out_left = (line->actual + 1) - i;\n\t\treturn FLAG_COMMENT;\n\t}\n\n\tif (c == '\\t') {\n\t\t*out_left = (line->actual + 1) - i;\n\t\treturn FLAG_NUMERAL;\n\t}\n\n\tif (i == 0) {\n\t\tint j = 0;\n\t\tfor (; j < line->actual; ++j) {\n\t\t\t/* Handle leading spaces */\n\t\t\tif (line->text[j].codepoint != ' ') break;\n\t\t}\n\t\tfor (int s = 0; syn_make_commands[s]; ++s) {\n\t\t\tint d = 0;\n\t\t\twhile (j + d < line->actual && line->text[j+d].codepoint == syn_make_commands[s][d]) d++;\n\t\t\tif (syn_make_commands[s][d] == '\\0') {\n\t\t\t\t*out_left = j+d;\n\t\t\t\treturn FLAG_PRAGMA;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (last == '(' && i > 1) {\n\t\tif (line->text[i-2].codepoint == '$') {\n\t\t\tint j = i;\n\t\t\tfor (int s = 0; syn_make_functions[s]; ++s) {\n\t\t\t\tint d = 0;\n\t\t\t\twhile (j + d < line->actual && line->text[j+d].codepoint == syn_make_functions[s][d]) d++;\n\t\t\t\tif (syn_make_functions[s][d] == '\\0' && (j + d == line->actual\n\t\t\t\t\t\t\t|| line->text[j+d].codepoint == ')' || line->text[j+d].codepoint == ' ')) {\n\t\t\t\t\t*out_left = d;\n\t\t\t\t\treturn FLAG_KEYWORD;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (i == 0) {\n\t\tint j = 0;\n\t\tfor (; j < line->actual; ++j) {\n\t\t\tif (line->text[j].codepoint == '=') {\n\t\t\t\t*out_left = j;\n\t\t\t\treturn FLAG_TYPE;\n\t\t\t}\n\t\t\tif (line->text[j].codepoint == ':') {\n\t\t\t\t*out_left = j;\n\t\t\t\treturn FLAG_TYPE;\n\t\t\t}\n\t\t}\n\t}\n\n\n\treturn FLAG_NONE;\n}\n\nstatic char * syn_bimrc_keywords[] = {\n\t\"theme\",\n\t\"padding\",\n\tNULL,\n};\n\nstatic int syn_bimrc_extended(line_t * line, int i, int c, int last, int * out_left) {\n\t(void)last;\n\tif (i == 0 && c == '#') {\n\t\t*out_left = line->actual+1;\n\t\treturn FLAG_COMMENT;\n\t}\n\treturn FLAG_NONE;\n}\n\nstatic char * syn_bimrc_ext[] = {\".bimrc\",NULL};\n\nstatic int syn_gitcommit_extended(line_t * line, int i, int c, int last, int * out_left) {\n\t(void)last;\n\n\tif (c == '#') {\n\t\t*out_left = (line->actual + 1) - i;\n\t\treturn FLAG_COMMENT;\n\t}\n\n\treturn FLAG_NONE;\n}\n\nstatic char * syn_gitcommit_ext[] = {\"COMMIT_EDITMSG\",NULL};\n\nstatic char * syn_gitrebase_commands[] = {\n\t\"p \",\"r \",\"e \",\"s \",\"f \",\"x \",\" d\",\n\t\"pick \",\"reword \",\"edit \",\"squash \",\"fixup \",\n\t\"exec \",\"drop \",\n\tNULL\n};\n\nstatic int syn_gitrebase_extended(line_t * line, int i, int c, int last, int * out_left) {\n\t(void)last;\n\n\tif (c == '#') {\n\t\t*out_left = (line->actual + 1) - i;\n\t\treturn FLAG_COMMENT;\n\t}\n\n\tif (i == 0) {\n\t\tint j = i;\n\t\tfor (int s = 0; syn_gitrebase_commands[s]; ++s) {\n\t\t\tint d = 0;\n\t\t\twhile (j + d < line->actual && line->text[j+d].codepoint == syn_gitrebase_commands[s][d]) d++;\n\t\t\tif (syn_gitrebase_commands[s][d] == '\\0') {\n\t\t\t\t*out_left = j+d-1;\n\t\t\t\treturn FLAG_KEYWORD;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (i > 0 && (line->text[i-1].flags & FLAG_KEYWORD)) {\n\t\tint j = i;\n\t\twhile (isxdigit(line->text[j].codepoint)) {\n\t\t\tj++;\n\t\t}\n\t\t*out_left = j-i-1;\n\t\treturn FLAG_NUMERAL;\n\t}\n\n\treturn FLAG_NONE;\n}\n\nstatic char * syn_gitrebase_ext[] = {\"git-rebase-todo\",NULL};\n\nstatic int syn_diff_extended(line_t * line, int i, int c, int last, int * out_left) {\n\t(void)last;\n\n\tif (i == 0) {\n\t\tif (c == '+') {\n\t\t\t*out_left = (line->actual + 1);\n\t\t\treturn FLAG_DIFFPLUS;\n\t\t} else if (c == '-') {\n\t\t\t*out_left = (line->actual + 1);\n\t\t\treturn FLAG_DIFFMINUS;\n\t\t} else if (c == '@') {\n\t\t\t*out_left = (line->actual + 1);\n\t\t\treturn FLAG_TYPE;\n\t\t} else if (c != ' ') {\n\t\t\t*out_left = (line->actual + 1);\n\t\t\treturn FLAG_KEYWORD;\n\t\t}\n\t}\n\n\treturn FLAG_NONE;\n}\n\nstatic char * syn_diff_ext[] = {\".diff\",\".patch\",NULL};\n\n\n\nstatic char * syn_rust_keywords[] = {\n\t\"as\",\"break\",\"const\",\"continue\",\"crate\",\"else\",\"enum\",\"extern\",\n\t\"false\",\"fn\",\"for\",\"if\",\"impl\",\"in\",\"let\",\"loop\",\"match\",\"mod\",\n\t\"move\",\"mut\",\"pub\",\"ref\",\"return\",\"Self\",\"self\",\"static\",\"struct\",\n\t\"super\",\"trait\",\"true\",\"type\",\"unsafe\",\"use\",\"where\",\"while\",\n\tNULL,\n};\n\nstatic char * syn_rust_types[] = {\n\t\"bool\",\"char\",\"str\",\n\t\"i8\",\"i16\",\"i32\",\"i64\",\n\t\"u8\",\"u16\",\"u32\",\"u64\",\n\t\"isize\",\"usize\",\n\t\"f32\",\"f64\",\n\tNULL,\n};\n\nstatic int syn_rust_extended(line_t * line, int i, int c, int last, int * out_left) {\n\tif ((!last || !syn_c_iskeywordchar(last)) && isdigit(c)) {\n\t\tif (c == '0' && i < line->actual - 1 && line->text[i+1].codepoint == 'x') {\n\t\t\tint j = 2;\n\t\t\tfor (; i + j < line->actual && isxdigit(line->text[i+j].codepoint); ++j);\n\t\t\tif (i + j < line->actual && syn_c_iskeywordchar(line->text[i+j].codepoint)) {\n\t\t\t\treturn FLAG_NONE;\n\t\t\t}\n\t\t\t*out_left = j - 1;\n\t\t\treturn FLAG_NUMERAL;\n\t\t} else {\n\t\t\tint j = 1;\n\t\t\twhile (i + j < line->actual && isdigit(line->text[i+j].codepoint)) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\tif (i + j < line->actual && syn_c_iskeywordchar(line->text[i+j].codepoint)) {\n\t\t\t\treturn FLAG_NONE;\n\t\t\t}\n\t\t\t*out_left = j - 1;\n\t\t\treturn FLAG_NUMERAL;\n\t\t}\n\t}\n\n\tif (c == '/') {\n\t\tif (i < line->actual - 1 && line->text[i+1].codepoint == '/') {\n\t\t\t*out_left = (line->actual + 1) - i;\n\t\t\treturn FLAG_COMMENT;\n\t\t}\n\n\t\t/* TODO: We can't support Rust's nested comments with this... */\n\t\tif (i < line->actual - 1 && line->text[i+1].codepoint == '*') {\n\t\t\tint last = 0;\n\t\t\tfor (int j = i + 2; j < line->actual; ++j) {\n\t\t\t\tint c = line->text[j].codepoint;\n\t\t\t\tif (c == '/' && last == '*') {\n\t\t\t\t\t*out_left = j - i;\n\t\t\t\t\treturn FLAG_COMMENT;\n\t\t\t\t}\n\t\t\t\tlast = c;\n\t\t\t}\n\t\t\t*out_left = (line->actual + 1) - i;\n\t\t\treturn FLAG_COMMENT | FLAG_CONTINUES;\n\t\t}\n\t}\n\n\tif (c == '\\'') {\n\t\tif (i < line->actual - 3 && line->text[i+1].codepoint == '\\\\' &&\n\t\t\tline->text[i+3].codepoint == '\\'') {\n\t\t\t*out_left = 3;\n\t\t\treturn FLAG_NUMERAL;\n\t\t}\n\t\tif (i < line->actual - 2 && line->text[i+2].codepoint == '\\'') {\n\t\t\t*out_left = 2;\n\t\t\treturn FLAG_NUMERAL;\n\t\t}\n\t}\n\n\tif (c == '\"') {\n\t\tint last = 0;\n\t\tfor (int j = i+1; j < line->actual; ++j) {\n\t\t\tint c = line->text[j].codepoint;\n\t\t\tif (last != '\\\\' && c == '\"') {\n\t\t\t\t*out_left = j - i;\n\t\t\t\treturn FLAG_STRING;\n\t\t\t}\n\t\t\tif (last == '\\\\' && c == '\\\\') {\n\t\t\t\tlast = 0;\n\t\t\t}\n\t\t\tlast = c;\n\t\t}\n\t\t*out_left = (line->actual + 1) - i; /* unterminated string */\n\t\treturn FLAG_STRING;\n\t}\n\n\treturn 0;\n}\n\nstatic int syn_rust_finish(line_t * line, int * left, int state) {\n\tif (state == (FLAG_COMMENT | FLAG_CONTINUES)) {\n\t\tint last = 0;\n\t\tfor (int i = 0; i < line->actual; ++i) {\n\t\t\tif (line->text[i].codepoint == '/' && last == '*') {\n\t\t\t\t*left = i+2;\n\t\t\t\treturn FLAG_COMMENT;\n\t\t\t}\n\t\t\tlast = line->text[i].codepoint;\n\t\t}\n\t\treturn FLAG_COMMENT | FLAG_CONTINUES;\n\t}\n\treturn 0;\n}\n\n\nstatic char * syn_rust_ext[] = {\".rs\",NULL};\n\nstatic int syn_conf_extended(line_t * line, int i, int c, int last, int * out_left) {\n\t(void)last;\n\n\tif (i == 0) {\n\t\tif (c == ';') {\n\t\t\t*out_left = (line->actual + 1) - i;\n\t\t\treturn FLAG_COMMENT;\n\t\t}\n\n\t\tif (c == '[') {\n\t\t\t*out_left = (line->actual + 1) - i;\n\t\t\treturn FLAG_KEYWORD;\n\t\t}\n\n\t\tint j = 0;\n\t\tfor (; j < line->actual; ++j) {\n\t\t\tif (line->text[j].codepoint == '=') {\n\t\t\t\t*out_left = j;\n\t\t\t\treturn FLAG_TYPE;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn FLAG_NONE;\n}\n\nstatic char * syn_conf_ext[] = {\".conf\",NULL};\n\n/**\n * Syntax hilighting definition database\n */\nstruct syntax_definition {\n\tchar * name;\n\tchar ** ext;\n\tchar ** keywords;\n\tchar ** types;\n\tint (*extended)(line_t *, int, int, int, int *);\n\tint (*iskwchar)(int);\n\tint (*finishml)(line_t *, int *, int);\n} syntaxes[] = {\n\t{\"c\",syn_c_ext,syn_c_keywords,syn_c_types,syn_c_extended,syn_c_iskeywordchar,syn_c_finish},\n\t{\"python\",syn_py_ext,syn_py_keywords,syn_py_types,syn_py_extended,syn_c_iskeywordchar,syn_py_finish},\n\t{\"esh\",syn_sh_ext,syn_sh_keywords,NULL,syn_sh_extended,syn_sh_iskeywordchar,NULL},\n\t{\"make\",syn_make_ext,NULL,NULL,syn_make_extended,NULL,NULL},\n\t{\"bimrc\",syn_bimrc_ext,syn_bimrc_keywords,NULL,syn_bimrc_extended,syn_c_iskeywordchar,NULL},\n\t{\"gitcommit\",syn_gitcommit_ext,NULL,NULL,syn_gitcommit_extended,NULL,NULL},\n\t{\"gitrebase\",syn_gitrebase_ext,NULL,NULL,syn_gitrebase_extended,NULL,NULL},\n\t{\"diff\",syn_diff_ext,NULL,NULL,syn_diff_extended,NULL,NULL},\n\t{\"rust\",syn_rust_ext,syn_rust_keywords,syn_rust_types,syn_rust_extended,syn_c_iskeywordchar,syn_rust_finish},\n\t{\"conf\",syn_conf_ext,NULL,NULL,syn_conf_extended,NULL,NULL},\n\t{NULL}\n};\n\n/**\n * Checks whether the character pointed to by `c` is the start of a match for\n * keyword or type name `str`.\n */\nint check_line(line_t * line, int c, char * str, int last) {\n\tif (env->syntax->iskwchar(last)) return 0;\n\tfor (int i = c; i < line->actual; ++i, ++str) {\n\t\tif (*str == '\\0' && !env->syntax->iskwchar(line->text[i].codepoint)) return 1;\n\t\tif (line->text[i].codepoint == *str) continue;\n\t\treturn 0;\n\t}\n\tif (*str == '\\0') return 1;\n\treturn 0;\n}\n\n/**\n * Calculate syntax hilighting for the given line.\n */\nvoid recalculate_syntax(line_t * line, int offset) {\n\tif (!env->syntax) {\n\t\tfor (int i = 0; i < line->actual; ++i) {\n\t\t\tline->text[i].flags = 0;\n\t\t}\n\t\treturn;\n\t}\n\n\t/* Start from the line's stored in initial state */\n\tint state = line->istate;\n\tint left  = 0;\n\tint last  = 0;\n\n\tif (state) {\n\t\t/*\n\t\t * If we are already highlighting coming in, then we need to check\n\t\t * for a finishing sequence for the curent state.\n\t\t */\n\t\tstate = env->syntax->finishml(line,&left,state);\n\n\t\tif (state & FLAG_CONTINUES) {\n\t\t\t/* The finish check said that this multiline state continues. */\n\t\t\tfor (int i = 0; i < line->actual; i++) {\n\t\t\t\t/* Set the entire line to draw with this state */\n\t\t\t\tline->text[i].flags = state;\n\t\t\t}\n\n\t\t\t/* Recalculate later lines if needed */\n\t\t\tgoto _multiline;\n\t\t}\n\t}\n\n\tfor (int i = 0; i < line->actual; last = line->text[i++].codepoint) {\n\t\tif (!left) state = 0;\n\n\t\tif (state) {\n\t\t\t/* Currently hilighting, have `left` characters remaining with this state */\n\t\t\tleft--;\n\t\t\tline->text[i].flags = state;\n\n\t\t\tif (!left) {\n\t\t\t\t/* Done hilighting this state, go back to parsing on next character */\n\t\t\t\tstate = 0;\n\t\t\t}\n\n\t\t\t/* If we are hilighting something, don't parse */\n\t\t\tcontinue;\n\t\t}\n\n\t\tint c = line->text[i].codepoint;\n\t\tline->text[i].flags = FLAG_NONE;\n\n\t\t/* Language-specific syntax hilighting */\n\t\tif (env->syntax->extended) {\n\t\t\tint s = env->syntax->extended(line,i,c,last,&left);\n\t\t\tif (s) {\n\t\t\t\tstate = s;\n\t\t\t\tif (state & FLAG_CONTINUES) {\n\t\t\t\t\t/* A multiline state was returned. Fill the rest of the line */\n\t\t\t\t\tfor (; i < line->actual; i++) {\n\t\t\t\t\t\tline->text[i].flags = state;\n\t\t\t\t\t}\n\t\t\t\t\t/* And recalculate later lines if needed */\n\t\t\t\t\tgoto _multiline;\n\t\t\t\t}\n\t\t\t\tgoto _continue;\n\t\t\t}\n\t\t}\n\n\t\t/* Keywords */\n\t\tif (env->syntax->keywords) {\n\t\t\tfor (char ** kw = env->syntax->keywords; *kw; kw++) {\n\t\t\t\tint c = check_line(line, i, *kw, last);\n\t\t\t\tif (c == 1) {\n\t\t\t\t\tleft = strlen(*kw)-1;\n\t\t\t\t\tstate = FLAG_KEYWORD;\n\t\t\t\t\tgoto _continue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/* Type names */\n\t\tif (env->syntax->types) {\n\t\t\tfor (char ** kw = env->syntax->types; *kw; kw++) {\n\t\t\t\tint c = check_line(line, i, *kw, last);\n\t\t\t\tif (c == 1) {\n\t\t\t\t\tleft = strlen(*kw)-1;\n\t\t\t\t\tstate = FLAG_TYPE;\n\t\t\t\t\tgoto _continue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n_continue:\n\t\tline->text[i].flags = state;\n\t}\n\n\tstate = 0;\n\n_multiline:\n\t/*\n\t * If the next line's initial state does not match the state we ended on,\n\t * then it needs to be recalculated (and redraw). This may lead to multiple\n\t * recursive calls until a match is found.\n\t */\n\tif (offset + 1 < env->line_count && env->lines[offset+1]->istate != state) {\n\t\t/* Set the next line's initial state to our ending state */\n\t\tenv->lines[offset+1]->istate = state;\n\n\t\t/* Recursively recalculate */\n\t\trecalculate_syntax(env->lines[offset+1],offset+1);\n\n\t\t/*\n\t\t * Determine if this is an on-screen line so we can redraw it;\n\t\t * this ends up drawing from bottom to top when multiple lines\n\t\t * need to be redrawn by a recursive call.\n\t\t */\n\t\tif (offset+1 >= env->offset && offset+1 < env->offset + global_config.term_height - global_config.bottom_size - 1) {\n\t\t\tredraw_line(offset + 1 - env->offset,offset+1);\n\t\t}\n\t}\n}\n\n/**\n * Recalculate tab widths.\n */\nvoid recalculate_tabs(line_t * line) {\n\tif (env->loading) return;\n\n\tint j = 0;\n\tfor (int i = 0; i < line->actual; ++i) {\n\t\tif (line->text[i].codepoint == '\\t') {\n\t\t\tline->text[i].display_width = env->tabstop - (j % env->tabstop);\n\t\t}\n\t\tj += line->text[i].display_width;\n\t}\n}\n\n/**\n * TODO:\n *\n * The line editing functions should probably take a buffer_t *\n * so that they can act on buffers other than the active one.\n */\n\nvoid recursive_history_free(history_t * root) {\n\tif (!root->next) return;\n\n\thistory_t * n = root->next;\n\trecursive_history_free(n);\n\n\tswitch (n->type) {\n\t\tcase HISTORY_REPLACE_LINE:\n\t\t\tfree(n->contents.remove_replace_line.contents);\n\t\t\t/* fall-through */\n\t\tcase HISTORY_REMOVE_LINE:\n\t\t\tfree(n->contents.remove_replace_line.old_contents);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t/* Nothing extra to free */\n\t\t\tbreak;\n\t}\n\n\tfree(n);\n\troot->next = NULL;\n}\n\n#define HIST_APPEND(e) do { \\\n\t\tif (env->history) { \\\n\t\t\te->previous = env->history; \\\n\t\t\trecursive_history_free(env->history); \\\n\t\t\tenv->history->next = e; \\\n\t\t\te->next = NULL; \\\n\t\t} \\\n\t\tenv->history = e; \\\n\t} while (0)\n\n/**\n * Mark a point where a complete set of actions has ended.\n */\nvoid set_history_break(void) {\n\tif (!global_config.history_enabled) return;\n\n\tif (env->history->type != HISTORY_BREAK && env->history->type != HISTORY_SENTINEL) {\n\t\thistory_t * e = malloc(sizeof(history_t));\n\t\te->type = HISTORY_BREAK;\n\t\tHIST_APPEND(e);\n\t}\n}\n\n/**\n * Insert a character into an existing line.\n */\nline_t * line_insert(line_t * line, char_t c, int offset, int lineno) {\n\n\tif (!env->loading && global_config.history_enabled) {\n\t\thistory_t * e = malloc(sizeof(history_t));\n\t\te->type = HISTORY_INSERT;\n\t\te->contents.insert_delete_replace.lineno = lineno;\n\t\te->contents.insert_delete_replace.offset = offset;\n\t\te->contents.insert_delete_replace.codepoint = c.codepoint;\n\t\tHIST_APPEND(e);\n\t}\n\n\t/* If there is not enough space... */\n\tif (line->actual == line->available) {\n\t\t/* Expand the line buffer */\n\t\tif (line->available == 0) {\n\t\t\tline->available = 8;\n\t\t} else {\n\t\t\tline->available *= 2;\n\t\t}\n\t\tline = realloc(line, sizeof(line_t) + sizeof(char_t) * line->available);\n\t}\n\n\t/* If this was not the last character, then shift remaining characters forward. */\n\tif (offset < line->actual) {\n\t\tmemmove(&line->text[offset+1], &line->text[offset], sizeof(char_t) * (line->actual - offset));\n\t}\n\n\t/* Insert the new character */\n\tline->text[offset] = c;\n\n\t/* There is one new character in the line */\n\tline->actual += 1;\n\n\tif (!env->loading) {\n\t\trecalculate_tabs(line);\n\t\trecalculate_syntax(line, lineno);\n\t}\n\n\treturn line;\n}\n\n/**\n * Delete a character from a line\n */\nvoid line_delete(line_t * line, int offset, int lineno) {\n\n\t/* Can't delete character before start of line. */\n\tif (offset == 0) return;\n\n\tif (!env->loading && global_config.history_enabled) {\n\t\thistory_t * e = malloc(sizeof(history_t));\n\t\te->type = HISTORY_DELETE;\n\t\te->contents.insert_delete_replace.lineno = lineno;\n\t\te->contents.insert_delete_replace.offset = offset;\n\t\te->contents.insert_delete_replace.old_codepoint = line->text[offset-1].codepoint;\n\t\tHIST_APPEND(e);\n\t}\n\n\t/* If this isn't the last character, we need to move all subsequent characters backwards */\n\tif (offset < line->actual) {\n\t\tmemmove(&line->text[offset-1], &line->text[offset], sizeof(char_t) * (line->actual - offset));\n\t}\n\n\t/* The line is one character shorter */\n\tline->actual -= 1;\n\n\trecalculate_tabs(line);\n\trecalculate_syntax(line, lineno);\n}\n\n/**\n * Replace a character in a line\n */\nvoid line_replace(line_t * line, char_t _c, int offset, int lineno) {\n\n\tif (!env->loading && global_config.history_enabled) {\n\t\thistory_t * e = malloc(sizeof(history_t));\n\t\te->type = HISTORY_REPLACE;\n\t\te->contents.insert_delete_replace.lineno = lineno;\n\t\te->contents.insert_delete_replace.offset = offset;\n\t\te->contents.insert_delete_replace.codepoint = _c.codepoint;\n\t\te->contents.insert_delete_replace.old_codepoint = line->text[offset].codepoint;\n\t\tHIST_APPEND(e);\n\t}\n\n\tline->text[offset] = _c;\n\n\tif (!env->loading) {\n\t\trecalculate_tabs(line);\n\t\trecalculate_syntax(line, lineno);\n\t}\n}\n\n/**\n * Remove a line from the active buffer\n */\nline_t ** remove_line(line_t ** lines, int offset) {\n\n\t/* If there is only one line, clear it instead of removing it. */\n\tif (env->line_count == 1) {\n\t\twhile (lines[offset]->actual > 0) {\n\t\t\tline_delete(lines[offset], lines[offset]->actual, offset);\n\t\t}\n\t\treturn lines;\n\t}\n\n\tif (!env->loading && global_config.history_enabled) {\n\t\thistory_t * e = malloc(sizeof(history_t));\n\t\te->type = HISTORY_REMOVE_LINE;\n\t\te->contents.remove_replace_line.lineno = offset;\n\t\te->contents.remove_replace_line.old_contents = malloc(sizeof(line_t) + sizeof(char_t) * lines[offset]->available);\n\t\tmemcpy(e->contents.remove_replace_line.old_contents, lines[offset], sizeof(line_t) + sizeof(char_t) * lines[offset]->available);\n\t\tHIST_APPEND(e);\n\t}\n\n\t/* Otherwise, free the data used by the line */\n\tfree(lines[offset]);\n\n\t/* Move other lines up */\n\tif (offset < env->line_count-1) {\n\t\tmemmove(&lines[offset], &lines[offset+1], sizeof(line_t *) * (env->line_count - (offset - 1)));\n\t\tlines[env->line_count-1] = NULL;\n\t}\n\n\t/* There is one less line */\n\tenv->line_count -= 1;\n\treturn lines;\n}\n\n/**\n * Add a new line to the active buffer.\n */\nline_t ** add_line(line_t ** lines, int offset) {\n\n\t/* Invalid offset? */\n\tif (offset > env->line_count) return lines;\n\n\tif (!env->loading && global_config.history_enabled) {\n\t\thistory_t * e = malloc(sizeof(history_t));\n\t\te->type = HISTORY_ADD_LINE;\n\t\te->contents.add_merge_split_lines.lineno = offset;\n\t\tHIST_APPEND(e);\n\t}\n\n\t/* Not enough space */\n\tif (env->line_count == env->line_avail) {\n\t\t/* Allocate more space */\n\t\tenv->line_avail *= 2;\n\t\tlines = realloc(lines, sizeof(line_t *) * env->line_avail);\n\t}\n\n\t/* If this isn't the last line, move other lines down */\n\tif (offset < env->line_count) {\n\t\tmemmove(&lines[offset+1], &lines[offset], sizeof(line_t *) * (env->line_count - offset));\n\t}\n\n\t/* Allocate the new line */\n\tlines[offset] = malloc(sizeof(line_t) + sizeof(char_t) * 32);\n\tlines[offset]->available = 32;\n\tlines[offset]->actual    = 0;\n\tlines[offset]->istate    = 0;\n\n\t/* There is one new line */\n\tenv->line_count += 1;\n\tenv->lines = lines;\n\n\tif (offset > 0 && !env->loading) {\n\t\trecalculate_syntax(lines[offset-1],offset-1);\n\t}\n\treturn lines;\n}\n\n/**\n * Replace a line with data from another line (used by paste to paste yanked lines)\n */\nvoid replace_line(line_t ** lines, int offset, line_t * replacement) {\n\n\tif (!env->loading && global_config.history_enabled) {\n\t\thistory_t * e = malloc(sizeof(history_t));\n\t\te->type = HISTORY_REPLACE_LINE;\n\t\te->contents.remove_replace_line.lineno = offset;\n\t\te->contents.remove_replace_line.old_contents = malloc(sizeof(line_t) + sizeof(char_t) * lines[offset]->available);\n\t\tmemcpy(e->contents.remove_replace_line.old_contents, lines[offset], sizeof(line_t) + sizeof(char_t) * lines[offset]->available);\n\t\te->contents.remove_replace_line.contents = malloc(sizeof(line_t) + sizeof(char_t) * replacement->available);\n\t\tmemcpy(e->contents.remove_replace_line.contents, replacement, sizeof(line_t) + sizeof(char_t) * replacement->available);\n\t\tHIST_APPEND(e);\n\t}\n\n\tif (lines[offset]->available < replacement->actual) {\n\t\tlines[offset] = realloc(lines[offset], sizeof(line_t) + sizeof(char_t) * replacement->available);\n\t\tlines[offset]->available = replacement->available;\n\t}\n\tlines[offset]->actual = replacement->actual;\n\tmemcpy(&lines[offset]->text, &replacement->text, sizeof(char_t) * replacement->actual);\n\n\tif (!env->loading) {\n\t\trecalculate_syntax(lines[offset],offset);\n\t}\n}\n\n/**\n * Merge two consecutive lines.\n * lineb is the offset of the second line.\n */\nline_t ** merge_lines(line_t ** lines, int lineb) {\n\n\t/* linea is the line immediately before lineb */\n\tint linea = lineb - 1;\n\n\tif (!env->loading && global_config.history_enabled) {\n\t\thistory_t * e = malloc(sizeof(history_t));\n\t\te->type = HISTORY_MERGE_LINES;\n\t\te->contents.add_merge_split_lines.lineno = lineb;\n\t\te->contents.add_merge_split_lines.split = env->lines[linea]->actual;\n\t\tHIST_APPEND(e);\n\t}\n\n\t/* If there isn't enough space in linea hold both... */\n\twhile (lines[linea]->available < lines[linea]->actual + lines[lineb]->actual) {\n\t\t/* ... allocate more space until it fits */\n\t\tif (lines[linea]->available == 0) {\n\t\t\tlines[linea]->available = 8;\n\t\t} else {\n\t\t\tlines[linea]->available *= 2;\n\t\t}\n\t\t/* XXX why not just do this once after calculating appropriate size */\n\t\tlines[linea] = realloc(lines[linea], sizeof(line_t) + sizeof(char_t) * lines[linea]->available);\n\t}\n\n\t/* Copy the second line into the first line */\n\tmemcpy(&lines[linea]->text[lines[linea]->actual], &lines[lineb]->text, sizeof(char_t) * lines[lineb]->actual);\n\n\t/* The first line is now longer */\n\tlines[linea]->actual = lines[linea]->actual + lines[lineb]->actual;\n\n\tif (!env->loading) {\n\t\trecalculate_tabs(lines[linea]);\n\t\trecalculate_syntax(lines[linea], linea);\n\t}\n\n\t/* Remove the second line */\n\tfree(lines[lineb]);\n\n\t/* Move other lines up */\n\tif (lineb < env->line_count) {\n\t\tmemmove(&lines[lineb], &lines[lineb+1], sizeof(line_t *) * (env->line_count - (lineb - 1)));\n\t\tlines[env->line_count-1] = NULL;\n\t}\n\n\t/* There is one less line */\n\tenv->line_count -= 1;\n\treturn lines;\n}\n\n/**\n * Split a line into two lines at the given column\n */\nline_t ** split_line(line_t ** lines, int line, int split) {\n\n\t/* If we're trying to split from the start, just add a new blank line before */\n\tif (split == 0) {\n\t\treturn add_line(lines, line);\n\t}\n\n\tif (!env->loading && global_config.history_enabled) {\n\t\thistory_t * e = malloc(sizeof(history_t));\n\t\te->type = HISTORY_SPLIT_LINE;\n\t\te->contents.add_merge_split_lines.lineno = line;\n\t\te->contents.add_merge_split_lines.split  = split;\n\t\tHIST_APPEND(e);\n\t}\n\n\t/* Allocate more space as needed */\n\tif (env->line_count == env->line_avail) {\n\t\tenv->line_avail *= 2;\n\t\tlines = realloc(lines, sizeof(line_t *) * env->line_avail);\n\t}\n\n\t/* Shift later lines down */\n\tif (line < env->line_count) {\n\t\tmemmove(&lines[line+2], &lines[line+1], sizeof(line_t *) * (env->line_count - line));\n\t}\n\n\t/* I have no idea what this is doing */\n\tint remaining = lines[line]->actual - split;\n\n\tint v = remaining;\n\tv--;\n\tv |= v >> 1;\n\tv |= v >> 2;\n\tv |= v >> 4;\n\tv |= v >> 8;\n\tv |= v >> 16;\n\tv++;\n\n\t/* Allocate space for the new line */\n\tlines[line+1] = malloc(sizeof(line_t) + sizeof(char_t) * v);\n\tlines[line+1]->available = v;\n\tlines[line+1]->actual = remaining;\n\tlines[line+1]->istate = 0;\n\n\t/* Move the data from the old line into the new line */\n\tmemmove(lines[line+1]->text, &lines[line]->text[split], sizeof(char_t) * remaining);\n\tlines[line]->actual = split;\n\n\tif (!env->loading) {\n\t\trecalculate_tabs(lines[line]);\n\t\trecalculate_tabs(lines[line+1]);\n\t\trecalculate_syntax(lines[line], line);\n\t\trecalculate_syntax(lines[line+1], line+1);\n\t}\n\n\t/* There is one new line */\n\tenv->line_count += 1;\n\n\t/* We may have reallocated lines */\n\treturn lines;\n}\n\n/**\n * Add indentation from the previous (temporally) line\n */\nvoid add_indent(int new_line, int old_line, int ignore_brace) {\n\tif (env->indent) {\n\t\tint changed = 0;\n\t\tfor (int i = 0; i < env->lines[old_line]->actual; ++i) {\n\t\t\tif (env->lines[old_line]->text[i].codepoint == ' ' ||\n\t\t\t\tenv->lines[old_line]->text[i].codepoint == '\\t') {\n\t\t\t\tenv->lines[new_line] = line_insert(env->lines[new_line],env->lines[old_line]->text[i],i,new_line);\n\t\t\t\tenv->col_no++;\n\t\t\t\tchanged = 1;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (old_line < new_line && !ignore_brace &&\n\t\t\t(env->lines[old_line]->text[env->lines[old_line]->actual-1].codepoint == '{' ||\n\t\t\tenv->lines[old_line]->text[env->lines[old_line]->actual-1].codepoint == ':')) {\n\t\t\tif (env->tabs) {\n\t\t\t\tchar_t c;\n\t\t\t\tc.codepoint = '\\t';\n\t\t\t\tc.display_width = env->tabstop;\n\t\t\t\tenv->lines[new_line] = line_insert(env->lines[new_line], c, env->lines[new_line]->actual, new_line);\n\t\t\t\tenv->col_no++;\n\t\t\t\tchanged = 1;\n\t\t\t} else {\n\t\t\t\tfor (int j = 0; j < env->tabstop; ++j) {\n\t\t\t\t\tchar_t c;\n\t\t\t\t\tc.codepoint = ' ';\n\t\t\t\t\tc.display_width = 1;\n\t\t\t\t\tc.flags = FLAG_SELECT;\n\t\t\t\t\tenv->lines[new_line] = line_insert(env->lines[new_line], c, env->lines[new_line]->actual, new_line);\n\t\t\t\t\tenv->col_no++;\n\t\t\t\t}\n\t\t\t\tchanged = 1;\n\t\t\t}\n\t\t}\n\t\tint was_whitespace = 1;\n\t\tfor (int i = 0; i < env->lines[old_line]->actual; ++i) {\n\t\t\tif (env->lines[old_line]->text[i].codepoint != ' ' &&\n\t\t\t\tenv->lines[old_line]->text[i].codepoint != '\\t') {\n\t\t\t\twas_whitespace = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (was_whitespace) {\n\t\t\twhile (env->lines[old_line]->actual) {\n\t\t\t\tline_delete(env->lines[old_line], env->lines[old_line]->actual, old_line);\n\t\t\t}\n\t\t}\n\t\tif (changed) {\n\t\t\trecalculate_syntax(env->lines[new_line],new_line);\n\t\t}\n\t}\n}\n\n/**\n * Initialize a buffer with default values\n */\nvoid setup_buffer(buffer_t * env) {\n\t/* If this buffer was already initialized, clear out its line data */\n\tif (env->lines) {\n\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\tfree(env->lines[i]);\n\t\t}\n\t\tfree(env->lines);\n\t}\n\n\t/* Default state parameters */\n\tenv->line_no     = 1; /* Default cursor position */\n\tenv->col_no      = 1;\n\tenv->line_count  = 1; /* Buffers always have at least one line */\n\tenv->modified    = 0;\n\tenv->readonly    = 0;\n\tenv->offset      = 0;\n\tenv->line_avail  = 8; /* Default line buffer capacity */\n\tenv->tabs        = 1; /* Tabs by default */\n\tenv->tabstop     = 4; /* Tab stop width */\n\tenv->indent      = 1; /* Auto-indent by default */\n\tenv->history     = malloc(sizeof(struct history));\n\tmemset(env->history, 0, sizeof(struct history));\n\tenv->last_save_history = env->history;\n\n\t/* Allocate line buffer */\n\tenv->lines = malloc(sizeof(line_t *) * env->line_avail);\n\n\t/* Initialize the first line */\n\tenv->lines[0] = malloc(sizeof(line_t) + sizeof(char_t) * 32);\n\tenv->lines[0]->available = 32;\n\tenv->lines[0]->actual    = 0;\n\tenv->lines[0]->istate    = 0;\n}\n\n/**\n * Toggle buffered / unbuffered modes\n */\nstruct termios old;\nvoid get_initial_termios(void) {\n\ttcgetattr(STDOUT_FILENO, &old);\n}\n\nvoid set_unbuffered(void) {\n\tstruct termios new = old;\n\tnew.c_iflag &= (~ICRNL);\n\tnew.c_lflag &= (~ICANON) & (~ECHO);\n\tnew.c_cc[VINTR] = 0;\n\ttcsetattr(STDOUT_FILENO, TCSAFLUSH, &new);\n}\n\nvoid set_buffered(void) {\n\ttcsetattr(STDOUT_FILENO, TCSAFLUSH, &old);\n}\n\n/**\n * Convert codepoint to utf-8 string\n */\nint to_eight(uint32_t codepoint, char * out) {\n\tmemset(out, 0x00, 7);\n\n\tif (codepoint < 0x0080) {\n\t\tout[0] = (char)codepoint;\n\t} else if (codepoint < 0x0800) {\n\t\tout[0] = 0xC0 | (codepoint >> 6);\n\t\tout[1] = 0x80 | (codepoint & 0x3F);\n\t} else if (codepoint < 0x10000) {\n\t\tout[0] = 0xE0 | (codepoint >> 12);\n\t\tout[1] = 0x80 | ((codepoint >> 6) & 0x3F);\n\t\tout[2] = 0x80 | (codepoint & 0x3F);\n\t} else if (codepoint < 0x200000) {\n\t\tout[0] = 0xF0 | (codepoint >> 18);\n\t\tout[1] = 0x80 | ((codepoint >> 12) & 0x3F);\n\t\tout[2] = 0x80 | ((codepoint >> 6) & 0x3F);\n\t\tout[3] = 0x80 | ((codepoint) & 0x3F);\n\t} else if (codepoint < 0x4000000) {\n\t\tout[0] = 0xF8 | (codepoint >> 24);\n\t\tout[1] = 0x80 | (codepoint >> 18);\n\t\tout[2] = 0x80 | ((codepoint >> 12) & 0x3F);\n\t\tout[3] = 0x80 | ((codepoint >> 6) & 0x3F);\n\t\tout[4] = 0x80 | ((codepoint) & 0x3F);\n\t} else {\n\t\tout[0] = 0xF8 | (codepoint >> 30);\n\t\tout[1] = 0x80 | ((codepoint >> 24) & 0x3F);\n\t\tout[2] = 0x80 | ((codepoint >> 18) & 0x3F);\n\t\tout[3] = 0x80 | ((codepoint >> 12) & 0x3F);\n\t\tout[4] = 0x80 | ((codepoint >> 6) & 0x3F);\n\t\tout[5] = 0x80 | ((codepoint) & 0x3F);\n\t}\n\n\treturn strlen(out);\n}\n\n/**\n * Get the presentation width of a codepoint\n */\nint codepoint_width(wchar_t codepoint) {\n\tif (codepoint == '\\t') {\n\t\treturn 1; /* Recalculate later */\n\t}\n\tif (codepoint < 32) {\n\t\t/* We render these as ^@ */\n\t\treturn 2;\n\t}\n\tif (codepoint == 0x7F) {\n\t\t/* Renders as ^? */\n\t\treturn 2;\n\t}\n\tif (codepoint > 0x7f && codepoint < 0xa0) {\n\t\t/* Upper control bytes <xx> */\n\t\treturn 4;\n\t}\n\tif (codepoint == 0xa0) {\n\t\t/* Non-breaking space _ */\n\t\treturn 1;\n\t}\n\t/* Skip wcwidth for anything under 256 */\n\tif (codepoint > 256) {\n\t\tif (global_config.can_unicode) {\n\t\t\t/* Higher codepoints may be wider (eg. Japanese) */\n\t\t\tint out = wcwidth(codepoint);\n\t\t\tif (out >= 1) return out;\n\t\t}\n\t\t/* Invalid character, render as [U+ABCD] or [U+ABCDEF] */\n\t\treturn (codepoint < 0x10000) ? 8 : 10;\n\t}\n\treturn 1;\n}\n\n/**\n * Move the terminal cursor\n */\nvoid place_cursor(int x, int y) {\n\tprintf(\"\\033[%d;%dH\", y, x);\n\tfflush(stdout);\n}\n\n/**\n * Set text colors\n *\n * Normally, text colors are just strings, but if they\n * start with @ they will be parsed as integers\n * representing one of the 16 standard colors, suitable\n * for terminals without support for the 256- or 24-bit\n * color modes.\n */\nvoid set_colors(const char * fg, const char * bg) {\n\tprintf(\"\\033[22;23;\");\n\tif (*bg == '@') {\n\t\tint _bg = atoi(bg+1);\n\t\tif (_bg < 10) {\n\t\t\tprintf(\"4%d;\", _bg);\n\t\t} else {\n\t\t\tprintf(\"10%d;\", _bg-10);\n\t\t}\n\t} else {\n\t\tprintf(\"48;%s;\", bg);\n\t}\n\tif (*fg == '@') {\n\t\tint _fg = atoi(fg+1);\n\t\tif (_fg < 10) {\n\t\t\tprintf(\"3%dm\", _fg);\n\t\t} else {\n\t\t\tprintf(\"9%dm\", _fg-10);\n\t\t}\n\t} else {\n\t\tprintf(\"38;%sm\", fg);\n\t}\n\tfflush(stdout);\n}\n\n/**\n * Set just the foreground color\n *\n * (See set_colors above)\n */\nvoid set_fg_color(const char * fg) {\n\tprintf(\"\\033[22;23;\");\n\tif (*fg == '@') {\n\t\tint _fg = atoi(fg+1);\n\t\tif (_fg < 10) {\n\t\t\tprintf(\"3%dm\", _fg);\n\t\t} else {\n\t\t\tprintf(\"9%dm\", _fg-10);\n\t\t}\n\t} else {\n\t\tprintf(\"38;%sm\", fg);\n\t}\n\tfflush(stdout);\n}\n\n/**\n * Clear the rest of this line\n */\nvoid clear_to_end(void) {\n\tif (global_config.can_bce) {\n\t\tprintf(\"\\033[K\");\n\t\tfflush(stdout);\n\t}\n}\n\n/**\n * For terminals without bce,\n * prepaint the whole line, so we don't have to track\n * where the cursor is for everything. Inefficient,\n * but effective.\n */\nvoid paint_line(const char * bg) {\n\tif (!global_config.can_bce) {\n\t\tset_colors(COLOR_FG, bg);\n\t\tfor (int i = 0; i < global_config.term_width; ++i) {\n\t\t\tprintf(\" \");\n\t\t}\n\t\tprintf(\"\\r\");\n\t}\n}\n\n/**\n * Enable bold text display\n */\nvoid set_bold(void) {\n\tprintf(\"\\033[1m\");\n\tfflush(stdout);\n}\n\n/**\n * Enable underlined text display\n */\nvoid set_underline(void) {\n\tprintf(\"\\033[4m\");\n\tfflush(stdout);\n}\n\n/**\n * Reset text display attributes\n */\nvoid reset(void) {\n\tprintf(\"\\033[0m\");\n\tfflush(stdout);\n}\n\n/**\n * Clear the entire screen\n */\nvoid clear_screen(void) {\n\tprintf(\"\\033[H\\033[2J\");\n\tfflush(stdout);\n}\n\n/**\n * Hide the cursor\n */\nvoid hide_cursor(void) {\n\tif (global_config.can_hideshow) {\n\t\tprintf(\"\\033[?25l\");\n\t}\n\tfflush(stdout);\n}\n\n/*\n * Show the cursor\n */\nvoid show_cursor(void) {\n\tif (global_config.can_hideshow) {\n\t\tprintf(\"\\033[?25h\");\n\t}\n\tfflush(stdout);\n}\n\n/**\n * Request mouse events\n */\nvoid mouse_enable(void) {\n\tif (global_config.can_mouse) {\n\t\tprintf(\"\\033[?1000h\");\n\t}\n\tfflush(stdout);\n}\n\n/**\n * Stop mouse events\n */\nvoid mouse_disable(void) {\n\tif (global_config.can_mouse) {\n\t\tprintf(\"\\033[?1000l\");\n\t}\n\tfflush(stdout);\n}\n\n/**\n * Shift the screen up one line\n */\nvoid shift_up(void) {\n\tprintf(\"\\033[1S\");\n}\n\n/**\n * Shift the screen down one line.\n */\nvoid shift_down(void) {\n\tprintf(\"\\033[1T\");\n}\n\n/**\n * Switch to the alternate terminal screen.\n */\nvoid set_alternate_screen(void) {\n\tif (global_config.can_altscreen) {\n\t\tprintf(\"\\033[?1049h\");\n\t}\n}\n\n/**\n * Restore the standard terminal screen.\n */\nvoid unset_alternate_screen(void) {\n\tif (global_config.can_altscreen) {\n\t\tprintf(\"\\033[?1049l\");\n\t}\n}\n\nchar * file_basename(char * file) {\n\tchar * c = strrchr(file, '/');\n\tif (!c) return file;\n\treturn (c+1);\n}\n\nint draw_tab_name(buffer_t * _env, char * out) {\n\treturn sprintf(out, \"%s %.40s \",\n\t\t_env->modified ? \" +\" : \"\",\n\t\t_env->file_name ? file_basename(_env->file_name) : \"[No Name]\");\n}\n\n/**\n * Redaw the tabbar, with a tab for each buffer.\n *\n * The active buffer is highlighted.\n */\nvoid redraw_tabbar(void) {\n\t/* Hide cursor while rendering UI */\n\thide_cursor();\n\n\t/* Move to upper left */\n\tplace_cursor(1,1);\n\n\tpaint_line(COLOR_TABBAR_BG);\n\n\t/* For each buffer... */\n\tint offset = 0;\n\tfor (int i = 0; i < buffers_len; i++) {\n\t\tbuffer_t * _env = buffers[i];\n\n\t\tif (_env == env) {\n\t\t\t/* If this is the active buffer, hilight it */\n\t\t\treset();\n\t\t\tset_colors(COLOR_FG, COLOR_BG);\n\t\t\tset_bold();\n\t\t} else {\n\t\t\t/* Otherwise use default tab color */\n\t\t\treset();\n\t\t\tset_colors(COLOR_FG, COLOR_TAB_BG);\n\t\t\tset_underline();\n\t\t}\n\n\t\tchar title[64];\n\t\tint size = draw_tab_name(_env, title);\n\n\t\tif (offset + size >= global_config.term_width) {\n\t\t\tif (global_config.term_width - offset - 1 > 0) {\n\t\t\t\tprintf(\"%*s\", global_config.term_width - offset - 1, title);\n\t\t\t}\n\t\t\tbreak;\n\t\t} else {\n\t\t\tprintf(\"%s\", title);\n\t\t}\n\n\t\toffset += size;\n\t}\n\n\t/* Reset bold/underline */\n\treset();\n\t/* Fill the rest of the tab bar */\n\tset_colors(COLOR_FG, COLOR_TABBAR_BG);\n\tclear_to_end();\n}\n\n/**\n * Braindead log10 implementation for the line numbers\n */\nint log_base_10(unsigned int v) {\n\tint r = (v >= 1000000000) ? 9 : (v >= 100000000) ? 8 : (v >= 10000000) ? 7 :\n\t\t(v >= 1000000) ? 6 : (v >= 100000) ? 5 : (v >= 10000) ? 4 :\n\t\t(v >= 1000) ? 3 : (v >= 100) ? 2 : (v >= 10) ? 1 : 0;\n\treturn r;\n}\n\n/**\n * Render a line of text\n *\n * This handles rendering the actual text content. A full line of text\n * also includes a line number and some padding.\n *\n * width: width of the text display region (term width - line number width)\n * offset: how many cells into the line to start rendering at\n */\nvoid render_line(line_t * line, int width, int offset) {\n\tint i = 0; /* Offset in char_t line data entries */\n\tint j = 0; /* Offset in terminal cells */\n\n\tconst char * last_color = NULL;\n\tint was_selecting = 0, was_searching = 0;\n\n\t/* Set default text colors */\n\tset_colors(COLOR_FG, COLOR_BG);\n\n\t/*\n\t * When we are rendering in the middle of a wide character,\n\t * we render -'s to fill the remaining amount of the \n\t * charater's width\n\t */\n\tint remainder = 0;\n\n\t/* For each character in the line ... */\n\twhile (i < line->actual) {\n\n\t\t/* If there is remaining text... */\n\t\tif (remainder) {\n\n\t\t\t/* If we should be drawing by now... */\n\t\t\tif (j >= offset) {\n\t\t\t\t/* Fill remainder with -'s */\n\t\t\t\tset_colors(COLOR_ALT_FG, COLOR_ALT_BG);\n\t\t\t\tprintf(\"-\");\n\t\t\t\tset_colors(COLOR_FG, COLOR_BG);\n\t\t\t}\n\n\t\t\t/* One less remaining width cell to fill */\n\t\t\tremainder--;\n\n\t\t\t/* Terminal offset moves forward */\n\t\t\tj++;\n\n\t\t\t/*\n\t\t\t * If this was the last remaining character, move to\n\t\t\t * the next codepoint in the line\n\t\t\t */\n\t\t\tif (remainder == 0) {\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* Get the next character to draw */\n\t\tchar_t c = line->text[i];\n\n\t\t/* If we should be drawing by now... */\n\t\tif (j >= offset) {\n\n\t\t\t/* If this character is going to fall off the edge of the screen... */\n\t\t\tif (j - offset + c.display_width >= width) {\n\t\t\t\t/* We draw this with special colors so it isn't ambiguous */\n\t\t\t\tset_colors(COLOR_ALT_FG, COLOR_ALT_BG);\n\n\t\t\t\t/* If it's wide, draw ---> as needed */\n\t\t\t\twhile (j - offset < width - 1) {\n\t\t\t\t\tprintf(\"-\");\n\t\t\t\t\tj++;\n\t\t\t\t}\n\n\t\t\t\t/* End the line with a > to show it overflows */\n\t\t\t\tprintf(\">\");\n\t\t\t\tset_colors(COLOR_FG, COLOR_BG);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/* Syntax hilighting */\n\t\t\tconst char * color = flag_to_color(c.flags);\n\t\t\tif (c.flags & FLAG_SELECT) {\n\t\t\t\tset_colors(COLOR_SELECTFG, COLOR_SELECTBG);\n\t\t\t\twas_selecting = 1;\n\t\t\t} else if (c.flags & FLAG_SEARCH) {\n\t\t\t\tset_colors(COLOR_SEARCH_FG, COLOR_SEARCH_BG);\n\t\t\t\twas_searching = 1;\n\t\t\t} else {\n\t\t\t\tif (was_selecting || was_searching) {\n\t\t\t\t\tset_colors(color, COLOR_BG);\n\t\t\t\t\tlast_color = color;\n\t\t\t\t} else if (!last_color || strcmp(color, last_color)) {\n\t\t\t\t\tset_fg_color(color);\n\t\t\t\t\tlast_color = color;\n\t\t\t\t}\n\t\t\t}\n\n#define _set_colors(fg,bg) if (!(c.flags & FLAG_SELECT)) { set_colors(fg,bg); }\n\n\t\t\t/* Render special characters */\n\t\t\tif (c.codepoint == '\\t') {\n\t\t\t\t_set_colors(COLOR_ALT_FG, COLOR_ALT_BG);\n\t\t\t\tif (global_config.can_unicode) {\n\t\t\t\t\tprintf(\"»\");\n\t\t\t\t\tfor (int i = 1; i < c.display_width; ++i) {\n\t\t\t\t\t\tprintf(\"·\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tprintf(\">\");\n\t\t\t\t\tfor (int i = 1; i < c.display_width; ++i) {\n\t\t\t\t\t\tprintf(\"-\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t_set_colors(last_color ? last_color : COLOR_FG, COLOR_BG);\n\t\t\t} else if (c.codepoint < 32) {\n\t\t\t\t/* Codepoints under 32 to get converted to ^@ escapes */\n\t\t\t\t_set_colors(COLOR_ALT_FG, COLOR_ALT_BG);\n\t\t\t\tprintf(\"^%c\", '@' + c.codepoint);\n\t\t\t\t_set_colors(last_color ? last_color : COLOR_FG, COLOR_BG);\n\t\t\t} else if (c.codepoint == 0x7f) {\n\t\t\t\t_set_colors(COLOR_ALT_FG, COLOR_ALT_BG);\n\t\t\t\tprintf(\"^?\");\n\t\t\t\t_set_colors(last_color ? last_color : COLOR_FG, COLOR_BG);\n\t\t\t} else if (c.codepoint > 0x7f && c.codepoint < 0xa0) {\n\t\t\t\t_set_colors(COLOR_ALT_FG, COLOR_ALT_BG);\n\t\t\t\tprintf(\"<%2x>\", c.codepoint);\n\t\t\t\t_set_colors(last_color ? last_color : COLOR_FG, COLOR_BG);\n\t\t\t} else if (c.codepoint == 0xa0) {\n\t\t\t\t_set_colors(COLOR_ALT_FG, COLOR_ALT_BG);\n\t\t\t\tprintf(\"_\");\n\t\t\t\t_set_colors(last_color ? last_color : COLOR_FG, COLOR_BG);\n\t\t\t} else if (c.display_width == 8) {\n\t\t\t\t_set_colors(COLOR_ALT_FG, COLOR_ALT_BG);\n\t\t\t\tprintf(\"[U+%04x]\", c.codepoint);\n\t\t\t\t_set_colors(last_color ? last_color : COLOR_FG, COLOR_BG);\n\t\t\t} else if (c.display_width == 10) {\n\t\t\t\t_set_colors(COLOR_ALT_FG, COLOR_ALT_BG);\n\t\t\t\tprintf(\"[U+%06x]\", c.codepoint);\n\t\t\t\t_set_colors(last_color ? last_color : COLOR_FG, COLOR_BG);\n\t\t\t} else if (c.codepoint == ' ' && i == line->actual - 1) {\n\t\t\t\t/* Special case: space at end of line */\n\t\t\t\t_set_colors(COLOR_ALT_FG, COLOR_ALT_BG);\n\t\t\t\t//printf(\"·\");\n\t\t\t\tprintf(\".\");\n\t\t\t\t_set_colors(COLOR_FG, COLOR_BG);\n\t\t\t} else {\n\t\t\t\t/* Normal characters get output */\n\t\t\t\tchar tmp[7]; /* Max six bytes, use 7 to ensure last is always nil */\n\t\t\t\tto_eight(c.codepoint, tmp);\n\t\t\t\tprintf(\"%s\", tmp);\n\t\t\t}\n\n\t\t\t/* Advance the terminal cell offset by the render width of this character */\n\t\t\tj += c.display_width;\n\n\t\t\t/* Advance to the next character */\n\t\t\ti++;\n\t\t} else if (c.display_width > 1) {\n\t\t\t/*\n\t\t\t * If this is a wide character but we aren't ready to render yet,\n\t\t\t * we may need to draw some filler text for the remainder of its\n\t\t\t * width to ensure we don't jump around when horizontally scrolling\n\t\t\t * past wide characters.\n\t\t\t */\n\t\t\tremainder = c.display_width - 1;\n\t\t\tj++;\n\t\t} else {\n\t\t\t/* Regular character, not ready to draw, advance without doing anything */\n\t\t\tj++;\n\t\t\ti++;\n\t\t}\n\t}\n\n\tif (env->mode != MODE_LINE_SELECTION) {\n\t\tset_colors(COLOR_FG, COLOR_BG);\n\t}\n\n\tif (!global_config.can_bce) {\n\t\t/* Paint the rest of the line */\n\t\tfor (; j < width; ++j) {\n\t\t\tprintf(\" \");\n\t\t}\n\t}\n\n\t/* Clear the rest of the line */\n\tclear_to_end();\n}\n\n/**\n * Get the width of the line number region\n */\nint num_width(void) {\n\tint w = log_base_10(env->line_count) + 1;\n\tif (w < 2) return 2;\n\treturn w;\n}\n\n/**\n * Draw the gutter and line numbers.\n */\nvoid draw_line_number(int x) {\n\t/* Draw the line number */\n\tset_colors(COLOR_NUMBER_FG, COLOR_NUMBER_BG);\n\tint num_size = num_width();\n\tfor (int y = 0; y < num_size - log_base_10(x + 1); ++y) {\n\t\tprintf(\" \");\n\t}\n\tprintf(\"%d%c\", x + 1, (x+1 == env->line_no && env->coffset > 0) ? '<' : ' ');\n}\n\n/**\n * Redraw line.\n *\n * This draws the line number as well as the actual text.\n * j = screen-relative line offset.\n */\nvoid redraw_line(int j, int x) {\n\tif (env->loading) return;\n\t/* Hide cursor when drawing */\n\thide_cursor();\n\n\t/* Move cursor to upper left most cell of this line */\n\tplace_cursor(1,2 + j);\n\n\t/* Draw a gutter on the left.\n\t * TODO: The gutter can be used to show single-character\n\t *       line annotations, such as collapse state, or\n\t *       whether a search result was found on this line.\n\t */\n\tset_colors(COLOR_NUMBER_FG, COLOR_ALT_FG);\n\tprintf(\" \");\n\n\tdraw_line_number(x);\n\n\t/*\n\t * Draw the line text \n\t * If this is the active line, the current character cell offset should be used.\n\t * (Non-active lines are not shifted and always render from the start of the line)\n\t */\n\trender_line(env->lines[x], global_config.term_width - 3 - num_width(), (x + 1 == env->line_no) ? env->coffset : 0);\n}\n\n/**\n * Draw a ~ line where there is no buffer text.\n */\nvoid draw_excess_line(int j) {\n\tplace_cursor(1,2 + j);\n\tpaint_line(COLOR_ALT_BG);\n\tset_colors(COLOR_ALT_FG, COLOR_ALT_BG);\n\tprintf(\"~\");\n\tclear_to_end();\n}\n\n/**\n * Redraw the entire text area\n */\nvoid redraw_text(void) {\n\t/* Hide cursor while rendering */\n\thide_cursor();\n\n\t/* Figure out the available size of the text region */\n\tint l = global_config.term_height - global_config.bottom_size - 1;\n\tint j = 0;\n\n\t/* Draw each line */\n\tfor (int x = env->offset; j < l && x < env->line_count; x++) {\n\t\tredraw_line(j,x);\n\t\tj++;\n\t}\n\n\t/* Draw the rest of the text region as ~ lines */\n\tfor (; j < l; ++j) {\n\t\tdraw_excess_line(j);\n\t}\n}\n\n/**\n * Draw the status bar\n *\n * The status bar shows the name of the file, whether it has modifications,\n * and (in the future) what syntax highlighting mode is enabled.\n *\n * The right side of the tatus bar shows the line number and column.\n */\nvoid redraw_statusbar(void) {\n\t/* Hide cursor while rendering */\n\thide_cursor();\n\n\t/* Move cursor to the status bar line (second from bottom */\n\tplace_cursor(1, global_config.term_height - 1);\n\n\t/* Set background colors for status line */\n\tpaint_line(COLOR_STATUS_BG);\n\tset_colors(COLOR_STATUS_FG, COLOR_STATUS_BG);\n\n\t/* Print the file name */\n\tif (env->file_name) {\n\t\tprintf(\"%s\", env->file_name);\n\t} else {\n\t\tprintf(\"[No Name]\");\n\t}\n\n\tprintf(\" \");\n\n\tif (env->syntax) {\n\t\tprintf(\"[%s]\", env->syntax->name);\n\t}\n\n\t/* Print file status indicators */\n\tif (env->modified) {\n\t\tprintf(\"[+]\");\n\t}\n\n\tif (env->readonly) {\n\t\tprintf(\"[ro]\");\n\t}\n\n\tprintf(\" \");\n\n\tif (env->tabs) {\n\t\tprintf(\"[tabs]\");\n\t} else {\n\t\tprintf(\"[spaces=%d]\", env->tabstop);\n\t}\n\n\tif (global_config.yanks) {\n\t\tprintf(\"[y:%ld]\", global_config.yank_count);\n\t}\n\n\tif (env->indent) {\n\t\tprintf(\"[indent]\");\n\t}\n\n\t/* Clear the rest of the status bar */\n\tclear_to_end();\n\n\t/* Pre-render the right hand side of the status bar */\n\tchar right_hand[1024];\n\tsnprintf(right_hand, 1024, \"Line %d/%d Col: %d \", env->line_no, env->line_count, env->col_no);\n\n\t/* Move the cursor appropriately to draw it */\n\tplace_cursor(global_config.term_width - strlen(right_hand), global_config.term_height - 1);\n\t/* TODO: What if we're localized and this has wide chars? */\n\tprintf(\"%s\",right_hand);\n\tfflush(stdout);\n}\n\n/**\n * Draw the command line\n *\n * The command line either has input from the user (:quit, :!make, etc.)\n * or shows the INSERT (or VISUAL in the future) mode name.\n */\nvoid redraw_commandline(void) {\n\t/* Hide cursor while rendering */\n\thide_cursor();\n\n\t/* Move cursor to the last line */\n\tplace_cursor(1, global_config.term_height);\n\n\t/* Set background color */\n\tpaint_line(COLOR_BG);\n\tset_colors(COLOR_FG, COLOR_BG);\n\n\t/* If we are in an edit mode, note that. */\n\tif (env->mode == MODE_INSERT) {\n\t\tset_bold();\n\t\tprintf(\"-- INSERT --\");\n\t\tclear_to_end();\n\t\treset();\n\t} else if (env->mode == MODE_LINE_SELECTION) {\n\t\tset_bold();\n\t\tprintf(\"-- LINE SELECTION --\");\n\t\tclear_to_end();\n\t\treset();\n\t} else if (env->mode == MODE_REPLACE) {\n\t\tset_bold();\n\t\tprintf(\"-- REPLACE --\");\n\t\tclear_to_end();\n\t\treset();\n\t} else if (env->mode == MODE_CHAR_SELECTION) {\n\t\tset_bold();\n\t\tprintf(\"-- CHAR SELECTION --\");\n\t\tclear_to_end();\n\t\treset();\n\t} else {\n\t\tclear_to_end();\n\t}\n}\n\n/**\n * Draw a message on the command line.\n */\nvoid render_commandline_message(char * message, ...) {\n\t/* varargs setup */\n\tva_list args;\n\tva_start(args, message);\n\tchar buf[1024];\n\n\t/* Process format string */\n\tvsnprintf(buf, 1024, message, args);\n\tva_end(args);\n\n\t/* Hide cursor while rendering */\n\thide_cursor();\n\n\t/* Move cursor to the last line */\n\tplace_cursor(1, global_config.term_height);\n\n\t/* Set background color */\n\tpaint_line(COLOR_BG);\n\tset_colors(COLOR_FG, COLOR_BG);\n\n\tprintf(\"%s\", buf);\n\n\t/* Clear the rest of the status bar */\n\tclear_to_end();\n}\n\n/**\n * Draw all screen elements\n */\nvoid redraw_all(void) {\n\tredraw_tabbar();\n\tredraw_text();\n\tredraw_statusbar();\n\tredraw_commandline();\n}\n\n/**\n * Update the terminal title bar\n */\nvoid update_title(void) {\n\tif (!global_config.can_title) return;\n\n\tchar cwd[1024] = {'/',0};\n\tgetcwd(cwd, 1024);\n\n\tfor (int i = 1; i < 3; ++i) {\n\t\tprintf(\"\\033]%d;%s%s (%s) - BIM\\007\", i, env->file_name ? env->file_name : \"[No Name]\", env->modified ? \" +\" : \"\", cwd);\n\t}\n}\n\n/**\n * Mark this buffer as modified and\n * redraw the status and tabbar if needed.\n */\nvoid set_modified(void) {\n\t/* If it was already marked modified, no need to do anything */\n\tif (env->modified) return;\n\n\t/* Mark as modified */\n\tenv->modified = 1;\n\n\t/* Redraw some things */\n\tupdate_title();\n\tredraw_tabbar();\n\tredraw_statusbar();\n}\n\n/**\n * Draw a message on the status line\n */\nvoid render_status_message(char * message, ...) {\n\t/* varargs setup */\n\tva_list args;\n\tva_start(args, message);\n\tchar buf[1024];\n\n\t/* Process format string */\n\tvsnprintf(buf, 1024, message, args);\n\tva_end(args);\n\n\t/* Hide cursor while rendering */\n\thide_cursor();\n\n\t/* Move cursor to the status bar line (second from bottom */\n\tplace_cursor(1, global_config.term_height - 1);\n\n\t/* Set background colors for status line */\n\tpaint_line(COLOR_STATUS_BG);\n\tset_colors(COLOR_STATUS_FG, COLOR_STATUS_BG);\n\n\tprintf(\"%s\", buf);\n\n\t/* Clear the rest of the status bar */\n\tclear_to_end();\n}\n\n/**\n * Draw an errormessage to the command line.\n */\nvoid render_error(char * message, ...) {\n\t/* varargs setup */\n\tva_list args;\n\tva_start(args, message);\n\tchar buf[1024];\n\n\t/* Process format string */\n\tvsnprintf(buf, 1024, message, args);\n\tva_end(args);\n\n\t/* Hide cursor while rendering */\n\thide_cursor();\n\n\t/* Move cursor to the command line */\n\tplace_cursor(1, global_config.term_height);\n\n\t/* Set appropriate error message colors */\n\tset_colors(COLOR_ERROR_FG, COLOR_ERROR_BG);\n\n\t/* Draw the message */\n\tprintf(\"%s\", buf);\n\tfflush(stdout);\n}\n\nchar * paren_pairs = \"()[]{}<>\";\nvoid find_matching_paren(int * out_line, int * out_col);\n\nint is_paren(int c) {\n\tchar * p = paren_pairs;\n\twhile (*p) {\n\t\tif (c == *p) return 1;\n\t\tp++;\n\t}\n\treturn 0;\n}\n\n/**\n * If the config option is enabled, find the matching\n * paren character and highlight it with the SELECT\n * colors, clearing out other SELECT values. As we\n * co-opt the SELECT flag, don't do this in selection\n * modes - only in normal and insert modes.\n */\nvoid highlight_matching_paren(void) {\n\tif (env->mode == MODE_LINE_SELECTION || env->mode == MODE_CHAR_SELECTION) return;\n\tif (!global_config.highlight_parens) return;\n\tint line = -1, col = -1;\n\tif (env->line_no <= env->line_count && env->col_no <= env->lines[env->line_no-1]->actual &&\n\t\tis_paren(env->lines[env->line_no-1]->text[env->col_no-1].codepoint)) {\n\t\tfind_matching_paren(&line, &col);\n\t\tif (line != -1) env->highlighting_paren = 1;\n\t}\n\tif (!env->highlighting_paren) return;\n\tfor (int i = 0; i < env->line_count; ++i) {\n\t\tint redraw = 0;\n\t\tfor (int j = 0; j < env->lines[i]->actual; ++j) {\n\t\t\tif (i == line-1 && j == col-1) {\n\t\t\t\tenv->lines[line-1]->text[col-1].flags |= FLAG_SELECT;\n\t\t\t\tredraw = 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (env->lines[i]->text[j].flags & FLAG_SELECT) {\n\t\t\t\tredraw = 1;\n\t\t\t}\n\t\t\tenv->lines[i]->text[j].flags &= (~FLAG_SELECT);\n\t\t}\n\t\tif (redraw) {\n\t\t\tif ((i) - env->offset > -1 &&\n\t\t\t\t(i) - env->offset - 1 < global_config.term_height - global_config.bottom_size - 2) {\n\t\t\t\tredraw_line((i) - env->offset, i);\n\t\t\t}\n\t\t}\n\t}\n\tif (line == -1) env->highlighting_paren = 0;\n}\n\n/**\n * Move the cursor to the appropriate location based\n * on where it is in the text region.\n *\n * This does some additional math to set the text\n * region horizontal offset.\n */\nvoid place_cursor_actual(void) {\n\n\t/* Invalid positions */\n\tif (env->line_no < 1) env->line_no = 1;\n\tif (env->col_no  < 1) env->col_no  = 1;\n\n\t/* Account for the left hand gutter */\n\tint num_size = num_width() + 3;\n\tint x = num_size + 1 - env->coffset;\n\n\t/* Determine where the cursor is physically */\n\tfor (int i = 0; i < env->col_no - 1; ++i) {\n\t\tchar_t * c = &env->lines[env->line_no-1]->text[i];\n\t\tx += c->display_width;\n\t}\n\n\t/* y is a bit easier to calculate */\n\tint y = env->line_no - env->offset + 1;\n\n\tint needs_redraw = 0;\n\n\twhile (y < 2 + global_config.cursor_padding && env->offset > 0) {\n\t\ty++;\n\t\tenv->offset--;\n\t\tneeds_redraw = 1;\n\t}\n\n\twhile (y > global_config.term_height - global_config.bottom_size - global_config.cursor_padding) {\n\t\ty--;\n\t\tenv->offset++;\n\t\tneeds_redraw = 1;\n\t}\n\n\tif (needs_redraw) {\n\t\tredraw_text();\n\t\tredraw_tabbar();\n\t\tredraw_statusbar();\n\t\tredraw_commandline();\n\t}\n\n\t/* If the cursor has gone off screen to the right... */\n\tif (x > global_config.term_width - 1) {\n\t\t/* Adjust the offset appropriately to scroll horizontally */\n\t\tint diff = x - (global_config.term_width - 1);\n\t\tenv->coffset += diff;\n\t\tx -= diff;\n\t\tredraw_text();\n\t}\n\n\t/* Same for scrolling horizontally to the left */\n\tif (x < num_size + 1) {\n\t\tint diff = (num_size + 1) - x;\n\t\tenv->coffset -= diff;\n\t\tx += diff;\n\t\tredraw_text();\n\t}\n\n\thighlight_matching_paren();\n\n\t/* Move the actual terminal cursor */\n\tplace_cursor(x,y);\n\n\t/* Show the cursor */\n\tshow_cursor();\n}\n\n/**\n * Update screen size\n */\nvoid update_screen_size(void) {\n\tstruct winsize w;\n\tioctl(STDOUT_FILENO, TIOCGWINSZ, &w);\n\tglobal_config.term_width = w.ws_col;\n\tglobal_config.term_height = w.ws_row;\n}\n\n/**\n * Handle terminal size changes\n */\nvoid SIGWINCH_handler(int sig) {\n\t(void)sig;\n\tupdate_screen_size();\n\tredraw_all();\n\n\tsignal(SIGWINCH, SIGWINCH_handler);\n}\n\n/**\n * Handle suspend\n */\nvoid SIGTSTP_handler(int sig) {\n\t(void)sig;\n\tmouse_disable();\n\tset_buffered();\n\treset();\n\tclear_screen();\n\tshow_cursor();\n\tunset_alternate_screen();\n\tfflush(stdout);\n\n\tsignal(SIGTSTP, SIG_DFL);\n\traise(SIGTSTP);\n}\n\nvoid SIGCONT_handler(int sig) {\n\t(void)sig;\n\tset_alternate_screen();\n\tset_unbuffered();\n\tmouse_enable();\n\tredraw_all();\n\tsignal(SIGCONT, SIGCONT_handler);\n\tsignal(SIGTSTP, SIGTSTP_handler);\n}\n\n/**\n * Move the cursor to a specific line.\n */\nvoid goto_line(int line) {\n\n\t/* Respect file bounds */\n\tif (line < 1) line = 1;\n\tif (line > env->line_count) line = env->line_count;\n\n\t/* Move the cursor / text region offsets */\n\tenv->coffset = 0;\n\tenv->offset = line - 1;\n\tenv->line_no = line;\n\tenv->col_no  = 1;\n\tredraw_all();\n}\n\n\n/**\n * UTF-8 parser state\n */\nstatic uint32_t codepoint_r;\nstatic uint32_t state = 0;\n\n#define UTF8_ACCEPT 0\n#define UTF8_REJECT 1\n\nstatic inline uint32_t decode(uint32_t* state, uint32_t* codep, uint32_t byte) {\n\tstatic int state_table[32] = {\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xxxxxxx */\n\t\t1,1,1,1,1,1,1,1,                 /* 10xxxxxx */\n\t\t2,2,2,2,                         /* 110xxxxx */\n\t\t3,3,                             /* 1110xxxx */\n\t\t4,                               /* 11110xxx */\n\t\t1                                /* 11111xxx */\n\t};\n\n\tstatic int mask_bytes[32] = {\n\t\t0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,\n\t\t0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,\n\t\t0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\n\t\t0x1F,0x1F,0x1F,0x1F,\n\t\t0x0F,0x0F,\n\t\t0x07,\n\t\t0x00\n\t};\n\n\tstatic int next[5] = {\n\t\t0,\n\t\t1,\n\t\t0,\n\t\t2,\n\t\t3\n\t};\n\n\tif (*state == UTF8_ACCEPT) {\n\t\t*codep = byte & mask_bytes[byte >> 3];\n\t\t*state = state_table[byte >> 3];\n\t} else if (*state > 0) {\n\t\t*codep = (byte & 0x3F) | (*codep << 6);\n\t\t*state = next[*state];\n\t}\n\treturn *state;\n}\n\n/**\n * Processs (part of) a file and add it to a buffer.\n */\nvoid add_buffer(uint8_t * buf, int size) {\n\tfor (int i = 0; i < size; ++i) {\n\t\tif (!decode(&state, &codepoint_r, buf[i])) {\n\t\t\tuint32_t c = codepoint_r;\n\t\t\tif (c == '\\n') {\n\t\t\t\tenv->lines = add_line(env->lines, env->line_no);\n\t\t\t\tenv->col_no = 1;\n\t\t\t\tenv->line_no += 1;\n\t\t\t} else {\n\t\t\t\tchar_t _c;\n\t\t\t\t_c.codepoint = (uint32_t)c;\n\t\t\t\t_c.flags = 0;\n\t\t\t\t_c.display_width = codepoint_width((wchar_t)c);\n\t\t\t\tline_t * line  = env->lines[env->line_no - 1];\n\t\t\t\tline_t * nline = line_insert(line, _c, env->col_no - 1, env->line_no-1);\n\t\t\t\tif (line != nline) {\n\t\t\t\t\tenv->lines[env->line_no - 1] = nline;\n\t\t\t\t}\n\t\t\t\tenv->col_no += 1;\n\t\t\t}\n\t\t} else if (state == UTF8_REJECT) {\n\t\t\tstate = 0;\n\t\t}\n\t}\n}\n\nstruct syntax_definition * match_syntax(char * file) {\n\tfor (struct syntax_definition * s = syntaxes; s->name; ++s) {\n\t\tfor (char ** ext = s->ext; *ext; ++ext) {\n\t\t\tint i = strlen(file);\n\t\t\tint j = strlen(*ext);\n\n\t\t\tdo {\n\t\t\t\tif (file[i] != (*ext)[j]) break;\n\t\t\t\tif (j == 0) return s;\n\t\t\t\tif (i == 0) break;\n\t\t\t\ti--;\n\t\t\t\tj--;\n\t\t\t} while (1);\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n/**\n * Check if a string is all numbers.\n */\nint is_all_numbers(const char * c) {\n\twhile (*c) {\n\t\tif (!isdigit((int) *c)) return 0;\n\t\tc++;\n\t}\n\treturn 1;\n}\n\n/**\n * Create a new buffer from a file.\n */\nvoid open_file(char * file) {\n\tenv = buffer_new();\n\tenv->loading = 1;\n\n\tsetup_buffer(env);\n\n\tFILE * f;\n\tint init_line = 1;\n\n\tif (!strcmp(file,\"-\")) {\n\t\t/**\n\t\t * Read file from stdin. stderr provides terminal input.\n\t\t */\n\t\tf = stdin;\n\t\tglobal_config.tty_in = STDERR_FILENO;\n\t\tenv->modified = 1;\n\t} else {\n\t\tchar * l = strrchr(file, ':');\n\t\tif (l && is_all_numbers(l+1)) {\n\t\t\t*l = '\\0';\n\t\t\tl++;\n\t\t\tinit_line = atoi(l);\n\t\t}\n\n\t\tstruct stat statbuf;\n\t\tif (!stat(file, &statbuf) && S_ISDIR(statbuf.st_mode)) {\n\t\t\tDIR * dirp = opendir(file);\n\t\t\tif (!dirp) {\n\t\t\t\tenv->loading = 0;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstruct dirent * ent = readdir(dirp);\n\t\t\twhile (ent) {\n\t\t\t\tadd_buffer((unsigned char*)ent->d_name, strlen(ent->d_name));\n\t\t\t\tadd_buffer((unsigned char*)\"\\n\",1);\n\t\t\t\tent = readdir(dirp);\n\t\t\t}\n\t\t\tclosedir(dirp);\n\t\t\tenv->file_name = strdup(file);\n\t\t\tenv->readonly = 1;\n\t\t\tenv->loading = 0;\n\t\t\treturn;\n\t\t}\n\t\tf = fopen(file, \"r\");\n\t\tenv->file_name = strdup(file);\n\t}\n\n\tif (!f) {\n\t\tif (global_config.hilight_on_open) {\n\t\t\tenv->syntax = match_syntax(file);\n\t\t}\n\t\tenv->loading = 0;\n\t\treturn;\n\t}\n\n\tuint8_t buf[BLOCK_SIZE];\n\n\tstate = 0;\n\n\twhile (!feof(f) && !ferror(f)) {\n\t\tsize_t r = fread(buf, 1, BLOCK_SIZE, f);\n\t\tadd_buffer(buf, r);\n\t}\n\n\tif (ferror(f)) {\n\t\tenv->loading = 0;\n\t\treturn;\n\t}\n\n\tif (env->line_no && env->lines[env->line_no-1] && env->lines[env->line_no-1]->actual == 0) {\n\t\t/* Remove blank line from end */\n\t\tremove_line(env->lines, env->line_no-1);\n\t}\n\n\tif (global_config.hilight_on_open) {\n\t\tenv->syntax = match_syntax(file);\n\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\trecalculate_syntax(env->lines[i],i);\n\t\t}\n\t}\n\n\t/* Try to automatically figure out tabs vs. spaces */\n\tint tabs = 0, spaces = 0;\n\tfor (int i = 0; i < env->line_count; ++i) {\n\t\tif (env->lines[i]->actual > 1) { /* Make sure line has at least some text on it */\n\t\t\tif (env->lines[i]->text[0].codepoint == '\\t') tabs++;\n\t\t\tif (env->lines[i]->text[0].codepoint == ' ' &&\n\t\t\t\tenv->lines[i]->text[1].codepoint == ' ') /* Ignore spaces at the start of asterisky C comments */\n\t\t\t\tspaces++;\n\t\t}\n\t}\n\tif (spaces > tabs) {\n\t\tenv->tabs = 0;\n\t}\n\n\t/* TODO figure out tabstop for spaces? */\n\n\tenv->loading = 0;\n\n\tfor (int i = 0; i < env->line_count; ++i) {\n\t\trecalculate_tabs(env->lines[i]);\n\t}\n\n\tif (global_config.go_to_line) {\n\t\tgoto_line(init_line);\n\t}\n\n\tfclose(f);\n}\n\n/**\n * Clean up the terminal and exit the editor.\n */\nvoid quit(void) {\n\tmouse_disable();\n\tset_buffered();\n\treset();\n\tclear_screen();\n\tshow_cursor();\n\tunset_alternate_screen();\n\texit(0);\n}\n\n/**\n * Try to quit, but don't continue if there are\n * modified buffers open.\n */\nvoid try_quit(void) {\n\tfor (int i = 0; i < buffers_len; i++ ) {\n\t\tbuffer_t * _env = buffers[i];\n\t\tif (_env->modified) {\n\t\t\tif (_env->file_name) {\n\t\t\t\trender_error(\"Modifications made to file `%s` in tab %d. Aborting.\", _env->file_name, i+1);\n\t\t\t} else {\n\t\t\t\trender_error(\"Unsaved new file in tab %d. Aborting.\", i+1);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\tquit();\n}\n\n/**\n * Switch to the previous buffer\n */\nvoid previous_tab(void) {\n\tbuffer_t * last = NULL;\n\tfor (int i = 0; i < buffers_len; i++) {\n\t\tbuffer_t * _env = buffers[i];\n\t\tif (_env == env) {\n\t\t\tif (last) {\n\t\t\t\t/* Wrap around */\n\t\t\t\tenv = last;\n\t\t\t\tredraw_all();\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tenv = buffers[buffers_len-1];\n\t\t\t\tredraw_all();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tlast = _env;\n\t}\n}\n\n/**\n * Switch to the next buffer\n */\nvoid next_tab(void) {\n\tfor (int i = 0; i < buffers_len; i++) {\n\t\tbuffer_t * _env = buffers[i];\n\t\tif (_env == env) {\n\t\t\tif (i != buffers_len - 1) {\n\t\t\t\tenv = buffers[i+1];\n\t\t\t\tredraw_all();\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\t/* Wrap around */\n\t\t\t\tenv = buffers[0];\n\t\t\t\tredraw_all();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Write active buffer to file\n */\nvoid write_file(char * file) {\n\tif (!file) {\n\t\trender_error(\"Need a file to write to.\");\n\t\treturn;\n\t}\n\n\tFILE * f = fopen(file, \"w+\");\n\n\tif (!f) {\n\t\trender_error(\"Failed to open file for writing.\");\n\t\treturn;\n\t}\n\n\t/* Go through each line and convert it back to UTF-8 */\n\tint i, j;\n\tfor (i = 0; i < env->line_count; ++i) {\n\t\tline_t * line = env->lines[i];\n\t\tfor (j = 0; j < line->actual; j++) {\n\t\t\tchar_t c = line->text[j];\n\t\t\tif (c.codepoint == 0) {\n\t\t\t\tchar buf[1] = {0};\n\t\t\t\tfwrite(buf, 1, 1, f);\n\t\t\t} else {\n\t\t\t\tchar tmp[8] = {0};\n\t\t\t\tint i = to_eight(c.codepoint, tmp);\n\t\t\t\tfwrite(tmp, i, 1, f);\n\t\t\t}\n\t\t}\n\t\tfputc('\\n', f);\n\t}\n\tfclose(f);\n\n\t/* Mark it no longer modified */\n\tenv->modified = 0;\n\tenv->last_save_history = env->history;\n\n\t/* If there was no file name set, set one */\n\tif (!env->file_name) {\n\t\tenv->file_name = malloc(strlen(file) + 1);\n\t\tmemcpy(env->file_name, file, strlen(file) + 1);\n\t}\n\n\tupdate_title();\n\tredraw_all();\n}\n\n/**\n * Close the active buffer\n */\nvoid close_buffer(void) {\n\tbuffer_t * previous_env = env;\n\tbuffer_t * new_env = buffer_close(env);\n\tif (new_env == previous_env) {\n\t\t/* ?? Failed to close buffer */\n\t\trender_error(\"lolwat\");\n\t}\n\t/* No more buffers, exit */\n\tif (!new_env) {\n\t\tquit();\n\t}\n\t/* Clean up the old buffer */\n\tfree(previous_env);\n\n\t/* Set the new active buffer */\n\tenv = new_env;\n\n\t/* Redraw the screen */\n\tredraw_all();\n}\n\nvoid set_preferred_column(void) {\n\tint c = 0;\n\tfor (int i = 0; i < env->lines[env->line_no-1]->actual && i < env->col_no-1; ++i) {\n\t\tc += env->lines[env->line_no-1]->text[i].display_width;\n\t}\n\tenv->preferred_column = c;\n}\n\n/**\n * Move the cursor down one line in the text region\n */\nvoid cursor_down(void) {\n\t/* If this isn't already the last line... */\n\tif (env->line_no < env->line_count) {\n\n\t\t/* Move the cursor down */\n\t\tenv->line_no += 1;\n\n\t\t/* Try to place the cursor horizontally at the preferred column */\n\t\tint _x = 0;\n\t\tfor (int i = 0; i < env->lines[env->line_no-1]->actual; ++i) {\n\t\t\tchar_t * c = &env->lines[env->line_no-1]->text[i];\n\t\t\t_x += c->display_width;\n\t\t\tenv->col_no = i+1;\n\t\t\tif (_x > env->preferred_column) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (env->mode == MODE_INSERT && _x <= env->preferred_column) {\n\t\t\tenv->col_no = env->lines[env->line_no-1]->actual + 1;\n\t\t}\n\n\t\t/*\n\t\t * If the horizontal cursor position exceeds the width the new line,\n\t\t * then move the cursor left to the extent of the new line.\n\t\t *\n\t\t * If we're in insert mode, we can go one cell beyond the end of the line\n\t\t */\n\t\tif (env->col_no > env->lines[env->line_no-1]->actual + (env->mode == MODE_INSERT)) {\n\t\t\tenv->col_no = env->lines[env->line_no-1]->actual + (env->mode == MODE_INSERT);\n\t\t\tif (env->col_no == 0) env->col_no = 1;\n\t\t}\n\n\t\t/*\n\t\t * If the screen was scrolled horizontally, unscroll it;\n\t\t * if it will be scrolled on this line as well, that will\n\t\t * be handled by place_cursor_actual\n\t\t */\n\t\tint redraw = 0;\n\t\tif (env->coffset != 0) {\n\t\t\tenv->coffset = 0;\n\t\t\tredraw = 1;\n\t\t}\n\n\t\t/* If we've scrolled past the bottom of the screen, scroll the screen */\n\t\tif (env->line_no > env->offset + global_config.term_height - global_config.bottom_size - 1 - global_config.cursor_padding) {\n\t\t\tenv->offset += 1;\n\n\t\t\t/* Tell terminal to scroll */\n\t\t\tif (global_config.can_scroll) {\n\t\t\t\tshift_up();\n\n\t\t\t\t/* A new line appears on screen at the bottom, draw it */\n\t\t\t\tint l = global_config.term_height - global_config.bottom_size - 1;\n\t\t\t\tif (env->offset + l < env->line_count + 1) {\n\t\t\t\t\tredraw_line(l-1, env->offset + l-1);\n\t\t\t\t} else {\n\t\t\t\t\tdraw_excess_line(l - 1);\n\t\t\t\t}\n\n\t\t\t\t/* Redraw elements that were moved by scrolling */\n\t\t\t\tredraw_tabbar();\n\t\t\t\tredraw_statusbar();\n\t\t\t\tredraw_commandline();\n\t\t\t\tplace_cursor_actual();\n\t\t\t} else {\n\t\t\t\tredraw_all();\n\t\t\t}\n\t\t\treturn;\n\t\t} else if (redraw) {\n\t\t\t/* Otherwise, if we need to redraw because of coffset change, do that */\n\t\t\tredraw_text();\n\t\t}\n\n\t\t/* Update the status bar */\n\t\tredraw_statusbar();\n\n\t\t/* Place the terminal cursor again */\n\t\tplace_cursor_actual();\n\t}\n}\n\n/**\n * Move the cursor up one line in the text region\n */\nvoid cursor_up(void) {\n\t/* If this isn't the first line already */\n\tif (env->line_no > 1) {\n\n\t\t/* Move the cursor down */\n\t\tenv->line_no -= 1;\n\n\t\t/* Try to place the cursor horizontally at the preferred column */\n\t\tint _x = 0;\n\t\tfor (int i = 0; i < env->lines[env->line_no-1]->actual; ++i) {\n\t\t\tchar_t * c = &env->lines[env->line_no-1]->text[i];\n\t\t\t_x += c->display_width;\n\t\t\tenv->col_no = i+1;\n\t\t\tif (_x > env->preferred_column) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (env->mode == MODE_INSERT && _x <= env->preferred_column) {\n\t\t\tenv->col_no = env->lines[env->line_no-1]->actual + 1;\n\t\t}\n\n\t\t/*\n\t\t * If the horizontal cursor position exceeds the width the new line,\n\t\t * then move the cursor left to the extent of the new line.\n\t\t *\n\t\t * If we're in insert mode, we can go one cell beyond the end of the line\n\t\t */\n\t\tif (env->col_no > env->lines[env->line_no-1]->actual + (env->mode == MODE_INSERT)) {\n\t\t\tenv->col_no = env->lines[env->line_no-1]->actual + (env->mode == MODE_INSERT);\n\t\t\tif (env->col_no == 0) env->col_no = 1;\n\t\t}\n\n\t\t/*\n\t\t * If the screen was scrolled horizontally, unscroll it;\n\t\t * if it will be scrolled on this line as well, that will\n\t\t * be handled by place_cursor_actual\n\t\t */\n\t\tint redraw = 0;\n\t\tif (env->coffset != 0) {\n\t\t\tenv->coffset = 0;\n\t\t\tredraw = 1;\n\t\t}\n\n\t\tint e = (env->offset == 0) ? env->offset : env->offset + global_config.cursor_padding;\n\t\tif (env->line_no <= e) {\n\t\t\tenv->offset -= 1;\n\n\t\t\t/* Tell terminal to scroll */\n\t\t\tif (global_config.can_scroll) {\n\t\t\t\tshift_down();\n\n\t\t\t\t/*\n\t\t\t\t * The line at the top of the screen should always be real\n\t\t\t\t * so we can just call redraw_line here\n\t\t\t\t */\n\t\t\t\tredraw_line(0,env->offset);\n\n\t\t\t\t/* Redraw elements that were moved by scrolling */\n\t\t\t\tredraw_tabbar();\n\t\t\t\tredraw_statusbar();\n\t\t\t\tredraw_commandline();\n\t\t\t\tplace_cursor_actual();\n\t\t\t} else {\n\t\t\t\tredraw_all();\n\t\t\t}\n\t\t\treturn;\n\t\t} else if (redraw) {\n\t\t\t/* Otherwise, if we need to redraw because of coffset change, do that */\n\t\t\tredraw_text();\n\t\t}\n\n\t\t/* Update the status bar */\n\t\tredraw_statusbar();\n\n\t\t/* Place the terminal cursor again */\n\t\tplace_cursor_actual();\n\t}\n}\n\n/**\n * Move the cursor one column left.\n */\nvoid cursor_left(void) {\n\tif (env->col_no > 1) {\n\t\tenv->col_no -= 1;\n\n\t\t/* Update the status bar */\n\t\tredraw_statusbar();\n\n\t\t/* Place the terminal cursor again */\n\t\tplace_cursor_actual();\n\t}\n\tset_preferred_column();\n}\n\n/**\n * Move the cursor one column right.\n */\nvoid cursor_right(void) {\n\n\t/* If this isn't already the rightmost column we can reach on this line in this mode... */\n\tif (env->col_no < env->lines[env->line_no-1]->actual + !!(env->mode == MODE_INSERT)) {\n\t\tenv->col_no += 1;\n\n\t\t/* Update the status bar */\n\t\tredraw_statusbar();\n\n\t\t/* Place the terminal cursor again */\n\t\tplace_cursor_actual();\n\t}\n\tset_preferred_column();\n}\n\n/**\n * Move the cursor to the fron the of the line\n */\nvoid cursor_home(void) {\n\tenv->col_no = 1;\n\tset_preferred_column();\n\n\t/* Update the status bar */\n\tredraw_statusbar();\n\n\t/* Place the terminal cursor again */\n\tplace_cursor_actual();\n}\n\n/**\n * Move the cursor to the end of the line.\n *\n * In INSERT mode, moves one cell right of the end of the line.\n * In NORMAL mode, moves the cursor to the last occupied cell.\n */\nvoid cursor_end(void) {\n\tenv->col_no = env->lines[env->line_no-1]->actual+!!(env->mode == MODE_INSERT);\n\tset_preferred_column();\n\n\t/* Update the status bar */\n\tredraw_statusbar();\n\n\t/* Place the terminal cursor again */\n\tplace_cursor_actual();\n}\n\n/**\n * Leave INSERT mode\n *\n * If the cursor is too far right, adjust it.\n * Redraw the command line.\n */\nvoid leave_insert(void) {\n\tif (env->col_no > env->lines[env->line_no-1]->actual) {\n\t\tenv->col_no = env->lines[env->line_no-1]->actual;\n\t\tif (env->col_no == 0) env->col_no = 1;\n\t\tset_preferred_column();\n\t}\n\tset_history_break();\n\tenv->mode = MODE_NORMAL;\n\tredraw_commandline();\n}\n\n/**\n * Process a user command.\n */\nvoid process_command(char * cmd) {\n\t/* Special case ! to run shell commands without parsing tokens */\n\tint c;\n\tif (*cmd == '!') {\n\t\t/* Reset and draw some line feeds */\n\t\treset();\n\t\tprintf(\"\\n\\n\");\n\n\t\t/* Set buffered for shell application */\n\t\tset_buffered();\n\n\t\t/* Call the shell and wait for completion */\n\t\tsystem(&cmd[1]);\n\n\t\t/* Return to the editor, wait for user to press enter. */\n\t\tset_unbuffered();\n\t\tprintf(\"\\n\\nPress ENTER to continue.\");\n\t\tfflush(stdout);\n\t\twhile ((c = bim_getch(), c != ENTER_KEY && c != LINE_FEED));\n\n\t\t/* Redraw the screen */\n\t\tredraw_all();\n\n\t\t/* Done processing command */\n\t\treturn;\n\t}\n\n\t/* Tokenize argument string on spaces */\n\tchar *p, *argv[512], *last;\n\tint argc = 0;\n\tfor ((p = strtok_r(cmd, \" \", &last)); p;\n\t\t\t(p = strtok_r(NULL, \" \", &last)), argc++) {\n\t\tif (argc < 511) argv[argc] = p;\n\t}\n\targv[argc] = NULL;\n\n\tif (argc < 1) {\n\t\t/* no op */\n\t\treturn;\n\t}\n\n\tif (!strcmp(argv[0], \"e\")) {\n\t\t/* e: edit file */\n\t\tif (argc > 1) {\n\t\t\t/* This actually opens a new tab */\n\t\t\topen_file(argv[1]);\n\t\t\tupdate_title();\n\t\t} else {\n\t\t\t/* TODO: Reopen file? */\n\t\t\trender_error(\"Expected a file to open...\");\n\t\t}\n\t} else if (!strcmp(argv[0], \"tabnew\")) {\n\t\tif (argc > 1) {\n\t\t\topen_file(argv[1]);\n\t\t\tupdate_title();\n\t\t} else {\n\t\t\tenv = buffer_new();\n\t\t\tsetup_buffer(env);\n\t\t\tredraw_all();\n\t\t\tupdate_title();\n\t\t}\n\t} else if (!strcmp(argv[0], \"w\")) {\n\t\t/* w: write file */\n\t\tif (argc > 1) {\n\t\t\twrite_file(argv[1]);\n\t\t} else {\n\t\t\twrite_file(env->file_name);\n\t\t}\n\t} else if (!strcmp(argv[0], \"wq\")) {\n\t\t/* wq: write file and close buffer; if there's no file to write to, may do weird things */\n\t\twrite_file(env->file_name);\n\t\tclose_buffer();\n\t} else if (!strcmp(argv[0], \"q\")) {\n\t\t/* close buffer if unmodified */\n\t\tif (env->modified) {\n\t\t\trender_error(\"No write since last change. Use :q! to force exit.\");\n\t\t} else {\n\t\t\tclose_buffer();\n\t\t}\n\t} else if (!strcmp(argv[0], \"q!\")) {\n\t\t/* close buffer without warning if unmodified */\n\t\tclose_buffer();\n\t} else if (!strcmp(argv[0], \"qa\") || !strcmp(argv[0], \"qall\")) {\n\t\t/* Close all */\n\t\ttry_quit();\n\t} else if (!strcmp(argv[0], \"qa!\")) {\n\t\t/* Forcefully exit editor */\n\t\tquit();\n\t} else if (!strcmp(argv[0], \"tabp\")) {\n\t\t/* Next tab */\n\t\tprevious_tab();\n\t\tupdate_title();\n\t} else if (!strcmp(argv[0], \"tabn\")) {\n\t\t/* Previous tab */\n\t\tnext_tab();\n\t\tupdate_title();\n\t} else if (!strcmp(argv[0], \"indent\")) {\n\t\tenv->indent = 1;\n\t\tredraw_statusbar();\n\t} else if (!strcmp(argv[0], \"noindent\")) {\n\t\tenv->indent = 0;\n\t\tredraw_statusbar();\n\t} else if (!strcmp(argv[0], \"cursorcolumn\")) {\n\t\trender_status_message(\"cursorcolumn=%d\", env->preferred_column);\n\t} else if (!strcmp(argv[0], \"noh\")) {\n\t\tif (env->search) {\n\t\t\tfree(env->search);\n\t\t\tenv->search = NULL;\n\t\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\t\trecalculate_syntax(env->lines[i],i);\n\t\t\t}\n\t\t\tredraw_text();\n\t\t}\n\t} else if (!strcmp(argv[0], \"help\")) {\n\t\t/*\n\t\t * The repeated calls to redraw_commandline here make use\n\t\t * of scrolling to draw this multiline help message on\n\t\t * the same background as the command line.\n\t\t */\n\t\trender_commandline_message(\"\"); /* To clear command line */\n\t\trender_commandline_message(\"\\n\");\n\t\trender_commandline_message(\" \\033[1mbim - The standard ToaruOS Text Editor\\033[22m\\n\");\n\t\trender_commandline_message(\"\\n\");\n\t\trender_commandline_message(\" Available commands:\\n\");\n\t\trender_commandline_message(\"   Quit with \\033[3m:q\\033[23m, \\033[3m:qa\\033[23m, \\033[3m:q!\\033[23m, \\033[3m:qa!\\033[23m\\n\");\n\t\trender_commandline_message(\"   Write out with \\033[3m:w \\033[4mfile\\033[24;23m\\n\");\n\t\trender_commandline_message(\"   Set syntax with \\033[3m:syntax \\033[4mlanguage\\033[24;23m\\n\");\n\t\trender_commandline_message(\"   Open a new tab with \\033[3m:e \\033[4mpath/to/file\\033[24;23m\\n\");\n\t\trender_commandline_message(\"   \\033[3m:tabn\\033[23m and \\033[3m:tabp\\033[23m can be used to switch tabs\\n\");\n\t\trender_commandline_message(\"   Set the color scheme with \\033[3m:theme \\033[4mtheme\\033[24;23m\\n\");\n\t\trender_commandline_message(\"   Set the behavior of the tab key with \\033[3m:tabs\\033[23m or \\033[3m:spaces\\033[23m\\n\");\n\t\trender_commandline_message(\"   Set tabstop with \\033[3m:tabstop \\033[4mwidth\\033[24;23m\\n\");\n\t\trender_commandline_message(\"\\n\");\n\t\trender_commandline_message(\" %s\\n\", BIM_COPYRIGHT);\n\t\trender_commandline_message(\"\\n\");\n\t\t/* Redrawing the tabbar makes it look like we just shifted the whole view up */\n\t\tredraw_tabbar();\n\t\tredraw_commandline();\n\t\tfflush(stdout);\n\t\t/* Wait for a character so we can redraw the screen before continuing */\n\t\tint c;\n\t\twhile ((c = bim_getch())== -1);\n\t\t/* Make sure that key press actually gets used */\n\t\tbim_unget(c);\n\t\t/*\n\t\t * Redraw everything to hide the help message and get the\n\t\t * upper few lines of text on screen again\n\t\t */\n\t\tredraw_all();\n\t} else if (!strcmp(argv[0], \"theme\")) {\n\t\tif (argc < 2) {\n\t\t\trender_status_message(\"theme=%s\", current_theme);\n\t\t\treturn;\n\t\t}\n\t\tfor (struct theme_def * d = themes; d->name; ++d) {\n\t\t\tif (!strcmp(argv[1], d->name)) {\n\t\t\t\td->load();\n\t\t\t\tredraw_all();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t} else if (!strcmp(argv[0], \"syntax\")) {\n\t\tif (argc < 2) {\n\t\t\trender_status_message(\"syntax=%s\", env->syntax ? env->syntax->name : \"none\");\n\t\t\treturn;\n\t\t}\n\t\tif (!strcmp(argv[1],\"none\")) {\n\t\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\t\tenv->lines[i]->istate = 0;\n\t\t\t\tfor (int j = 0; j < env->lines[i]->actual; ++j) {\n\t\t\t\t\tenv->lines[i]->text[j].flags = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\tredraw_all();\n\t\t\treturn;\n\t\t}\n\t\tfor (struct syntax_definition * s = syntaxes; s->name; ++s) {\n\t\t\tif (!strcmp(argv[1],s->name)) {\n\t\t\t\tenv->syntax = s;\n\t\t\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\t\t\tenv->lines[i]->istate = 0;\n\t\t\t\t}\n\t\t\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\t\t\trecalculate_syntax(env->lines[i],i);\n\t\t\t\t}\n\t\t\t\tredraw_all();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\trender_error(\"unrecognized syntax type\");\n\t} else if (!strcmp(argv[0], \"recalc\")) {\n\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\tenv->lines[i]->istate = 0;\n\t\t}\n\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\trecalculate_syntax(env->lines[i],i);\n\t\t}\n\t\tredraw_all();\n\t} else if (!strcmp(argv[0], \"tabs\")) {\n\t\tenv->tabs = 1;\n\t\tredraw_statusbar();\n\t} else if (!strcmp(argv[0], \"spaces\")) {\n\t\tenv->tabs = 0;\n\t\tredraw_statusbar();\n\t} else if (!strcmp(argv[0], \"tabstop\")) {\n\t\tif (argc < 2) {\n\t\t\trender_status_message(\"tabstop=%d\", env->tabstop);\n\t\t} else {\n\t\t\tint t = atoi(argv[1]);\n\t\t\tif (t > 0 && t < 32) {\n\t\t\t\tenv->tabstop = t;\n\t\t\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\t\t\trecalculate_tabs(env->lines[i]);\n\t\t\t\t}\n\t\t\t\tredraw_all();\n\t\t\t} else {\n\t\t\t\trender_error(\"Invalid tabstop: %s\", argv[1]);\n\t\t\t}\n\t\t}\n\t} else if (!strcmp(argv[0], \"clearyank\")) {\n\t\tif (global_config.yanks) {\n\t\t\tfor (unsigned int i = 0; i < global_config.yank_count; ++i) {\n\t\t\t\tfree(global_config.yanks[i]);\n\t\t\t}\n\t\t\tfree(global_config.yanks);\n\t\t\tglobal_config.yanks = NULL;\n\t\t\tglobal_config.yank_count = 0;\n\t\t\tredraw_statusbar();\n\t\t}\n\t} else if (!strcmp(argv[0], \"padding\")) {\n\t\tif (argc < 2) {\n\t\t\trender_status_message(\"padding=%d\", global_config.cursor_padding);\n\t\t} else {\n\t\t\tglobal_config.cursor_padding = atoi(argv[1]);\n\t\t\tplace_cursor_actual();\n\t\t}\n\t} else if (!strcmp(argv[0], \"smartcase\")) {\n\t\tif (argc < 2) {\n\t\t\trender_status_message(\"smartcase=%d\", global_config.smart_case);\n\t\t} else {\n\t\t\tglobal_config.smart_case = atoi(argv[1]);\n\t\t\tplace_cursor_actual();\n\t\t}\n\t} else if (!strcmp(argv[0], \"hlparen\")) {\n\t\tif (argc < 2) {\n\t\t\trender_status_message(\"hlparen=%d\", global_config.highlight_parens);\n\t\t} else {\n\t\t\tglobal_config.highlight_parens = atoi(argv[1]);\n\t\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\t\trecalculate_syntax(env->lines[i],i);\n\t\t\t}\n\t\t\tredraw_text();\n\t\t\tplace_cursor_actual();\n\t\t}\n\t} else if (isdigit((int) *argv[0])) {\n\t\t/* Go to line number */\n\t\tgoto_line(atoi(argv[0]));\n\t} else {\n\t\t/* Unrecognized command */\n\t\trender_error(\"Not an editor command: %s\", argv[0]);\n\t}\n}\n\n/**\n * Tab completion for command mode.\n */\nvoid command_tab_complete(char * buffer) {\n\t/* Figure out which argument this is and where it starts */\n\tint arg = 0;\n\tchar * buf = strdup(buffer);\n\tchar * b = buf;\n\n\tchar * args[32];\n\n\tint candidate_count= 0;\n\tint candidate_space = 4;\n\tchar ** candidates = malloc(sizeof(char*)*candidate_space);\n\n\t/* Accept whitespace before first argument */\n\twhile (*b == ' ') b++;\n\tchar * start = b;\n\targs[0] = start;\n\twhile (*b && *b != ' ') b++;\n\twhile (*b) {\n\t\twhile (*b == ' ') {\n\t\t\t*b = '\\0';\n\t\t\tb++;\n\t\t}\n\t\tstart = b;\n\t\targ++;\n\t\tif (arg < 32) {\n\t\t\targs[arg] = start;\n\t\t}\n\t\twhile (*b && *b != ' ') b++;\n\t}\n\n\t/**\n\t * Check a possible candidate and add it to the\n\t * candidates list, expanding as necessary,\n\t * if it matches for the current argument.\n\t */\n#define add_candidate(candidate) \\\n\tdo { \\\n\t\tchar * _arg = args[arg]; \\\n\t\tint r = strncmp(_arg, candidate, strlen(_arg)); \\\n\t\tif (!r) { \\\n\t\t\tif (candidate_count == candidate_space) { \\\n\t\t\t\tcandidate_space *= 2; \\\n\t\t\t\tcandidates = realloc(candidates,sizeof(char *) * candidate_space); \\\n\t\t\t} \\\n\t\t\tcandidates[candidate_count] = strdup(candidate); \\\n\t\t\tcandidate_count++; \\\n\t\t} \\\n\t} while (0)\n\n\tif (arg == 0) {\n\t\t/* Complete command names */\n\t\tadd_candidate(\"help\");\n\t\tadd_candidate(\"recalc\");\n\t\tadd_candidate(\"syntax\");\n\t\tadd_candidate(\"tabn\");\n\t\tadd_candidate(\"tabp\");\n\t\tadd_candidate(\"tabnew\");\n\t\tadd_candidate(\"theme\");\n\t\tadd_candidate(\"tabs\");\n\t\tadd_candidate(\"tabstop\");\n\t\tadd_candidate(\"spaces\");\n\t\tadd_candidate(\"noh\");\n\t\tadd_candidate(\"clearyank\");\n\t\tadd_candidate(\"indent\");\n\t\tadd_candidate(\"noindent\");\n\t\tadd_candidate(\"padding\");\n\t\tadd_candidate(\"hlparen\");\n\t\tadd_candidate(\"cursorcolumn\");\n\t\tadd_candidate(\"smartcase\");\n\t\tgoto _accept_candidate;\n\t}\n\n\tif (arg == 1 && !strcmp(args[0], \"syntax\")) {\n\t\t/* Complete syntax options */\n\t\tadd_candidate(\"none\");\n\t\tfor (struct syntax_definition * s = syntaxes; s->name; ++s) {\n\t\t\tadd_candidate(s->name);\n\t\t}\n\t\tgoto _accept_candidate;\n\t}\n\n\tif (arg == 1 && !strcmp(args[0], \"theme\")) {\n\t\t/* Complete color theme names */\n\t\tfor (struct theme_def * s = themes; s->name; ++s) {\n\t\t\tadd_candidate(s->name);\n\t\t}\n\t\tgoto _accept_candidate;\n\t}\n\n\tif (arg == 1 && (!strcmp(args[0], \"e\") || !strcmp(args[0], \"tabnew\"))) {\n\t\t/* Complete file paths */\n\n\t\t/* First, find the deepest directory match */\n\t\tchar * tmp = strdup(args[arg]);\n\t\tchar * last_slash = strrchr(tmp, '/');\n\t\tDIR * dirp;\n\t\tif (last_slash) {\n\t\t\t*last_slash = '\\0';\n\t\t\tif (last_slash == tmp) {\n\t\t\t\t/* Started with slash, and it was the only slash */\n\t\t\t\tdirp = opendir(\"/\");\n\t\t\t} else {\n\t\t\t\tdirp = opendir(tmp);\n\t\t\t}\n\t\t} else {\n\t\t\t/* No directory match, completing from current directory */\n\t\t\tdirp = opendir(\".\");\n\t\t\ttmp[0] = '\\0';\n\t\t}\n\n\t\tif (!dirp) {\n\t\t\t/* Directory match doesn't exist, no candidates to populate */\n\t\t\tfree(tmp);\n\t\t\tgoto done;\n\t\t}\n\n\t\tstruct dirent * ent = readdir(dirp);\n\t\twhile (ent != NULL) {\n\t\t\tif (ent->d_name[0] != '.' || (last_slash ? (last_slash[1] == '.') : (tmp[0] == '.'))) {\n\t\t\t\tstruct stat statbuf;\n\t\t\t\t/* Figure out if this file is a directory */\n\t\t\t\tif (last_slash) {\n\t\t\t\t\tchar * x = malloc(strlen(tmp) + 1 + strlen(ent->d_name) + 1);\n\t\t\t\t\tsnprintf(x, strlen(tmp) + 1 + strlen(ent->d_name) + 1, \"%s/%s\",tmp,ent->d_name);\n\t\t\t\t\tstat(x, &statbuf);\n\t\t\t\t\tfree(x);\n\t\t\t\t} else {\n\t\t\t\t\tstat(ent->d_name, &statbuf);\n\t\t\t\t}\n\n\t\t\t\t/* Build the complete argument name to tab complete */\n\t\t\t\tchar s[1024] = {0};\n\t\t\t\tif (last_slash == tmp) {\n\t\t\t\t\tstrcat(s,\"/\");\n\t\t\t\t} else if (*tmp) {\n\t\t\t\t\tstrcat(s,tmp);\n\t\t\t\t\tstrcat(s,\"/\");\n\t\t\t\t}\n\t\t\t\tstrcat(s,ent->d_name);\n\t\t\t\t/*\n\t\t\t\t * If it is a directory, add a / to the end so the next completion\n\t\t\t\t * attempt will complete the directory's contents.\n\t\t\t\t */\n\t\t\t\tif (S_ISDIR(statbuf.st_mode)) {\n\t\t\t\t\tstrcat(s,\"/\");\n\t\t\t\t}\n\t\t\t\tadd_candidate(s);\n\t\t\t}\n\t\t\tent = readdir(dirp);\n\t\t}\n\t\tclosedir(dirp);\n\t\tfree(tmp);\n\t\tgoto _accept_candidate;\n\t}\n\n_accept_candidate:\n\tif (candidate_count == 0) {\n\t\tredraw_statusbar();\n\t\tgoto done;\n\t}\n\n\tif (candidate_count == 1) {\n\t\t/* Only one completion possibility */\n\t\tredraw_statusbar();\n\n\t\t/* Fill out the rest of the command */\n\t\tchar * cstart = (buffer) + (start - buf);\n\t\tfor (unsigned int i = 0; i < strlen(candidates[0]); ++i) {\n\t\t\t*cstart = candidates[0][i];\n\t\t\tcstart++;\n\t\t}\n\t\t*cstart = '\\0';\n\t} else {\n\t\t/* Print candidates in status bar */\n\t\tchar * tmp = malloc(global_config.term_width+1);\n\t\tmemset(tmp, 0, global_config.term_width+1);\n\t\tint offset = 0;\n\t\tfor (int i = 0; i < candidate_count; ++i) {\n\t\t\tif (offset + 1 + (signed)strlen(candidates[i]) > global_config.term_width - 5) {\n\t\t\t\tstrcat(tmp, \"...\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (offset > 0) {\n\t\t\t\tstrcat(tmp, \" \");\n\t\t\t\toffset++;\n\t\t\t}\n\t\t\tstrcat(tmp, candidates[i]);\n\t\t\toffset += strlen(candidates[i]);\n\t\t}\n\t\trender_status_message(\"%s\", tmp);\n\t\tfree(tmp);\n\n\t\t/* Complete to longest common substring */\n\t\tchar * cstart = (buffer) + (start - buf);\n\t\tfor (int i = 0; i < 1023 /* max length of command */; i++) {\n\t\t\tfor (int j = 1; j < candidate_count; ++j) {\n\t\t\t\tif (candidates[0][i] != candidates[j][i]) goto _reject;\n\t\t\t}\n\t\t\t*cstart = candidates[0][i];\n\t\t\tcstart++;\n\t\t}\n\t\t/* End of longest common substring */\n_reject:\n\t\t*cstart = '\\0';\n\t}\n\n\t/* Free candidates */\n\tfor (int i = 0; i < candidate_count; ++i) {\n\t\tfree(candidates[i]);\n\t}\n\n\t/* Redraw command line */\ndone:\n\tredraw_commandline();\n\tprintf(\":%s\", buffer);\n\n\tfree(candidates);\n\tfree(buf);\n}\n\n/**\n * Command mode\n *\n * Accept a user command and then process it and\n * return to normal mode.\n *\n * TODO: We only have basic line editing here; it might be\n *       nice to add more advanced line editing, like cursor\n *       movement, tab completion, etc. This is easier than\n *       with the shell since we have a lot more control over\n *       where the command input bar is rendered.\n */\nvoid command_mode(void) {\n\tint c;\n\tchar buffer[1024] = {0};\n\tint  buffer_len = 0;\n\n\tredraw_commandline();\n\tprintf(\":\");\n\tshow_cursor();\n\n\twhile ((c = bim_getch())) {\n\t\tif (c == -1) {\n\t\t\t/* Time out */\n\t\t\tcontinue;\n\t\t}\n\t\tif (c == '\\033') {\n\t\t\t/* Escape, cancel command */\n\t\t\tbreak;\n\t\t} else if (c == ENTER_KEY || c == LINE_FEED) {\n\t\t\t/* Enter, run command */\n\t\t\tprocess_command(buffer);\n\t\t\tbreak;\n\t\t} else if (c == '\\t') {\n\t\t\t/* Handle tab completion */\n\t\t\tcommand_tab_complete(buffer);\n\t\t\tbuffer_len = strlen(buffer);\n\t\t} else if (c == BACKSPACE_KEY || c == DELETE_KEY) {\n\t\t\t/* Backspace, delete last character in command buffer */\n\t\t\tif (buffer_len > 0) {\n\t\t\t\tbuffer_len -= 1;\n\t\t\t\tbuffer[buffer_len] = '\\0';\n\t\t\t\tredraw_commandline();\n\t\t\t\tprintf(\":%s\", buffer);\n\t\t\t} else {\n\t\t\t\t/* If backspaced through entire command, cancel command mode */\n\t\t\t\tredraw_commandline();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\t/* Regular character */\n\t\t\tbuffer[buffer_len] = c;\n\t\t\tbuffer_len++;\n\t\t\tprintf(\"%c\", c);\n\t\t}\n\t\tshow_cursor();\n\t}\n}\n\nint search_matches(uint32_t a, uint32_t b, int mode) {\n\tif (mode == 0) {\n\t\treturn a == b;\n\t} else if (mode == 1) {\n\t\treturn tolower(a) == tolower(b);\n\t}\n\treturn 0;\n}\n\nint smart_case(uint32_t * str) {\n\tif (!global_config.smart_case) return 0;\n\n\tfor (uint32_t * s = str; *s; ++s) {\n\t\tif (tolower(*s) != (int)*s) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\treturn 1;\n}\n\n/**\n * Search forward from the given cursor position\n * to find a basic search match.\n *\n * This could be more complicated...\n */\nvoid find_match(int from_line, int from_col, int * out_line, int * out_col, uint32_t * str) {\n\tint col = from_col;\n\n\tint ignorecase = smart_case(str);\n\n\tfor (int i = from_line; i <= env->line_count; ++i) {\n\t\tline_t * line = env->lines[i - 1];\n\n\t\tint j = col - 1;\n\t\twhile (j < line->actual + 1) {\n\t\t\tint k = j;\n\t\t\tuint32_t * match = str;\n\t\t\twhile (k < line->actual + 1) {\n\t\t\t\tif (*match == '\\0') {\n\t\t\t\t\t*out_line = i;\n\t\t\t\t\t*out_col = j + 1;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!(search_matches(*match, line->text[k].codepoint, ignorecase))) break;\n\t\t\t\tmatch++;\n\t\t\t\tk++;\n\t\t\t}\n\t\t\tj++;\n\t\t}\n\t\tcol = 0;\n\t}\n}\n\n/**\n * Search backwards for matching string.\n */\nvoid find_match_backwards(int from_line, int from_col, int * out_line, int * out_col, uint32_t * str) {\n\tint col = from_col;\n\n\tint ignorecase = smart_case(str);\n\n\tfor (int i = from_line; i >= 1; --i) {\n\t\tline_t * line = env->lines[i-1];\n\n\t\tint j = col - 1;\n\t\twhile (j > -1) {\n\t\t\tint k = j;\n\t\t\tuint32_t * match = str;\n\t\t\twhile (k < line->actual + 1) {\n\t\t\t\tif (*match == '\\0') {\n\t\t\t\t\t*out_line = i;\n\t\t\t\t\t*out_col = j + 1;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!(search_matches(*match, line->text[k].codepoint, ignorecase))) break;\n\t\t\t\tmatch++;\n\t\t\t\tk++;\n\t\t\t}\n\t\t\tj--;\n\t\t}\n\t\tcol = (i > 1) ? (env->lines[i-2]->actual) : -1;\n\t}\n\n}\n\n/**\n * Draw the matched search result.\n */\nvoid draw_search_match(uint32_t * buffer, int redraw_buffer) {\n\tfor (int i = 0; i < env->line_count; ++i) {\n\t\tfor (int j = 0; j < env->lines[i]->actual; ++j) {\n\t\t\tenv->lines[i]->text[j].flags &= (~FLAG_SEARCH);\n\t\t}\n\t}\n\tint line = -1, col = -1, _line = 1, _col = 1;\n\tdo {\n\t\tfind_match(_line, _col, &line, &col, buffer);\n\t\tif (line != -1) {\n\t\t\tline_t * l = env->lines[line-1];\n\t\t\tuint32_t * t = buffer;\n\t\t\tfor (int i = col; *t; ++i, ++t) {\n\t\t\t\tl->text[i-1].flags |= FLAG_SEARCH;\n\t\t\t}\n\t\t}\n\t\t_line = line;\n\t\t_col  = col+1;\n\t\tline  = -1;\n\t\tcol   = -1;\n\t} while (_line != -1);\n\tredraw_text();\n\tplace_cursor_actual();\n\tredraw_statusbar();\n\tredraw_commandline();\n\tif (redraw_buffer != -1) {\n\t\tprintf(redraw_buffer == 1 ? \"/\" : \"?\");\n\t\tuint32_t * c = buffer;\n\t\twhile (*c) {\n\t\t\tchar tmp[7] = {0}; /* Max six bytes, use 7 to ensure last is always nil */\n\t\t\tto_eight(*c, tmp);\n\t\t\tprintf(\"%s\", tmp);\n\t\t\tc++;\n\t\t}\n\t}\n}\n\n/**\n * Search mode\n *\n * Search text for substring match.\n */\nvoid search_mode(int direction) {\n\tuint32_t c;\n\tuint32_t buffer[1024] = {0};\n\tint  buffer_len = 0;\n\n\t/* utf-8 decoding */\n\n\t/* Remember where the cursor is so we can cancel */\n\tint prev_line = env->line_no;\n\tint prev_col  = env->col_no;\n\tint prev_coffset = env->coffset;\n\tint prev_offset = env->offset;\n\n\tredraw_commandline();\n\tprintf(direction == 1 ? \"/\" : \"?\");\n\tshow_cursor();\n\n\tuint32_t state = 0;\n\tint cin;\n\n\twhile ((cin = bim_getch())) {\n\t\tif (cin == -1) {\n\t\t\t/* Time out */\n\t\t\tcontinue;\n\t\t}\n\t\tif (!decode(&state, &c, cin)) {\n\t\t\tif (c == '\\033') {\n\t\t\t\t/* Cancel search */\n\t\t\t\tenv->line_no = prev_line;\n\t\t\t\tenv->col_no  = prev_col;\n\t\t\t\t/* Unhighlight search matches */\n\t\t\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\t\t\tfor (int j = 0; j < env->lines[i]->actual; ++j) {\n\t\t\t\t\t\tenv->lines[i]->text[j].flags &= (~FLAG_SEARCH);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tredraw_all();\n\t\t\t\tbreak;\n\t\t\t} else if (c == ENTER_KEY || c == LINE_FEED) {\n\t\t\t\t/* Exit search */\n\t\t\t\tif (env->search) {\n\t\t\t\t\tfree(env->search);\n\t\t\t\t}\n\t\t\t\tenv->search = malloc((buffer_len + 1) * sizeof(uint32_t));\n\t\t\t\tmemcpy(env->search, buffer, (buffer_len + 1) * sizeof(uint32_t));\n\t\t\t\tbreak;\n\t\t\t} else if (c == BACKSPACE_KEY || c == DELETE_KEY) {\n\t\t\t\t/* Backspace, delete last character in search buffer */\n\t\t\t\tif (buffer_len > 0) {\n\t\t\t\t\tbuffer_len -= 1;\n\t\t\t\t\tbuffer[buffer_len] = '\\0';\n\t\t\t\t\t/* Search from beginning to find first match */\n\t\t\t\t\tint line = -1, col = -1;\n\t\t\t\t\tif (direction == 1) {\n\t\t\t\t\t\tfind_match(prev_line, prev_col, &line, &col, buffer);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfind_match_backwards(prev_line, prev_col, &line, &col, buffer);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (line != -1) {\n\t\t\t\t\t\tenv->col_no = col;\n\t\t\t\t\t\tenv->line_no = line;\n\t\t\t\t\t\tset_preferred_column();\n\t\t\t\t\t}\n\n\t\t\t\t\tdraw_search_match(buffer, direction);\n\n\t\t\t\t} else {\n\t\t\t\t\t/* If backspaced through entire search term, cancel search */\n\t\t\t\t\tredraw_commandline();\n\t\t\t\t\tenv->coffset = prev_coffset;\n\t\t\t\t\tenv->offset = prev_offset;\n\t\t\t\t\tenv->col_no = prev_col;\n\t\t\t\t\tset_preferred_column();\n\t\t\t\t\tenv->line_no = prev_line;\n\t\t\t\t\tredraw_all();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t/* Regular character */\n\t\t\t\tbuffer[buffer_len] = c;\n\t\t\t\tbuffer_len++;\n\t\t\t\tbuffer[buffer_len] = '\\0';\n\t\t\t\tchar tmp[7] = {0}; /* Max six bytes, use 7 to ensure last is always nil */\n\t\t\t\tto_eight(c, tmp);\n\t\t\t\tprintf(\"%s\", tmp);\n\n\t\t\t\t/* Find the next search match */\n\t\t\t\tint line = -1, col = -1;\n\t\t\t\tif (direction == 1) {\n\t\t\t\t\tfind_match(prev_line, prev_col, &line, &col, buffer);\n\t\t\t\t} else {\n\t\t\t\t\tfind_match_backwards(prev_line, prev_col, &line, &col, buffer);\n\t\t\t\t}\n\n\t\t\t\tif (line != -1) {\n\t\t\t\t\tenv->col_no = col;\n\t\t\t\t\tenv->line_no = line;\n\t\t\t\t\tset_preferred_column();\n\t\t\t\t} else {\n\t\t\t\t\tenv->coffset = prev_coffset;\n\t\t\t\t\tenv->offset = prev_offset;\n\t\t\t\t\tenv->col_no = prev_col;\n\t\t\t\t\tset_preferred_column();\n\t\t\t\t\tenv->line_no = prev_line;\n\t\t\t\t}\n\t\t\t\tdraw_search_match(buffer, direction);\n\t\t\t}\n\t\t\tshow_cursor();\n\t\t} else if (state == UTF8_REJECT) {\n\t\t\tstate = 0;\n\t\t}\n\t}\n}\n\n/**\n * Find the next search result, or loop back around if at the end.\n */\nvoid search_next(void) {\n\tif (!env->search) return;\n\tif (env->coffset) env->coffset = 0;\n\tint line = -1, col = -1;\n\tfind_match(env->line_no, env->col_no+1, &line, &col, env->search);\n\n\tif (line == -1) {\n\t\tfind_match(1,1, &line, &col, env->search);\n\t\tif (line == -1) return;\n\t}\n\n\tenv->col_no = col;\n\tenv->line_no = line;\n\tset_preferred_column();\n\tdraw_search_match(env->search, -1);\n}\n\n/**\n * Find the previous search result, or loop to the end of the file.\n */\nvoid search_prev(void) {\n\tif (!env->search) return;\n\tif (env->coffset) env->coffset = 0;\n\tint line = -1, col = -1;\n\tfind_match_backwards(env->line_no, env->col_no-1, &line, &col, env->search);\n\n\tif (line == -1) {\n\t\tfind_match_backwards(env->line_count, env->lines[env->line_count-1]->actual, &line, &col, env->search);\n\t\tif (line == -1) return;\n\t}\n\n\tenv->col_no = col;\n\tenv->line_no = line;\n\tset_preferred_column();\n\tdraw_search_match(env->search, -1);\n}\n\n/**\n * Find the matching paren for this one.\n *\n * This approach skips having to do its own syntax parsing\n * to deal with, eg., erroneous parens in comments. It does\n * this by finding the matching paren with the same flag\n * value, thus parens in strings will match, parens outside\n * of strings will match, but parens in strings won't\n * match parens outside of strings and so on.\n */\nvoid find_matching_paren(int * out_line, int * out_col) {\n\tif (env->col_no > env->lines[env->line_no-1]->actual) {\n\t\treturn; /* Invalid cursor position */\n\t}\n\n\t/* TODO: vim can find the nearest paren to start searching from, we need to be on one right now */\n\n\tint paren_match = 0;\n\tint direction = 0;\n\tint start = env->lines[env->line_no-1]->text[env->col_no-1].codepoint;\n\tint flags = env->lines[env->line_no-1]->text[env->col_no-1].flags & 0xF;\n\tint count = 0;\n\n\t/* TODO what about unicode parens? */\n\tfor (int i = 0; paren_pairs[i]; ++i) {\n\t\tif (start == paren_pairs[i]) {\n\t\t\tdirection = (i % 2 == 0) ? 1 : -1;\n\t\t\tparen_match = paren_pairs[(i % 2 == 0) ? (i+1) : (i-1)];\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!paren_match) return;\n\n\t/* Scan for match */\n\tint line = env->line_no;\n\tint col  = env->col_no;\n\n\tdo {\n\t\twhile (col > 0 && col < env->lines[line-1]->actual + 1) {\n\t\t\t/* Only match on same syntax */\n\t\t\tif ((env->lines[line-1]->text[col-1].flags & 0xF) == flags) {\n\t\t\t\t/* Count up on same direction */\n\t\t\t\tif (env->lines[line-1]->text[col-1].codepoint == start) count++;\n\t\t\t\t/* Count down on opposite direction */\n\t\t\t\tif (env->lines[line-1]->text[col-1].codepoint == paren_match) {\n\t\t\t\t\tcount--;\n\t\t\t\t\t/* When count == 0 we have a match */\n\t\t\t\t\tif (count == 0) goto _match_found;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcol += direction;\n\t\t}\n\n\t\tline += direction;\n\n\t\t/* Reached first/last line with no match */\n\t\tif (line == 0 || line == env->line_count + 1) {\n\t\t\treturn;\n\t\t}\n\n\t\t/* Reset column to start/end of line, depending on direction */\n\t\tif (direction > 0) {\n\t\t\tcol = 1;\n\t\t} else {\n\t\t\tcol = env->lines[line-1]->actual;\n\t\t}\n\t} while (1);\n\n_match_found:\n\t*out_line = line;\n\t*out_col  = col;\n}\n\n/**\n * Handle mouse event\n */\nvoid handle_mouse(void) {\n\tint buttons = bim_getch() - 32;\n\tint x = bim_getch() - 32;\n\tint y = bim_getch() - 32;\n\n\tif (buttons == 64) {\n\t\t/* Scroll up */\n\t\tfor (int i = 0; i < 5; ++i) {\n\t\t\tcursor_up();\n\t\t}\n\t\treturn;\n\t} else if (buttons == 65) {\n\t\t/* Scroll down */\n\t\tfor (int i = 0; i < 5; ++i) {\n\t\t\tcursor_down();\n\t\t}\n\t\treturn;\n\t} else if (buttons == 3) {\n\t\t/* Move cursor to position */\n\n\t\tif (x < 0) return;\n\t\tif (y < 0) return;\n\n\t\tif (y == 1) {\n\t\t\t/* Pick from tabs */\n\t\t\tint _x = 0;\n\t\t\tfor (int i = 0; i < buffers_len; i++) {\n\t\t\t\tbuffer_t * _env = buffers[i];\n\t\t\t\tchar tmp[64];\n\t\t\t\t_x += draw_tab_name(_env, tmp);\n\t\t\t\tif (_x >= x) {\n\t\t\t\t\tenv = buffers[i];\n\t\t\t\t\tredraw_all();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t/* Figure out y coordinate */\n\t\tint line_no = y + env->offset - 1;\n\t\tint col_no = -1;\n\n\t\tif (line_no > env->line_count) {\n\t\t\tline_no = env->line_count;\n\t\t}\n\n\t\t/* Account for the left hand gutter */\n\t\tint num_size = num_width() + 3;\n\t\tint _x = num_size - (line_no == env->line_no ? env->coffset : 0);\n\n\t\t/* Determine where the cursor is physically */\n\t\tfor (int i = 0; i < env->lines[line_no-1]->actual; ++i) {\n\t\t\tchar_t * c = &env->lines[line_no-1]->text[i];\n\t\t\t_x += c->display_width;\n\t\t\tif (_x > x-1) {\n\t\t\t\tcol_no = i+1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (col_no == -1 || col_no > env->lines[line_no-1]->actual) {\n\t\t\tcol_no = env->lines[line_no-1]->actual;\n\t\t}\n\n\t\tenv->line_no = line_no;\n\t\tenv->col_no = col_no;\n\t\tset_preferred_column();\n\t\tplace_cursor_actual();\n\t}\n\treturn;\n}\n\n/**\n * Append a character at the current cursor point.\n */\nvoid insert_char(unsigned int c) {\n\tif (!c) {\n\t\trender_error(\"Inserted nil byte?\");\n\t\treturn;\n\t}\n\tchar_t _c;\n\t_c.codepoint = c;\n\t_c.flags = 0;\n\t_c.display_width = codepoint_width(c);\n\tline_t * line  = env->lines[env->line_no - 1];\n\tline_t * nline = line_insert(line, _c, env->col_no - 1, env->line_no - 1);\n\tif (line != nline) {\n\t\tenv->lines[env->line_no - 1] = nline;\n\t}\n\tenv->col_no += 1;\n\tset_modified();\n}\n\n/**\n * Replace a single character at the current cursor point\n */\nvoid replace_char(unsigned int c) {\n\tif (env->col_no < 1 || env->col_no > env->lines[env->line_no-1]->actual) return;\n\n\tchar_t _c;\n\t_c.codepoint = c;\n\t_c.flags = 0;\n\t_c.display_width = codepoint_width(c);\n\n\tline_replace(env->lines[env->line_no-1], _c, env->col_no-1, env->line_no-1);\n\n\tredraw_line(env->line_no - env->offset - 1, env->line_no-1);\n\tset_modified();\n}\n\n/**\n * Undo a history entry.\n */\nvoid undo_history(void) {\n\tif (!global_config.history_enabled) return;\n\n\tenv->loading = 1;\n\thistory_t * e = env->history;\n\n\tif (e->type == HISTORY_SENTINEL) {\n\t\tenv->loading = 0;\n\t\trender_commandline_message(\"Already at oldest change\");\n\t\treturn;\n\t}\n\n\tint count_chars = 0;\n\tint count_lines = 0;\n\n\tdo {\n\t\tif (e->type == HISTORY_SENTINEL) break;\n\n\t\tswitch (e->type) {\n\t\t\tcase HISTORY_INSERT:\n\t\t\t\t/* Delete */\n\t\t\t\tline_delete(\n\t\t\t\t\t\tenv->lines[e->contents.insert_delete_replace.lineno],\n\t\t\t\t\t\te->contents.insert_delete_replace.offset+1,\n\t\t\t\t\t\te->contents.insert_delete_replace.lineno\n\t\t\t\t);\n\t\t\t\tenv->line_no = e->contents.insert_delete_replace.lineno + 1;\n\t\t\t\tenv->col_no  = e->contents.insert_delete_replace.offset + 1;\n\t\t\t\tcount_chars++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_DELETE:\n\t\t\t\t{\n\t\t\t\t\tchar_t _c = {codepoint_width(e->contents.insert_delete_replace.old_codepoint),0,e->contents.insert_delete_replace.old_codepoint};\n\t\t\t\t\tenv->lines[e->contents.insert_delete_replace.lineno] = line_insert(\n\t\t\t\t\t\t\tenv->lines[e->contents.insert_delete_replace.lineno],\n\t\t\t\t\t\t\t_c,\n\t\t\t\t\t\t\te->contents.insert_delete_replace.offset-1,\n\t\t\t\t\t\t\te->contents.insert_delete_replace.lineno\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tenv->line_no = e->contents.insert_delete_replace.lineno + 1;\n\t\t\t\tenv->col_no  = e->contents.insert_delete_replace.offset + 2;\n\t\t\t\tcount_chars++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_REPLACE:\n\t\t\t\t{\n\t\t\t\t\tchar_t _o = {codepoint_width(e->contents.insert_delete_replace.old_codepoint),0,e->contents.insert_delete_replace.old_codepoint};\n\t\t\t\t\tline_replace(\n\t\t\t\t\t\t\tenv->lines[e->contents.insert_delete_replace.lineno],\n\t\t\t\t\t\t\t_o,\n\t\t\t\t\t\t\te->contents.insert_delete_replace.offset,\n\t\t\t\t\t\t\te->contents.insert_delete_replace.lineno\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tenv->line_no = e->contents.insert_delete_replace.lineno + 1;\n\t\t\t\tenv->col_no  = e->contents.insert_delete_replace.offset + 1;\n\t\t\t\tcount_chars++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_REMOVE_LINE:\n\t\t\t\tenv->lines = add_line(env->lines, e->contents.remove_replace_line.lineno);\n\t\t\t\treplace_line(env->lines, e->contents.remove_replace_line.lineno, e->contents.remove_replace_line.old_contents);\n\t\t\t\tenv->line_no = e->contents.remove_replace_line.lineno + 2;\n\t\t\t\tenv->col_no = 1;\n\t\t\t\tcount_lines++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_ADD_LINE:\n\t\t\t\tenv->lines = remove_line(env->lines, e->contents.add_merge_split_lines.lineno);\n\t\t\t\tenv->line_no = e->contents.add_merge_split_lines.lineno + 1;\n\t\t\t\tenv->col_no = 1;\n\t\t\t\tcount_lines++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_REPLACE_LINE:\n\t\t\t\treplace_line(env->lines, e->contents.remove_replace_line.lineno, e->contents.remove_replace_line.old_contents);\n\t\t\t\tenv->line_no = e->contents.remove_replace_line.lineno + 1;\n\t\t\t\tenv->col_no = 1;\n\t\t\t\tcount_lines++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_SPLIT_LINE:\n\t\t\t\tenv->lines = merge_lines(env->lines, e->contents.add_merge_split_lines.lineno+1);\n\t\t\t\tenv->line_no = e->contents.add_merge_split_lines.lineno + 2;\n\t\t\t\tenv->col_no = 1;\n\t\t\t\tcount_lines++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_MERGE_LINES:\n\t\t\t\tenv->lines = split_line(env->lines, e->contents.add_merge_split_lines.lineno-1, e->contents.add_merge_split_lines.split);\n\t\t\t\tenv->line_no = e->contents.add_merge_split_lines.lineno;\n\t\t\t\tenv->col_no = 1;\n\t\t\t\tcount_lines++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_BREAK:\n\t\t\t\t/* Ignore break */\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\trender_error(\"Unknown type %d!\\n\", e->type);\n\t\t\t\tbreak;\n\t\t}\n\n\t\tenv->history = e->previous;\n\t\te = env->history;\n\t} while (e->type != HISTORY_BREAK);\n\n\tif (env->line_no > env->line_count) env->line_no = env->line_count;\n\tif (env->col_no > env->lines[env->line_no-1]->actual) env->col_no = env->lines[env->line_no-1]->actual;\n\n\tenv->modified = (env->history != env->last_save_history);\n\n\tenv->loading = 0;\n\n\tfor (int i = 0; i < env->line_count; ++i) {\n\t\tenv->lines[i]->istate = 0;\n\t\trecalculate_tabs(env->lines[i]);\n\t}\n\tfor (int i = 0; i < env->line_count; ++i) {\n\t\trecalculate_syntax(env->lines[i],i);\n\t}\n\tplace_cursor_actual();\n\tupdate_title();\n\tredraw_all();\n\trender_commandline_message(\"%d character%s, %d line%s changed\",\n\t\t\tcount_chars, (count_chars == 1) ? \"\" : \"s\",\n\t\t\tcount_lines, (count_lines == 1) ? \"\" : \"s\");\n}\n\n/**\n * Replay a history entry.\n */\nvoid redo_history(void) {\n\tif (!global_config.history_enabled) return;\n\n\tenv->loading = 1;\n\thistory_t * e = env->history->next;\n\n\tif (!e) {\n\t\tenv->loading = 0;\n\t\trender_commandline_message(\"Already at newest change\");\n\t\treturn;\n\t}\n\n\tint count_chars = 0;\n\tint count_lines = 0;\n\n\twhile (e) {\n\t\tif (e->type == HISTORY_BREAK) {\n\t\t\tenv->history = e;\n\t\t\tbreak;\n\t\t}\n\n\t\tswitch (e->type) {\n\t\t\tcase HISTORY_INSERT:\n\t\t\t\t{\n\t\t\t\t\tchar_t _c = {codepoint_width(e->contents.insert_delete_replace.codepoint),0,e->contents.insert_delete_replace.codepoint};\n\t\t\t\t\tenv->lines[e->contents.insert_delete_replace.lineno] = line_insert(\n\t\t\t\t\t\t\tenv->lines[e->contents.insert_delete_replace.lineno],\n\t\t\t\t\t\t\t_c,\n\t\t\t\t\t\t\te->contents.insert_delete_replace.offset,\n\t\t\t\t\t\t\te->contents.insert_delete_replace.lineno\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tenv->line_no = e->contents.insert_delete_replace.lineno + 1;\n\t\t\t\tenv->col_no  = e->contents.insert_delete_replace.offset + 2;\n\t\t\t\tcount_chars++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_DELETE:\n\t\t\t\t/* Delete */\n\t\t\t\tline_delete(\n\t\t\t\t\t\tenv->lines[e->contents.insert_delete_replace.lineno],\n\t\t\t\t\t\te->contents.insert_delete_replace.offset,\n\t\t\t\t\t\te->contents.insert_delete_replace.lineno\n\t\t\t\t);\n\t\t\t\tenv->line_no = e->contents.insert_delete_replace.lineno + 1;\n\t\t\t\tenv->col_no  = e->contents.insert_delete_replace.offset + 1;\n\t\t\t\tcount_chars++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_REPLACE:\n\t\t\t\t{\n\t\t\t\t\tchar_t _o = {codepoint_width(e->contents.insert_delete_replace.codepoint),0,e->contents.insert_delete_replace.codepoint};\n\t\t\t\t\tline_replace(\n\t\t\t\t\t\t\tenv->lines[e->contents.insert_delete_replace.lineno],\n\t\t\t\t\t\t\t_o,\n\t\t\t\t\t\t\te->contents.insert_delete_replace.offset,\n\t\t\t\t\t\t\te->contents.insert_delete_replace.lineno\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tenv->line_no = e->contents.insert_delete_replace.lineno + 1;\n\t\t\t\tenv->col_no  = e->contents.insert_delete_replace.offset + 2;\n\t\t\t\tcount_chars++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_ADD_LINE:\n\t\t\t\tenv->lines = add_line(env->lines, e->contents.remove_replace_line.lineno);\n\t\t\t\tenv->line_no = e->contents.remove_replace_line.lineno + 2;\n\t\t\t\tenv->col_no = 1;\n\t\t\t\tcount_lines++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_REMOVE_LINE:\n\t\t\t\tenv->lines = remove_line(env->lines, e->contents.remove_replace_line.lineno);\n\t\t\t\tenv->line_no = e->contents.add_merge_split_lines.lineno + 1;\n\t\t\t\tenv->col_no = 1;\n\t\t\t\tcount_lines++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_REPLACE_LINE:\n\t\t\t\treplace_line(env->lines, e->contents.remove_replace_line.lineno, e->contents.remove_replace_line.contents);\n\t\t\t\tenv->line_no = e->contents.remove_replace_line.lineno + 2;\n\t\t\t\tenv->col_no = 1;\n\t\t\t\tcount_lines++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_MERGE_LINES:\n\t\t\t\tenv->lines = merge_lines(env->lines, e->contents.add_merge_split_lines.lineno);\n\t\t\t\tenv->line_no = e->contents.remove_replace_line.lineno + 1;\n\t\t\t\tenv->col_no = 1;\n\t\t\t\tcount_lines++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_SPLIT_LINE:\n\t\t\t\tenv->lines = split_line(env->lines, e->contents.add_merge_split_lines.lineno, e->contents.add_merge_split_lines.split);\n\t\t\t\tenv->line_no = e->contents.remove_replace_line.lineno + 2;\n\t\t\t\tenv->col_no = 1;\n\t\t\t\tcount_lines++;\n\t\t\t\tbreak;\n\t\t\tcase HISTORY_BREAK:\n\t\t\t\t/* Ignore break */\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\trender_error(\"Unknown type %d!\\n\", e->type);\n\t\t\t\tbreak;\n\t\t}\n\n\t\tenv->history = e;\n\t\te = e->next;\n\t}\n\n\tif (env->line_no > env->line_count) env->line_no = env->line_count;\n\tif (env->col_no > env->lines[env->line_no-1]->actual) env->col_no = env->lines[env->line_no-1]->actual;\n\n\tenv->modified = (env->history != env->last_save_history);\n\n\tenv->loading = 0;\n\n\tfor (int i = 0; i < env->line_count; ++i) {\n\t\tenv->lines[i]->istate = 0;\n\t\trecalculate_tabs(env->lines[i]);\n\t}\n\tfor (int i = 0; i < env->line_count; ++i) {\n\t\trecalculate_syntax(env->lines[i],i);\n\t}\n\tplace_cursor_actual();\n\tupdate_title();\n\tredraw_all();\n\trender_commandline_message(\"%d character%s, %d line%s changed\",\n\t\t\tcount_chars, (count_chars == 1) ? \"\" : \"s\",\n\t\t\tcount_lines, (count_lines == 1) ? \"\" : \"s\");\n}\n\n/**\n * Move the cursor the start of the previous word.\n */\nvoid word_left(void) {\n\tint line_no = env->line_no;\n\tint col_no = env->col_no;\n\n\tdo {\n\t\tcol_no--;\n\t\twhile (col_no == 0) {\n\t\t\tline_no--;\n\t\t\tif (line_no == 0) {\n\t\t\t\tgoto_line(1);\n\t\t\t\tset_preferred_column();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcol_no = env->lines[line_no-1]->actual;\n\t\t}\n\t} while (isspace(env->lines[line_no-1]->text[col_no-1].codepoint));\n\n\tdo {\n\t\tcol_no--;\n\t\tif (col_no == 0) {\n\t\t\tcol_no = 1;\n\t\t\tbreak;\n\t\t}\n\t\tif (col_no == 1) {\n\t\t\tenv->col_no = 1;\n\t\t\tenv->line_no = line_no;\n\t\t\tset_preferred_column();\n\t\t\tredraw_statusbar();\n\t\t\tplace_cursor_actual();\n\t\t\treturn;\n\t\t}\n\t} while (!isspace(env->lines[line_no-1]->text[col_no-1].codepoint));\n\n\tenv->col_no = col_no;\n\tenv->line_no = line_no;\n\tset_preferred_column();\n\tcursor_right();\n}\n\n/**\n * Word right\n */\nvoid word_right(void) {\n\tint line_no = env->line_no;\n\tint col_no = env->col_no;\n\n\tdo {\n\t\tcol_no++;\n\t\tif (col_no > env->lines[line_no-1]->actual) {\n\t\t\tline_no++;\n\t\t\tif (line_no > env->line_count) {\n\t\t\t\tenv->line_no = env->line_count;\n\t\t\t\tenv->col_no  = env->lines[env->line_no-1]->actual;\n\t\t\t\tset_preferred_column();\n\t\t\t\tredraw_statusbar();\n\t\t\t\tplace_cursor_actual();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcol_no = 0;\n\t\t\tbreak;\n\t\t}\n\t} while (!isspace(env->lines[line_no-1]->text[col_no-1].codepoint));\n\n\tdo {\n\t\tcol_no++;\n\t\twhile (col_no > env->lines[line_no-1]->actual) {\n\t\t\tline_no++;\n\t\t\tif (line_no >= env->line_count) {\n\t\t\t\tenv->col_no = env->lines[env->line_count-1]->actual;\n\t\t\t\tenv->line_no = env->line_count;\n\t\t\t\tset_preferred_column();\n\t\t\t\tredraw_statusbar();\n\t\t\t\tplace_cursor_actual();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcol_no = 1;\n\t\t}\n\t} while (isspace(env->lines[line_no-1]->text[col_no-1].codepoint));\n\n\tenv->col_no = col_no;\n\tenv->line_no = line_no;\n\tset_preferred_column();\n\tredraw_statusbar();\n\tplace_cursor_actual();\n\treturn;\n}\n\n/**\n * Backspace from the current cursor position.\n */\nvoid delete_at_cursor(void) {\n\tif (env->col_no > 1) {\n\t\tline_delete(env->lines[env->line_no - 1], env->col_no - 1, env->line_no - 1);\n\t\tenv->col_no -= 1;\n\t\tif (env->coffset > 0) env->coffset--;\n\t\tredraw_line(env->line_no - env->offset - 1, env->line_no-1);\n\t\tset_modified();\n\t\tredraw_statusbar();\n\t\tplace_cursor_actual();\n\t} else if (env->line_no > 1) {\n\t\tint tmp = env->lines[env->line_no - 2]->actual;\n\t\tmerge_lines(env->lines, env->line_no - 1);\n\t\tenv->line_no -= 1;\n\t\tenv->col_no = tmp+1;\n\t\tset_preferred_column();\n\t\tredraw_text();\n\t\tset_modified();\n\t\tredraw_statusbar();\n\t\tplace_cursor_actual();\n\t}\n}\n\nvoid delete_word(void) {\n\tif (!env->lines[env->line_no-1]) return;\n\tif (env->col_no > 1) {\n\n\t\tdo {\n\t\t\tif (env->col_no > 1) {\n\t\t\t\tline_delete(env->lines[env->line_no - 1], env->col_no - 1, env->line_no - 1);\n\t\t\t\tenv->col_no -= 1;\n\t\t\t\tif (env->coffset > 0) env->coffset--;\n\t\t\t}\n\t\t} while (env->col_no > 1 && env->lines[env->line_no - 1]->text[env->col_no - 2].codepoint != ' ');\n\n\t\tset_preferred_column();\n\t\tredraw_text();\n\t\tset_modified();\n\t\tredraw_statusbar();\n\t\tplace_cursor_actual();\n\t}\n}\n\n/**\n * Break the current line in two at the current cursor position.\n */\nvoid insert_line_feed(void) {\n\tif (env->col_no == env->lines[env->line_no - 1]->actual + 1) {\n\t\tenv->lines = add_line(env->lines, env->line_no);\n\t} else {\n\t\tenv->lines = split_line(env->lines, env->line_no-1, env->col_no - 1);\n\t}\n\tenv->col_no = 1;\n\tenv->line_no += 1;\n\tset_preferred_column();\n\tadd_indent(env->line_no-1,env->line_no-2,0);\n\tif (env->line_no > env->offset + global_config.term_height - global_config.bottom_size - 1) {\n\t\tenv->offset += 1;\n\t}\n\tset_modified();\n}\n\n/**\n * Yank lines between line start and line end (which may be in either order)\n */\nvoid yank_lines(int start, int end) {\n\tif (global_config.yanks) {\n\t\tfor (unsigned int i = 0; i < global_config.yank_count; ++i) {\n\t\t\tfree(global_config.yanks[i]);\n\t\t}\n\t\tfree(global_config.yanks);\n\t}\n\tint lines_to_yank;\n\tint start_point;\n\tif (start <= end) {\n\t\tlines_to_yank = end - start + 1;\n\t\tstart_point = start - 1;\n\t} else {\n\t\tlines_to_yank = start - end + 1;\n\t\tstart_point = end - 1;\n\t}\n\tglobal_config.yanks = malloc(sizeof(line_t *) * lines_to_yank);\n\tglobal_config.yank_count = lines_to_yank;\n\tglobal_config.yank_is_full_lines = 1;\n\tfor (int i = 0; i < lines_to_yank; ++i) {\n\t\tglobal_config.yanks[i] = malloc(sizeof(line_t) + sizeof(char_t) * (env->lines[start_point+i]->available));\n\t\tglobal_config.yanks[i]->available = env->lines[start_point+i]->available;\n\t\tglobal_config.yanks[i]->actual = env->lines[start_point+i]->actual;\n\t\tglobal_config.yanks[i]->istate = 0;\n\t\tmemcpy(&global_config.yanks[i]->text, &env->lines[start_point+i]->text, sizeof(char_t) * (env->lines[start_point+i]->actual));\n\n\t\tfor (int j = 0; j < global_config.yanks[i]->actual; ++j) {\n\t\t\tglobal_config.yanks[i]->text[j].flags = 0;\n\t\t}\n\t}\n}\n\n/**\n * Helper to yank part of a line into a new yank line.\n */\nvoid yank_partial_line(int yank_no, int line_no, int start_off, int count) {\n\tglobal_config.yanks[yank_no] = malloc(sizeof(line_t) + sizeof(char_t) * (count + 1));\n\tglobal_config.yanks[yank_no]->available = count + 1; /* ensure extra space */\n\tglobal_config.yanks[yank_no]->actual = count;\n\tglobal_config.yanks[yank_no]->istate = 0;\n\tmemcpy(&global_config.yanks[yank_no]->text, &env->lines[line_no]->text[start_off], sizeof(char_t) * count);\n\tfor (int i = 0; i < count; ++i) {\n\t\tglobal_config.yanks[yank_no]->text[i].flags = 0;\n\t}\n}\n\n/**\n * Yank text...\n */\nvoid yank_text(int start_line, int start_col, int end_line, int end_col) {\n\tif (global_config.yanks) {\n\t\tfor (unsigned int i = 0; i < global_config.yank_count; ++i) {\n\t\t\tfree(global_config.yanks[i]);\n\t\t}\n\t\tfree(global_config.yanks);\n\t}\n\tint lines_to_yank = end_line - start_line + 1;\n\tint start_point = start_line - 1;\n\tglobal_config.yanks = malloc(sizeof(line_t *) * lines_to_yank);\n\tglobal_config.yank_count = lines_to_yank;\n\tglobal_config.yank_is_full_lines = 0;\n\tif (lines_to_yank == 1) {\n\t\tyank_partial_line(0, start_point, start_col - 1, (end_col - start_col + 1));\n\t} else {\n\t\tyank_partial_line(0, start_point, start_col - 1, (env->lines[start_point]->actual - start_col + 1));\n\t\t/* Yank middle lines */\n\t\tfor (int i = 1; i < lines_to_yank - 1; ++i) {\n\t\t\tglobal_config.yanks[i] = malloc(sizeof(line_t) + sizeof(char_t) * (env->lines[start_point+i]->available));\n\t\t\tglobal_config.yanks[i]->available = env->lines[start_point+i]->available;\n\t\t\tglobal_config.yanks[i]->actual = env->lines[start_point+i]->actual;\n\t\t\tglobal_config.yanks[i]->istate = 0;\n\t\t\tmemcpy(&global_config.yanks[i]->text, &env->lines[start_point+i]->text, sizeof(char_t) * (env->lines[start_point+i]->actual));\n\n\t\t\tfor (int j = 0; j < global_config.yanks[i]->actual; ++j) {\n\t\t\t\tglobal_config.yanks[i]->text[j].flags = 0;\n\t\t\t}\n\t\t}\n\t\t/* Yank end line */\n\t\tyank_partial_line(lines_to_yank-1, end_line - 1, 0, end_col);\n\t}\n}\n\n/**\n * Handle shared escape keys (mostly navigation)\n */\nint handle_escape(int * this_buf, int * timeout, int c) {\n\tif (*timeout >=  1 && this_buf[*timeout-1] == '\\033' && c == '\\033') {\n\t\tthis_buf[*timeout] = c;\n\t\t(*timeout)++;\n\t\treturn 1;\n\t}\n\tif (*timeout >= 1 && this_buf[*timeout-1] == '\\033' && c != '[') {\n\t\t*timeout = 0;\n\t\tbim_unget(c);\n\t\treturn 1;\n\t}\n\tif (*timeout >= 1 && this_buf[*timeout-1] == '\\033' && c == '[') {\n\t\t*timeout = 1;\n\t\tthis_buf[*timeout] = c;\n\t\t(*timeout)++;\n\t\treturn 0;\n\t}\n\tif (*timeout >= 2 && this_buf[0] == '\\033' && this_buf[1] == '[' &&\n\t\t\t(isdigit(c) || c == ';')) {\n\t\tthis_buf[*timeout] = c;\n\t\t(*timeout)++;\n\t\treturn 0;\n\t}\n\tif (*timeout >= 2 && this_buf[0] == '\\033' && this_buf[1] == '[') {\n\t\tswitch (c) {\n\t\t\tcase 'M':\n\t\t\t\thandle_mouse();\n\t\t\t\tbreak;\n\t\t\tcase 'A': // up\n\t\t\t\tcursor_up();\n\t\t\t\tbreak;\n\t\t\tcase 'B': // down\n\t\t\t\tcursor_down();\n\t\t\t\tbreak;\n\t\t\tcase 'C': // right\n\t\t\t\tif (this_buf[*timeout-1] == '5') {\n\t\t\t\t\tword_right();\n\t\t\t\t} else {\n\t\t\t\t\tcursor_right();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'D': // left\n\t\t\t\tif (this_buf[*timeout-1] == '5') {\n\t\t\t\t\tword_left();\n\t\t\t\t} else {\n\t\t\t\t\tcursor_left();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'H': // home\n\t\t\t\tcursor_home();\n\t\t\t\tbreak;\n\t\t\tcase 'F': // end\n\t\t\t\tcursor_end();\n\t\t\t\tbreak;\n\t\t\tcase 'I':\n\t\t\t\tgoto_line(env->line_no - (global_config.term_height - 6));\n\t\t\t\tbreak;\n\t\t\tcase 'G':\n\t\t\t\tgoto_line(env->line_no + global_config.term_height - 6);\n\t\t\t\tbreak;\n\t\t\tcase 'Z':\n\t\t\t\t/* Shift tab */\n\t\t\t\tif (env->mode == MODE_LINE_SELECTION) {\n\t\t\t\t\t*timeout = 0;\n\t\t\t\t\treturn 'Z';\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase '~':\n\t\t\t\tswitch (this_buf[*timeout-1]) {\n\t\t\t\t\tcase '1':\n\t\t\t\t\t\tcursor_home();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '3':\n\t\t\t\t\t\tif (env->mode == MODE_INSERT || env->mode == MODE_REPLACE) {\n\t\t\t\t\t\t\tif (env->col_no < env->lines[env->line_no - 1]->actual + 1) {\n\t\t\t\t\t\t\t\tline_delete(env->lines[env->line_no - 1], env->col_no, env->line_no - 1);\n\t\t\t\t\t\t\t\tredraw_line(env->line_no - env->offset - 1, env->line_no-1);\n\t\t\t\t\t\t\t\tset_modified();\n\t\t\t\t\t\t\t\tredraw_statusbar();\n\t\t\t\t\t\t\t\tplace_cursor_actual();\n\t\t\t\t\t\t\t} else if (env->line_no < env->line_count) {\n\t\t\t\t\t\t\t\tmerge_lines(env->lines, env->line_no);\n\t\t\t\t\t\t\t\tredraw_text();\n\t\t\t\t\t\t\t\tset_modified();\n\t\t\t\t\t\t\t\tredraw_statusbar();\n\t\t\t\t\t\t\t\tplace_cursor_actual();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '4':\n\t\t\t\t\t\tcursor_end();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '5':\n\t\t\t\t\t\tgoto_line(env->line_no - (global_config.term_height - 6));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '6':\n\t\t\t\t\t\tgoto_line(env->line_no + global_config.term_height - 6);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\trender_error(\"Unrecognized escape sequence identifier: %c\", c);\n\t\t\t\tbreak;\n\t\t}\n\t\t*timeout = 0;\n\t\treturn 0;\n\t}\n\n\t*timeout = 0;\n\treturn 0;\n}\n\n/**\n * Standard navigation shared by normal, line, and char selection.\n */\nvoid handle_navigation(int c) {\n\tswitch (c) {\n\t\tcase ':': /* Switch to command mode */\n\t\t\tcommand_mode();\n\t\t\tbreak;\n\t\tcase '/': /* Switch to search mode */\n\t\t\tsearch_mode(1);\n\t\t\tbreak;\n\t\tcase '?': /* Switch to search mode */\n\t\t\tsearch_mode(0);\n\t\t\tbreak;\n\t\tcase 'n': /* Jump to next search result */\n\t\t\tsearch_next();\n\t\t\tbreak;\n\t\tcase 'N': /* Jump backwards to previous search result */\n\t\t\tsearch_prev();\n\t\t\tbreak;\n\t\tcase 'j': /* Move cursor down */\n\t\t\tcursor_down();\n\t\t\tbreak;\n\t\tcase 'k': /* Move cursor up */\n\t\t\tcursor_up();\n\t\t\tbreak;\n\t\tcase 'h': /* Move cursor left */\n\t\t\tcursor_left();\n\t\t\tbreak;\n\t\tcase 'l': /* Move cursor right*/\n\t\t\tcursor_right();\n\t\t\tbreak;\n\t\tcase 'w': /* Move cursor one word right */\n\t\t\tword_right();\n\t\t\tbreak;\n\t\tcase ' ': /* Jump forward several lines */\n\t\t\tgoto_line(env->line_no + global_config.term_height - 6);\n\t\t\tbreak;\n\t\tcase '%': /* Jump to matching brace/bracket */\n\t\t\tif (env->mode == MODE_LINE_SELECTION || env->mode == MODE_CHAR_SELECTION) {\n\t\t\t\t/* These modes need to recalculate syntax as find_matching_brace uses it to find appropriate match */\n\t\t\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\t\t\trecalculate_syntax(env->lines[i],i);\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tint paren_line = -1, paren_col = -1;\n\t\t\t\tfind_matching_paren(&paren_line, &paren_col);\n\t\t\t\tif (paren_line != -1) {\n\t\t\t\t\tenv->line_no = paren_line;\n\t\t\t\t\tenv->col_no = paren_col;\n\t\t\t\t\tset_preferred_column();\n\t\t\t\t\tplace_cursor_actual();\n\t\t\t\t\tredraw_statusbar();\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase '{': /* Jump to previous blank line */\n\t\t\tenv->col_no = 1;\n\t\t\tif (env->line_no == 1) break;\n\t\t\tdo {\n\t\t\t\tenv->line_no--;\n\t\t\t\tif (env->lines[env->line_no-1]->actual == 0) break;\n\t\t\t} while (env->line_no > 1);\n\t\t\tset_preferred_column();\n\t\t\tredraw_statusbar();\n\t\t\tbreak;\n\t\tcase '}': /* Jump to next blank line */\n\t\t\tenv->col_no = 1;\n\t\t\tif (env->line_no == env->line_count) break;\n\t\t\tdo {\n\t\t\t\tenv->line_no++;\n\t\t\t\tif (env->lines[env->line_no-1]->actual == 0) break;\n\t\t\t} while (env->line_no < env->line_count);\n\t\t\tset_preferred_column();\n\t\t\tredraw_statusbar();\n\t\t\tbreak;\n\t\tcase '$': /* Move cursor to end of line */\n\t\t\tcursor_end();\n\t\t\tbreak;\n\t\tcase '^':\n\t\tcase '0': /* Move cursor to beginning of line */\n\t\t\tcursor_home();\n\t\t\tbreak;\n\t}\n}\n\n/**\n * Macro for redrawing selected lines with appropriate highlighting.\n */\n#define _redraw_line(line, force_start_line) \\\n\tdo { \\\n\t\tif (!(force_start_line) && (line) == start_line) break; \\\n\t\tif ((line) > env->line_count + 1) { \\\n\t\t\tif ((line) - env->offset - 1 < global_config.term_height - global_config.bottom_size - 1) { \\\n\t\t\t\tdraw_excess_line((line) - env->offset - 1); \\\n\t\t\t} \\\n\t\t\tbreak; \\\n\t\t} \\\n\t\tif ((env->line_no < start_line  && ((line) < env->line_no || (line) > start_line)) || \\\n\t\t\t(env->line_no > start_line  && ((line) > env->line_no || (line) < start_line)) || \\\n\t\t\t(env->line_no == start_line && (line) != start_line)) { \\\n\t\t\trecalculate_syntax(env->lines[(line)-1],(line)-1); \\\n\t\t} else { \\\n\t\t\tfor (int j = 0; j < env->lines[(line)-1]->actual; ++j) { \\\n\t\t\t\tenv->lines[(line)-1]->text[j].flags |= FLAG_SELECT; \\\n\t\t\t} \\\n\t\t} \\\n\t\tif ((line) - env->offset + 1 > 1 && \\\n\t\t\t(line) - env->offset - 1< global_config.term_height - global_config.bottom_size - 1) { \\\n\t\t\tredraw_line((line) - env->offset - 1, (line)-1); \\\n\t\t} \\\n\t} while (0)\n\n/**\n * Adjust indentation on selected lines.\n */\nvoid adjust_indent(int start_line, int direction) {\n\tint lines_to_cover = 0;\n\tint start_point = 0;\n\tif (start_line <= env->line_no) {\n\t\tstart_point = start_line - 1;\n\t\tlines_to_cover = env->line_no - start_line + 1;\n\t} else {\n\t\tstart_point = env->line_no - 1;\n\t\tlines_to_cover = start_line - env->line_no + 1;\n\t}\n\tfor (int i = 0; i < lines_to_cover; ++i) {\n\t\tif ((direction == -1) && env->lines[start_point + i]->actual < 1) continue;\n\t\tif (direction == -1) {\n\t\t\tif (env->tabs) {\n\t\t\t\tif (env->lines[start_point + i]->text[0].codepoint == '\\t') {\n\t\t\t\t\tline_delete(env->lines[start_point + i],1,start_point+i);\n\t\t\t\t\t_redraw_line(start_point+i+1,1);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (int j = 0; j < env->tabstop; ++j) {\n\t\t\t\t\tif (env->lines[start_point + i]->text[0].codepoint == ' ') {\n\t\t\t\t\t\tline_delete(env->lines[start_point + i],1,start_point+i);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t_redraw_line(start_point+i+1,1);\n\t\t\t}\n\t\t} else if (direction == 1) {\n\t\t\tif (env->tabs) {\n\t\t\t\tchar_t c;\n\t\t\t\tc.codepoint = '\\t';\n\t\t\t\tc.display_width = env->tabstop;\n\t\t\t\tc.flags = FLAG_SELECT;\n\t\t\t\tenv->lines[start_point + i] = line_insert(env->lines[start_point + i], c, 0, start_point + i);\n\t\t\t} else {\n\t\t\t\tfor (int j = 0; j < env->tabstop; ++j) {\n\t\t\t\t\tchar_t c;\n\t\t\t\t\tc.codepoint = ' ';\n\t\t\t\t\tc.display_width = 1;\n\t\t\t\t\tc.flags = FLAG_SELECT;\n\t\t\t\t\tenv->lines[start_point + i] = line_insert(env->lines[start_point + i], c, 0, start_point + i);\n\t\t\t\t}\n\t\t\t}\n\t\t\t_redraw_line(start_point+i+1,1);\n\t\t}\n\t}\n\tif (env->col_no > env->lines[env->line_no-1]->actual) {\n\t\tenv->col_no = env->lines[env->line_no-1]->actual;\n\t}\n\tset_preferred_column();\n\tset_modified();\n}\n\n/**\n * LINE SELECTION mode\n *\n * Equivalent to visual line in vim; selects lines of texts.\n */\nvoid line_selection_mode(void) {\n\tint start_line = env->line_no;\n\tint prev_line  = start_line;\n\n\tenv->mode = MODE_LINE_SELECTION;\n\tredraw_commandline();\n\n\tint c;\n\tint timeout = 0;\n\tint this_buf[20];\n\n\tfor (int j = 0; j < env->lines[env->line_no-1]->actual; ++j) {\n\t\tenv->lines[env->line_no-1]->text[j].flags |= FLAG_SELECT;\n\t}\n\tredraw_line(env->line_no - env->offset - 1, env->line_no-1);\n\n\twhile ((c = bim_getch())) {\n\t\tif (c == -1) {\n\t\t\tif (timeout && this_buf[timeout-1] == '\\033') {\n\t\t\t\tgoto _leave_select_line;\n\t\t\t}\n\t\t\ttimeout = 0;\n\t\t\tcontinue;\n\t\t} else {\n\t\t\tif (timeout == 0) {\n\t\t\t\tswitch (c) {\n\t\t\t\t\tcase '\\033':\n\t\t\t\t\t\tif (timeout == 0) {\n\t\t\t\t\t\t\tthis_buf[timeout] = c;\n\t\t\t\t\t\t\ttimeout++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase DELETE_KEY:\n\t\t\t\t\tcase BACKSPACE_KEY:\n\t\t\t\t\t\tcursor_left();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '\\t':\n\t\t\t\t\t\tif (env->readonly) goto _readonly;\n\t\t\t\t\t\tadjust_indent(start_line, 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'V':\n\t\t\t\t\t\tgoto _leave_select_line;\n\t\t\t\t\tcase 'y':\n\t\t\t\t\t\tyank_lines(start_line, env->line_no);\n\t\t\t\t\t\tgoto _leave_select_line;\n\t\t\t\t\tcase 'D':\n\t\t\t\t\tcase 'd':\n\t\t\t\t\t\tif (env->readonly) goto _readonly;\n\t\t\t\t\t\tyank_lines(start_line, env->line_no);\n\t\t\t\t\t\tif (start_line <= env->line_no) {\n\t\t\t\t\t\t\tint lines_to_delete = env->line_no - start_line + 1;\n\t\t\t\t\t\t\tfor (int i = 0; i < lines_to_delete; ++i) {\n\t\t\t\t\t\t\t\tremove_line(env->lines, start_line-1);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tenv->line_no = start_line;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tint lines_to_delete = start_line - env->line_no + 1;\n\t\t\t\t\t\t\tfor (int i = 0; i < lines_to_delete; ++i) {\n\t\t\t\t\t\t\t\tremove_line(env->lines, env->line_no-1);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (env->line_no > env->line_count) {\n\t\t\t\t\t\t\tenv->line_no = env->line_count;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (env->col_no > env->lines[env->line_no-1]->actual) {\n\t\t\t\t\t\t\tenv->col_no = env->lines[env->line_no-1]->actual;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tset_preferred_column();\n\t\t\t\t\t\tset_modified();\n\t\t\t\t\t\tgoto _leave_select_line;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\thandle_navigation(c);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tswitch (handle_escape(this_buf,&timeout,c)) {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\tbim_unget(c);\n\t\t\t\t\t\tgoto _leave_select_line;\n\t\t\t\t\tcase 'Z':\n\t\t\t\t\t\t/* Unindent */\n\t\t\t\t\t\tif (env->readonly) goto _readonly;\n\t\t\t\t\t\tadjust_indent(start_line, -1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Mark current line */\n\t\t\t_redraw_line(env->line_no,0);\n\n\t\t\t/* Properly mark everything in the span we just moved through */\n\t\t\tif (prev_line < env->line_no) {\n\t\t\t\tfor (int i = prev_line; i < env->line_no; ++i) {\n\t\t\t\t\t_redraw_line(i,0);\n\t\t\t\t}\n\t\t\t\tprev_line = env->line_no;\n\t\t\t} else if (prev_line > env->line_no) {\n\t\t\t\tfor (int i = env->line_no + 1; i <= prev_line; ++i) {\n\t\t\t\t\t_redraw_line(i,0);\n\t\t\t\t}\n\t\t\t\tprev_line = env->line_no;\n\t\t\t}\n\t\t\tplace_cursor_actual();\n\t\t\tcontinue;\n_readonly:\n\t\t\trender_error(\"Buffer is read-only\");\n\t\t}\n\t}\n\n_leave_select_line:\n\tset_history_break();\n\tenv->mode = MODE_NORMAL;\n\tfor (int i = 0; i < env->line_count; ++i) {\n\t\trecalculate_syntax(env->lines[i],i);\n\t}\n\tredraw_all();\n}\n\n/**\n * Determine if a column + line number are within range of the\n * current character selection specified by start_line, etc.\n *\n * Used to determine how syntax flags should be set when redrawing\n * selected text in CHAR SELECTION mode.\n */\nint point_in_range(int start_line, int end_line, int start_col, int end_col, int line, int col) {\n\tif (start_line == end_line) {\n\t\tif ( end_col < start_col) {\n\t\t\tint tmp = end_col;\n\t\t\tend_col = start_col;\n\t\t\tstart_col = tmp;\n\t\t}\n\t\treturn (col >= start_col && col <= end_col);\n\t}\n\n\tif (start_line > end_line) {\n\t\tint tmp = end_line;\n\t\tend_line = start_line;\n\t\tstart_line = tmp;\n\n\t\ttmp = end_col;\n\t\tend_col = start_col;\n\t\tstart_col = tmp;\n\t}\n\n\tif (line < start_line || line > end_line) return 0;\n\n\tif (line == start_line) {\n\t\treturn col >= start_col;\n\t}\n\n\tif (line == end_line) {\n\t\treturn col <= end_col;\n\t}\n\n\treturn 1;\n}\n\n#define _redraw_line_char(line, force_start_line) \\\n\tdo { \\\n\t\tif (!(force_start_line) && (line) == start_line) break; \\\n\t\tif ((line) > env->line_count + 1) { \\\n\t\t\tif ((line) - env->offset - 1 < global_config.term_height - global_config.bottom_size - 1) { \\\n\t\t\t\tdraw_excess_line((line) - env->offset - 1); \\\n\t\t\t} \\\n\t\t\tbreak; \\\n\t\t} \\\n\t\tif ((env->line_no < start_line  && ((line) < env->line_no || (line) > start_line)) || \\\n\t\t\t(env->line_no > start_line  && ((line) > env->line_no || (line) < start_line)) || \\\n\t\t\t(env->line_no == start_line && (line) != start_line)) { \\\n\t\t\t/* Line is completely outside selection */ \\\n\t\t\trecalculate_syntax(env->lines[(line)-1],(line)-1); \\\n\t\t} else { \\\n\t\t\tif ((line) == start_line || (line) == env->line_no) { \\\n\t\t\t\trecalculate_syntax(env->lines[(line)-1],(line)-1); \\\n\t\t\t} \\\n\t\t\tfor (int j = 0; j < env->lines[(line)-1]->actual; ++j) { \\\n\t\t\t\tif (point_in_range(start_line, env->line_no,start_col, env->col_no, (line), j+1)) { \\\n\t\t\t\t\tenv->lines[(line)-1]->text[j].flags |= FLAG_SELECT; \\\n\t\t\t\t} \\\n\t\t\t} \\\n\t\t} \\\n\t\tif ((line) - env->offset + 1 > 1 && \\\n\t\t\t(line) - env->offset - 1< global_config.term_height - global_config.bottom_size - 1) { \\\n\t\t\tredraw_line((line) - env->offset - 1, (line)-1); \\\n\t\t} \\\n\t} while (0)\n\n/**\n * CHAR SELECTION mode.\n */\nvoid char_selection_mode(void) {\n\tint start_line = env->line_no;\n\tint start_col  = env->col_no;\n\tint prev_line  = start_line;\n\n\tenv->mode = MODE_CHAR_SELECTION;\n\tredraw_commandline();\n\n\tint c;\n\tint timeout = 0;\n\tint this_buf[20];\n\n\t/* Select single character */\n\tenv->lines[env->line_no-1]->text[env->col_no-1].flags |= FLAG_SELECT;\n\tredraw_line(env->line_no - env->offset - 1, env->line_no-1);\n\n\twhile ((c = bim_getch())) {\n\t\tif (c == -1) {\n\t\t\tif (timeout && this_buf[timeout-1] == '\\033') {\n\t\t\t\tgoto _leave_select_char;\n\t\t\t}\n\t\t\ttimeout = 0;\n\t\t\tcontinue;\n\t\t} else {\n\t\t\tif (timeout == 0) {\n\t\t\t\tswitch (c) {\n\t\t\t\t\tcase '\\033':\n\t\t\t\t\t\tif (timeout == 0) {\n\t\t\t\t\t\t\tthis_buf[timeout] = c;\n\t\t\t\t\t\t\ttimeout++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase DELETE_KEY:\n\t\t\t\t\tcase BACKSPACE_KEY:\n\t\t\t\t\t\tcursor_left();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'v':\n\t\t\t\t\t\tgoto _leave_select_char;\n\t\t\t\t\tcase 'y':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint end_line = env->line_no;\n\t\t\t\t\t\t\tint end_col  = env->col_no;\n\t\t\t\t\t\t\tif (start_line == end_line) {\n\t\t\t\t\t\t\t\tif (start_col > end_col) {\n\t\t\t\t\t\t\t\t\tint tmp = start_col;\n\t\t\t\t\t\t\t\t\tstart_col = end_col;\n\t\t\t\t\t\t\t\t\tend_col = tmp;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if (start_line > end_line) {\n\t\t\t\t\t\t\t\tint tmp = start_line;\n\t\t\t\t\t\t\t\tstart_line = end_line;\n\t\t\t\t\t\t\t\tend_line = tmp;\n\t\t\t\t\t\t\t\ttmp = start_col;\n\t\t\t\t\t\t\t\tstart_col = end_col;\n\t\t\t\t\t\t\t\tend_col = tmp;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tyank_text(start_line, start_col, end_line, end_col);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tgoto _leave_select_char;\n\t\t\t\t\tcase 'D':\n\t\t\t\t\tcase 'd':\n\t\t\t\t\t\tif (env->readonly) goto _readonly;\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tint end_line = env->line_no;\n\t\t\t\t\t\t\tint end_col  = env->col_no;\n\t\t\t\t\t\t\tif (start_line == end_line) {\n\t\t\t\t\t\t\t\tif (start_col > end_col) {\n\t\t\t\t\t\t\t\t\tint tmp = start_col;\n\t\t\t\t\t\t\t\t\tstart_col = end_col;\n\t\t\t\t\t\t\t\t\tend_col = tmp;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tyank_text(start_line, start_col, end_line, end_col);\n\t\t\t\t\t\t\t\tfor (int i = start_col; i <= end_col; ++i) {\n\t\t\t\t\t\t\t\t\tline_delete(env->lines[start_line-1], start_col, start_line - 1);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tenv->col_no = start_col;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tif (start_line > end_line) {\n\t\t\t\t\t\t\t\t\tint tmp = start_line;\n\t\t\t\t\t\t\t\t\tstart_line = end_line;\n\t\t\t\t\t\t\t\t\tend_line = tmp;\n\t\t\t\t\t\t\t\t\ttmp = start_col;\n\t\t\t\t\t\t\t\t\tstart_col = end_col;\n\t\t\t\t\t\t\t\t\tend_col = tmp;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t/* Copy lines */\n\t\t\t\t\t\t\t\tyank_text(start_line, start_col, end_line, end_col);\n\t\t\t\t\t\t\t\t/* Delete lines */\n\t\t\t\t\t\t\t\tfor (int i = start_line+1; i < end_line; ++i) {\n\t\t\t\t\t\t\t\t\tremove_line(env->lines, start_line);\n\t\t\t\t\t\t\t\t} /* end_line is no longer valid; should be start_line+1*/\n\t\t\t\t\t\t\t\t/* Delete from start_col forward */\n\t\t\t\t\t\t\t\tint tmp = env->lines[start_line-1]->actual;\n\t\t\t\t\t\t\t\tfor (int i = start_col; i <= tmp; ++i) {\n\t\t\t\t\t\t\t\t\tline_delete(env->lines[start_line-1], start_col, start_line - 1);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfor (int i = 1; i <= end_col; ++i) {\n\t\t\t\t\t\t\t\t\tline_delete(env->lines[start_line], 1, start_line);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t/* Merge start and end lines */\n\t\t\t\t\t\t\t\tmerge_lines(env->lines, start_line);\n\t\t\t\t\t\t\t\tenv->line_no = start_line;\n\t\t\t\t\t\t\t\tenv->col_no = start_col;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (env->line_no > env->line_count) {\n\t\t\t\t\t\t\tenv->line_no = env->line_count;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tset_preferred_column();\n\t\t\t\t\t\tset_modified();\n\t\t\t\t\t\tgoto _leave_select_char;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\thandle_navigation(c);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tswitch (handle_escape(this_buf,&timeout,c)) {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\tbim_unget(c);\n\t\t\t\t\t\tgoto _leave_select_char;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Mark current line */\n\t\t\t_redraw_line_char(env->line_no,1);\n\n\t\t\t/* Properly mark everything in the span we just moved through */\n\t\t\tif (prev_line < env->line_no) {\n\t\t\t\tfor (int i = prev_line; i < env->line_no; ++i) {\n\t\t\t\t\t_redraw_line_char(i,1);\n\t\t\t\t}\n\t\t\t\tprev_line = env->line_no;\n\t\t\t} else if (prev_line > env->line_no) {\n\t\t\t\tfor (int i = env->line_no + 1; i <= prev_line; ++i) {\n\t\t\t\t\t_redraw_line_char(i,1);\n\t\t\t\t}\n\t\t\t\tprev_line = env->line_no;\n\t\t\t}\n\t\t\tplace_cursor_actual();\n\t\t\tcontinue;\n_readonly:\n\t\t\trender_error(\"Buffer is read-only\");\n\t\t}\n\t}\n\n_leave_select_char:\n\tset_history_break();\n\tenv->mode = MODE_NORMAL;\n\tfor (int i = 0; i < env->line_count; ++i) {\n\t\trecalculate_syntax(env->lines[i],i);\n\t}\n\tredraw_all();\n}\n\n/**\n * INSERT mode\n *\n * Accept input into the text buffer.\n */\nvoid insert_mode(void) {\n\tint cin;\n\tuint32_t c;\n\n\t/* Set mode line */\n\tenv->mode = MODE_INSERT;\n\tredraw_commandline();\n\n\t/* Place the cursor in the text area */\n\tplace_cursor_actual();\n\n\tint timeout = 0;\n\tint this_buf[20];\n\tuint32_t istate = 0;\n\tint redraw = 0;\n\twhile ((cin = bim_getch_timeout((redraw ? 10 : 200)))) {\n\t\tif (cin == -1) {\n\t\t\tif (redraw) {\n\t\t\t\tif (redraw & 2) {\n\t\t\t\t\tredraw_text();\n\t\t\t\t} else {\n\t\t\t\t\tredraw_line(env->line_no - env->offset - 1, env->line_no-1);\n\t\t\t\t}\n\t\t\t\tredraw_statusbar();\n\t\t\t\tplace_cursor_actual();\n\t\t\t\tredraw = 0;\n\t\t\t}\n\t\t\tif (timeout && this_buf[timeout-1] == '\\033') {\n\t\t\t\tleave_insert();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttimeout = 0;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!decode(&istate, &c, cin)) {\n\t\t\tif (timeout == 0) {\n\t\t\t\tswitch (c) {\n\t\t\t\t\tcase '\\033':\n\t\t\t\t\t\tif (timeout == 0) {\n\t\t\t\t\t\t\tthis_buf[timeout] = c;\n\t\t\t\t\t\t\ttimeout++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase DELETE_KEY:\n\t\t\t\t\tcase BACKSPACE_KEY:\n\t\t\t\t\t\tdelete_at_cursor();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ENTER_KEY:\n\t\t\t\t\tcase LINE_FEED:\n\t\t\t\t\t\tinsert_line_feed();\n\t\t\t\t\t\tredraw |= 2;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 22: /* ^V */\n\t\t\t\t\t\t/* Insert next byte raw */\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t/* Indicate we're in literal mode */\n\t\t\t\t\t\t\trender_commandline_message(\"^V\");\n\t\t\t\t\t\t\t/* Put the cursor back into the text field */\n\t\t\t\t\t\t\tplace_cursor_actual();\n\t\t\t\t\t\t\t/* Get next character */\n\t\t\t\t\t\t\twhile ((cin = bim_getch()) == -1);\n\t\t\t\t\t\t\t/* Insert literal */\n\t\t\t\t\t\t\tinsert_char(cin);\n\t\t\t\t\t\t\t/* Redraw INSERT */\n\t\t\t\t\t\t\tredraw_commandline();\n\t\t\t\t\t\t\t/* Draw text */\n\t\t\t\t\t\t\tredraw |= 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 23: /* ^W */\n\t\t\t\t\t\tdelete_word();\n\t\t\t\t\t\tset_preferred_column();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '\\t':\n\t\t\t\t\t\tif (env->tabs) {\n\t\t\t\t\t\t\tinsert_char('\\t');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfor (int i = 0; i < env->tabstop; ++i) {\n\t\t\t\t\t\t\t\tinsert_char(' ');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tredraw |= 1;\n\t\t\t\t\t\tset_preferred_column();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '}':\n\t\t\t\t\t\tif (env->indent) {\n\t\t\t\t\t\t\tint was_whitespace = 1;\n\t\t\t\t\t\t\tfor (int i = 0; i < env->lines[env->line_no-1]->actual; ++i) {\n\t\t\t\t\t\t\t\tif (env->lines[env->line_no-1]->text[i].codepoint != ' ' &&\n\t\t\t\t\t\t\t\t\tenv->lines[env->line_no-1]->text[i].codepoint != '\\t') {\n\t\t\t\t\t\t\t\t\twas_whitespace = 0;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tinsert_char('}');\n\t\t\t\t\t\t\tif (was_whitespace) {\n\t\t\t\t\t\t\t\tint line = -1, col = -1;\n\t\t\t\t\t\t\t\tenv->col_no--;\n\t\t\t\t\t\t\t\tfind_matching_paren(&line,&col);\n\t\t\t\t\t\t\t\tif (line != -1) {\n\t\t\t\t\t\t\t\t\twhile (env->lines[env->line_no-1]->actual) {\n\t\t\t\t\t\t\t\t\t\tline_delete(env->lines[env->line_no-1], env->lines[env->line_no-1]->actual, env->line_no-1);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tadd_indent(env->line_no-1,line-1,1);\n\t\t\t\t\t\t\t\t\tenv->col_no = env->lines[env->line_no-1]->actual + 1;\n\t\t\t\t\t\t\t\t\tinsert_char('}');\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tset_preferred_column();\n\t\t\t\t\t\t\tredraw |= 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* fallthrough */\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tinsert_char(c);\n\t\t\t\t\t\tset_preferred_column();\n\t\t\t\t\t\tredraw |= 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (handle_escape(this_buf,&timeout,c)) {\n\t\t\t\t\tbim_unget(c);\n\t\t\t\t\tleave_insert();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (istate == UTF8_REJECT) {\n\t\t\tistate = 0;\n\t\t}\n\t}\n}\n\n/*\n * REPLACE mode\n *\n * Like insert, but replaces characters.\n */\nvoid replace_mode(void) {\n\tint cin;\n\tuint32_t c;\n\n\t/* Set mode line */\n\tenv->mode = MODE_REPLACE;\n\tredraw_commandline();\n\n\t/* Place the cursor in the text area */\n\tplace_cursor_actual();\n\n\tint timeout = 0;\n\tint this_buf[20];\n\tuint32_t istate = 0;\n\twhile ((cin = bim_getch())) {\n\t\tif (cin == -1) {\n\t\t\tif (timeout && this_buf[timeout-1] == '\\033') {\n\t\t\t\tleave_insert();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttimeout = 0;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!decode(&istate, &c, cin)) {\n\t\t\tif (timeout == 0) {\n\t\t\t\tswitch (c) {\n\t\t\t\t\tcase '\\033':\n\t\t\t\t\t\tif (timeout == 0) {\n\t\t\t\t\t\t\tthis_buf[timeout] = c;\n\t\t\t\t\t\t\ttimeout++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase DELETE_KEY:\n\t\t\t\t\tcase BACKSPACE_KEY:\n\t\t\t\t\t\tif (env->line_no > 1 && env->col_no == 1) {\n\t\t\t\t\t\t\tenv->line_no--;\n\t\t\t\t\t\t\tenv->col_no = env->lines[env->line_no-1]->actual;\n\t\t\t\t\t\t\tset_preferred_column();\n\t\t\t\t\t\t\tplace_cursor_actual();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcursor_left();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ENTER_KEY:\n\t\t\t\t\tcase LINE_FEED:\n\t\t\t\t\t\tinsert_line_feed();\n\t\t\t\t\t\tredraw_text();\n\t\t\t\t\t\tset_modified();\n\t\t\t\t\t\tredraw_statusbar();\n\t\t\t\t\t\tplace_cursor_actual();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (env->col_no <= env->lines[env->line_no - 1]->actual) {\n\t\t\t\t\t\t\treplace_char(c);\n\t\t\t\t\t\t\tenv->col_no += 1;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tinsert_char(c);\n\t\t\t\t\t\t\tredraw_line(env->line_no - env->offset - 1, env->line_no-1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tredraw_statusbar();\n\t\t\t\t\t\tplace_cursor_actual();\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (handle_escape(this_buf,&timeout,c)) {\n\t\t\t\t\tbim_unget(c);\n\t\t\t\t\tleave_insert();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (istate == UTF8_REJECT) {\n\t\t\tistate = 0;\n\t\t}\n\t}\n}\n\n/**\n * NORMAL mode\n *\n * Default editor mode - just cursor navigation and keybinds\n * to enter the other modes.\n */\nvoid normal_mode(void) {\n\n\twhile (1) {\n\t\tplace_cursor_actual();\n\t\tint c;\n\t\tint timeout = 0;\n\t\tint this_buf[20];\n\t\twhile ((c = bim_getch())) {\n\t\t\tif (c == -1) {\n\t\t\t\t/* getch timed out, nothing to do in normal mode */\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (timeout == 0) {\n\t\t\t\tswitch (c) {\n\t\t\t\t\tcase '\\033':\n\t\t\t\t\t\tif (timeout == 0) {\n\t\t\t\t\t\t\tthis_buf[timeout] = c;\n\t\t\t\t\t\t\ttimeout++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase DELETE_KEY:\n\t\t\t\t\tcase BACKSPACE_KEY:\n\t\t\t\t\t\tif (env->line_no > 1 && env->col_no == 1) {\n\t\t\t\t\t\t\tenv->line_no--;\n\t\t\t\t\t\t\tenv->col_no = env->lines[env->line_no-1]->actual;\n\t\t\t\t\t\t\tset_preferred_column();\n\t\t\t\t\t\t\tplace_cursor_actual();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcursor_left();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'V': /* Enter LINE SELECTION mode */\n\t\t\t\t\t\tline_selection_mode();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'v': /* Enter CHAR SELECTION mode */\n\t\t\t\t\t\tchar_selection_mode();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'O': /* Append line before and enter INSERT mode */\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (env->readonly) goto _readonly;\n\t\t\t\t\t\t\tenv->lines = add_line(env->lines, env->line_no-1);\n\t\t\t\t\t\t\tenv->col_no = 1;\n\t\t\t\t\t\t\tadd_indent(env->line_no-1,env->line_no,0);\n\t\t\t\t\t\t\tredraw_text();\n\t\t\t\t\t\t\tset_preferred_column();\n\t\t\t\t\t\t\tset_modified();\n\t\t\t\t\t\t\tplace_cursor_actual();\n\t\t\t\t\t\t\tgoto _insert;\n\t\t\t\t\t\t}\n\t\t\t\t\tcase 'o': /* Append line after and enter INSERT mode */\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (env->readonly) goto _readonly;\n\t\t\t\t\t\t\tenv->lines = add_line(env->lines, env->line_no);\n\t\t\t\t\t\t\tenv->col_no = 1;\n\t\t\t\t\t\t\tenv->line_no += 1;\n\t\t\t\t\t\t\tadd_indent(env->line_no-1,env->line_no-2,0);\n\t\t\t\t\t\t\tset_preferred_column();\n\t\t\t\t\t\t\tif (env->line_no > env->offset + global_config.term_height - global_config.bottom_size - 1) {\n\t\t\t\t\t\t\t\tenv->offset += 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tredraw_text();\n\t\t\t\t\t\t\tset_modified();\n\t\t\t\t\t\t\tplace_cursor_actual();\n\t\t\t\t\t\t\tgoto _insert;\n\t\t\t\t\t\t}\n\t\t\t\t\tcase 'a': /* Enter INSERT mode with cursor after current position */\n\t\t\t\t\t\tif (env->col_no < env->lines[env->line_no-1]->actual + 1) {\n\t\t\t\t\t\t\tenv->col_no += 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tgoto _insert;\n\t\t\t\t\tcase 'P': /* Paste before */\n\t\t\t\t\tcase 'p': /* Paste after */\n\t\t\t\t\t\tif (env->readonly) goto _readonly;\n\t\t\t\t\t\tif (global_config.yanks) {\n\t\t\t\t\t\t\tif (!global_config.yank_is_full_lines) {\n\t\t\t\t\t\t\t\t/* Handle P for paste before, p for past after */\n\t\t\t\t\t\t\t\tint target_column = (c == 'P' ? (env->col_no) : (env->col_no+1));\n\t\t\t\t\t\t\t\tif (target_column > env->lines[env->line_no-1]->actual + 1) {\n\t\t\t\t\t\t\t\t\ttarget_column = env->lines[env->line_no-1]->actual + 1;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (global_config.yank_count > 1) {\n\t\t\t\t\t\t\t\t\t/* Spit the current line at the current position */\n\t\t\t\t\t\t\t\t\tenv->lines = split_line(env->lines, env->line_no - 1, target_column - 1); /* Split after */\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t/* Insert first line at current position */\n\t\t\t\t\t\t\t\tfor (int i = 0; i < global_config.yanks[0]->actual; ++i) {\n\t\t\t\t\t\t\t\t\tenv->lines[env->line_no - 1] = line_insert(env->lines[env->line_no - 1], global_config.yanks[0]->text[i], target_column + i - 1, env->line_no - 1); \n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (global_config.yank_count > 1) {\n\t\t\t\t\t\t\t\t\t/* Insert full lines */\n\t\t\t\t\t\t\t\t\tfor (unsigned int i = 1; i < global_config.yank_count - 1; ++i) {\n\t\t\t\t\t\t\t\t\t\tenv->lines = add_line(env->lines, env->line_no);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tfor (unsigned int i = 1; i < global_config.yank_count - 1; ++i) {\n\t\t\t\t\t\t\t\t\t\treplace_line(env->lines, env->line_no + i - 1, global_config.yanks[i]);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t/* Insert characters from last line into (what was) the next line */\n\t\t\t\t\t\t\t\t\tfor (int i = 0; i < global_config.yanks[global_config.yank_count-1]->actual; ++i) {\n\t\t\t\t\t\t\t\t\t\tenv->lines[env->line_no + global_config.yank_count - 2] = line_insert(env->lines[env->line_no + global_config.yank_count - 2], global_config.yanks[global_config.yank_count-1]->text[i], i, env->line_no + global_config.yank_count - 2);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t/* Insert full lines */\n\t\t\t\t\t\t\t\tfor (unsigned int i = 0; i < global_config.yank_count; ++i) {\n\t\t\t\t\t\t\t\t\tenv->lines = add_line(env->lines, env->line_no - (c == 'P' ? 1 : 0));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfor (unsigned int i = 0; i < global_config.yank_count; ++i) {\n\t\t\t\t\t\t\t\t\treplace_line(env->lines, env->line_no - (c == 'P' ? 1 : 0) + i, global_config.yanks[i]);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* Recalculate whole document syntax */\n\t\t\t\t\t\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\t\t\t\t\t\tenv->lines[i]->istate = 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\t\t\t\t\t\trecalculate_syntax(env->lines[i],i);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tset_history_break();\n\t\t\t\t\t\t\tset_modified();\n\t\t\t\t\t\t\tredraw_all();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'u': /* Undo one block of history */\n\t\t\t\t\t\tundo_history();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 18: /* ^R - Redo one block of history */\n\t\t\t\t\t\tredo_history();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 12: /* ^L - Repaint the whole screen */\n\t\t\t\t\t\tredraw_all();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'i': /* Enter INSERT mode */\n_insert:\n\t\t\t\t\t\tif (env->readonly) goto _readonly;\n\t\t\t\t\t\tinsert_mode();\n\t\t\t\t\t\tredraw_statusbar();\n\t\t\t\t\t\tredraw_commandline();\n\t\t\t\t\t\ttimeout = 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'R': /* Enter REPLACE mode */\n\t\t\t\t\t\tif (env->readonly) goto _readonly;\n\t\t\t\t\t\treplace_mode();\n\t\t\t\t\t\tredraw_statusbar();\n\t\t\t\t\t\tredraw_commandline();\n\t\t\t\t\t\ttimeout = 0;\n\t\t\t\t\t\tbreak;\n_readonly:\n\t\t\t\t\t\trender_error(\"Buffer is read-only\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\thandle_navigation(c);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\thandle_escape(this_buf,&timeout,c);\n\t\t\t}\n\t\t\tplace_cursor_actual();\n\t\t}\n\t}\n\n}\n\n/**\n * Show help text for -?\n */\nstatic void show_usage(char * argv[]) {\n#define _s \"\\033[3m\"\n#define _e \"\\033[0m\\n\"\n\tprintf(\n\t\t\t\"bim - Text editor\\n\"\n\t\t\t\"\\n\"\n\t\t\t\"usage: %s [options] [file]\\n\"\n\t\t\t\"       %s [options] -- -\\n\"\n\t\t\t\"\\n\"\n\t\t\t\" -R     \" _s \"open initial buffer read-only\" _e\n\t\t\t\" -O     \" _s \"set various options:\" _e\n\t\t\t\"        noscroll    \" _s \"disable terminal scrolling\" _e\n\t\t\t\"        noaltscreen \" _s \"disable alternate screen buffer\" _e\n\t\t\t\"        nomouse     \" _s \"disable mouse support\" _e\n\t\t\t\"        nounicode   \" _s \"disable unicode display\" _e\n\t\t\t\"        nobright    \" _s \"disable bright next\" _e\n\t\t\t\"        nohideshow  \" _s \"disable togglging cursor visibility\" _e\n\t\t\t\"        nosyntax    \" _s \"disable syntax highlighting on load\" _e\n\t\t\t\"        notitle     \" _s \"disable title-setting escapes\" _e\n\t\t\t\"        history     \" _s \"enable experimental undo/redo\" _e\n\t\t\t\" -c,-C  \" _s \"print file to stdout with syntax hilighting\" _e\n\t\t\t\"        \" _s \"-C includes line numbers, -c does not\" _e\n\t\t\t\" -u     \" _s \"override bimrc file\" _e\n\t\t\t\" -?     \" _s \"show this help text\" _e\n\t\t\t\"\\n\", argv[0], argv[0]);\n#undef _e\n#undef _s\n}\n\n/**\n * Load bimrc configuration file.\n *\n * At the moment, this a simple key=value list.\n */\nvoid load_bimrc(void) {\n\tif (!global_config.bimrc_path) return;\n\n\t/* Default is ~/.bimrc */\n\tchar * tmp = strdup(global_config.bimrc_path);\n\n\tif (!*tmp) {\n\t\tfree(tmp);\n\t\treturn;\n\t}\n\n\t/* Parse ~ at the front of the path. */\n\tif (*tmp == '~') {\n\t\tchar path[1024] = {0};\n\t\tchar * home = getenv(\"HOME\");\n\t\tif (!home) {\n\t\t\t/* $HOME is unset? */\n\t\t\tfree(tmp);\n\t\t\treturn;\n\t\t}\n\n\t\t/* New path is $HOME/.bimrc */\n\t\tsnprintf(path, 1024, \"%s%s\", home, tmp+1);\n\t\tfree(tmp);\n\t\ttmp = strdup(path);\n\t}\n\n\t/* Try to open the file */\n\tFILE * bimrc = fopen(tmp, \"r\");\n\tfree(tmp);\n\n\tif (!bimrc) {\n\t\t/* No bimrc, or bad permissions */\n\t\treturn;\n\t}\n\n\t/* Parse through lines */\n\tchar line[1024];\n\twhile (!feof(bimrc)) {\n\t\tchar * l = fgets(line, 1023, bimrc);\n\n\t\t/* Ignore bad lines */\n\t\tif (!l) break;\n\t\tif (!*l) continue;\n\t\tif (*l == '\\n') continue;\n\n\t\t/* Ignore comment lines */\n\t\tif (*l == '#') continue;\n\n\t\t/* Remove linefeed at the end */\n\t\tchar *nl = strstr(l,\"\\n\");\n\t\tif (nl) *nl = '\\0';\n\n\t\t/* Extract value from keypair, if available\n\t\t * (I foresee options without values in the future) */\n\t\tchar *value= strstr(l,\"=\");\n\t\tif (value) {\n\t\t\t*value = '\\0';\n\t\t\tvalue++;\n\t\t}\n\n\t\t/* theme=... */\n\t\tif (!strcmp(l,\"theme\") && value) {\n\t\t\t/* Examine available themes for a match. */\n\t\t\tfor (struct theme_def * d = themes; d->name; ++d) {\n\t\t\t\tif (!strcmp(value, d->name)) {\n\t\t\t\t\td->load();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/* enable history (experimental) */\n\t\tif (!strcmp(l,\"history\")) {\n\t\t\tglobal_config.history_enabled = (value ? atoi(value) : 1);\n\t\t}\n\n\t\t/* padding= */\n\t\tif (!strcmp(l,\"padding\") && value) {\n\t\t\tglobal_config.cursor_padding = atoi(value);\n\t\t}\n\n\t\tif (!strcmp(l,\"hlparen\") && value) {\n\t\t\tglobal_config.highlight_parens = atoi(value);\n\t\t}\n\t}\n\n\tfclose(bimrc);\n}\n\n/**\n * Set some default values when certain terminals are detected.\n */\nvoid detect_weird_terminals(void) {\n\n\tchar * term = getenv(\"TERM\");\n\tif (term && !strcmp(term,\"linux\")) {\n\t\t/* Linux VTs can't scroll. */\n\t\tglobal_config.can_scroll = 0;\n\t}\n\tif (term && !strcmp(term,\"cons25\")) {\n\t\t/* Dragonfly BSD console */\n\t\tglobal_config.can_hideshow = 0;\n\t\tglobal_config.can_altscreen = 0;\n\t\tglobal_config.can_mouse = 0;\n\t\tglobal_config.can_unicode = 0;\n\t\tglobal_config.can_bright = 0;\n\t}\n\tif (term && !strcmp(term,\"sortix\")) {\n\t\t/* sortix will spew title escapes to the screen, no good */\n\t\tglobal_config.can_title = 0;\n\t}\n\tif (term && strstr(term,\"tmux\") == term) {\n\t\tglobal_config.can_scroll = 0;\n\t\tglobal_config.can_bce = 0;\n\t}\n\tif (term && strstr(term,\"screen\") == term) {\n\t\t/* unfortunately */\n\t\tglobal_config.can_24bit = 0;\n\t\tglobal_config.can_italic = 0;\n\t}\n\tif (term && strstr(term,\"toaru-vga\") == term) {\n\t\tglobal_config.can_altscreen = 0;\n\t\tglobal_config.can_24bit = 0; /* Also not strictly true */\n\t\tglobal_config.can_256color = 0; /* Not strictly true */\n\t}\n\n}\n\n/**\n * Run global initialization tasks\n */\nvoid initialize(void) {\n\tsetlocale(LC_ALL, \"\");\n\n\tdetect_weird_terminals();\n\tload_colorscheme_ansi();\n\tload_bimrc();\n\n\tbuffers_avail = 4;\n\tbuffers = malloc(sizeof(buffer_t *) * buffers_avail);\n}\n\n/**\n * Initialize terminal for editor display.\n */\nvoid init_terminal(void) {\n\tfcntl(0, F_SETFD, O_RDONLY | O_NONBLOCK);\n\tset_alternate_screen();\n\tupdate_screen_size();\n\tget_initial_termios();\n\tset_unbuffered();\n\tmouse_enable();\n\n\tsignal(SIGWINCH, SIGWINCH_handler);\n\tsignal(SIGCONT,  SIGCONT_handler);\n\tsignal(SIGTSTP,  SIGTSTP_handler);\n}\n\nAQBOX_APPLET(bim)(int argc, char * argv[]) {\n\tint opt;\n\twhile ((opt = getopt(argc, argv, \"?c:C:u:RO:-:\")) != -1) {\n\t\tswitch (opt) {\n\t\t\tcase 'R':\n\t\t\t\tglobal_config.initial_file_is_read_only = 1;\n\t\t\t\tbreak;\n\t\t\tcase 'c':\n\t\t\tcase 'C':\n\t\t\t\t/* Print file to stdout using our syntax highlighting and color theme */\n\t\t\t\tinitialize();\n\t\t\t\tglobal_config.go_to_line = 0;\n\t\t\t\topen_file(optarg);\n\t\t\t\tfor (int i = 0; i < env->line_count; ++i) {\n\t\t\t\t\tif (opt == 'C') {\n\t\t\t\t\t\tdraw_line_number(i);\n\t\t\t\t\t}\n\t\t\t\t\trender_line(env->lines[i], 6 * (env->lines[i]->actual + 1), 0);\n\t\t\t\t\treset();\n\t\t\t\t\tfprintf(stdout, \"\\n\");\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\tcase 'u':\n\t\t\t\tglobal_config.bimrc_path = optarg;\n\t\t\t\tbreak;\n\t\t\tcase 'O':\n\t\t\t\t/* Set various display options */\n\t\t\t\tif (!strcmp(optarg,\"noaltscreen\"))     global_config.can_altscreen = 0;\n\t\t\t\telse if (!strcmp(optarg,\"noscroll\"))   global_config.can_scroll = 0;\n\t\t\t\telse if (!strcmp(optarg,\"nomouse\"))    global_config.can_mouse = 0;\n\t\t\t\telse if (!strcmp(optarg,\"nounicode\"))  global_config.can_unicode = 0;\n\t\t\t\telse if (!strcmp(optarg,\"nobright\"))   global_config.can_bright = 0;\n\t\t\t\telse if (!strcmp(optarg,\"nohideshow\")) global_config.can_hideshow = 0;\n\t\t\t\telse if (!strcmp(optarg,\"nosyntax\"))   global_config.hilight_on_open = 0;\n\t\t\t\telse if (!strcmp(optarg,\"nohistory\"))  global_config.history_enabled = 0;\n\t\t\t\telse if (!strcmp(optarg,\"notitle\"))    global_config.can_title = 0;\n\t\t\t\telse if (!strcmp(optarg,\"nobce\"))      global_config.can_bce = 0;\n\t\t\t\telse {\n\t\t\t\t\tfprintf(stderr, \"%s: unrecognized -O option: %s\\n\", argv[0], optarg);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase '-':\n\t\t\t\tif (!strcmp(optarg,\"version\")) {\n\t\t\t\t\tfprintf(stderr, \"bim %s %s\\n\", BIM_VERSION, BIM_COPYRIGHT);\n\t\t\t\t\tfprintf(stderr, \" Available syntax highlighters:\");\n\t\t\t\t\tfor (struct syntax_definition * s = syntaxes; s->name; ++s) {\n\t\t\t\t\t\tfprintf(stderr, \" %s\", s->name);\n\t\t\t\t\t}\n\t\t\t\t\tfprintf(stderr, \"\\n\");\n\t\t\t\t\tfprintf(stderr, \" Available color themes:\");\n\t\t\t\t\tfor (struct theme_def * d = themes; d->name; ++d) {\n\t\t\t\t\t\tfprintf(stderr, \" %s\", d->name);\n\t\t\t\t\t}\n\t\t\t\t\tfprintf(stderr, \"\\n\");\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase '?':\n\t\t\t\tshow_usage(argv);\n\t\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/* Set up terminal */\n\tinitialize();\n\tinit_terminal();\n\n\t/* Open file */\n\tif (argc > optind) {\n\t\topen_file(argv[optind]);\n\t\tupdate_title();\n\t\tif (global_config.initial_file_is_read_only) {\n\t\t\tenv->readonly = 1;\n\t\t}\n\t} else {\n\t\tenv = buffer_new();\n\t\tupdate_title();\n\t\tsetup_buffer(env);\n\t}\n\n\t/* Draw the screen once */\n\tredraw_all();\n\n\t/* Start accepting key commands */\n\tnormal_mode();\n\n\treturn 0;\n}\n"
  },
  {
    "path": "system/aqbox/extra/clear.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n\nAQBOX_APPLET(clear)(int argc, char *argv[])\n{\n\tprintf(\"\\033[H\\033[2J\");    /* VT100/ANSI Clear sequence */\n\tfflush(stdout);\n\treturn 0;\n}\n"
  },
  {
    "path": "system/aqbox/extra/mknod.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <sys/stat.h>\n#include <errno.h>\n\nvoid mknod_usage()\n{\n    fprintf(stderr, \"Usage: mknod NAME TYPE MAJOR MINOR\\n\");\n}\n\nAQBOX_APPLET(mknod)(int argc, char **argv)\n{\n    if (argc != 5) {\n        mknod_usage();\n        return -1;\n    }\n\n    char *path  = argv[1];\n    char *type  = argv[2];\n    char *major = argv[3];\n    char *minor = argv[4];\n\n    umask(0660);\n    mode_t mode = umask(0660);\n\n    switch (type[0]) {\n        case 'b': mode |= S_IFBLK; break;\n        case 'c': mode |= S_IFCHR; break;\n    }\n\n    unsigned major_n, minor_n;\n    sscanf(major, \"%u\", &major_n);\n    sscanf(minor, \"%u\", &minor_n);\n\n    dev_t dev = (((major_n) & 0xFF) << 8) | ((minor_n) & 0xFF);\n\n    if (mknod(path, mode, dev)) {\n        perror(\"mknod\");\n        return -1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/extra/mktemp.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include <errno.h>\n\nstatic void usage()\n{\n    fprintf(stderr, \"Usage: mktemp [-d] TEMPLATE\\n\");\n}\n\nAQBOX_APPLET(mktemp)(int argc, char **argv)\n{\n    const char *dir = \"/tmp\";\n    char fn[] = \"tmp.XXXXXX\";\n    int fd;\n\n    if ((fd = mkstemp(fn)) == -1) {\n        fprintf(stderr, \"mkstemp: %s\\n\", strerror(errno));\n        return -1;\n    }\n\n    printf(\"%s\\n\", fn);\n    close(fd);\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/extra/readmbr.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <stdint.h>\n#include <string.h>\n\n#define MBR_TYPE_UNUSED             0x00\n#define MBR_BOOT_SIGNATURE          0xAA55\n\nconst char *part_type[] = {\n    [0x00] = \"Empty\",\n    [0x01] = \"FAT12\",\n    [0x02] = \"XENIX root\",\n    [0x03] = \"XENIX usr\",\n    [0x04] = \"FAT16 <32M\",\n    [0x05] = \"Extended\",\n    [0x06] = \"FAT16\",\n    [0x07] = \"HPFS/NTFS/exFAT\",\n    [0x08] = \"AIX\",\n    [0x09] = \"AIX bootable\",\n    [0x0a] = \"OS/2 Boot Manag\",\n    [0x0b] = \"W95 FAT32\",\n    [0x0c] = \"W95 FAT32 (LBA)\",\n    [0x0e] = \"W95 FAT16 (LBA)\",\n    [0x0f] = \"W95 Ext'd (LBA)\",\n    [0x10] = \"OPUS\",\n    [0x11] = \"Hidden FAT12\",\n    [0x12] = \"Compaq diagnost\",\n    [0x14] = \"Hidden FAT16 <3\",\n    [0x16] = \"Hidden FAT16\",\n    [0x17] = \"Hidden HPFS/NTF\",\n    [0x18] = \"AST SmartSleep\",\n    [0x1b] = \"Hidden W95 FAT3\",\n    [0x1c] = \"Hidden W95 FAT3\",\n    [0x1e] = \"Hidden W95 FAT1\",\n    [0x24] = \"NEC DOS\",\n    [0x27] = \"Hidden NTFS Win\",\n    [0x39] = \"Plan 9\",\n    [0x3c] = \"PartitionMagic\",\n    [0x40] = \"Venix 80286\",\n    [0x41] = \"PPC PReP Boot\",\n    [0x42] = \"SFS\",\n    [0x4d] = \"QNX4.x\",\n    [0x4e] = \"QNX4.x 2nd part\",\n    [0x4f] = \"QNX4.x 3rd part\",\n    [0x50] = \"OnTrack DM\",\n    [0x51] = \"OnTrack DM6 Aux\",\n    [0x52] = \"CP/M\",\n    [0x53] = \"OnTrack DM6 Aux\",\n    [0x54] = \"OnTrackDM6\",\n    [0x55] = \"EZ-Drive\",\n    [0x56] = \"Golden Bow\",\n    [0x5c] = \"Priam Edisk\",\n    [0x61] = \"SpeedStor\",\n    [0x63] = \"GNU HURD or Sys\",\n    [0x64] = \"Novell Netware\",\n    [0x65] = \"Novell Netware \",\n    [0x70] = \"DiskSecure Mult\",\n    [0x75] = \"PC/IX \",\n    [0x80] = \"Old Minix\",\n    [0x81] = \"Minix\",\n    [0x82] = \"Linux swap / So\",\n    [0x83] = \"Linux\",\n    [0x84] = \"OS/2 hidden C: \",\n    [0x85] = \"Linux extended\",\n    [0x86] = \"NTFS volume set\",\n    [0x87] = \"NTFS volume set\",\n    [0x88] = \"Linux plaintext\",\n    [0x8e] = \"Linux LVM\",\n    [0x93] = \"Amoeba\",\n    [0x94] = \"Amoeba BBT\",\n    [0x9f] = \"BSD/OS\",\n    [0xa0] = \"IBM Thinkpad hi\",\n    [0xa5] = \"FreeBSD\",\n    [0xa6] = \"OpenBSD\",\n    [0xa7] = \"NeXTSTEP\",\n    [0xa8] = \"Darwin UFS\",\n    [0xa9] = \"NetBSD\",\n    [0xab] = \"Darwin boot\",\n    [0xaf] = \"HFS / HFS+\",\n    [0xb7] = \"BSDI fs\",\n    [0xb8] = \"BSDI swap\",\n    [0xbb] = \"Boot Wizard hid\",\n    [0xbe] = \"Solaris boot\",\n    [0xbf] = \"Solaris\",\n    [0xc1] = \"DRDOS/sec (FAT-\",\n    [0xc4] = \"DRDOS/sec (FAT-\",\n    [0xc6] = \"DRDOS/sec (FAT-\",\n    [0xc7] = \"Syrinx\",\n    [0xda] = \"Non-FS data\",\n    [0xdb] = \"CP/M / CTOS / .\",\n    [0xde] = \"Dell Utility\",\n    [0xdf] = \"BootIt\",\n    [0xe1] = \"DOS access\",\n    [0xe3] = \"DOS R/O\",\n    [0xe4] = \"SpeedStor\",\n    [0xeb] = \"BeOS fs\",\n    [0xee] = \"GPT\",\n    [0xef] = \"EFI (FAT-12/16/\",\n    [0xf0] = \"Linux/PA-RISC b\",\n    [0xf1] = \"SpeedStor\",\n    [0xf2] = \"DOS secondary\",\n    [0xf4] = \"SpeedStor\",\n    [0xfb] = \"VMware VMFS\",\n    [0xfc] = \"VMware VMKCORE\",\n    [0xfd] = \"Linux raid auto\",\n    [0xfe] = \"LANstep\",\n    [0xff] = \"BBT\",\n};\n\nstruct part {\n    uint8_t   status;\n    struct {\n        uint8_t  h;\n        uint8_t  s: 6;\n        uint16_t c: 10;\n    } __packed start_chs;\n    uint8_t   type;\n    struct {\n        uint8_t  h;\n        uint8_t  s: 6;\n        uint16_t c: 10;\n    } __packed end_chs;\n    uint32_t  start_lba;\n    uint32_t  sectors_count;\n} __packed;\n\nstruct mbr {\n    /* Actual Bootloader code */\n    uint8_t  bootloader[440];\n    uint32_t disk_signiture;\n    uint16_t copy_protected;\n\n    /* Partition table */\n    struct part ptab[4];\n\n    uint16_t boot_signature;\n} __packed;\n\nstatic int readmbr(const char *path)\n{\n    int fd;\n    \n    if ((fd = open(path, O_RDONLY)) < 0) {\n        perror(\"read\");\n        return -1;\n    }\n\n    struct mbr mbr;\n    memset(&mbr, 0, sizeof(struct mbr));\n\n    ssize_t r;\n    if ((r = read(fd, &mbr, sizeof(struct mbr))) < 0) {\n        close(fd);\n        perror(\"read\");\n        return -1;\n    }\n\n    for (int i = 0; i < 4; ++i) {\n        if (mbr.ptab[i].type == MBR_TYPE_UNUSED)\n            continue;\n\n        printf(\"Partition %d\\n\", i);\n        printf(\"  Status: %x\\n\", mbr.ptab[i].status);\n        unsigned type = mbr.ptab[i].type;\n        printf(\"  Type: 0x%x (%s)\\n\", mbr.ptab[i].type, part_type[type]? part_type[type] : \"Unkown\");\n        printf(\"  Start C/H/S: %u/%u/%u\\n\", mbr.ptab[i].start_chs.c, mbr.ptab[i].start_chs.h, mbr.ptab[i].start_chs.s);\n        printf(\"  End C/H/S: %u/%u/%u\\n\", mbr.ptab[i].end_chs.c, mbr.ptab[i].end_chs.h, mbr.ptab[i].end_chs.s);\n        printf(\"  Start LBA: 0x%lx\\n\", mbr.ptab[i].start_lba);\n        printf(\"  Sectors: %lu\\n\", mbr.ptab[i].sectors_count);\n    }\n\n    return 0;\n}\n\nAQBOX_APPLET(readmbr)(int argc, char *argv[])\n{\n    if (argc < 2) {\n        fprintf(stderr, \"Usage: readmbr DEVICE\\n\");\n        return -1;\n    }\n\n    return readmbr(argv[1]);\n}\n"
  },
  {
    "path": "system/aqbox/extra/stat.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <pwd.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <time.h>\n\nAQBOX_APPLET(stat)(int argc, char *argv[])\n{\n    if (argc < 2) {\n        fprintf(stderr, \"Usage: stat FILE...\\n\");\n        return -1;\n    }\n\n    int err = 0;\n\n    for (int i = 1; i < argc; ++i) {\n        const char *path = argv[i];\n\n        struct stat buf = {0};\n\n        if (lstat(path, &buf)) {\n            fprintf(stderr, \"stat: cannot stat '%s': \", path);\n            perror(\"\");\n            err = errno;\n            continue;\n        }\n\n        char *type = NULL, a_t = '\\0';\n        switch (buf.st_mode & S_IFMT) { \n            case S_IFDIR:  a_t = 'd'; type = \"directory\"; break;\n            case S_IFCHR:  a_t = 'c'; type = \"character special file\"; break;\n            case S_IFBLK:  a_t = 'b'; type = \"block special file\"; break;\n            case S_IFREG:  a_t = '-'; type = \"regular file\"; break;\n            case S_IFLNK:  a_t = 'l'; type = \"symbolic link\"; break;\n            case S_IFSOCK: a_t = 'x'; type = \"socket\"; break;\n            case S_IFIFO:  a_t = 'p'; type = \"fifo\"; break;\n        };\n\n        char perm[] = {\n            a_t, \n            buf.st_mode & S_IRUSR? 'r' : '-',\n            buf.st_mode & S_IWUSR? 'w' : '-',\n            buf.st_mode & S_IXUSR? 'x' : '-',\n            buf.st_mode & S_IRGRP? 'r' : '-',\n            buf.st_mode & S_IWGRP? 'w' : '-',\n            buf.st_mode & S_IXGRP? 'x' : '-',\n            buf.st_mode & S_IROTH? 'r' : '-',\n            buf.st_mode & S_IWOTH? 'w' : '-',\n            buf.st_mode & S_IXOTH? 'x' : '-',\n            '\\0'\n        };\n\n        struct passwd *passwd = getpwuid(buf.st_uid);\n\n        if (a_t == 'l') {\n            char sym[1024];\n            int fd = open(path, O_RDONLY | O_NOFOLLOW);\n            ssize_t len = read(fd, sym, 1024);\n            close(fd);\n            sym[len] = 0;\n            printf(\"  File: %s -> %s\\n\", path, sym);\n        } else {\n            printf(\"  File: %s\\n\", path);\n        }\n\n        char atim[64], mtim[64], ctim[64];\n\n        /* FIXME */\n        strftime(atim, 64, \"%F\", (struct tm *) &buf.st_atim);\n        strftime(mtim, 64, \"%F\", (struct tm *) &buf.st_mtim);\n        strftime(ctim, 64, \"%F\", (struct tm *) &buf.st_ctim);\n\n        printf(\"      Type: %s\\n\", type);\n        printf(\"    Device: %x/%x\\n\", buf.st_dev >> 8, buf.st_dev & 0xff);\n        printf(\"     Inode: %d\\n\", buf.st_ino);\n        printf(\"Permission: %s\\n\", perm);\n        printf(\"     Links: %d\\n\", buf.st_nlink);\n        printf(\"       UID: %lu (%s)\\n\", buf.st_uid, passwd? passwd->pw_name : \"not in /etc/passwd\");\n        printf(\"       GID: %lu (%s)\\n\", buf.st_gid, \"root\");\n        printf(\"      rDev: %x/%x\\n\", buf.st_rdev >> 8, buf.st_rdev & 0xff);\n        printf(\"      Size: %lu\\n\", buf.st_size);\n        printf(\"Block Size: %lu\\n\", buf.st_blksize);\n        printf(\"    Blocks: %lu\\n\", buf.st_blocks);\n        printf(\"    Access: %s\\n\", atim);\n        printf(\"    Modify: %s\\n\", mtim);\n        printf(\"    Change: %s\\n\", ctim);\n    }\n\n\treturn err;\n}\n"
  },
  {
    "path": "system/aqbox/extra/truncate.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n\nvoid truncate_usage()\n{\n    fprintf(stderr, \"Usage: truncate OPTION... FILE...\\n\");\n}\n\n#define FLAG_c  0x01\n#define FLAG_o  0x02\n#define FLAG_r  0x04\n#define FLAG_s  0x08\n\nAQBOX_APPLET(truncate)(int argc, char **argv)\n{\n    int opt, flags = 0;\n    const char *ref = NULL;\n    int size = 0;\n\n    while ((opt = getopt(argc, argv, \"cor:s:\")) != -1) {\n        switch (opt) {\n            case 'c': flags |= FLAG_c; break;\n            case 'o': flags |= FLAG_o; break;\n            case 'r': flags |= FLAG_r; ref = optarg; break;\n            case 's': flags |= FLAG_s; size = atoi(optarg); break;\n            default: truncate_usage(); return -1;\n        }\n    }\n\n    if (flags & ((FLAG_r | FLAG_s) == 0)) {\n        fprintf(stderr, \"truncate: you must specify either '-s' or '-r'\\n\");\n        return -1;\n    }\n\n    if (optind >= argc) {\n        fprintf(stderr, \"truncate: missing file operand\\n\");\n        return -1;\n    }\n\n    for (opt = optind; opt < argc; ++opt) {\n        if (truncate(argv[opt], size)) {\n            perror(\"truncate\");\n            return -1;\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/extra/vmstat.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <string.h>\n\n#define KVMEM   \"/proc/kvmem\"\n#define BUFSIZE 1024\n\nchar buf[BUFSIZE];\n\nAQBOX_APPLET(vmstat)(int argc, char *argv[])\n{\n    int err = 0;\n\n    FILE *file = fopen(KVMEM, \"r\");\n\n    if (!file) {\n        fprintf(stderr, \"failed to open %s: %s\\n\", KVMEM, strerror(errno));\n        return -1;\n    }\n\n    while ((fgets(buf, sizeof(buf), file) != NULL)) {\n        fprintf(stderr, \"got %s\\n\", buf);\n        //write(2, buf, r);\n    }\n\n\treturn err;\n}\n"
  },
  {
    "path": "system/aqbox/include/aq_applets.h",
    "content": "#ifndef AQ_APPLETS\n#define AQ_APPLETS\n\nint cmd_cat(int, char**);\nint cmd_clear(int, char**);\nint cmd_echo(int, char**);\nint cmd_env(int, char**);\nint cmd_getty(int, char**);\nint cmd_login(int, char**);\nint cmd_ls(int, char**);\nint cmd_mkdir(int, char**);\nint cmd_mknod(int, char**);\nint cmd_mount(int, char**);\nint cmd_ps(int, char**);\nint cmd_pwd(int, char**);\nint cmd_readmbr(int, char**);\nint cmd_sh(int, char**);\nint cmd_stat(int, char**);\nint cmd_touch(int, char**);\nint cmd_uname(int, char**);\nint cmd_unlink(int, char**);\nint cmd_kill(int, char**);\nint cmd_reboot(int, char**);\nint cmd_bim(int, char**);\nint cmd_truncate(int, char**);\nint cmd_mktemp(int, char**);\nint cmd_vmstat(int, char**);\nint cmd_date(int, char**);\n\n#define APPLET(name) {#name, cmd_##name}\n\nstruct applet {\n    char *name;\n    int (*f)(int, char **);\n} applets[] = {\n    APPLET(bim),\n    APPLET(cat),\n    APPLET(clear),\n    APPLET(date),\n    APPLET(echo),\n    APPLET(env),\n    APPLET(getty),\n    APPLET(kill),\n    APPLET(login),\n    APPLET(ls),\n    APPLET(mkdir),\n    APPLET(mknod),\n    APPLET(mktemp),\n    APPLET(mount),\n    APPLET(ps),\n    APPLET(pwd),\n    APPLET(readmbr),\n    APPLET(reboot),\n    APPLET(sh),\n    APPLET(stat),\n    APPLET(touch),\n    APPLET(truncate),\n    APPLET(uname),\n    APPLET(unlink),\n    APPLET(vmstat),\n};\n\n#define APPLETS_NR (sizeof(applets)/sizeof(*applets))\n\n#endif /* ! AQ_APPLETS */\n"
  },
  {
    "path": "system/aqbox/include/aqbox.h",
    "content": "#ifndef _AQBOX_H\n#define _AQBOX_H\n\n#ifndef _AQ_STANDALONE\n#define AQBOX_APPLET(n) int cmd_##n\n#else\n#define AQBOX_APPLET(n) int main\n#endif\n\nint (*aqbox_get_applet(char *name))();\n\n#endif /* ! _AQBOX_H */\n"
  },
  {
    "path": "system/aqbox/posix/Build.mk",
    "content": "obj-y += sh.o\nobj-y += cat.o\nobj-y += echo.o\nobj-y += env.o\nobj-y += ls.o\nobj-y += mkdir.o\nobj-y += ps.o\nobj-y += pwd.o\nobj-y += uname.o\nobj-y += unlink.o\nobj-y += touch.o\nobj-y += kill.o\nobj-y += date.o\n"
  },
  {
    "path": "system/aqbox/posix/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  SYSLD   \" $(CWD)/builtin.o\n\t@$(SYSLD) $(SYSLDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  SYSCC   \" $(CWD)/$@\n\t@$(SYSCC) $(SYSCFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) builtin.o\n\t@$(RM) $(obj-y) builtin.o\n"
  },
  {
    "path": "system/aqbox/posix/cat.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <string.h>\n#include <errno.h>\n\n#ifndef CAT_BUFSIZE\n#define CAT_BUFSIZE 512\n#endif\n\nstatic void usage()\n{\n    fprintf(stderr, \n            \"Usage: cat [-u] [file...]\\n\"\n            \"Concatenate and print files\\n\");\n}\n\nchar buf[CAT_BUFSIZE];\nstatic int do_cat(const char *path)\n{\n    int err = 0;\n    int fd = 0; /* Use stdin by default */\n\n    if (path) {\n        fd = open(path, O_RDONLY);\n\n        if (fd < 0) {\n            fprintf(stderr, \"cat: %s: %s\\n\", path, strerror(errno));\n            return -1;\n        }\n    }\n\n\n    int r;\n    while ((r = read(fd, buf, CAT_BUFSIZE)) > 0) {\n        if ((err = write(1, buf, r)) < 0) {\n            fprintf(stderr, \"cat: write: %s\\n\", strerror(errno));\n            goto error;\n        }\n    }\n\n    if (r < 0) {\n        fprintf(stderr, \"cat: read: %s\\n\", strerror(errno));\n        err = r;\n        goto error;\n    }\n\nerror:\n    close(fd);\n    return err;\n}\n\nAQBOX_APPLET(cat)(int argc, char **argv)\n{\n    int opt;\n    while ((opt = getopt(argc, argv, \"uh\")) != -1) {\n        switch (opt) {\n            case 'u':\n                /* ignore */\n                break;\n            case 'h':\n                usage();\n                return 0;\n            default:\n                usage();\n                return -1;\n        }\n    }\n\n    for (int i = optind; i < argc; ++i) {\n        if (!strcmp(argv[i], \"-\"))\n            do_cat(NULL);\n        else\n            do_cat(argv[i]);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/posix/date.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <time.h>\n#include <errno.h>\n#include <sys/time.h>\n\nstatic void usage()\n{\n    fprintf(stderr, \n            \"Usage: date [-u] [+format]\\n\"\n            \"Write the date and time\\n\");\n}\n\nAQBOX_APPLET(date)(int argc, char **argv)\n{\n    int opt;\n    while ((opt = getopt(argc, argv, \"u\")) != -1) {\n        switch (opt) {\n            case 'u':\n                /* ignore */\n                break;\n            default:\n                usage();\n                return -1;\n        }\n    }\n\n    time_t rawtime;\n    struct tm *timeinfo;\n    char buf[128];\n\n    time(&rawtime);\n    timeinfo = localtime(&rawtime);\n\n    strftime(buf, sizeof(buf), \"%c\", timeinfo);\n    puts(buf);\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/posix/echo.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n\n#define FLAG_n  0x0001\n#define FLAG_e  0x0002\n\nstatic void usage()\n{\n    fprintf(stderr, \n            \"Usage: echo [-ne] [string...]\\n\"\n            \"Write arguments to standard output.\\n\");\n}\n\nstatic int do_echo(int argc, const char *argv[], int flags)\n{\n    for (int i = 0; i < argc; ++i) {\n        if (flags & FLAG_e) {\n            const char *s = argv[i];\n            int len = strlen(s);\n            for (int j = 0; j < len; ++j) {\n                if (s[j] == '\\\\') {\n                    /* XXX Sanity checking */\n                    switch (s[++j]) {\n                        case 'e':\n                            putchar('\\033');\n                            break;\n                        case 'n':\n                            putchar('\\n');\n                            break;\n                    }\n                } else {\n                    putchar(s[j]);\n                }\n            }\n        } else {\n            printf(\"%s \", argv[i]);\n        }\n    }\n\n    if (!(flags & FLAG_n))\n        printf(\"\\n\");\n\n    return 0;\n}\n\nAQBOX_APPLET(echo)(int argc, char *argv[])\n{\n    int newline = 1, escape = 0, flags = 0, opt;\n\n    while ((opt = getopt(argc, argv, \"ne\")) != -1) {\n        switch (opt) {\n            case 'n':\n                newline = 0;\n                flags  |= FLAG_n;\n                break;\n            case 'e':\n                escape = 1;\n                flags  |= FLAG_e;\n                break;\n        }\n    }\n\n    do_echo(argc - optind, (const char **) &argv[optind], flags);\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/posix/env.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <string.h>\n\nextern char **environ;\n\nstatic void usage(void)\n{\n    fprintf(stderr,\n            \"Usage: env [-i] [name=value]... [utility [argument...]]\\n\"\n            \"Set the environment for command invocation\\n\");\n}\n\nstatic void __clearenv(void)\n{\n    environ = NULL;\n}\n\nstatic void print_env(void)\n{\n    char **e = environ;\n    while (e && *e) {\n        printf(\"%s\\n\", *e++);\n    }\n}\n\nstatic int run(int argc, char *argv[])\n{\n    /* TODO check PATH */\n    fprintf(stderr, \"run: \");\n    for (int i = 0; i < argc; ++i)\n        fprintf(stderr, \"%s \", argv[i]);\n    fprintf(stderr, \"\\n\");\n\n    return execv(argv[0], argv);\n}\n\n#define FLAG_i  1\n\nAQBOX_APPLET(env)(int argc, char *argv[])\n{\n    int flags = 0, opt;\n\n    while ((opt = getopt(argc, argv, \"i\")) != -1) {\n        switch (opt) {\n            case 'i': flags |= FLAG_i; break;\n            default: usage(); exit(1);\n        }\n    }\n\n#if 0\n    if (flags & FLAG_i)\n        __clearenv();\n#endif\n\n    if (optind >= argc) {\n        /* No arguments passed */\n        print_env();\n        exit(0);\n    }\n\n    for (int i = optind; i < argc; ++i) {\n        if (strchr(argv[i], '=')) {\n            putenv(argv[i]);\n        } else {\n            exit(run(argc - i, &argv[i]));\n        }\n    }\n\n    print_env();\n    exit(0);\n}\n"
  },
  {
    "path": "system/aqbox/posix/kill.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <signal.h>\n#include <string.h>\n#include <errno.h>\n\nstatic void usage()\n{\n    fprintf(stderr, \n            \"Usage: kill [-signal_number] pid...\\n\"\n            \"Terminate or signal processes\\n\");\n}\n\nstatic int do_kill(int argc, const char *argv[], int sig)\n{\n    for (int i = 0; i < argc; ++i) {\n        int pid;\n        sscanf(argv[i], \"%d\", &pid);\n        if (kill(pid, sig)) {\n            fprintf(stderr, \"kill: %s\\n\", strerror(errno));\n        }\n    }\n\n    return 0;\n}\n\nAQBOX_APPLET(kill)(int argc, char *argv[])\n{\n    int sig = SIGTERM;\n\n    if (argc < 2) {\n        usage();\n        return -1;\n    }\n\n    int i = 1;\n\n    if (argv[1][0] == '-') {\n        sscanf(&argv[1][1], \"%d\", &sig);\n        ++i;\n    }\n\n    do_kill(argc - i, (const char **) &argv[i], sig);\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/posix/ls.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <dirent.h>\n#include <errno.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#include <pwd.h>\n#include <fcntl.h>\n#include <time.h>\n#include <string.h>\n\n#define FLAG_A  0x0000001\n#define FLAG_C  0x0000002\n#define FLAG_F  0x0000004\n#define FLAG_H  0x0000008\n#define FLAG_L  0x0000010\n#define FLAG_R  0x0000020\n#define FLAG_S  0x0000040\n#define FLAG_a  0x0000080\n#define FLAG_c  0x0000100\n#define FLAG_d  0x0000200\n#define FLAG_f  0x0000400\n#define FLAG_g  0x0000800\n#define FLAG_i  0x0001000\n#define FLAG_k  0x0002000\n#define FLAG_l  0x0004000\n#define FLAG_m  0x0008000\n#define FLAG_n  0x0010000\n#define FLAG_o  0x0020000\n#define FLAG_p  0x0040000\n#define FLAG_q  0x0080000\n#define FLAG_r  0x0100000\n#define FLAG_s  0x0200000\n#define FLAG_t  0x0400000\n#define FLAG_u  0x0800000\n#define FLAG_x  0x1000000\n\n#define MAX_ENTRIES 1024\nstruct dirent entries[MAX_ENTRIES];\n\nchar *file_mode(struct stat *buf)\n{\n    char a_t = '\\0';\n    switch (buf->st_mode & S_IFMT) { \n        case S_IFDIR:  a_t = 'd'; break;\n        case S_IFCHR:  a_t = 'c'; break;\n        case S_IFBLK:  a_t = 'b'; break;\n        case S_IFREG:  a_t = '-'; break;\n        case S_IFLNK:  a_t = 'l'; break;\n        case S_IFSOCK: a_t = 'x'; break;\n        case S_IFIFO:  a_t = 'p'; break;\n    };\n\n    static char mode[11];\n\n    mode[0] = a_t; \n    mode[1] = buf->st_mode & S_IRUSR? 'r' : '-';\n    mode[2] = buf->st_mode & S_IWUSR? 'w' : '-';\n    mode[3] = buf->st_mode & S_IXUSR? 'x' : '-';\n    mode[4] = buf->st_mode & S_IRGRP? 'r' : '-';\n    mode[5] = buf->st_mode & S_IWGRP? 'w' : '-';\n    mode[6] = buf->st_mode & S_IXGRP? 'x' : '-';\n    mode[7] = buf->st_mode & S_IROTH? 'r' : '-';\n    mode[8] = buf->st_mode & S_IWOTH? 'w' : '-';\n    mode[9] = buf->st_mode & S_IXOTH? 'x' : '-';\n    mode[10] = '\\0';\n\n    return mode;\n}\n\nint print_long_entry(char *path, char *fn)\n{\n    char full_path[512];\n    snprintf(full_path, 512, \"%s/%s\", path, fn);\n\n    struct stat buf = {0};\n\n    if (lstat(full_path, &buf)) {\n        fprintf(stderr, \"stat: cannot stat '%s': \", fn);\n        perror(\"\");\n        return -1;\n    }\n\n    /* <file mode> */\n    char *mode = file_mode(&buf);\n\n    /* <number of links> */\n    unsigned nlink = buf.st_nlink;\n\n    /* <owner name> */\n    struct passwd *passwd = getpwuid(buf.st_uid);\n    char *owner = passwd? passwd->pw_name : \"\";\n\n    /* <group name> */\n    char *group = \"root\";\n\n    /* <device info> */\n    char device[16] = \"\";\n    dev_t dev = buf.st_rdev;\n\n    if (dev)\n        snprintf(device, 16, \"%u, %u\", (dev >> 8) & 0xFF, dev & 0xFF);\n\n    /* <size> */\n    size_t size = buf.st_size;\n\n    /* <date and time> */\n    char time[64] = \"\";\n    struct tm *tm = gmtime(&buf.st_mtim.tv_sec);\n    strftime(time, 64, \"%b %e %Y %H:%M\", tm);\n    \n    /* <pathname> */\n    char name[512];\n\n    if (S_ISLNK(buf.st_mode)) {\n        int fd = open(full_path, O_RDONLY | O_NOFOLLOW);\n        char symlink[512];\n        symlink[0] = 0;\n        read(fd, symlink, 512);\n        close(fd);\n        snprintf(name, 512, \"%s -> %s\", fn, symlink);\n    } else {\n        snprintf(name, 512, \"%s\", fn);\n    }\n\n    if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode))\n        printf(\"%s %4u %s %s %8s %s %s\\n\", mode, nlink, owner, group, device, time, name);\n    else\n        printf(\"%s %4u %s %s %8lu %s %s\\n\", mode, nlink, owner, group, size, time, name);\n\n    return 0;\n}\n\nint do_ls(char *path, uint32_t flags)\n{\n    /* Open directory */\n    DIR *dir = NULL;\n\n    if (!(dir = opendir(path))) {\n        fprintf(stderr, \"ls: cannot access '%s': %s\\n\", path, strerror(errno));\n        return -1;\n    }\n\n    int entries_idx;\n\n    /* fetch enteries */\n    for (entries_idx = -1; entries_idx < MAX_ENTRIES - 1;) {\n        struct dirent *entry;\n\n        if ((entry = readdir(dir))) {\n            memcpy(&entries[++entries_idx], entry, sizeof(struct dirent));\n        } else {\n            break;\n        }\n    }\n\n    /* sort entries - TODO */\n\n    size_t maxlen = 0;\n    for (int i = 0; i < entries_idx + 1; ++i) {\n        size_t len = strlen(entries[i].d_name);\n        if (len > maxlen)\n            maxlen = len;\n    }\n\n    size_t termwidth = 80;\n    size_t entries_per_line = termwidth / (maxlen + 2);\n\n    /* print entries */\n    if (flags & FLAG_l) {   /* long mode */\n        for (int i = 0; i < entries_idx + 1; ++i) {\n            if ((flags & FLAG_a) || (entries[i].d_name[0] != '.'))\n                print_long_entry(path, entries[i].d_name);\n        }\n    } else {\n        int j = 0;\n        for (int i = 0; i < entries_idx + 1; ++i) {\n            if ((flags & FLAG_a) || (entries[i].d_name[0] != '.')) {\n                printf(\"%-*s  \", (int) maxlen, entries[i].d_name);\n                fflush(stdout);\n                ++j;\n\n                if (j == (int) entries_per_line) {\n                    j = 0;\n                    printf(\"\\n\");\n                    fflush(stdout);\n                }\n            }\n        }\n\n        if (j != 0) {\n            printf(\"\\n\");\n            fflush(stdout);\n        }\n    }\n\n    closedir(dir);\n\n    return 0;\n}\n\nint ls_usage()\n{\n    return 0;\n}\n\nAQBOX_APPLET(ls)(int argc, char **argv)\n{\n    int print_name = 0;\n    uint32_t flags = 0;\n\n    int pathc = 0;\n    char *pathv[argc];\n\n    int opt;\n\n    while ((opt = getopt(argc, argv, \"al\")) != -1) {\n        switch (opt) {\n            case 'a': flags |= FLAG_a; break;\n            case 'l': flags |= FLAG_l; break;\n            default: ls_usage(); exit(-1);\n        }\n    }\n\n    while (optind < argc)\n        pathv[pathc++] = argv[optind++];\n\n    if (pathc == 0) {\n        do_ls(\".\", flags);\n    } else {\n        print_name = pathc > 2;\n        for (int i = 0; i < pathc; ++i) {\n            print_name? printf(\"%s:\\n\", pathv[i]): 0;\n            do_ls(pathv[i], flags);\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/posix/mkdir.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <sys/stat.h>\n\nstatic void usage()\n{\n    fprintf(stderr, \n            \"Usage: mkdir [-m mode] dir...\\n\"\n            \"Make directories\\n\");\n}\n\nAQBOX_APPLET(mkdir)(int argc, char **argv)\n{\n    int opt;\n    unsigned mode = 0775;\n\n    while ((opt = getopt(argc, argv, \"hm:\")) != -1) {\n        switch (opt) {\n            case 'm':\n                sscanf(optarg, \"%o\", &mode);\n                break;\n            case 'h':\n                usage();\n                return 0;\n        }\n    }\n\n    for (int i = optind; i < argc; ++i) {\n        if (mkdir(argv[i], mode)) {\n            perror(\"mkdir\");\n            return -1;\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/posix/ps.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <sys/types.h>\n#include <dirent.h>\n\nvoid print_info(char *ent)\n{\n    char path[512];\n    snprintf(path, 512, \"/proc/%s/status\", ent);\n\n    char buf[512];\n    FILE *status;\n\n    if (!(status = fopen(path, \"r\"))) {\n        perror(\"fopen\");\n        return;\n    }\n\n    fread(buf, 512, 1, status);\n    fclose(status);\n\n    char name[64];\n    int pid;\n    int ppid;\n\n    sscanf(buf, \n        \"name: %s\\n\"\n        \"pid: %d\\n\"\n        \"ppid: %d\\n\",\n        name, &pid, &ppid);\n\n    printf(\"%5d %5d %s\\n\", pid, ppid, name);\n}\n\nAQBOX_APPLET(ps)(int argc, char **argv)\n{\n    DIR *proc;\n    struct dirent *dirent;\n\n    if (!(proc = opendir(\"/proc\"))) {\n        perror(\"opendir\");\n        return -1;\n    }\n\n    printf(\"  PID  PPID PATH\\n\");\n    while ((dirent = readdir(proc))) {\n        if (dirent->d_name[0] > '0' && dirent->d_name[0] <= '9') {\n            print_info(dirent->d_name);\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/posix/pwd.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n\nAQBOX_APPLET(pwd)(int argc, char **argv)\n{\n    char buf[1024];\n    getcwd(buf, 1024);\n    printf(\"%s\\n\", buf);\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/posix/sh.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#include <fcntl.h>\n#include <errno.h>\n#include <dirent.h>\n#include <unistd.h>\n#include <glob.h>\n#include <termios.h>\n#include <signal.h>\n\n#include <sys/wait.h>\n#include <sys/mount.h>\n#include <sys/utsname.h>\n\n#include <sys/ioctl.h>\n#include <termios.h>\n\nint flags = 0;\n\n#define F_DEBUG 1\n\n/*\n * Built-in commands\n */\n\nint builtin_cd(int argc, char **argv)\n{\n    char *path = NULL;\n    if (argc == 1) {\n        if (!(path = getenv(\"HOME\")))\n            path = \"/\";\n    } else if (argc == 2) {\n        path = argv[1];\n    } else {\n        fprintf(stderr, \"aqsh: cd: too many arguments\\n\");\n        return -1;\n    }\n\n    if (chdir(path)) {\n        fprintf(stderr, \"aqsh: cd: %s: \", path);\n        perror(\"\");\n        return errno;\n    }\n\n    /* Update environment */\n    char buf[512], cwd[512];\n    getcwd(cwd, 512);\n    snprintf(buf, 512, \"PWD=%s\", cwd);\n    putenv(buf);\n    return 0;\n}\n\nint builtin_export(int argc, char **argv)\n{\n    for (int i = 0; i < argc; ++i) {\n        putenv(argv[i]);    /* FIXME */\n    }\n\n    return 0;\n}\n\nint builtin_exit(int argc, char **argv)\n{\n    exit(0);\n}\n\nint builtin_true(int argc, char **argv)\n{\n    return 0;\n}\n\nint builtin_set(int argc, char **argv)\n{\n    for (int i = 0; i < argc; ++i) {\n        if (!strcmp(argv[i], \"-x\"))\n            flags |= F_DEBUG;\n    }\n\n    return 0;\n}\n\n#if 0\nint builtin_glob(int argc, char **argv)\n{\n    if (argc > 1) {\n        glob_t pglob = {.gl_offs = 0};\n        int ret = glob(argv[1], 0, NULL, &pglob);\n        if (ret) {\n            perror(\"glob\");\n        }\n\n        for (size_t i = 0; i < pglob.gl_pathc; ++i) {\n            printf(\"%s\\n\", pglob.gl_pathv[i]);\n        }\n    }\n\n    return 0;\n}\n#endif\n\nstruct aqsh_command {\n    char *name;\n    int (*f)(int, char**);\n} builtin_commands[] = {    /* Commands must be sorted */\n    {\"cd\", builtin_cd},\n    {\"exit\", builtin_exit},\n    {\"export\", builtin_export},\n    {\"set\", builtin_set},\n    {\"true\", builtin_true},\n    //{\"glob\", builtin_glob},\n};\n\n#define BUILTIN_COMMANDS_NR ((sizeof(builtin_commands)/sizeof(builtin_commands[0])))\n\nstatic int bsearch_helper(const void *a, const void *b)\n{\n    struct aqsh_command *_a = (struct aqsh_command *) a;\n    struct aqsh_command *_b = (struct aqsh_command *) b;\n    return strcmp(_a->name, _b->name);\n}\n\nint (*aqsh_get_command(char *name))()\n{\n    /* Perform binary search on commands */\n    struct aqsh_command *cmd = (struct aqsh_command *) \n        bsearch(&(struct aqsh_command){.name=name}, builtin_commands, BUILTIN_COMMANDS_NR, sizeof(builtin_commands[0]), bsearch_helper);\n\n    return cmd? cmd->f : NULL;\n}\n\n/*\n * Global variables \n */\n\nextern char **environ;\nchar *hostname = \"aquila\";\nchar *user = \"root\";\nchar *pwd = \"/\";\n\n/***********/\nvoid print_prompt()\n{\n    int root_prompt = getuid() == 0;\n    printf(\"[%s@%s %s]%c \", user, hostname, pwd, root_prompt? '#' : '$');\n    fflush(stdout);\n}\n\nint run_prog(char *name, char **argv, int wait)\n{\n    int cld;\n    if ((cld = fork())) {\n        if (wait) {\n            int s, pid;\n            do {\n                pid = waitpid(cld, &s, 0);\n            } while (pid != cld);\n\n            if (WIFSIGNALED(s)) {   /* Terminated due to signal */\n                switch (WTERMSIG(s)) {\n                    case SIGINT:    /* Ignore */\n                        break;\n                    case SIGSEGV:\n                        fprintf(stderr, \"Segmentation fault\\n\");\n                        break;\n                    default:\n                        fprintf(stderr, \"Terminated due to signal %d\\n\", WTERMSIG(s));\n                        break;\n                }\n            }\n        }\n    } else {\n        int x = execve(name, argv, environ);\n        fprintf(stderr, \"sh: execve: %s\\n\", strerror(errno));\n        exit(x);\n    }\n\n    return 0;\n}\n\nenum KEY_ACTION {\n    KEY_NULL = 0,       /* NULL */\n    CTRL_C = 3,         /* Ctrl-c */\n    CTRL_D = 4,         /* Ctrl-d */\n    CTRL_F = 6,         /* Ctrl-f */\n    CTRL_H = 8,         /* Ctrl-h */\n    TAB = 9,            /* Tab */\n    CTRL_L = 12,        /* Ctrl+l */\n    ENTER = 13,         /* Enter */\n    CTRL_Q = 17,        /* Ctrl-q */\n    CTRL_S = 19,        /* Ctrl-s */\n    CTRL_U = 21,        /* Ctrl-u */\n    ESC = 27,           /* Escape */\n    BACKSPACE =  127,   /* Backspace */\n    /* The following are just soft codes, not really reported by the\n     * terminal directly. */\n    ARROW_LEFT = 1000,\n    ARROW_RIGHT,\n    ARROW_UP,\n    ARROW_DOWN,\n    DEL_KEY,\n    HOME_KEY,\n    END_KEY,\n    PAGE_UP,\n    PAGE_DOWN\n};\n\nint read_key(int fd)\n{\n    int nread;\n    char c, seq[3];\n    while ((nread = read(fd,&c,1)) == 0);\n    if (nread == -1) exit(1);\n\n    while (1) {\n        switch(c) {\n        case ESC:    /* escape sequence */\n            /* If this is just an ESC, we'll timeout here. */\n            if (read(fd,seq,1) == 0) return ESC;\n            if (read(fd,seq+1,1) == 0) return ESC;\n\n            /* ESC [ sequences. */\n            if (seq[0] == '[') {\n                if (seq[1] >= '0' && seq[1] <= '9') {\n                    /* Extended escape, read additional byte. */\n                    if (read(fd,seq+2,1) == 0) return ESC;\n                    if (seq[2] == '~') {\n                        switch(seq[1]) {\n                        case '3': return DEL_KEY;\n                        case '5': return PAGE_UP;\n                        case '6': return PAGE_DOWN;\n                        }\n                    }\n                } else {\n                    switch(seq[1]) {\n                    case 'A': return ARROW_UP;\n                    case 'B': return ARROW_DOWN;\n                    case 'C': return ARROW_RIGHT;\n                    case 'D': return ARROW_LEFT;\n                    case 'H': return HOME_KEY;\n                    case 'F': return END_KEY;\n                    }\n                }\n            }\n\n            /* ESC O sequences. */\n            else if (seq[0] == 'O') {\n                switch(seq[1]) {\n                case 'H': return HOME_KEY;\n                case 'F': return END_KEY;\n                }\n            }\n            break;\n        default:\n            return c;\n        }\n    }\n}\n\nstruct termios orig;\nchar read_buf[1024];\n\nchar *read_input()\n{\n    tcgetattr(0, &orig);\n    struct termios new = orig;\n    new.c_lflag &= ~(ECHO | ICANON);\n    tcsetattr(0, TCSAFLUSH, &new);\n    memset(read_buf, 0, 1024);\n\n    size_t off = 0, len = 0;\n    char newline = 0;\n    while (!newline) {\n        int c = read_key(0);\n        switch(c) {\n        case '\\t':  /* Tab character */\n            goto skip_echo;\n        case '\\n':\n        case ENTER:\n            read_buf[len] = '\\0';\n            write(1, \"\\n\", 1);\n            goto done;\n        case CTRL_C:\n        case CTRL_Q:\n        case CTRL_S:\n        case CTRL_F:\n            goto skip_echo;\n        case BACKSPACE:\n        case CTRL_H:\n        case DEL_KEY:\n            if (off > 0) {\n                read_buf[--off] = '\\0';\n                write(1, \"\\b \\b\", 3);\n                --len;\n\n                if (off < len) {\n                    char seq[20];\n                    memmove(read_buf + off, read_buf + off + 1, len - off);\n                    printf(\"\\r\\033[0J\");\n                    print_prompt();\n                    read_buf[len] = '\\0';\n                    printf(\"%s\", read_buf);\n\n                    /* XXX */\n                    snprintf(seq, 20, \"\\x1b[%luD\", len-off);\n                    printf(\"%s\", seq);\n\n                    fflush(stdout);\n                }\n            }\n\n            goto skip_echo;\n        case PAGE_UP:\n        case PAGE_DOWN:\n            goto skip_echo;\n        case ARROW_UP:\n        case ARROW_DOWN:\n            goto skip_echo;\n        case ARROW_LEFT:\n            if (off > 0) {\n                --off;\n                printf(\"\\x1b[D\");\n                fflush(stdout);\n            }\n            goto skip_echo;\n        case ARROW_RIGHT:\n            if (off < len) {\n                ++off;\n                printf(\"\\x1b[C\");\n                fflush(stdout);\n            }\n            goto skip_echo;\n        case CTRL_L:\n            printf(\"\\033[H\\033[2J\");    /* VT100/ANSI Clear sequence */\n            print_prompt();\n            read_buf[len] = '\\0';\n            printf(\"%s\", read_buf);\n            fflush(stdout);\n            goto skip_echo;\n        case ESC:\n            goto skip_echo;\n        default:\n            if (c < ' ')    /* Non-printable */\n                break;\n\n            if (off < len) {\n                char seq[20];\n                memmove(read_buf + off + 1, read_buf + off, len - off);\n                read_buf[off++] = c;\n                ++len;\n\n                printf(\"\\r\\033[0J\");\n                print_prompt();\n                read_buf[len] = '\\0';\n                printf(\"%s\", read_buf);\n\n                snprintf(seq, 20, \"\\x1b[%luD\", len-off);\n                printf(\"%s\", seq);\n\n                fflush(stdout);\n                goto skip_echo;\n            } else {\n                read_buf[off++] = c;\n                ++len;\n            }\n            break;\n        }\n\n        write(1, &c, 1);\nskip_echo:\n        ;\n    }\ndone:\n    tcsetattr(0, TCSAFLUSH, &orig);\n    return read_buf;\n}\n\nint eval(char *buf)\n{\n    //fprintf(stderr, \"eval(\\\"%s\\\")\\n\", buf);\n    if (!strlen(buf))\n        return 0;\n\n    char *argv[50];\n    int args_i = 0;\n\n    /* replace # with NULL */\n    char *hash;\n    if ((hash = strchr(buf, '#')))\n        *hash = 0;\n\n    char *tok = strtok(buf, \" \\t\\n\");\n\n    while (tok) {\n        argv[args_i++] = tok;\n        tok = strtok(NULL, \" \\t\\n\");\n    }\n\n    /* return if line is empty */\n    if (!args_i)\n        return 0;\n\n    argv[args_i] = NULL;\n\n    int wait = 1;\n    if (!strcmp(argv[args_i-1], \"&\")) {\n        --args_i;\n        argv[args_i] = NULL;\n        wait = 0;\n    }\n\n    if (flags & F_DEBUG) {\n        fprintf(stderr, \"+ \");\n        for (int i = 0; i < args_i; ++i) {\n            fprintf(stderr, \"%s \", argv[i]);\n        }\n        fprintf(stderr, \"\\n\");\n    }\n\n    /* path? */\n    if (args_i && (argv[0][0] == '/' || argv[0][0] == '.')) {\n        int fd = open(argv[0], O_RDONLY);\n        if (fd > 0) {\n            close(fd);\n            return run_prog(argv[0], argv, wait);\n        } else {\n            fprintf(stderr, \"aqsh: %s: \", argv[0]);\n            perror(\"\");\n            return errno;\n        }\n    }\n\n    /* Check if command is built-in */\n    int (*f)() = aqsh_get_command(argv[0]);\n    if (f) return f(args_i, argv);\n\n    /* Check commands from PATH */\n    char *env_path = getenv(\"PATH\");\n    if (env_path) {\n        char *path = strdup(env_path);\n        char *comp = strtok(path, \":\");\n        char buf[1024];\n        do {\n            sprintf(buf, \"%s/%s\", comp, argv[0]);\n            int fd = open(buf, O_RDONLY);\n            if (fd > 0) {\n                close(fd);\n                int ret = run_prog(buf, argv, wait);\n                free(path);\n                return ret;\n            }\n        } while ((comp = strtok(NULL, \":\")));\n    }\n\n    fprintf(stderr, \"aqsh: %s: command not found\\n\", argv[0]);\n    return -1;\n}\n\nvoid sigpass(int s)\n{\n\n}\n\nvoid shell()\n{\n    signal(2, sigpass);\n    setpgid(0, 0);\n    pid_t pid = getpid();\n    ioctl(0, TIOCSPGRP, &pid);\n    char buf[1024];\n\n    for (;;) {\n        user = getenv(\"USER\");\n        pwd = getenv(\"PWD\");\n        print_prompt();\n        memset(buf, 0, 1024);\n        char *input = read_input();\n        //char *input = fgets(buf, 1024, stdin);\n        eval(input);\n    }\n}\n\nvoid shell_batch(const char *path)\n{\n    FILE *file = fopen(path, \"r\");\n\n    if (!file) {\n        fprintf(stderr, \"aqsh: can not execute %s: \", path);\n        perror(\"\");\n        return;\n    }\n\n    char buf[1024];\n    memset(buf, 0, sizeof(buf));\n\n    while (fgets(buf, sizeof(buf), file)) {\n        //printf(\"aqsh: buf: %s\\n\", buf);\n        //write(2, \">> \", 3);\n        //write(2, buf, sizeof(buf));\n        eval(buf);\n    }\n}\n\nAQBOX_APPLET(sh)(int argc, char **argv)\n{\n    if (argc > 1) {\n        /* batch */\n        for (int i = 1; i < argc; ++i)\n            shell_batch(argv[i]);\n    } else {\n        /* interactive */\n        shell();\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/posix/touch.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <errno.h>\n\nstatic void usage()\n{\n    fprintf(stderr, \n            \"Usage: touch file...\\n\"\n            \"Change file access and modification times\\n\");\n}\n\nstatic int do_touch(int argc, const char *argv[], int flags)\n{\n    for (int i = 0; i < argc; ++i) {\n        int fd;\n        if ((fd = open(argv[i], O_RDONLY)) > 0) {\n            /* TODO */\n            close(fd);\n        } else {\n            fd = creat(argv[i], S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);\n\n            if (fd < 0) {\n                fprintf(stderr, \"touch: creat: %s\\n\", strerror(errno));\n                return -1;\n            }\n        }\n    }\n\n    return 0;\n}\n\nAQBOX_APPLET(touch)(int argc, char *argv[])\n{\n    int opt, flags = 0;\n\n    while ((opt = getopt(argc, argv, \"\")) != -1) {\n    }\n\n    do_touch(argc - optind, (const char **) &argv[optind], flags);\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/posix/uname.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/utsname.h>\n\n/* Flags */\n#define PRINT_MACHINE   0x01\n#define PRINT_NODENAME  0x02\n#define PRINT_RELEASE   0x04\n#define PRINT_SYSNAME   0x08\n#define PRINT_VERSION   0x10\n\nAQBOX_APPLET(uname)(int argc, char **argv)\n{\n    struct utsname name;\n    uname(&name);\n\n    if (argc == 1) {\n        printf(\"%s\\n\", name.sysname);\n    } else {\n        int opt, flags = 0;\n        while ((opt = getopt(argc, argv, \"amnrsv\")) != -1) {\n            switch (opt) {\n                case 'a': flags = -1; break;\n                case 'm': flags |= PRINT_MACHINE; break;\n                case 'n': flags |= PRINT_NODENAME; break;\n                case 'r': flags |= PRINT_RELEASE; break;\n                case 's': flags |= PRINT_SYSNAME; break;\n                case 'v': flags |= PRINT_VERSION; break;\n                default: exit(-1);\n            }\n        }\n\n        if (flags & PRINT_SYSNAME)\n            printf(\"%s \", name.sysname);\n        if (flags & PRINT_NODENAME)\n            printf(\"%s \", name.nodename);\n        if (flags & PRINT_RELEASE)\n            printf(\"%s \", name.release);\n        if (flags & PRINT_VERSION)\n            printf(\"%s \", name.version);\n        if (flags & PRINT_MACHINE)\n            printf(\"%s \", name.machine);\n\n        printf(\"\\n\");\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/posix/unlink.c",
    "content": "#include <aqbox.h>\n#include <unistd.h>\n#include <stdio.h>\n\nAQBOX_APPLET(unlink)(int argc, char **argv)\n{\n    if (argc < 2)\n        return -1;\n\n    if (unlink(argv[1])) {\n        perror(\"unlink\");\n        return -1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/sys/Build.mk",
    "content": "obj-y += mount.o\nobj-y += login.o\nobj-y += getty.o\nobj-y += reboot.o\n"
  },
  {
    "path": "system/aqbox/sys/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  SYSLD   \" $(CWD)/builtin.o\n\t@$(SYSLD) $(SYSLDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  SYSCC   \" $(CWD)/$@\n\t@$(SYSCC) $(SYSCFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) builtin.o\n\t@$(RM) $(obj-y) builtin.o\n"
  },
  {
    "path": "system/aqbox/sys/getty.c",
    "content": "#include <aqbox.h>\n#include <unistd.h>\n#include <fcntl.h>\n\nAQBOX_APPLET(getty)(int argc, char **argv)\n{\n    if (argc < 2) {\n        /* should print usage */\n    }\n\n    for (int i = 0; i < 3; ++i)\n        close(i);\n\n    open(argv[1], O_RDONLY);\n    open(argv[1], O_WRONLY);\n    open(argv[1], O_WRONLY);\n\n    char *argp[] = {\"/sbin/login\", 0};\n\n_retry:\n    //if (!fork()) {\n        execve(argp[0], argp, 0);\n    //}\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/sys/login.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <termios.h>\n#include <signal.h>\n#include <pwd.h>\n#include <sys/utsname.h>\n#include <sys/aq_auth.h>\n#include <sys/ioctl.h>\n#include <sys/types.h>\n#include <sys/wait.h>\n#include <fcntl.h>\n#include <string.h>\n\nAQBOX_APPLET(login)(int argc, char **argv)\n{\n    struct utsname utsname;\n    uname(&utsname);\n\n    printf(\"AquilaOS version %s\\n\", utsname.release);\n\n    char username[1024], pass[1024];\n    size_t len = 0;\n\n    printf(\"login: \");\n    fgets(username, 1024, stdin);\n    len = strlen(username);\n    if (username[len-1] == '\\n')\n        username[len-1] = 0;\n\n    struct termios orig;\n    tcgetattr(0, &orig);\n    struct termios new = orig;\n    new.c_lflag &= ~(ECHO | ECHOE);\n    tcsetattr(0, TCSAFLUSH, &new);\n\n    fflush(stdin);\n    printf(\"password: \");\n    fgets(pass, 1024, stdin);\n    len = strlen(pass);\n    if (pass[len-1] == '\\n')\n        pass[len-1] = 0;\n\n    tcsetattr(0, TCSAFLUSH, &orig);\n    printf(\"\\n\");\n    fflush(stdout);\n\n    struct passwd *passwd = NULL;\n\n    if (!(passwd = getpwnam(username))) {\n        fprintf(stderr, \"Login failed\\n\");\n        return -1;\n    }\n\n    if (aquila_auth(passwd->pw_uid, pass)) {\n        fprintf(stderr, \"Login failed\\n\");\n        return -1;\n    }\n\n    /* We are now running with PID=pw_uid */\n\n    /* XXX Don't do this! */\n    setenv(\"USER\", username, 1);\n    setenv(\"HOME\", passwd->pw_dir, 1);\n    setenv(\"PWD\", passwd->pw_dir, 1);\n    setenv(\"PATH\", \"/bin:/sbin:/usr/bin\", 1);\n\n    chdir(passwd->pw_dir);\n\n    int motd = open(\"/etc/motd\", O_RDONLY);\n    if (motd > 0) {\n        char buf[512]; int r;\n        while ((r = read(motd, buf, sizeof(buf))) > 0)\n            write(1, buf, r);\n        write(1, \"\\n\", 1);\n        close(motd);\n    }\n\n    extern char **environ;\n    char *args[] = {passwd->pw_shell, NULL}; /* XXX */\n    int pid, status;\n\n    if ((pid = fork())) {\n        int r = waitpid(pid, &status, 0);\n        printf(\"Shell returned status %x\\n\", status);\n\n        if (WIFSIGNALED(status)) {   /* Terminated due to signal */\n            switch (WTERMSIG(status)) {\n                case SIGINT:    /* Ignore */\n                    break;\n                case SIGSEGV:\n                    fprintf(stderr, \"Segmentation fault\\n\");\n                    break;\n                default:\n                    fprintf(stderr, \"Terminated due to signal %d\\n\", WTERMSIG(status));\n                    break;\n            }\n        }\n    } else {\n        int x = execve(passwd->pw_shell, args, environ);\n        exit(x);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/sys/mount.c",
    "content": "#include <aqbox.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <sys/mount.h>\n\nvoid usage(char *name)\n{\n    fprintf(stderr, \"usage: %s -t fstype [-o options] [dev] dir\", name);\n    exit(-1);\n}\n\nAQBOX_APPLET(mount)(int argc, char **argv)\n{\n    // mount -t fstype [-o options] [dev] dir\n    char *type = NULL, *opt = NULL, *dev  = NULL, *dir  = NULL;\n\n    for (int i = 1; i < argc; ++i) {\n        if (argv[i][0] == '-') {\n            switch (argv[i][1]) {\n                case 't':\n                    if (i < argc - 1) type = argv[++i];\n                    else usage(argv[0]);\n                    break;\n                case 'o':\n                    if (i < argc - 1) opt  = argv[++i];\n                    else usage(argv[0]);\n                    break;\n                default:\n                    fprintf(stderr, \"Unrecognized option %s\\n\", argv[i]);\n                    return -1;\n            }\n            continue;\n        }\n\n        if (dev) dir = argv[i];\n        else     dev = argv[i];\n\n    }\n\n    if (!type) {\n        fprintf(stderr, \"Filesystem type must be supplied\\n\");\n        return -1;\n    }\n\n    if (dev && !dir) {\n        dir = dev;\n        dev = NULL;\n    }\n\n    if (!dir) {\n        fprintf(stderr, \"Directory must be supplied\\n\");\n        return -1;\n    }\n\n    struct {\n        char *dev;\n        char *opt;\n    } data = {dev, opt};\n\n    int ret;\n    if ((ret = mount(type, dir, 0, &data))) {\n        perror(\"mount\");\n    }\n    \n    return 0;\n}\n"
  },
  {
    "path": "system/aqbox/sys/reboot.c",
    "content": "#include <aqbox.h>\n#include <signal.h>\n\nAQBOX_APPLET(reboot)(int argc, char **argv)\n{\n    return kill(1, SIGTERM);\n}\n"
  },
  {
    "path": "system/fbterm/Build.mk",
    "content": "obj-y += font.o\nobj-y += fb.o\nobj-y += nanojpeg.o\nobj-y += fbterm.o\nobj-y += aqkb.o\ndirs-y += libvterm/\n"
  },
  {
    "path": "system/fbterm/Makefile",
    "content": "export\n\nPDIR := $(SRCDIR)/system/fbterm\nCWD != realpath --relative-to=$(SRCDIR) .\n\nSYSCFLAGS += -I$(PDIR)/include\nSYSLDLIBS += -lpthread\n\ninclude Build.mk\n\nall: builtin.o fbterm\n\nfbterm: builtin.o\n\t@$(ECHO) \"  ELF     \" $(CWD)/$@;\n\t@$(SYSCC) $(SYSLDFLAGS) $< $(SYSLDLIBS) -o $@;\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  SYSLD   \" $(CWD)/builtin.o;\n\t@$(SYSLD) $(SYSLDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  SYSCC   \" $(CWD)/$@;\n\t@$(SYSCC) $(SYSCFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) builtin.o fbterm\n\t@$(RM) -f fbterm builtin.o $(obj-y)\n"
  },
  {
    "path": "system/fbterm/aqkb.c",
    "content": "#include <stdint.h>\n#include <unistd.h>\n#include <fbterm.h>\n#include <vterm.h>\n#include <vterm_keycodes.h>\n#include <aqkb.h>\n\n/* Keyboard */\n#define ESC\t\t0x01\n\n#define  LSHIFT\t0x2A\n#define _LSHIFT\t0xAA\n#define  RSHIFT\t0x36\n#define _RSHIFT 0xB6\n#define  CAPS\t0x3A\n#define _CAPS\t0xBA\n#define  LALT\t0x38\n#define _LALT\t0xB8\n#define  LCTL\t0x1D\n#define _LCTL\t0x9D\n#define F1\t\t0x3B\n\nuint8_t kbd_us[] = \n{\n\t'\\0',  ESC,  '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  '0',  '-',  '=',  '\\b',\n\t'\\t',  'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',  'o',  'p',  '[', ']', '\\n',\n\t'\\0',  'a',  's',  'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';', '\\'',\n\t'\\0', '\\0', '\\\\',  'z',  'x',  'c',  'v',  'b',  'n',  'm',  ',',  '.', '/',\n\t'\\0', '\\0', '\\0',  ' ',\n};\n\nuint8_t kbd_us_shift[] = \n{\n\t'\\0', ESC, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\\b',\n\t'\\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\\n',\n\t'\\0', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '\\\"',\n\t'\\0', '\\0', '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',\n};\n\nstruct fbterm_ctx *active;\n\nvoid handle_keyboard(int fd, int scancode)\n{\n    static char shift = 0, alt = 0, ctl = 0, caps = 0, spec = 0;\n#define VTERM_MOD ( (shift? VTERM_MOD_SHIFT : 0) \\\n                  | (alt?   VTERM_MOD_ALT   : 0) \\\n                  | (ctl?   VTERM_MOD_CTRL  : 0))\n\n    if (spec) {\n        switch (scancode) {\n            case 0x53:  /* Delete */\n                vterm_keyboard_key(active->vt, VTERM_KEY_BACKSPACE, VTERM_MOD);\n                break;\n            case 0x48:  /* Cursor Up */\n                vterm_keyboard_key(active->vt, VTERM_KEY_UP, VTERM_MOD);\n                break;\n            case 0x4B:  /* Cursor Left */\n                vterm_keyboard_key(active->vt, VTERM_KEY_LEFT, VTERM_MOD);\n                break;\n            case 0x4D:  /* Cursor Right */\n                vterm_keyboard_key(active->vt, VTERM_KEY_RIGHT, VTERM_MOD);\n                break;\n            case 0x50:  /* Cursor Down */\n                vterm_keyboard_key(active->vt, VTERM_KEY_DOWN, VTERM_MOD);\n                break;\n        }\n\n        spec = 0;\n        return;\n    }\n\n    /* Detect special scancodes first */\n    switch (scancode) {\n        case  LSHIFT:\n        case  RSHIFT:\n            shift = 1; return;\n        case _LSHIFT:\n        case _RSHIFT:\n            shift = 0; return;\n        case    CAPS:\n            caps = !caps; return;\n        case    LALT:\n            alt = 1; return;\n        case   _LALT:\n            alt = 0; return;\n        case    LCTL: \n            ctl = 1; return;\n        case   _LCTL:\n            ctl = 0; return;\n\n        case 0xE0:\n            spec = 1; return;\n\n        case 0x01:  /* ESC */\n            vterm_keyboard_key(active->vt, VTERM_KEY_ESCAPE, VTERM_MOD);\n            return;\n\n        case 0x1C:  /* Enter */\n            vterm_keyboard_key(active->vt, VTERM_KEY_ENTER, VTERM_MOD);\n            return;\n    }\n\n    if (scancode < 60) {\n        char c = 0;\n        if (ctl) {\n            c = kbd_us_shift[scancode] - 0x40;\n        } else {\n            switch ((caps << 1) | shift) {\n                case 0: /* Normal */\n                    c = kbd_us[scancode];\n                    break;\n                case 1: /* Shift */\n                    c = kbd_us_shift[scancode];\n                    break;\n                case 2: /* Caps */\n                    c = kbd_us[scancode];\n                    if (c >= 'a' && c <= 'z')\n                        c = kbd_us_shift[scancode];\n                    break;\n                case 3: /* Caps + Shift */\n                    c = kbd_us_shift[scancode];\n                    if (c >= 'A' && c <= 'Z')\n                        c = kbd_us[scancode];\n                    break;\n            }\n        }\n        \n        void vterm_push_output_sprintf(VTerm *vt, const char *format, ...);\n        vterm_push_output_sprintf(active->vt, \"%c\", c);\n    }\n}\n\nvoid *aqkb_thread(void *arg)\n{\n    extern struct fbterm_ctx term[10];\n    extern int kbd_fd;\n    extern int pty;\n\n    active = &term[0];\n\n    for (;;) {\n        int scancode;\n        if (read(kbd_fd, &scancode, sizeof(scancode)) > 0) {\n            handle_keyboard(pty, scancode);\n\n            char buf[1024];\n            size_t s;\n            while ((s = vterm_output_read(active->vt, buf, 1024))) {\n                write(pty, buf, s);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "system/fbterm/fb.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <string.h>\n#include <fcntl.h>\n#include <errno.h>\n#include <sys/ioctl.h>\n#include <sys/mman.h>\n#include <fb.h>\n#include <config.h>\n\n#define _NJ_INCLUDE_HEADER_ONLY\n#include \"nanojpeg.c\"\n\n/* Framebuffer API */\nstatic struct fb_fix_screeninfo fix_screeninfo;\nstatic struct fb_var_screeninfo var_screeninfo;\nstatic int fb = -1;\nstatic void *fb_addr = NULL;\nstatic unsigned xres = 0, yres = 0, line_length = 0, bpp = 0;\n\n#define COLORMERGE(f, b, c)\t((b) + (((f) - (b)) * (c) >> 8u))\n#define _R(c)   (((c) >> 1*8) & 0xFF)\n#define _G(c)   (((c) >> 2*8) & 0xFF)\n#define _B(c)   (((c) >> 3*8) & 0xFF)\n#define _A(c)   (((c) >> 0*8) & 0xFF)\n\nvoid fb_put_pixel(struct fbterm_ctx *ctx, int x, int y, uint32_t fg, uint32_t bg)\n{\n    unsigned char a = _A(fg);\n    unsigned char *p = (unsigned char *) &ctx->textbuf[y * line_length + bpp*x];\n\n    p[0] = COLORMERGE(_R(fg), _R(bg), a);  /* Red */\n    p[1] = COLORMERGE(_G(fg), _G(bg), a);  /* Green */\n    p[2] = COLORMERGE(_B(fg), _B(bg), a);  /* Blue */\n\n    unsigned char *q = (unsigned char *) &ctx->backbuf[y * line_length + bpp*x];\n    q[0] = COLORMERGE(p[0], q[0], ctx->op);  /* Red */\n    q[1] = COLORMERGE(p[1], q[1], ctx->op);  /* Green */\n    q[2] = COLORMERGE(p[2], q[2], ctx->op);  /* Blue */\n}\n\nvoid fb_clear(struct fbterm_ctx *ctx)\n{\n    memset(ctx->textbuf, 0, yres*line_length);\n    memset(ctx->backbuf, 0, yres*line_length);\n\n    if (ctx->wallpaper)\n        memcpy(ctx->backbuf, ctx->wallpaper, yres*line_length);\n}\n\nvoid fb_rect_clear(struct fbterm_ctx *ctx, size_t x0, size_t x1, size_t y0, size_t y1)\n{\n    for (size_t y = y0; y < y1; ++y) {\n        memset(ctx->textbuf + (y * line_length) + x0 * bpp, 0, (x1 - x0) * bpp);\n        memset(ctx->backbuf + (y * line_length) + x0 * bpp, 0, (x1 - x0) * bpp);\n    }\n\n    if (ctx->wallpaper) {\n        for (size_t y = y0; y < y1; ++y) {\n            size_t off = (y * line_length) + x0 * bpp;\n            memcpy(ctx->backbuf + off, ctx->wallpaper + off, (x1 - x0) * bpp);\n        }\n    }\n}\n\nvoid fb_rect_move(struct fbterm_ctx *ctx, size_t dx0, size_t dx1, size_t dy0, size_t dy1,\n        size_t sx0, size_t sx1, size_t sy0, size_t sy1)\n{\n    for (size_t y = dy0; y < dy1; ++y) {\n        memset(ctx->backbuf + (y * line_length) + dx0 * bpp, 0, (dx1 - dx0) * bpp);\n    }\n\n    if (ctx->wallpaper) {\n        for (size_t y = dy0; y < dy1; ++y) {\n            size_t off = (y * line_length) + dx0 * bpp;\n            memcpy(ctx->backbuf + off, ctx->wallpaper + off, (dx1 - dx0) * bpp);\n        }\n    }\n\n    for (size_t y = 0; y < (dy1 - dy0); ++y) {\n        memmove(ctx->textbuf + ((dy0 + y) * line_length) + dx0 * bpp,\n                ctx->textbuf + ((sy0 + y) * line_length) + sx0 * bpp,\n                (sx1 - sx0) * bpp);\n    }\n\n    for (size_t y = dy0; y < dy1; ++y) {\n        for (size_t x = dx0; x < dx1; ++x) {\n            unsigned char *p = (unsigned char *) &ctx->textbuf[y * line_length + bpp*x];\n            unsigned char *q = (unsigned char *) &ctx->backbuf[y * line_length + bpp*x];\n            q[0] = COLORMERGE(p[0], q[0], ctx->op);  /* Red */\n            q[1] = COLORMERGE(p[1], q[1], ctx->op);  /* Green */\n            q[2] = COLORMERGE(p[2], q[2], ctx->op);  /* Blue */\n        }\n    }\n}\n\nvoid fb_render(struct fbterm_ctx *ctx)\n{\n    memcpy(fb_addr, ctx->backbuf, line_length * yres);\n}\n\nvoid fb_term_init(struct fbterm_ctx *ctx)\n{\n    ctx->op   = 230;\n    ctx->rows = yres/ctx->font->rows;\n    ctx->cols = xres/ctx->font->cols;\n    ctx->textbuf = calloc(1, yres * line_length);\n    ctx->backbuf = calloc(1, yres * line_length);\n}\n\nint fb_cook_wallpaper(struct fbterm_ctx *ctx, char *path)\n{\n    int img = open(path, O_RDONLY);\n\n    if (img < 0)\n        return -1;\n\n    size_t size = lseek(img, 0, SEEK_END);\n    lseek(img, 0, SEEK_SET);\n\n    char *buf = calloc(1, size);\n    read(img, buf, size);\n    close(img);\n\n    njInit();\n    int err = 0;\n\n    if ((err = njDecode(buf, size))) {\n        free(buf);\n        debug(1, \"Error decoding input file: %d\\n\", err);\n        return -1;\n    }\n\n    free(buf);\n    size_t height = njGetHeight();\n    size_t width  = njGetWidth();\n    size_t cook_height, cook_width;\n    char *img_buf = (char *) njGetImage();\n    size_t ncomp = njGetImageSize() / (height * width);\n    size_t img_line_length = width * ncomp;\n    size_t xpan = 0, ypan = 0, xoffset = 0, yoffset = 0;\n\n    /* Pan or crop image to match screen size */\n    if (width < xres) {\n        xpan = (xres-width)/2;\n        cook_width = width;\n    } else {\n        xoffset = (width-xres)/2;\n        cook_width = xres;\n    }\n\n    if (height < yres) {\n        ypan = (yres-height)/2;\n        cook_height = height;\n    } else {\n        yoffset = (height-yres)/2;\n        cook_height = yres;\n    }\n\n    ctx->wallpaper = calloc(1, yres*line_length);\n\n#define WP_POS(i, j) (((i) + ypan) * line_length + ((j) + xpan) * bpp)\n#define IMG_POS(i, j) (((i) + yoffset) * img_line_length + ((j) + xoffset) * ncomp)\n\n    for (size_t i = 0; i < cook_height; ++i) {\n        for (size_t j = 0; j < cook_width; ++j) {\n            ctx->wallpaper[WP_POS(i, j) + 2] = img_buf[IMG_POS(i, j) + 0];\n            ctx->wallpaper[WP_POS(i, j) + 1] = img_buf[IMG_POS(i, j) + 1];\n            ctx->wallpaper[WP_POS(i, j) + 0] = img_buf[IMG_POS(i, j) + 2];\n        }\n    }\n\n    njDone();\n\n    memcpy(ctx->backbuf, ctx->wallpaper, yres*line_length);\n    return 0;\n}\n\nchar *dbuf = NULL;\nvoid fb_debug(char r, char g, char b)\n{\n    if (!dbuf)\n        dbuf = calloc(1, line_length * yres);\n\n    for (size_t y = 0; y < yres; ++y) {\n        for (size_t x = 0; x < xres; ++x) {\n            dbuf[y * line_length + bpp * x + 0] = r;\n            dbuf[y * line_length + bpp * x + 1] = g;\n            dbuf[y * line_length + bpp * x + 2] = b;\n        }\n    }\n\n    lseek(fb, 0, SEEK_SET);\n    write(fb, dbuf, line_length * yres);\n}\n\nint fb_init(const char *path)\n{\n    debug(INFO, \"initializing framebuffer %s\\n\", path);\n\n    if ((fb = open(path, O_RDWR)) < 0) {\n        debug(ERROR, \"%s: open: %s\\n\", path, strerror(errno));\n        return -1;\n    }\n\n    if (ioctl(fb, FBIOGET_FSCREENINFO, &fix_screeninfo) < 0) {\n        debug(ERROR, \"%s: ioctl: %s\\n\", path, strerror(errno));\n        return -1;\n    }\n\n    line_length = fix_screeninfo.line_length;\n\n    if (ioctl(fb, FBIOGET_VSCREENINFO, &var_screeninfo) < 0) {\n        debug(ERROR, \"%s: ioctl: %s\\n\", path, strerror(errno));\n        return -1;\n    }\n\n    xres = var_screeninfo.xres;\n    yres = var_screeninfo.yres;\n    bpp  = var_screeninfo.bits_per_pixel/8;\n\n    debug(INFO, \"%s: xres = %u, yres = %u, depth = %u\\n\", path, xres, yres, var_screeninfo.bits_per_pixel);\n\n    fb_addr = mmap(NULL, line_length * yres, PROT_WRITE, MAP_SHARED, fb, 0);\n\n    if (fb_addr == MAP_FAILED) {\n        return errno;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "system/fbterm/fbterm.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <string.h>\n#include <errno.h>\n#include <sys/ioctl.h>\n#include <sys/wait.h>\n\n#define _POSIX_THREADS\n#define _POSIX_PTHREAD\n#include <pthread.h>\n\n#include <fb.h>\n#include <tinyfont.h>\n#include <fbterm.h>\n#include <config.h>\n\n#include <vterm.h>\n\n#include <aqkb.h>\n\nint debug_fd = -1;\nint debug_init()\n{\n    debug_fd = open(\"/dev/kmsg\", O_WRONLY);\n    return 0;\n}\n\nint debug(int level, const char *fmt, ...)\n{\n    static char buf[512];\n\n    if (debug_fd >= 0) {\n        va_list ap;\n        va_start(ap, fmt);\n        int mlen = 0; //vsnprintf(buf, sizeof(buf), \"%s: \", \"fbterm\");\n        memcpy(buf, \"fbterm: \", 8);\n        int len = vsnprintf(buf + 8, sizeof(buf) - 8, fmt, ap);\n        va_end(ap);\n        write(debug_fd, buf, mlen + len);\n    }\n\n    return 0;\n}\n\n/* Terminals */\nstruct fbterm_ctx term[10];\n\n/* Term helpers */\nstatic void fbterm_putc(struct fbterm_ctx *ctx, int row, int col, char c, uint32_t fg, uint32_t bg)\n{\n    struct font *font = ctx->font;\n\n    char fbuf[font->rows * font->cols];\n    font_bitmap(font, fbuf, c);\n\n    for (int i = 0; i < font->rows; ++i) {\n        int cx = col * font->cols;\n        for (int j = 0; j < font->cols; ++j) {\n            char v = fbuf[i * font->cols + j];\n            fb_put_pixel(ctx, cx, row*font->rows+i, _ALPHA(fg, v), bg);\n            ++cx;\n        }\n    }\n}\n\nvoid fbterm_set_cursor(struct fbterm_ctx *ctx, int row, int col)\n{\n    ctx->cr = row;\n    ctx->cc = col;\n}\n\nvoid fbterm_clear(struct fbterm_ctx *ctx)\n{\n    fb_clear(ctx);\n}\n\nvoid fbterm_rect_clear(struct fbterm_ctx *ctx, int r0, int r1, int c0, int c1)\n{\n    size_t x0 = c0 * ctx->font->cols;\n    size_t x1 = c1 * ctx->font->cols;\n    size_t y0 = r0 * ctx->font->rows;\n    size_t y1 = r1 * ctx->font->rows;\n\n    fb_rect_clear(ctx, x0, x1, y0, y1);\n}\n\nvoid fbterm_rect_move(struct fbterm_ctx *ctx, int dr0, int dr1, int dc0, int dc1,\n    int sr0, int sr1, int sc0, int sc1)\n{\n    size_t dx0 = dc0 * ctx->font->cols;\n    size_t dx1 = dc1 * ctx->font->cols;\n    size_t dy0 = dr0 * ctx->font->rows;\n    size_t dy1 = dr1 * ctx->font->rows;\n\n    size_t sx0 = sc0 * ctx->font->cols;\n    size_t sx1 = sc1 * ctx->font->cols;\n    size_t sy0 = sr0 * ctx->font->rows;\n    size_t sy1 = sr1 * ctx->font->rows;\n\n    fb_rect_move(ctx, dx0, dx1, dy0, dy1, sx0, sx1, sy0, sy1);\n}\n\nvoid fbterm_cursor_draw(struct fbterm_ctx *ctx, int row, int col)\n{\n    struct font *font = ctx->font;\n    for (int i = font->rows-1; i < font->rows; ++i) {\n        int cx = col * font->cols;\n        for (int j = 0; j < font->cols; ++j) {\n            fb_put_pixel(ctx, cx, row*font->rows+i, -1, 0);\n            ++cx;\n        }\n    }\n}\n\nvoid fbterm_redraw(struct fbterm_ctx *ctx)\n{\n    /* Draw cursor */\n    fbterm_cursor_draw(ctx, ctx->cr, ctx->cc);\n    fb_render(ctx);\n}\n\nchar *fbterm_openpty(int *fd)\n{\n    int pty = open(\"/dev/ptmx\", O_RDWR);\n    *fd = pty;\n\n    int pts_id = 0;\n    ioctl(pty, TIOCGPTN, &pts_id);\n\n    static char pts_fn[] = \"/dev/pts/ \";\n    pts_fn[9] = '0' + pts_id;\n\n    return pts_fn;\n}\n\nint damage(VTermRect rect, void *user)\n{\n    struct fbterm_ctx *ctx = (struct fbterm_ctx *) user;\n    fbterm_rect_clear(ctx, rect.start_row, rect.end_row, rect.start_col, rect.end_col);\n\n    VTermScreenCell cell;\n    VTermPos pos;\n\n    int row, col;\n    for (row = rect.start_row; row < rect.end_row; row++) {\n        for (col = rect.start_col; col < rect.end_col; col++) {\n            pos.col = col;\n            pos.row = row;\n            vterm_screen_get_cell(ctx->screen, pos, &cell);\n            uint32_t fg = _RGB(cell.fg.red, cell.fg.green, cell.fg.blue);\n            uint32_t bg = _RGB(cell.bg.red, cell.bg.green, cell.bg.blue);\n            fbterm_putc(ctx, row, col, cell.chars[0], fg, bg);\n        }\n    }\n\n    return 0;\n}\n\nint moverect(VTermRect dest, VTermRect src, void *user)\n{\n    struct fbterm_ctx *ctx = (struct fbterm_ctx *) user;\n\n    size_t dr0 = dest.start_row;\n    size_t dr1 = dest.end_row;\n    size_t dc0 = dest.start_col;\n    size_t dc1 = dest.end_col;\n    size_t sr0 = src.start_row;\n    size_t sr1 = src.end_row;\n    size_t sc0 = src.start_col;\n    size_t sc1 = src.end_col;\n\n    fbterm_rect_move(ctx, dr0, dr1, dc0, dc1, sr0, sr1, sc0, sc1);\n\n    return 0;\n}\n\nint movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)\n{\n    struct fbterm_ctx *ctx = (struct fbterm_ctx *) user;\n\n    /* Remove cursor and redraw cell */\n    fbterm_rect_clear(ctx, oldpos.row, oldpos.row+1, oldpos.col, oldpos.col+1);\n    VTermScreenCell cell;\n    vterm_screen_get_cell(ctx->screen, oldpos, &cell);\n    uint32_t fg = _RGB(cell.fg.red, cell.fg.green, cell.fg.blue);\n    uint32_t bg = _RGB(cell.bg.red, cell.bg.green, cell.bg.blue);\n\n    fbterm_putc(ctx, oldpos.row, oldpos.col, cell.chars[0], fg, bg);\n\n    /* Set new cursor if visible */\n    //if (visible)\n        fbterm_set_cursor(ctx, pos.row, pos.col);\n\n    return 0;\n}\n\nint settermprop(VTermProp prop, VTermValue *val, void *user)\n{\n    return 0;\n}\n\nint bell(void *user)\n{\n    return 0;\n}\n\nint resize(int rows, int cols, void *user)\n{\n    return 0;\n}\n\nint sb_pushline(int cols, const VTermScreenCell *cells, void *user)\n{\n    return 0;\n}\n\nint sb_popline(int cols, VTermScreenCell *cells, void *user)\n{\n    return 0;\n}\n\nstruct font *font = NULL;\nVTermScreenCallbacks screen_cbs = {\n    .damage      = damage,\n    .moverect    = moverect,\n    .movecursor  = movecursor,\n    .settermprop = settermprop,\n    .bell        = bell,\n    .resize      = resize,\n    .sb_pushline = sb_pushline,\n    .sb_popline  = sb_popline,\n};\n\nint fbterm_init(struct fbterm_ctx *ctx)\n{\n    if (!font) {\n        font = font_open(DEFAULT_FONT);\n\n        if (!font)\n            return -1;\n    }\n\n    memset(ctx, 0, sizeof(struct fbterm_ctx));\n    ctx->font = font;\n\n    fb_term_init(ctx);\n    fb_cook_wallpaper(ctx, DEFAULT_WALLPAPER);\n\n    VTerm *vt = vterm_new(ctx->rows, ctx->cols);\n    ctx->vt = vt;\n\n    VTermScreen *sc = vterm_obtain_screen(vt);\n    vterm_screen_set_callbacks(sc, &screen_cbs, ctx);\n    vterm_screen_reset(sc, 0);\n    ctx->screen = sc;\n\n    VTermRect r = {.start_row = 0, .end_row = ctx->rows, .start_col = 0, .end_col = ctx->cols};\n    damage(r, ctx);\n\n    return 0;\n}\n\nint kbd_fd = -1;\nint pty    = -1;\n\nint fbterm_main()\n{\n    struct fbterm_ctx *active = &term[0]; \n\n    struct winsize ws;\n    ws.ws_row = active->rows;\n    ws.ws_col = active->cols;\n    ioctl(pty, TIOCSWINSZ, &ws);\n\n    fbterm_redraw(active);\n\n    size_t len;\n    char buf[1024];\n\n    while (1) {\n        /* Read input */\n        if ((len = read(pty, buf, sizeof(buf))) > 0) {\n            vterm_input_write(active->vt, buf, len);\n        }\n\n        fbterm_redraw(active);\n\n        /* Write output */\n        while (vterm_output_get_buffer_current(active->vt) > 0) {\n            size_t s = vterm_output_read(active->vt, buf, 1024);\n            write(pty, buf, s);\n        }\n    }\n\n    return 0;\n}\n\nchar *pts_fn = NULL;    /* XXX */\nvoid launch_shell()\n{\n    int shell_pid = 0;\nrelaunch:\n    if ((shell_pid = fork())) {   /* Relaunch shell if died */\n        int s, pid;\n        do {\n            pid = waitpid(shell_pid, &s, 0);\n        } while (pid != shell_pid);\n\n        /* Uh..Oh shell died */\n        goto relaunch;\n    } else {\n        for (int i = 0; i < 10; ++i)\n            close(i);\n\n        int stdin_fd  = open(pts_fn, O_RDONLY);\n        int stdout_fd = open(pts_fn, O_WRONLY);\n        int stderr_fd = open(pts_fn, O_WRONLY);\n\n        /* run login shell */\n        char *argp[] = {DEFAULT_SHELL, \"login\", NULL};\n        char *envp[] = {\"PWD=/\", \"TERM=VT100\", NULL};\n        execve(DEFAULT_SHELL, argp, envp);\n        for (;;);\n    }\n}\n\nint main(int argc, char **argv)\n{\n    debug_init();\n    debug(INFO, \"starting...\\n\");\n\n    int shell_pid = 0;\n    pts_fn = fbterm_openpty(&pty);\n\n    if ((shell_pid = fork())) {\n        if (fb_init(\"/dev/fb0\")) {\n            exit(-1);\n        }\n\n        if (fbterm_init(&term[0]) < 0) {\n            debug(1, \"Error initalizing fbterm\\n\");\n            exit(-1);\n        }\n\n        kbd_fd = open(KBD_PATH, O_RDONLY);\n\n        if (kbd_fd < 0) {\n            debug(1, \"Error initalizing keyboard\\n\");\n            exit(-1);\n        }\n\n        pthread_t aqkb;\n        pthread_create(&aqkb, NULL, aqkb_thread, NULL);\n\n        fbterm_main();\n    } else {\n        launch_shell();\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "system/fbterm/font.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <string.h>\n#include <fcntl.h>\n#include <tinyfont.h>\n\nstatic void *xread(int fd, int len)\n{\n\tvoid *buf = calloc(1, len);\n\tif (buf && read(fd, buf, len) == len)\n\t\treturn buf;\n\tfree(buf);\n\treturn NULL;\n}\n\nstruct font *font_open(char *path)\n{\n\tstruct font *font;\n    struct tinyfont head = {0};\n\tint fd = open(path, O_RDONLY);\n    lseek(fd, 0, SEEK_SET);\n\n\tif (fd < 0 || (size_t) read(fd, &head, sizeof(head)) != sizeof(head)) {\n\t\tclose(fd);\n\t\treturn NULL;\n\t}\n\n\tfont = calloc(1, sizeof(*font));\n\tfont->n = head.n;\n\tfont->rows = head.rows;\n\tfont->cols = head.cols;\n\tfont->glyphs = xread(fd, font->n * sizeof(int));\n\tfont->data = xread(fd, font->n * font->rows * font->cols);\n\tclose(fd);\n\n\tif (!font->glyphs || !font->data) {\n\t\tfont_free(font);\n\t\treturn NULL;\n\t}\n\n\treturn font;\n}\n\nstatic int find_glyph(struct font *font, int c)\n{\n\tint l = 0;\n\tint h = font->n;\n\twhile (l < h) {\n\t\tint m = (l + h) / 2;\n\t\tif (font->glyphs[m] == c)\n\t\t\treturn m;\n\t\tif (c < font->glyphs[m])\n\t\t\th = m;\n\t\telse\n\t\t\tl = m + 1;\n\t}\n\treturn -1;\n}\n\nint font_bitmap(struct font *font, void *dst, int c)\n{\n\tint i = find_glyph(font, c);\n\tint len = font->rows * font->cols;\n\tif (i < 0)\n\t\treturn 1;\n\tmemcpy(dst, font->data + i * len, len);\n\treturn 0;\n}\n\nvoid font_free(struct font *font)\n{\n\tif (font->data)\n\t\tfree(font->data);\n\tif (font->glyphs)\n\t\tfree(font->glyphs);\n\tfree(font);\n}\n\nint font_rows(struct font *font)\n{\n\treturn font->rows;\n}\n\nint font_cols(struct font *font)\n{\n\treturn font->cols;\n}\n"
  },
  {
    "path": "system/fbterm/include/aqkb.h",
    "content": "#ifndef _KBD_H\n#define _KBD_H\n\nvoid *aqkb_thread(void *arg);\n\n#endif /* ! _KBD_H */\n"
  },
  {
    "path": "system/fbterm/include/config.h",
    "content": "#ifndef _CONFIG_H\n#define _CONFIG_H\n\n/* Defaults */\n#define DEFAULT_WALLPAPER  \"/etc/wallpaper.jpg\"\n#define DEFAULT_FONT       \"/etc/font.tf\"\n#define DEFAULT_SHELL      \"/bin/aqbox\"\n\n#define FB_PATH            \"/dev/fb0\"\n#define KBD_PATH           \"/dev/kbd\"\n\nint debug(int level, const char *fmt, ...);\n\nenum {\n    DEBUG,\n    INFO,\n    WARNING,\n    ERROR\n};\n\n#endif /* !_CONFIG_H */\n"
  },
  {
    "path": "system/fbterm/include/fb.h",
    "content": "#ifndef _FBTERM_FB_H\n#define _FBTERM_FB_H\n\n#include <stdint.h>\n#include <fbterm.h>\n\n/* Framebuffer API */\n\n#define FBIOGET_VSCREENINFO\t0x4600\n#define FBIOPUT_VSCREENINFO\t0x4601\n#define FBIOGET_FSCREENINFO\t0x4602\n\nstruct fb_fix_screeninfo {\n\tchar id[16];\t\t\t/* identification string eg \"TT Builtin\" */\n\tunsigned long smem_start;\t/* Start of frame buffer mem */\n\t\t\t\t\t/* (physical address) */\n\tuint32_t smem_len;\t\t\t/* Length of frame buffer mem */\n\tuint32_t type;\t\t\t/* see FB_TYPE_*\t\t*/\n\tuint32_t type_aux;\t\t\t/* Interleave for interleaved Planes */\n\tuint32_t visual;\t\t\t/* see FB_VISUAL_*\t\t*/\n\tuint16_t xpanstep;\t\t\t/* zero if no hardware panning  */\n\tuint16_t ypanstep;\t\t\t/* zero if no hardware panning  */\n\tuint16_t ywrapstep;\t\t/* zero if no hardware ywrap    */\n\tuint32_t line_length;\t\t/* length of a line in bytes    */\n\tunsigned long mmio_start;\t/* Start of Memory Mapped I/O   */\n\t\t\t\t\t/* (physical address) */\n\tuint32_t mmio_len;\t\t\t/* Length of Memory Mapped I/O  */\n\tuint32_t accel;\t\t\t/* Indicate to driver which\t*/\n\t\t\t\t\t/*  specific chip/card we have\t*/\n\tuint16_t capabilities;\t\t/* see FB_CAP_*\t\t\t*/\n\tuint16_t reserved[2];\t\t/* Reserved for future compatibility */\n};\n\nstruct fb_bitfield {\n    uint32_t offset;    /* beginning of bitfield    */\n    uint32_t length;    /* length of bitfield       */\n    uint32_t msb_right; /* != 0 : Most significant bit is right */\n};\n\nstruct fb_var_screeninfo {\n    uint32_t xres;          /* visible resolution       */\n    uint32_t yres;\n    uint32_t xres_virtual;  /* virtual resolution       */\n    uint32_t yres_virtual;\n    uint32_t xoffset;       /* offset from virtual to visible */\n    uint32_t yoffset;       /* resolution           */\n\n    uint32_t bits_per_pixel;    /* guess what           */\n    uint32_t grayscale;     /* 0 = color, 1 = grayscale, >1 = FOURCC          */\n    struct fb_bitfield red;     /* bitfield in fb mem if true color, */\n    struct fb_bitfield green;   /* else only length is significant */\n    struct fb_bitfield blue;\n    struct fb_bitfield transp;  /* transparency         */\n\n    uint32_t nonstd;            /* != 0 Non standard pixel format */\n\n    uint32_t activate;          /* see FB_ACTIVATE_*        */\n\n    uint32_t height;            /* height of picture in mm    */\n    uint32_t width;         /* width of picture in mm     */\n\n    uint32_t accel_flags;       /* (OBSOLETE) see fb_info.flags */\n\n    /* Timing: All values in pixclocks, except pixclock (of course) */\n    uint32_t pixclock;          /* pixel clock in ps (pico seconds) */\n    uint32_t left_margin;       /* time from sync to picture    */\n    uint32_t right_margin;      /* time from picture to sync    */\n    uint32_t upper_margin;      /* time from sync to picture    */\n    uint32_t lower_margin;\n    uint32_t hsync_len;     /* length of horizontal sync    */\n    uint32_t vsync_len;     /* length of vertical sync  */\n    uint32_t sync;          /* see FB_SYNC_*        */\n    uint32_t vmode;         /* see FB_VMODE_*       */\n    uint32_t rotate;            /* angle we rotate counter clockwise */\n    uint32_t colorspace;        /* colorspace for FOURCC-based modes */\n    uint32_t reserved[4];       /* Reserved for future compatibility */\n};\n\nvoid fb_put_pixel(struct fbterm_ctx *ctx, int x, int y, uint32_t fg, uint32_t bg);\nvoid fb_clear(struct fbterm_ctx *ctx);\nvoid fb_render(struct fbterm_ctx *ctx);\nvoid fb_term_init(struct fbterm_ctx *ctx);\nint fb_init(const char *path);\nint fb_cook_wallpaper(struct fbterm_ctx *ctx, char *path);\nvoid fb_rect_clear(struct fbterm_ctx *ctx, size_t x0, size_t x1, size_t y0, size_t y1);\nvoid fb_rect_move(struct fbterm_ctx *ctx, size_t dx0, size_t dx1, size_t dy0, size_t dy1,\n        size_t sx0, size_t sx1, size_t sy0, size_t sy1);\n\n#define _RGBA(r, g, b, a) (((r) << 3*8) | ((g) << 2*8) | ((b) << 1*8) | ((a) << 0*8))\n#define _RGB(r, g, b) (((r) << 3*8) | ((g) << 2*8) | ((b) << 1*8))\n#define _ALPHA(c, a) (((c) & (~0xFF)) | ((a) & 0xFF))\n\n#endif\n"
  },
  {
    "path": "system/fbterm/include/fbterm.h",
    "content": "#ifndef _FBTERM_H\n#define _FBTERM_H\n\n#include <tinyfont.h>\n#include <stdint.h>\n#include <vterm.h>\n\nstruct fbterm_ctx {\n    int         ptm;    /* terminal master */\n    const char *pts;    /* terminal slave  */\n\n\n    unsigned rows;      /* Number of rows */\n    unsigned cols;      /* Number of cols */\n\n    unsigned cr, cc;    /* Cursor position */\n\n    char *wallpaper;    /* Wallpaper buffer */\n    char *textbuf;      /* Rendered text buffer */\n    char *backbuf;      /* Back buffer for terminal */\n    struct font *font;  /* Font used */\n\n    unsigned char op;   /* Opacity 0-255 */\n\n    VTerm *vt;\n    VTermScreen *screen;\n};\n\nvoid fbterm_set_cursor(struct fbterm_ctx *ctx, int cc, int cr);\nsize_t fbterm_write(struct fbterm_ctx *ctx, const char *buf, size_t size);\nvoid fbterm_clear(struct fbterm_ctx *ctx);\n\n#endif\n"
  },
  {
    "path": "system/fbterm/include/tinyfont.h",
    "content": "#ifndef _TINYFONT_H\n#define _TINYFONT_H\n\nstruct font {\n\tint rows, cols;\t/* glyph bitmap rows and columns */\n\tint n;\t\t/* number of font glyphs */\n\tint *glyphs;\t/* glyph unicode character codes */\n\tchar *data;\t/* glyph bitmaps */\n};\n\n/*\n * This tinyfont header is followed by:\n *\n * glyphs[n]\tunicode character codes (int)\n * bitmaps[n]\tcharacter bitmaps (char[rows * cols])\n */\nstruct tinyfont {\n\tchar sig[8];\t/* tinyfont signature; \"tinyfont\" */\n\tint ver;\t/* version; 0 */\n\tint n;\t\t/* number of glyphs */\n\tint rows, cols;\t/* glyph dimensions */\n};\n\n\nstruct font *font_open(char *path);\nint font_bitmap(struct font *font, void *dst, int c);\nvoid font_free(struct font *font);\nint font_rows(struct font *font);\nint font_cols(struct font *font);\n\n#endif\n"
  },
  {
    "path": "system/fbterm/include/vterm.h",
    "content": "#ifndef __VTERM_H__\n#define __VTERM_H__\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <stdbool.h>\n\n#include \"vterm_keycodes.h\"\n\ntypedef struct VTerm VTerm;\ntypedef struct VTermState VTermState;\ntypedef struct VTermScreen VTermScreen;\n\ntypedef struct {\n  int row;\n  int col;\n} VTermPos;\n\n/* some small utility functions; we can just keep these static here */\n\n/* order points by on-screen flow order */\nstatic inline int vterm_pos_cmp(VTermPos a, VTermPos b)\n{\n  return (a.row == b.row) ? a.col - b.col : a.row - b.row;\n}\n\ntypedef struct {\n  int start_row;\n  int end_row;\n  int start_col;\n  int end_col;\n} VTermRect;\n\n/* true if the rect contains the point */\nstatic inline int vterm_rect_contains(VTermRect r, VTermPos p)\n{\n  return p.row >= r.start_row && p.row < r.end_row &&\n         p.col >= r.start_col && p.col < r.end_col;\n}\n\n/* move a rect */\nstatic inline void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta)\n{\n  rect->start_row += row_delta; rect->end_row += row_delta;\n  rect->start_col += col_delta; rect->end_col += col_delta;\n}\n\ntypedef struct {\n  uint8_t red, green, blue;\n} VTermColor;\n\ntypedef enum {\n  /* VTERM_VALUETYPE_NONE = 0 */\n  VTERM_VALUETYPE_BOOL = 1,\n  VTERM_VALUETYPE_INT,\n  VTERM_VALUETYPE_STRING,\n  VTERM_VALUETYPE_COLOR,\n\n  VTERM_N_VALUETYPES\n} VTermValueType;\n\ntypedef union {\n  int boolean;\n  int number;\n  char *string;\n  VTermColor color;\n} VTermValue;\n\ntypedef enum {\n  /* VTERM_ATTR_NONE = 0 */\n  VTERM_ATTR_BOLD = 1,   // bool:   1, 22\n  VTERM_ATTR_UNDERLINE,  // number: 4, 21, 24\n  VTERM_ATTR_ITALIC,     // bool:   3, 23\n  VTERM_ATTR_BLINK,      // bool:   5, 25\n  VTERM_ATTR_REVERSE,    // bool:   7, 27\n  VTERM_ATTR_STRIKE,     // bool:   9, 29\n  VTERM_ATTR_FONT,       // number: 10-19\n  VTERM_ATTR_FOREGROUND, // color:  30-39 90-97\n  VTERM_ATTR_BACKGROUND, // color:  40-49 100-107\n\n  VTERM_N_ATTRS\n} VTermAttr;\n\ntypedef enum {\n  /* VTERM_PROP_NONE = 0 */\n  VTERM_PROP_CURSORVISIBLE = 1, // bool\n  VTERM_PROP_CURSORBLINK,       // bool\n  VTERM_PROP_ALTSCREEN,         // bool\n  VTERM_PROP_TITLE,             // string\n  VTERM_PROP_ICONNAME,          // string\n  VTERM_PROP_REVERSE,           // bool\n  VTERM_PROP_CURSORSHAPE,       // number\n  VTERM_PROP_MOUSE,             // number\n\n  VTERM_N_PROPS\n} VTermProp;\n\nenum {\n  VTERM_PROP_CURSORSHAPE_BLOCK = 1,\n  VTERM_PROP_CURSORSHAPE_UNDERLINE,\n  VTERM_PROP_CURSORSHAPE_BAR_LEFT,\n\n  VTERM_N_PROP_CURSORSHAPES\n};\n\nenum {\n  VTERM_PROP_MOUSE_NONE = 0,\n  VTERM_PROP_MOUSE_CLICK,\n  VTERM_PROP_MOUSE_DRAG,\n  VTERM_PROP_MOUSE_MOVE,\n\n  VTERM_N_PROP_MOUSES\n};\n\ntypedef struct {\n  const uint32_t *chars;\n  int             width;\n  unsigned int    protected_cell:1;  /* DECSCA-protected against DECSEL/DECSED */\n  unsigned int    dwl:1;             /* DECDWL or DECDHL double-width line */\n  unsigned int    dhl:2;             /* DECDHL double-height line (1=top 2=bottom) */\n} VTermGlyphInfo;\n\ntypedef struct {\n  unsigned int    doublewidth:1;     /* DECDWL or DECDHL line */\n  unsigned int    doubleheight:2;    /* DECDHL line (1=top 2=bottom) */\n} VTermLineInfo;\n\ntypedef struct {\n  /* libvterm relies on this memory to be zeroed out before it is returned\n   * by the allocator. */\n  void *(*malloc)(size_t size, void *allocdata);\n  void  (*free)(void *ptr, void *allocdata);\n} VTermAllocatorFunctions;\n\nVTerm *vterm_new(int rows, int cols);\nVTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata);\nvoid   vterm_free(VTerm* vt);\n\nvoid vterm_get_size(const VTerm *vt, int *rowsp, int *colsp);\nvoid vterm_set_size(VTerm *vt, int rows, int cols);\n\nint  vterm_get_utf8(const VTerm *vt);\nvoid vterm_set_utf8(VTerm *vt, int is_utf8);\n\nsize_t vterm_input_write(VTerm *vt, const char *bytes, size_t len);\n\nsize_t vterm_output_get_buffer_size(const VTerm *vt);\nsize_t vterm_output_get_buffer_current(const VTerm *vt);\nsize_t vterm_output_get_buffer_remaining(const VTerm *vt);\n\nsize_t vterm_output_read(VTerm *vt, char *buffer, size_t len);\n\nvoid vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod);\nvoid vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod);\n\nvoid vterm_keyboard_start_paste(VTerm *vt);\nvoid vterm_keyboard_end_paste(VTerm *vt);\n\nvoid vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod);\nvoid vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod);\n\n// ------------\n// Parser layer\n// ------------\n\n/* Flag to indicate non-final subparameters in a single CSI parameter.\n * Consider\n *   CSI 1;2:3:4;5a\n * 1 4 and 5 are final.\n * 2 and 3 are non-final and will have this bit set\n *\n * Don't confuse this with the final byte of the CSI escape; 'a' in this case.\n */\n#define CSI_ARG_FLAG_MORE (1U<<31)\n#define CSI_ARG_MASK      (~(1U<<31))\n\n#define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE)\n#define CSI_ARG(a)          ((a) & CSI_ARG_MASK)\n\n/* Can't use -1 to indicate a missing argument; use this instead */\n#define CSI_ARG_MISSING ((1UL<<31)-1)\n\n#define CSI_ARG_IS_MISSING(a) (CSI_ARG(a) == CSI_ARG_MISSING)\n#define CSI_ARG_OR(a,def)     (CSI_ARG(a) == CSI_ARG_MISSING ? (def) : CSI_ARG(a))\n#define CSI_ARG_COUNT(a)      (CSI_ARG(a) == CSI_ARG_MISSING || CSI_ARG(a) == 0 ? 1 : CSI_ARG(a))\n\ntypedef struct {\n  int (*text)(const char *bytes, size_t len, void *user);\n  int (*control)(unsigned char control, void *user);\n  int (*escape)(const char *bytes, size_t len, void *user);\n  int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);\n  int (*osc)(const char *command, size_t cmdlen, void *user);\n  int (*dcs)(const char *command, size_t cmdlen, void *user);\n  int (*resize)(int rows, int cols, void *user);\n} VTermParserCallbacks;\n\nvoid  vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user);\nvoid *vterm_parser_get_cbdata(VTerm *vt);\n\n// -----------\n// State layer\n// -----------\n\ntypedef struct {\n  int (*putglyph)(VTermGlyphInfo *info, VTermPos pos, void *user);\n  int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user);\n  int (*scrollrect)(VTermRect rect, int downward, int rightward, void *user);\n  int (*moverect)(VTermRect dest, VTermRect src, void *user);\n  int (*erase)(VTermRect rect, int selective, void *user);\n  int (*initpen)(void *user);\n  int (*setpenattr)(VTermAttr attr, VTermValue *val, void *user);\n  int (*settermprop)(VTermProp prop, VTermValue *val, void *user);\n  int (*bell)(void *user);\n  int (*resize)(int rows, int cols, VTermPos *delta, void *user);\n  int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user);\n} VTermStateCallbacks;\n\nVTermState *vterm_obtain_state(VTerm *vt);\n\nvoid  vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user);\nvoid *vterm_state_get_cbdata(VTermState *state);\n\n// Only invokes control, csi, osc, dcs\nvoid  vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermParserCallbacks *fallbacks, void *user);\nvoid *vterm_state_get_unrecognised_fbdata(VTermState *state);\n\nvoid vterm_state_reset(VTermState *state, int hard);\nvoid vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos);\nvoid vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg);\nvoid vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col);\nvoid vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg);\nvoid vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col);\nvoid vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright);\nint  vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val);\nint  vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val);\nvoid vterm_state_focus_in(VTermState *state);\nvoid vterm_state_focus_out(VTermState *state);\nconst VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row);\n\n// ------------\n// Screen layer\n// ------------\n\ntypedef struct {\n    unsigned int bold      : 1;\n    unsigned int underline : 2;\n    unsigned int italic    : 1;\n    unsigned int blink     : 1;\n    unsigned int reverse   : 1;\n    unsigned int strike    : 1;\n    unsigned int font      : 4; /* 0 to 9 */\n    unsigned int dwl       : 1; /* On a DECDWL or DECDHL line */\n    unsigned int dhl       : 2; /* On a DECDHL line (1=top 2=bottom) */\n} VTermScreenCellAttrs;\n\ntypedef struct {\n#define VTERM_MAX_CHARS_PER_CELL 6\n  uint32_t chars[VTERM_MAX_CHARS_PER_CELL];\n  char     width;\n  VTermScreenCellAttrs attrs;\n  VTermColor fg, bg;\n} VTermScreenCell;\n\ntypedef struct {\n  int (*damage)(VTermRect rect, void *user);\n  int (*moverect)(VTermRect dest, VTermRect src, void *user);\n  int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user);\n  int (*settermprop)(VTermProp prop, VTermValue *val, void *user);\n  int (*bell)(void *user);\n  int (*resize)(int rows, int cols, void *user);\n  int (*sb_pushline)(int cols, const VTermScreenCell *cells, void *user);\n  int (*sb_popline)(int cols, VTermScreenCell *cells, void *user);\n} VTermScreenCallbacks;\n\nVTermScreen *vterm_obtain_screen(VTerm *vt);\n\nvoid  vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user);\nvoid *vterm_screen_get_cbdata(VTermScreen *screen);\n\n// Only invokes control, csi, osc, dcs\nvoid  vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user);\nvoid *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen);\n\nvoid vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen);\n\ntypedef enum {\n  VTERM_DAMAGE_CELL,    /* every cell */\n  VTERM_DAMAGE_ROW,     /* entire rows */\n  VTERM_DAMAGE_SCREEN,  /* entire screen */\n  VTERM_DAMAGE_SCROLL,  /* entire screen + scrollrect */\n\n  VTERM_N_DAMAGES\n} VTermDamageSize;\n\nvoid vterm_screen_flush_damage(VTermScreen *screen);\nvoid vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size);\n\nvoid   vterm_screen_reset(VTermScreen *screen, int hard);\n\n/* Neither of these functions NUL-terminate the buffer */\nsize_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect);\nsize_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect);\n\ntypedef enum {\n  VTERM_ATTR_BOLD_MASK       = 1 << 0,\n  VTERM_ATTR_UNDERLINE_MASK  = 1 << 1,\n  VTERM_ATTR_ITALIC_MASK     = 1 << 2,\n  VTERM_ATTR_BLINK_MASK      = 1 << 3,\n  VTERM_ATTR_REVERSE_MASK    = 1 << 4,\n  VTERM_ATTR_STRIKE_MASK     = 1 << 5,\n  VTERM_ATTR_FONT_MASK       = 1 << 6,\n  VTERM_ATTR_FOREGROUND_MASK = 1 << 7,\n  VTERM_ATTR_BACKGROUND_MASK = 1 << 8,\n\n  VTERM_ALL_ATTRS_MASK = (1 << 9) - 1\n} VTermAttrMask;\n\nint vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs);\n\nint vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell);\n\nint vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos);\n\n// ---------\n// Utilities\n// ---------\n\nVTermValueType vterm_get_attr_type(VTermAttr attr);\nVTermValueType vterm_get_prop_type(VTermProp prop);\n\nvoid vterm_scroll_rect(VTermRect rect,\n                       int downward,\n                       int rightward,\n                       int (*moverect)(VTermRect src, VTermRect dest, void *user),\n                       int (*eraserect)(VTermRect rect, int selective, void *user),\n                       void *user);\n\nvoid vterm_copy_cells(VTermRect dest,\n                      VTermRect src,\n                      void (*copycell)(VTermPos dest, VTermPos src, void *user),\n                      void *user);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "system/fbterm/include/vterm_keycodes.h",
    "content": "#ifndef __VTERM_INPUT_H__\n#define __VTERM_INPUT_H__\n\ntypedef enum {\n  VTERM_MOD_NONE  = 0x00,\n  VTERM_MOD_SHIFT = 0x01,\n  VTERM_MOD_ALT   = 0x02,\n  VTERM_MOD_CTRL  = 0x04,\n\n  VTERM_ALL_MODS_MASK = 0x07 \n} VTermModifier;\n\ntypedef enum {\n  VTERM_KEY_NONE,\n\n  VTERM_KEY_ENTER,\n  VTERM_KEY_TAB,\n  VTERM_KEY_BACKSPACE,\n  VTERM_KEY_ESCAPE,\n\n  VTERM_KEY_UP,\n  VTERM_KEY_DOWN,\n  VTERM_KEY_LEFT,\n  VTERM_KEY_RIGHT,\n\n  VTERM_KEY_INS,\n  VTERM_KEY_DEL,\n  VTERM_KEY_HOME,\n  VTERM_KEY_END,\n  VTERM_KEY_PAGEUP,\n  VTERM_KEY_PAGEDOWN,\n\n  VTERM_KEY_FUNCTION_0   = 256,\n  VTERM_KEY_FUNCTION_MAX = VTERM_KEY_FUNCTION_0 + 255,\n\n  VTERM_KEY_KP_0,\n  VTERM_KEY_KP_1,\n  VTERM_KEY_KP_2,\n  VTERM_KEY_KP_3,\n  VTERM_KEY_KP_4,\n  VTERM_KEY_KP_5,\n  VTERM_KEY_KP_6,\n  VTERM_KEY_KP_7,\n  VTERM_KEY_KP_8,\n  VTERM_KEY_KP_9,\n  VTERM_KEY_KP_MULT,\n  VTERM_KEY_KP_PLUS,\n  VTERM_KEY_KP_COMMA,\n  VTERM_KEY_KP_MINUS,\n  VTERM_KEY_KP_PERIOD,\n  VTERM_KEY_KP_DIVIDE,\n  VTERM_KEY_KP_ENTER,\n  VTERM_KEY_KP_EQUAL,\n\n  VTERM_KEY_MAX, // Must be last\n  VTERM_N_KEYS = VTERM_KEY_MAX\n} VTermKey;\n\n#define VTERM_KEY_FUNCTION(n) (VTERM_KEY_FUNCTION_0+(n))\n\n#endif\n"
  },
  {
    "path": "system/fbterm/libvterm/Build.mk",
    "content": "#dirs-y += encoding/\nobj-y += encoding.o\nobj-y += keyboard.o\nobj-y += mouse.o\nobj-y += parser.o\nobj-y += pen.o\nobj-y += screen.o\nobj-y += state.o\nobj-y += unicode.o\nobj-y += vterm.o\n"
  },
  {
    "path": "system/fbterm/libvterm/Makefile",
    "content": "include Build.mk\n\nCWD != realpath --relative-to=$(SRCDIR) .\n\nall: builtin.o\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@$(ECHO) \"  SYSLD   \" $(CWD)/builtin.o\n\t@$(SYSLD) $(SYSLDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@$(ECHO) \"  MK      \" $(CWD)/$@\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@$(ECHO) \"  SYSCC   \" $(CWD)/$@\n\t@$(SYSCC) $(SYSCFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t@$(ECHO) \"  RM      \" $(obj-y) builtin.o\n\t@$(RM) $(obj-y) builtin.o\n"
  },
  {
    "path": "system/fbterm/libvterm/encoding/DECdrawing.inc",
    "content": "static const struct StaticTableEncoding encoding_DECdrawing = {\n  { .decode = &decode_table },\n  {\n    [0x60] = 0x25C6,\n    [0x61] = 0x2592,\n    [0x62] = 0x2409,\n    [0x63] = 0x240C,\n    [0x64] = 0x240D,\n    [0x65] = 0x240A,\n    [0x66] = 0x00B0,\n    [0x67] = 0x00B1,\n    [0x68] = 0x2424,\n    [0x69] = 0x240B,\n    [0x6a] = 0x2518,\n    [0x6b] = 0x2510,\n    [0x6c] = 0x250C,\n    [0x6d] = 0x2514,\n    [0x6e] = 0x253C,\n    [0x6f] = 0x23BA,\n    [0x70] = 0x23BB,\n    [0x71] = 0x2500,\n    [0x72] = 0x23BC,\n    [0x73] = 0x23BD,\n    [0x74] = 0x251C,\n    [0x75] = 0x2524,\n    [0x76] = 0x2534,\n    [0x77] = 0x252C,\n    [0x78] = 0x2502,\n    [0x79] = 0x2A7D,\n    [0x7a] = 0x2A7E,\n    [0x7b] = 0x03C0,\n    [0x7c] = 0x2260,\n    [0x7d] = 0x00A3,\n    [0x7e] = 0x00B7,\n  }\n};\n"
  },
  {
    "path": "system/fbterm/libvterm/encoding/DECdrawing.tbl",
    "content": "6/0 = U+25C6 # BLACK DIAMOND\n6/1 = U+2592 # MEDIUM SHADE (checkerboard)\n6/2 = U+2409 # SYMBOL FOR HORIZONTAL TAB\n6/3 = U+240C # SYMBOL FOR FORM FEED\n6/4 = U+240D # SYMBOL FOR CARRIAGE RETURN\n6/5 = U+240A # SYMBOL FOR LINE FEED\n6/6 = U+00B0 # DEGREE SIGN\n6/7 = U+00B1 # PLUS-MINUS SIGN (plus or minus)\n6/8 = U+2424 # SYMBOL FOR NEW LINE\n6/9 = U+240B # SYMBOL FOR VERTICAL TAB\n6/10 = U+2518 # BOX DRAWINGS LIGHT UP AND LEFT (bottom-right corner)\n6/11 = U+2510 # BOX DRAWINGS LIGHT DOWN AND LEFT (top-right corner)\n6/12 = U+250C # BOX DRAWINGS LIGHT DOWN AND RIGHT (top-left corner)\n6/13 = U+2514 # BOX DRAWINGS LIGHT UP AND RIGHT (bottom-left corner)\n6/14 = U+253C # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL (crossing lines)\n6/15 = U+23BA # HORIZONTAL SCAN LINE-1\n7/0 = U+23BB # HORIZONTAL SCAN LINE-3\n7/1 = U+2500 # BOX DRAWINGS LIGHT HORIZONTAL\n7/2 = U+23BC # HORIZONTAL SCAN LINE-7\n7/3 = U+23BD # HORIZONTAL SCAN LINE-9\n7/4 = U+251C # BOX DRAWINGS LIGHT VERTICAL AND RIGHT\n7/5 = U+2524 # BOX DRAWINGS LIGHT VERTICAL AND LEFT\n7/6 = U+2534 # BOX DRAWINGS LIGHT UP AND HORIZONTAL\n7/7 = U+252C # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL\n7/8 = U+2502 # BOX DRAWINGS LIGHT VERTICAL\n7/9 = U+2A7D # LESS-THAN OR SLANTED EQUAL-TO\n7/10 = U+2A7E # GREATER-THAN OR SLANTED EQUAL-TO\n7/11 = U+03C0 # GREEK SMALL LETTER PI\n7/12 = U+2260 # NOT EQUAL TO\n7/13 = U+00A3 # POUND SIGN\n7/14 = U+00B7 # MIDDLE DOT\n"
  },
  {
    "path": "system/fbterm/libvterm/encoding/uk.inc",
    "content": "static const struct StaticTableEncoding encoding_uk = {\n  { .decode = &decode_table },\n  {\n    [0x23] = 0x00a3,\n  }\n};\n"
  },
  {
    "path": "system/fbterm/libvterm/encoding/uk.tbl",
    "content": "2/3 = \"£\"\n"
  },
  {
    "path": "system/fbterm/libvterm/encoding.c",
    "content": "#include \"vterm_internal.h\"\n\n#define UNICODE_INVALID 0xFFFD\n\n#if defined(DEBUG) && DEBUG > 1\n# define DEBUG_PRINT_UTF8\n#endif\n\nstruct UTF8DecoderData {\n  // number of bytes remaining in this codepoint\n  int bytes_remaining;\n\n  // number of bytes total in this codepoint once it's finished\n  // (for detecting overlongs)\n  int bytes_total;\n\n  int this_cp;\n};\n\nstatic void init_utf8(VTermEncoding *enc, void *data_)\n{\n  struct UTF8DecoderData *data = data_;\n\n  data->bytes_remaining = 0;\n  data->bytes_total     = 0;\n}\n\nstatic void decode_utf8(VTermEncoding *enc, void *data_,\n                        uint32_t cp[], int *cpi, int cplen,\n                        const char bytes[], size_t *pos, size_t bytelen)\n{\n  struct UTF8DecoderData *data = data_;\n\n#ifdef DEBUG_PRINT_UTF8\n  printf(\"BEGIN UTF-8\\n\");\n#endif\n\n  for(; *pos < bytelen && *cpi < cplen; (*pos)++) {\n    unsigned char c = bytes[*pos];\n\n#ifdef DEBUG_PRINT_UTF8\n    printf(\" pos=%zd c=%02x rem=%d\\n\", *pos, c, data->bytes_remaining);\n#endif\n\n    if(c < 0x20) // C0\n      return;\n\n    else if(c >= 0x20 && c < 0x7f) {\n      if(data->bytes_remaining)\n        cp[(*cpi)++] = UNICODE_INVALID;\n\n      cp[(*cpi)++] = c;\n#ifdef DEBUG_PRINT_UTF8\n      printf(\" UTF-8 char: U+%04x\\n\", c);\n#endif\n      data->bytes_remaining = 0;\n    }\n\n    else if(c == 0x7f) // DEL\n      return;\n\n    else if(c >= 0x80 && c < 0xc0) {\n      if(!data->bytes_remaining) {\n        cp[(*cpi)++] = UNICODE_INVALID;\n        continue;\n      }\n\n      data->this_cp <<= 6;\n      data->this_cp |= c & 0x3f;\n      data->bytes_remaining--;\n\n      if(!data->bytes_remaining) {\n#ifdef DEBUG_PRINT_UTF8\n        printf(\" UTF-8 raw char U+%04x bytelen=%d \", data->this_cp, data->bytes_total);\n#endif\n        // Check for overlong sequences\n        switch(data->bytes_total) {\n        case 2:\n          if(data->this_cp <  0x0080) data->this_cp = UNICODE_INVALID;\n          break;\n        case 3:\n          if(data->this_cp <  0x0800) data->this_cp = UNICODE_INVALID;\n          break;\n        case 4:\n          if(data->this_cp < 0x10000) data->this_cp = UNICODE_INVALID;\n          break;\n        case 5:\n          if(data->this_cp < 0x200000) data->this_cp = UNICODE_INVALID;\n          break;\n        case 6:\n          if(data->this_cp < 0x4000000) data->this_cp = UNICODE_INVALID;\n          break;\n        }\n        // Now look for plain invalid ones\n        if((data->this_cp >= 0xD800 && data->this_cp <= 0xDFFF) ||\n           data->this_cp == 0xFFFE ||\n           data->this_cp == 0xFFFF)\n          data->this_cp = UNICODE_INVALID;\n#ifdef DEBUG_PRINT_UTF8\n        printf(\" char: U+%04x\\n\", data->this_cp);\n#endif\n        cp[(*cpi)++] = data->this_cp;\n      }\n    }\n\n    else if(c >= 0xc0 && c < 0xe0) {\n      if(data->bytes_remaining)\n        cp[(*cpi)++] = UNICODE_INVALID;\n\n      data->this_cp = c & 0x1f;\n      data->bytes_total = 2;\n      data->bytes_remaining = 1;\n    }\n\n    else if(c >= 0xe0 && c < 0xf0) {\n      if(data->bytes_remaining)\n        cp[(*cpi)++] = UNICODE_INVALID;\n\n      data->this_cp = c & 0x0f;\n      data->bytes_total = 3;\n      data->bytes_remaining = 2;\n    }\n\n    else if(c >= 0xf0 && c < 0xf8) {\n      if(data->bytes_remaining)\n        cp[(*cpi)++] = UNICODE_INVALID;\n\n      data->this_cp = c & 0x07;\n      data->bytes_total = 4;\n      data->bytes_remaining = 3;\n    }\n\n    else if(c >= 0xf8 && c < 0xfc) {\n      if(data->bytes_remaining)\n        cp[(*cpi)++] = UNICODE_INVALID;\n\n      data->this_cp = c & 0x03;\n      data->bytes_total = 5;\n      data->bytes_remaining = 4;\n    }\n\n    else if(c >= 0xfc && c < 0xfe) {\n      if(data->bytes_remaining)\n        cp[(*cpi)++] = UNICODE_INVALID;\n\n      data->this_cp = c & 0x01;\n      data->bytes_total = 6;\n      data->bytes_remaining = 5;\n    }\n\n    else {\n      cp[(*cpi)++] = UNICODE_INVALID;\n    }\n  }\n}\n\nstatic VTermEncoding encoding_utf8 = {\n  .init   = &init_utf8,\n  .decode = &decode_utf8,\n};\n\nstatic void decode_usascii(VTermEncoding *enc, void *data,\n                           uint32_t cp[], int *cpi, int cplen,\n                           const char bytes[], size_t *pos, size_t bytelen)\n{\n  int is_gr = bytes[*pos] & 0x80;\n\n  for(; *pos < bytelen && *cpi < cplen; (*pos)++) {\n    unsigned char c = bytes[*pos] ^ is_gr;\n\n    if(c < 0x20 || c == 0x7f || c >= 0x80)\n      return;\n\n    cp[(*cpi)++] = c;\n  }\n}\n\nstatic VTermEncoding encoding_usascii = {\n  .decode = &decode_usascii,\n};\n\nstruct StaticTableEncoding {\n  const VTermEncoding enc;\n  const uint32_t chars[128];\n};\n\nstatic void decode_table(VTermEncoding *enc, void *data,\n                         uint32_t cp[], int *cpi, int cplen,\n                         const char bytes[], size_t *pos, size_t bytelen)\n{\n  struct StaticTableEncoding *table = (struct StaticTableEncoding *)enc;\n  int is_gr = bytes[*pos] & 0x80;\n\n  for(; *pos < bytelen && *cpi < cplen; (*pos)++) {\n    unsigned char c = bytes[*pos] ^ is_gr;\n\n    if(c < 0x20 || c == 0x7f || c >= 0x80)\n      return;\n\n    if(table->chars[c])\n      cp[(*cpi)++] = table->chars[c];\n    else\n      cp[(*cpi)++] = c;\n  }\n}\n\n#include \"encoding/DECdrawing.inc\"\n#include \"encoding/uk.inc\"\n\nstatic struct {\n  VTermEncodingType type;\n  char designation;\n  VTermEncoding *enc;\n}\nencodings[] = {\n  { ENC_UTF8,      'u', &encoding_utf8 },\n  { ENC_SINGLE_94, '0', (VTermEncoding*)&encoding_DECdrawing },\n  { ENC_SINGLE_94, 'A', (VTermEncoding*)&encoding_uk },\n  { ENC_SINGLE_94, 'B', &encoding_usascii },\n  { 0 },\n};\n\n/* This ought to be INTERNAL but isn't because it's used by unit testing */\nVTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation)\n{\n  for(int i = 0; encodings[i].designation; i++)\n    if(encodings[i].type == type && encodings[i].designation == designation)\n      return encodings[i].enc;\n  return NULL;\n}\n"
  },
  {
    "path": "system/fbterm/libvterm/keyboard.c",
    "content": "#include \"vterm_internal.h\"\n\n#include <stdio.h>\n\n#include \"utf8.h\"\n\nvoid vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod)\n{\n  /* The shift modifier is never important for Unicode characters\n   * apart from Space\n   */\n  if(c != ' ')\n    mod &= ~VTERM_MOD_SHIFT;\n\n  if(mod == 0) {\n    // Normal text - ignore just shift\n    char str[6];\n    int seqlen = fill_utf8(c, str);\n    vterm_push_output_bytes(vt, str, seqlen);\n    return;\n  }\n\n  int needs_CSIu;\n  switch(c) {\n    /* Special Ctrl- letters that can't be represented elsewise */\n    case 'i': case 'j': case 'm': case '[':\n      needs_CSIu = 1;\n      break;\n    /* Ctrl-\\ ] ^ _ don't need CSUu */\n    case '\\\\': case ']': case '^': case '_':\n      needs_CSIu = 0;\n      break;\n    /* Shift-space needs CSIu */\n    case ' ':\n      needs_CSIu = !!(mod & VTERM_MOD_SHIFT);\n      break;\n    /* All other characters needs CSIu except for letters a-z */\n    default:\n      needs_CSIu = (c < 'a' || c > 'z');\n  }\n\n  /* ALT we can just prefix with ESC; anything else requires CSI u */\n  if(needs_CSIu && (mod & ~VTERM_MOD_ALT)) {\n    vterm_push_output_sprintf_ctrl(vt, C1_CSI, \"%d;%du\", c, mod+1);\n    return;\n  }\n\n  if(mod & VTERM_MOD_CTRL)\n    c &= 0x1f;\n\n  vterm_push_output_sprintf(vt, \"%s%c\", mod & VTERM_MOD_ALT ? ESC_S : \"\", c);\n}\n\ntypedef struct {\n  enum {\n    KEYCODE_NONE,\n    KEYCODE_LITERAL,\n    KEYCODE_TAB,\n    KEYCODE_ENTER,\n    KEYCODE_SS3,\n    KEYCODE_CSI,\n    KEYCODE_CSI_CURSOR,\n    KEYCODE_CSINUM,\n    KEYCODE_KEYPAD,\n  } type;\n  char literal;\n  int csinum;\n} keycodes_s;\n\nstatic keycodes_s keycodes[] = {\n  { KEYCODE_NONE }, // NONE\n\n  { KEYCODE_ENTER,   '\\r',   0}, // ENTER\n  { KEYCODE_TAB,     '\\t',   0}, // TAB\n  { KEYCODE_LITERAL, '\\x7f', 0}, // BACKSPACE == ASCII DEL\n  { KEYCODE_LITERAL, '\\x1b', 0}, // ESCAPE\n\n  { KEYCODE_CSI_CURSOR, 'A', 0}, // UP\n  { KEYCODE_CSI_CURSOR, 'B', 0}, // DOWN\n  { KEYCODE_CSI_CURSOR, 'D', 0}, // LEFT\n  { KEYCODE_CSI_CURSOR, 'C', 0}, // RIGHT\n\n  { KEYCODE_CSINUM, '~', 2 },  // INS\n  { KEYCODE_CSINUM, '~', 3 },  // DEL\n  { KEYCODE_CSI_CURSOR, 'H', 0}, // HOME\n  { KEYCODE_CSI_CURSOR, 'F', 0}, // END\n  { KEYCODE_CSINUM, '~', 5 },  // PAGEUP\n  { KEYCODE_CSINUM, '~', 6 },  // PAGEDOWN\n};\n\nstatic keycodes_s keycodes_fn[] = {\n  { KEYCODE_NONE },            // F0 - shouldn't happen\n  { KEYCODE_CSI_CURSOR, 'P', 0}, // F1\n  { KEYCODE_CSI_CURSOR, 'Q', 0}, // F2\n  { KEYCODE_CSI_CURSOR, 'R', 0}, // F3\n  { KEYCODE_CSI_CURSOR, 'S', 0}, // F4\n  { KEYCODE_CSINUM, '~', 15 }, // F5\n  { KEYCODE_CSINUM, '~', 17 }, // F6\n  { KEYCODE_CSINUM, '~', 18 }, // F7\n  { KEYCODE_CSINUM, '~', 19 }, // F8\n  { KEYCODE_CSINUM, '~', 20 }, // F9\n  { KEYCODE_CSINUM, '~', 21 }, // F10\n  { KEYCODE_CSINUM, '~', 23 }, // F11\n  { KEYCODE_CSINUM, '~', 24 }, // F12\n};\n\nstatic keycodes_s keycodes_kp[] = {\n  { KEYCODE_KEYPAD, '0', 'p' }, // KP_0\n  { KEYCODE_KEYPAD, '1', 'q' }, // KP_1\n  { KEYCODE_KEYPAD, '2', 'r' }, // KP_2\n  { KEYCODE_KEYPAD, '3', 's' }, // KP_3\n  { KEYCODE_KEYPAD, '4', 't' }, // KP_4\n  { KEYCODE_KEYPAD, '5', 'u' }, // KP_5\n  { KEYCODE_KEYPAD, '6', 'v' }, // KP_6\n  { KEYCODE_KEYPAD, '7', 'w' }, // KP_7\n  { KEYCODE_KEYPAD, '8', 'x' }, // KP_8\n  { KEYCODE_KEYPAD, '9', 'y' }, // KP_9\n  { KEYCODE_KEYPAD, '*', 'j' }, // KP_MULT\n  { KEYCODE_KEYPAD, '+', 'k' }, // KP_PLUS\n  { KEYCODE_KEYPAD, ',', 'l' }, // KP_COMMA\n  { KEYCODE_KEYPAD, '-', 'm' }, // KP_MINUS\n  { KEYCODE_KEYPAD, '.', 'n' }, // KP_PERIOD\n  { KEYCODE_KEYPAD, '/', 'o' }, // KP_DIVIDE\n  { KEYCODE_KEYPAD, '\\n', 'M' }, // KP_ENTER\n  { KEYCODE_KEYPAD, '=', 'X' }, // KP_EQUAL\n};\n\nvoid vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod)\n{\n  if(key == VTERM_KEY_NONE)\n    return;\n\n  keycodes_s k;\n  if(key < VTERM_KEY_FUNCTION_0) {\n    if(key >= sizeof(keycodes)/sizeof(keycodes[0]))\n      return;\n    k = keycodes[key];\n  }\n  else if(key >= VTERM_KEY_FUNCTION_0 && key <= VTERM_KEY_FUNCTION_MAX) {\n    if((key - VTERM_KEY_FUNCTION_0) >= sizeof(keycodes_fn)/sizeof(keycodes_fn[0]))\n      return;\n    k = keycodes_fn[key - VTERM_KEY_FUNCTION_0];\n  }\n  else if(key >= VTERM_KEY_KP_0) {\n    if((key - VTERM_KEY_KP_0) >= sizeof(keycodes_kp)/sizeof(keycodes_kp[0]))\n      return;\n    k = keycodes_kp[key - VTERM_KEY_KP_0];\n  }\n\n  switch(k.type) {\n  case KEYCODE_NONE:\n    break;\n\n  case KEYCODE_TAB:\n    /* Shift-Tab is CSI Z but plain Tab is 0x09 */\n    if(mod == VTERM_MOD_SHIFT)\n      vterm_push_output_sprintf_ctrl(vt, C1_CSI, \"Z\");\n    else if(mod & VTERM_MOD_SHIFT)\n      vterm_push_output_sprintf_ctrl(vt, C1_CSI, \"1;%dZ\", mod+1);\n    else\n      goto case_LITERAL;\n    break;\n\n  case KEYCODE_ENTER:\n    /* Enter is CRLF in newline mode, but just CR in linefeed */\n    if(vt->state->mode.newline)\n      vterm_push_output_sprintf(vt, \"\\r\\n\");\n    else\n      goto case_LITERAL;\n    break;\n\n  case KEYCODE_LITERAL: case_LITERAL:\n    if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL))\n      vterm_push_output_sprintf_ctrl(vt, C1_CSI, \"%d;%du\", k.literal, mod+1);\n    else\n      vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? ESC_S \"%c\" : \"%c\", k.literal);\n    break;\n\n  case KEYCODE_SS3: case_SS3:\n    if(mod == 0)\n      vterm_push_output_sprintf_ctrl(vt, C1_SS3, \"%c\", k.literal);\n    else\n      goto case_CSI;\n    break;\n\n  case KEYCODE_CSI: case_CSI:\n    if(mod == 0)\n      vterm_push_output_sprintf_ctrl(vt, C1_CSI, \"%c\", k.literal);\n    else\n      vterm_push_output_sprintf_ctrl(vt, C1_CSI, \"1;%d%c\", mod + 1, k.literal);\n    break;\n\n  case KEYCODE_CSINUM:\n    if(mod == 0)\n      vterm_push_output_sprintf_ctrl(vt, C1_CSI, \"%d%c\", k.csinum, k.literal);\n    else\n      vterm_push_output_sprintf_ctrl(vt, C1_CSI, \"%d;%d%c\", k.csinum, mod + 1, k.literal);\n    break;\n\n  case KEYCODE_CSI_CURSOR:\n    if(vt->state->mode.cursor)\n      goto case_SS3;\n    else\n      goto case_CSI;\n\n  case KEYCODE_KEYPAD:\n    if(vt->state->mode.keypad) {\n      k.literal = k.csinum;\n      goto case_SS3;\n    }\n    else\n      goto case_LITERAL;\n  }\n}\n\nvoid vterm_keyboard_start_paste(VTerm *vt)\n{\n  if(vt->state->mode.bracketpaste)\n    vterm_push_output_sprintf_ctrl(vt, C1_CSI, \"200~\");\n}\n\nvoid vterm_keyboard_end_paste(VTerm *vt)\n{\n  if(vt->state->mode.bracketpaste)\n    vterm_push_output_sprintf_ctrl(vt, C1_CSI, \"201~\");\n}\n"
  },
  {
    "path": "system/fbterm/libvterm/mouse.c",
    "content": "#include \"vterm_internal.h\"\n\n#include \"utf8.h\"\n\nstatic void output_mouse(VTermState *state, int code, int pressed, int modifiers, int col, int row)\n{\n  modifiers <<= 2;\n\n  switch(state->mouse_protocol) {\n  case MOUSE_X10:\n    if(col + 0x21 > 0xff)\n      col = 0xff - 0x21;\n    if(row + 0x21 > 0xff)\n      row = 0xff - 0x21;\n\n    if(!pressed)\n      code = 3;\n\n    vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, \"M%c%c%c\",\n        (code | modifiers) + 0x20, col + 0x21, row + 0x21);\n    break;\n\n  case MOUSE_UTF8:\n    {\n      char utf8[18]; size_t len = 0;\n\n      if(!pressed)\n        code = 3;\n\n      len += fill_utf8((code | modifiers) + 0x20, utf8 + len);\n      len += fill_utf8(col + 0x21, utf8 + len);\n      len += fill_utf8(row + 0x21, utf8 + len);\n      utf8[len] = 0;\n\n      vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, \"M%s\", utf8);\n    }\n    break;\n\n  case MOUSE_SGR:\n    vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, \"<%d;%d;%d%c\",\n        code | modifiers, col + 1, row + 1, pressed ? 'M' : 'm');\n    break;\n\n  case MOUSE_RXVT:\n    if(!pressed)\n      code = 3;\n\n    vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, \"%d;%d;%dM\",\n        code | modifiers, col + 1, row + 1);\n    break;\n  }\n}\n\nvoid vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod)\n{\n  VTermState *state = vt->state;\n\n  if(col == state->mouse_col && row == state->mouse_row)\n    return;\n\n  state->mouse_col = col;\n  state->mouse_row = row;\n\n  if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) ||\n     (state->mouse_flags & MOUSE_WANT_MOVE)) {\n    int button = state->mouse_buttons & 0x01 ? 1 :\n                 state->mouse_buttons & 0x02 ? 2 :\n                 state->mouse_buttons & 0x04 ? 3 : 4;\n    output_mouse(state, button-1 + 0x20, 1, mod, col, row);\n  }\n}\n\nvoid vterm_mouse_button(VTerm *vt, int button, bool pressed, VTermModifier mod)\n{\n  VTermState *state = vt->state;\n\n  int old_buttons = state->mouse_buttons;\n\n  if(button > 0 && button <= 3) {\n    if(pressed)\n      state->mouse_buttons |= (1 << (button-1));\n    else\n      state->mouse_buttons &= ~(1 << (button-1));\n  }\n\n  /* Most of the time we don't get button releases from 4/5 */\n  if(state->mouse_buttons == old_buttons && button < 4)\n    return;\n\n  if(button < 4) {\n    output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row);\n  }\n  else if(button < 6) {\n    output_mouse(state, button-4 + 0x40, pressed, mod, state->mouse_col, state->mouse_row);\n  }\n}\n"
  },
  {
    "path": "system/fbterm/libvterm/parser.c",
    "content": "#include \"vterm_internal.h\"\n\n#include <stdio.h>\n#include <string.h>\n\n#undef DEBUG_PARSER\n\nstatic bool is_intermed(unsigned char c)\n{\n  return c >= 0x20 && c <= 0x2f;\n}\n\nstatic void do_control(VTerm *vt, unsigned char control)\n{\n  if(vt->parser.callbacks && vt->parser.callbacks->control)\n    if((*vt->parser.callbacks->control)(control, vt->parser.cbdata))\n      return;\n\n  DEBUG_LOG(\"libvterm: Unhandled control 0x%02x\\n\", control);\n}\n\nstatic void do_csi(VTerm *vt, char command)\n{\n#ifdef DEBUG_PARSER\n  printf(\"Parsed CSI args as:\\n\", arglen, args);\n  printf(\" leader: %s\\n\", vt->parser.csi_leader);\n  for(int argi = 0; argi < vt->parser.csi_argi; argi++) {\n    printf(\" %lu\", CSI_ARG(vt->parser.csi_args[argi]));\n    if(!CSI_ARG_HAS_MORE(vt->parser.csi_args[argi]))\n      printf(\"\\n\");\n  printf(\" intermed: %s\\n\", vt->parser.intermed);\n  }\n#endif\n\n  if(vt->parser.callbacks && vt->parser.callbacks->csi)\n    if((*vt->parser.callbacks->csi)(\n          vt->parser.csi_leaderlen ? vt->parser.csi_leader : NULL, \n          vt->parser.csi_args,\n          vt->parser.csi_argi,\n          vt->parser.intermedlen ? vt->parser.intermed : NULL,\n          command,\n          vt->parser.cbdata))\n      return;\n\n  DEBUG_LOG(\"libvterm: Unhandled CSI %c\\n\", command);\n}\n\nstatic void do_escape(VTerm *vt, char command)\n{\n  char seq[INTERMED_MAX+1];\n\n  size_t len = vt->parser.intermedlen;\n  strncpy(seq, vt->parser.intermed, len);\n  seq[len++] = command;\n  seq[len]   = 0;\n\n  if(vt->parser.callbacks && vt->parser.callbacks->escape)\n    if((*vt->parser.callbacks->escape)(seq, len, vt->parser.cbdata))\n      return;\n\n  DEBUG_LOG(\"libvterm: Unhandled escape ESC 0x%02x\\n\", command);\n}\n\nstatic void append_strbuffer(VTerm *vt, const char *str, size_t len)\n{\n  if(len > vt->parser.strbuffer_len - vt->parser.strbuffer_cur) {\n    len = vt->parser.strbuffer_len - vt->parser.strbuffer_cur;\n    DEBUG_LOG(\"Truncating strbuffer preserve to %zd bytes\\n\", len);\n  }\n\n  if(len > 0) {\n    strncpy(vt->parser.strbuffer + vt->parser.strbuffer_cur, str, len);\n    vt->parser.strbuffer_cur += len;\n  }\n}\n\nstatic void start_string(VTerm *vt, VTermParserStringType type)\n{\n  vt->parser.stringtype = type;\n\n  vt->parser.strbuffer_cur = 0;\n}\n\nstatic void more_string(VTerm *vt, const char *str, size_t len)\n{\n  append_strbuffer(vt, str, len);\n}\n\nstatic void done_string(VTerm *vt, const char *str, size_t len)\n{\n  if(vt->parser.strbuffer_cur) {\n    if(str)\n      append_strbuffer(vt, str, len);\n\n    str = vt->parser.strbuffer;\n    len = vt->parser.strbuffer_cur;\n  }\n  else if(!str) {\n    DEBUG_LOG(\"parser.c: TODO: No strbuffer _and_ no final fragment???\\n\");\n    len = 0;\n  }\n\n  switch(vt->parser.stringtype) {\n  case VTERM_PARSER_OSC:\n    if(vt->parser.callbacks && vt->parser.callbacks->osc)\n      if((*vt->parser.callbacks->osc)(str, len, vt->parser.cbdata))\n        return;\n\n    DEBUG_LOG(\"libvterm: Unhandled OSC %.*s\\n\", (int)len, str);\n    return;\n\n  case VTERM_PARSER_DCS:\n    if(vt->parser.callbacks && vt->parser.callbacks->dcs)\n      if((*vt->parser.callbacks->dcs)(str, len, vt->parser.cbdata))\n        return;\n\n    DEBUG_LOG(\"libvterm: Unhandled DCS %.*s\\n\", (int)len, str);\n    return;\n\n  case VTERM_N_PARSER_TYPES:\n    return;\n  }\n}\n\nsize_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)\n{\n  size_t pos = 0;\n  const char *string_start = NULL;\n\n  switch(vt->parser.state) {\n  case NORMAL:\n  case CSI_LEADER:\n  case CSI_ARGS:\n  case CSI_INTERMED:\n  case ESC:\n    string_start = NULL;\n    break;\n  case STRING:\n  case ESC_IN_STRING:\n    string_start = bytes;\n    break;\n  }\n\n#define ENTER_STRING_STATE(st) do { vt->parser.state = STRING; string_start = bytes + pos + 1; } while(0)\n#define ENTER_STATE(st)        do { vt->parser.state = st; string_start = NULL; } while(0)\n#define ENTER_NORMAL_STATE()   ENTER_STATE(NORMAL)\n\n  for( ; pos < len; pos++) {\n    unsigned char c = bytes[pos];\n\n    if(c == 0x00 || c == 0x7f) { // NUL, DEL\n      if(vt->parser.state >= STRING) {\n        more_string(vt, string_start, bytes + pos - string_start);\n        string_start = bytes + pos + 1;\n      }\n      continue;\n    }\n    if(c == 0x18 || c == 0x1a) { // CAN, SUB\n      ENTER_NORMAL_STATE();\n      continue;\n    }\n    else if(c == 0x1b) { // ESC\n      vt->parser.intermedlen = 0;\n      if(vt->parser.state == STRING)\n        vt->parser.state = ESC_IN_STRING;\n      else\n        ENTER_STATE(ESC);\n      continue;\n    }\n    else if(c == 0x07 &&  // BEL, can stand for ST in OSC or DCS state\n            vt->parser.state == STRING) {\n      // fallthrough\n    }\n    else if(c < 0x20) { // other C0\n      if(vt->parser.state >= STRING)\n        more_string(vt, string_start, bytes + pos - string_start);\n      do_control(vt, c);\n      if(vt->parser.state >= STRING)\n        string_start = bytes + pos + 1;\n      continue;\n    }\n    // else fallthrough\n\n    switch(vt->parser.state) {\n    case ESC_IN_STRING:\n      if(c == 0x5c) { // ST\n        vt->parser.state = STRING;\n        done_string(vt, string_start, bytes + pos - string_start - 1);\n        ENTER_NORMAL_STATE();\n        break;\n      }\n      vt->parser.state = ESC;\n      // else fallthrough\n\n    case ESC:\n      switch(c) {\n      case 0x50: // DCS\n        start_string(vt, VTERM_PARSER_DCS);\n        ENTER_STRING_STATE();\n        break;\n      case 0x5b: // CSI\n        vt->parser.csi_leaderlen = 0;\n        ENTER_STATE(CSI_LEADER);\n        break;\n      case 0x5d: // OSC\n        start_string(vt, VTERM_PARSER_OSC);\n        ENTER_STRING_STATE();\n        break;\n      default:\n        if(is_intermed(c)) {\n          if(vt->parser.intermedlen < INTERMED_MAX-1)\n            vt->parser.intermed[vt->parser.intermedlen++] = c;\n        }\n        else if(!vt->parser.intermedlen && c >= 0x40 && c < 0x60) {\n          do_control(vt, c + 0x40);\n          ENTER_NORMAL_STATE();\n        }\n        else if(c >= 0x30 && c < 0x7f) {\n          do_escape(vt, c);\n          ENTER_NORMAL_STATE();\n        }\n        else {\n          DEBUG_LOG(\"TODO: Unhandled byte %02x in Escape\\n\", c);\n        }\n      }\n      break;\n\n    case CSI_LEADER:\n      /* Extract leader bytes 0x3c to 0x3f */\n      if(c >= 0x3c && c <= 0x3f) {\n        if(vt->parser.csi_leaderlen < CSI_LEADER_MAX-1)\n          vt->parser.csi_leader[vt->parser.csi_leaderlen++] = c;\n        break;\n      }\n\n      /* else fallthrough */\n      vt->parser.csi_leader[vt->parser.csi_leaderlen] = 0;\n\n      vt->parser.csi_argi = 0;\n      vt->parser.csi_args[0] = CSI_ARG_MISSING;\n      vt->parser.state = CSI_ARGS;\n\n      /* fallthrough */\n    case CSI_ARGS:\n      /* Numerical value of argument */\n      if(c >= '0' && c <= '9') {\n        if(vt->parser.csi_args[vt->parser.csi_argi] == CSI_ARG_MISSING)\n          vt->parser.csi_args[vt->parser.csi_argi] = 0;\n        vt->parser.csi_args[vt->parser.csi_argi] *= 10;\n        vt->parser.csi_args[vt->parser.csi_argi] += c - '0';\n        break;\n      }\n      if(c == ':') {\n        vt->parser.csi_args[vt->parser.csi_argi] |= CSI_ARG_FLAG_MORE;\n        c = ';';\n      }\n      if(c == ';') {\n        vt->parser.csi_argi++;\n        vt->parser.csi_args[vt->parser.csi_argi] = CSI_ARG_MISSING;\n        break;\n      }\n\n      /* else fallthrough */\n      vt->parser.csi_argi++;\n      vt->parser.intermedlen = 0;\n      vt->parser.state = CSI_INTERMED;\n      /* fallthrough */\n    case CSI_INTERMED:\n      if(is_intermed(c)) {\n        if(vt->parser.intermedlen < INTERMED_MAX-1)\n          vt->parser.intermed[vt->parser.intermedlen++] = c;\n        break;\n      }\n      else if(c == 0x1b) {\n        /* ESC in CSI cancels */\n      }\n      else if(c >= 0x40 && c <= 0x7e) {\n        vt->parser.intermed[vt->parser.intermedlen] = 0;\n        do_csi(vt, c);\n      }\n      /* else was invalid CSI */\n\n      ENTER_NORMAL_STATE();\n      break;\n\n    case STRING:\n      if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) {\n        done_string(vt, string_start, bytes + pos - string_start);\n        ENTER_NORMAL_STATE();\n      }\n      break;\n\n    case NORMAL:\n      if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) {\n        switch(c) {\n        case 0x90: // DCS\n          start_string(vt, VTERM_PARSER_DCS);\n          ENTER_STRING_STATE();\n          break;\n        case 0x9b: // CSI\n          ENTER_STATE(CSI_LEADER);\n          break;\n        case 0x9d: // OSC\n          start_string(vt, VTERM_PARSER_OSC);\n          ENTER_STRING_STATE();\n          break;\n        default:\n          do_control(vt, c);\n          break;\n        }\n      }\n      else {\n        size_t eaten = 0;\n        if(vt->parser.callbacks && vt->parser.callbacks->text)\n          eaten = (*vt->parser.callbacks->text)(bytes + pos, len - pos, vt->parser.cbdata);\n\n        if(!eaten) {\n          DEBUG_LOG(\"libvterm: Text callback did not consume any input\\n\");\n          /* force it to make progress */\n          eaten = 1;\n        }\n\n        pos += (eaten - 1); // we'll ++ it again in a moment\n      }\n      break;\n    }\n  }\n\n  return len;\n}\n\nvoid vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user)\n{\n  vt->parser.callbacks = callbacks;\n  vt->parser.cbdata = user;\n}\n\nvoid *vterm_parser_get_cbdata(VTerm *vt)\n{\n  return vt->parser.cbdata;\n}\n"
  },
  {
    "path": "system/fbterm/libvterm/pen.c",
    "content": "#include \"vterm_internal.h\"\n\n#include <stdio.h>\n\nstatic const VTermColor ansi_colors[] = {\n  /* R    G    B */\n  {   0,   0,   0 }, // black\n  { 224,   0,   0 }, // red\n  {   0, 224,   0 }, // green\n  { 224, 224,   0 }, // yellow\n  {   0,   0, 224 }, // blue\n  { 224,   0, 224 }, // magenta\n  {   0, 224, 224 }, // cyan\n  { 224, 224, 224 }, // white == light grey\n\n  // high intensity\n  { 128, 128, 128 }, // black\n  { 255,  64,  64 }, // red\n  {  64, 255,  64 }, // green\n  { 255, 255,  64 }, // yellow\n  {  64,  64, 255 }, // blue\n  { 255,  64, 255 }, // magenta\n  {  64, 255, 255 }, // cyan\n  { 255, 255, 255 }, // white for real\n};\n\nstatic int ramp6[] = {\n  0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF,\n};\n\nstatic int ramp24[] = {\n  0x00, 0x0B, 0x16, 0x21, 0x2C, 0x37, 0x42, 0x4D, 0x58, 0x63, 0x6E, 0x79,\n  0x85, 0x90, 0x9B, 0xA6, 0xB1, 0xBC, 0xC7, 0xD2, 0xDD, 0xE8, 0xF3, 0xFF,\n};\n\nstatic bool lookup_colour_ansi(const VTermState *state, long index, VTermColor *col)\n{\n  if(index >= 0 && index < 16) {\n    *col = state->colors[index];\n    return true;\n  }\n\n  return false;\n}\n\nstatic bool lookup_colour_palette(const VTermState *state, long index, VTermColor *col)\n{\n  if(index >= 0 && index < 16) {\n    // Normal 8 colours or high intensity - parse as palette 0\n    return lookup_colour_ansi(state, index, col);\n  }\n  else if(index >= 16 && index < 232) {\n    // 216-colour cube\n    index -= 16;\n\n    col->blue  = ramp6[index     % 6];\n    col->green = ramp6[index/6   % 6];\n    col->red   = ramp6[index/6/6 % 6];\n\n    return true;\n  }\n  else if(index >= 232 && index < 256) {\n    // 24 greyscales\n    index -= 232;\n\n    col->blue  = ramp24[index];\n    col->green = ramp24[index];\n    col->red   = ramp24[index];\n\n    return true;\n  }\n\n  return false;\n}\n\nstatic int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col, int *index)\n{\n  switch(palette) {\n  case 2: // RGB mode - 3 args contain colour values directly\n    if(argcount < 3)\n      return argcount;\n\n    col->red   = CSI_ARG(args[0]);\n    col->green = CSI_ARG(args[1]);\n    col->blue  = CSI_ARG(args[2]);\n\n    return 3;\n\n  case 5: // XTerm 256-colour mode\n    if(index)\n      *index = CSI_ARG_OR(args[0], -1);\n\n    lookup_colour_palette(state, argcount ? CSI_ARG_OR(args[0], -1) : -1, col);\n\n    return argcount ? 1 : 0;\n\n  default:\n    DEBUG_LOG(\"Unrecognised colour palette %d\\n\", palette);\n    return 0;\n  }\n}\n\n// Some conveniences\n\nstatic void setpenattr(VTermState *state, VTermAttr attr, VTermValueType type, VTermValue *val)\n{\n#ifdef DEBUG\n  if(type != vterm_get_attr_type(attr)) {\n    DEBUG_LOG(\"Cannot set attr %d as it has type %d, not type %d\\n\",\n        attr, vterm_get_attr_type(attr), type);\n    return;\n  }\n#endif\n  if(state->callbacks && state->callbacks->setpenattr)\n    (*state->callbacks->setpenattr)(attr, val, state->cbdata);\n}\n\nstatic void setpenattr_bool(VTermState *state, VTermAttr attr, int boolean)\n{\n  VTermValue val = { .boolean = boolean };\n  setpenattr(state, attr, VTERM_VALUETYPE_BOOL, &val);\n}\n\nstatic void setpenattr_int(VTermState *state, VTermAttr attr, int number)\n{\n  VTermValue val = { .number = number };\n  setpenattr(state, attr, VTERM_VALUETYPE_INT, &val);\n}\n\nstatic void setpenattr_col(VTermState *state, VTermAttr attr, VTermColor color)\n{\n  VTermValue val = { .color = color };\n  setpenattr(state, attr, VTERM_VALUETYPE_COLOR, &val);\n}\n\nstatic void set_pen_col_ansi(VTermState *state, VTermAttr attr, long col)\n{\n  VTermColor *colp = (attr == VTERM_ATTR_BACKGROUND) ? &state->pen.bg : &state->pen.fg;\n\n  lookup_colour_ansi(state, col, colp);\n\n  setpenattr_col(state, attr, *colp);\n}\n\nINTERNAL void vterm_state_newpen(VTermState *state)\n{\n  // 90% grey so that pure white is brighter\n  state->default_fg.red = state->default_fg.green = state->default_fg.blue = 240;\n  state->default_bg.red = state->default_bg.green = state->default_bg.blue = 0;\n\n  for(int col = 0; col < 16; col++)\n    state->colors[col] = ansi_colors[col];\n}\n\nINTERNAL void vterm_state_resetpen(VTermState *state)\n{\n  state->pen.bold = 0;      setpenattr_bool(state, VTERM_ATTR_BOLD, 0);\n  state->pen.underline = 0; setpenattr_int( state, VTERM_ATTR_UNDERLINE, 0);\n  state->pen.italic = 0;    setpenattr_bool(state, VTERM_ATTR_ITALIC, 0);\n  state->pen.blink = 0;     setpenattr_bool(state, VTERM_ATTR_BLINK, 0);\n  state->pen.reverse = 0;   setpenattr_bool(state, VTERM_ATTR_REVERSE, 0);\n  state->pen.strike = 0;    setpenattr_bool(state, VTERM_ATTR_STRIKE, 0);\n  state->pen.font = 0;      setpenattr_int( state, VTERM_ATTR_FONT, 0);\n\n  state->fg_index = -1;\n  state->bg_index = -1;\n  state->pen.fg = state->default_fg;  setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->default_fg);\n  state->pen.bg = state->default_bg;  setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->default_bg);\n}\n\nINTERNAL void vterm_state_savepen(VTermState *state, int save)\n{\n  if(save) {\n    state->saved.pen = state->pen;\n  }\n  else {\n    state->pen = state->saved.pen;\n\n    setpenattr_bool(state, VTERM_ATTR_BOLD,       state->pen.bold);\n    setpenattr_int( state, VTERM_ATTR_UNDERLINE,  state->pen.underline);\n    setpenattr_bool(state, VTERM_ATTR_ITALIC,     state->pen.italic);\n    setpenattr_bool(state, VTERM_ATTR_BLINK,      state->pen.blink);\n    setpenattr_bool(state, VTERM_ATTR_REVERSE,    state->pen.reverse);\n    setpenattr_bool(state, VTERM_ATTR_STRIKE,     state->pen.strike);\n    setpenattr_int( state, VTERM_ATTR_FONT,       state->pen.font);\n    setpenattr_col( state, VTERM_ATTR_FOREGROUND, state->pen.fg);\n    setpenattr_col( state, VTERM_ATTR_BACKGROUND, state->pen.bg);\n  }\n}\n\nvoid vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg)\n{\n  *default_fg = state->default_fg;\n  *default_bg = state->default_bg;\n}\n\nvoid vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col)\n{\n  lookup_colour_palette(state, index, col);\n}\n\nvoid vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg)\n{\n  state->default_fg = *default_fg;\n  state->default_bg = *default_bg;\n}\n\nvoid vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col)\n{\n  if(index >= 0 && index < 16)\n    state->colors[index] = *col;\n}\n\nvoid vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright)\n{\n  state->bold_is_highbright = bold_is_highbright;\n}\n\nINTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argcount)\n{\n  // SGR - ECMA-48 8.3.117\n\n  int argi = 0;\n  int value;\n\n  while(argi < argcount) {\n    // This logic is easier to do 'done' backwards; set it true, and make it\n    // false again in the 'default' case\n    int done = 1;\n\n    long arg;\n    switch(arg = CSI_ARG(args[argi])) {\n    case CSI_ARG_MISSING:\n    case 0: // Reset\n      vterm_state_resetpen(state);\n      break;\n\n    case 1: // Bold on\n      state->pen.bold = 1;\n      setpenattr_bool(state, VTERM_ATTR_BOLD, 1);\n      if(state->fg_index > -1 && state->fg_index < 8 && state->bold_is_highbright)\n        set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, state->fg_index + (state->pen.bold ? 8 : 0));\n      break;\n\n    case 3: // Italic on\n      state->pen.italic = 1;\n      setpenattr_bool(state, VTERM_ATTR_ITALIC, 1);\n      break;\n\n    case 4: // Underline single\n      state->pen.underline = 1;\n      setpenattr_int(state, VTERM_ATTR_UNDERLINE, 1);\n      break;\n\n    case 5: // Blink\n      state->pen.blink = 1;\n      setpenattr_bool(state, VTERM_ATTR_BLINK, 1);\n      break;\n\n    case 7: // Reverse on\n      state->pen.reverse = 1;\n      setpenattr_bool(state, VTERM_ATTR_REVERSE, 1);\n      break;\n\n    case 9: // Strikethrough on\n      state->pen.strike = 1;\n      setpenattr_bool(state, VTERM_ATTR_STRIKE, 1);\n      break;\n\n    case 10: case 11: case 12: case 13: case 14:\n    case 15: case 16: case 17: case 18: case 19: // Select font\n      state->pen.font = CSI_ARG(args[argi]) - 10;\n      setpenattr_int(state, VTERM_ATTR_FONT, state->pen.font);\n      break;\n\n    case 21: // Underline double\n      state->pen.underline = 2;\n      setpenattr_int(state, VTERM_ATTR_UNDERLINE, 2);\n      break;\n\n    case 22: // Bold off\n      state->pen.bold = 0;\n      setpenattr_bool(state, VTERM_ATTR_BOLD, 0);\n      break;\n\n    case 23: // Italic and Gothic (currently unsupported) off\n      state->pen.italic = 0;\n      setpenattr_bool(state, VTERM_ATTR_ITALIC, 0);\n      break;\n\n    case 24: // Underline off\n      state->pen.underline = 0;\n      setpenattr_int(state, VTERM_ATTR_UNDERLINE, 0);\n      break;\n\n    case 25: // Blink off\n      state->pen.blink = 0;\n      setpenattr_bool(state, VTERM_ATTR_BLINK, 0);\n      break;\n\n    case 27: // Reverse off\n      state->pen.reverse = 0;\n      setpenattr_bool(state, VTERM_ATTR_REVERSE, 0);\n      break;\n\n    case 29: // Strikethrough off\n      state->pen.strike = 0;\n      setpenattr_bool(state, VTERM_ATTR_STRIKE, 0);\n      break;\n\n    case 30: case 31: case 32: case 33:\n    case 34: case 35: case 36: case 37: // Foreground colour palette\n      value = CSI_ARG(args[argi]) - 30;\n      state->fg_index = value;\n      if(state->pen.bold && state->bold_is_highbright)\n        value += 8;\n      set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value);\n      break;\n\n    case 38: // Foreground colour alternative palette\n      state->fg_index = -1;\n      if(argcount - argi < 1)\n        return;\n      argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg, &state->fg_index);\n      setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg);\n      break;\n\n    case 39: // Foreground colour default\n      state->fg_index = -1;\n      state->pen.fg = state->default_fg;\n      setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg);\n      break;\n\n    case 40: case 41: case 42: case 43:\n    case 44: case 45: case 46: case 47: // Background colour palette\n      value = CSI_ARG(args[argi]) - 40;\n      state->bg_index = value;\n      set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value);\n      break;\n\n    case 48: // Background colour alternative palette\n      state->bg_index = -1;\n      if(argcount - argi < 1)\n        return;\n      argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg, &state->bg_index);\n      setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg);\n      break;\n\n    case 49: // Default background\n      state->bg_index = -1;\n      state->pen.bg = state->default_bg;\n      setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg);\n      break;\n\n    case 90: case 91: case 92: case 93:\n    case 94: case 95: case 96: case 97: // Foreground colour high-intensity palette\n      value = CSI_ARG(args[argi]) - 90 + 8;\n      state->fg_index = value;\n      set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value);\n      break;\n\n    case 100: case 101: case 102: case 103:\n    case 104: case 105: case 106: case 107: // Background colour high-intensity palette\n      value = CSI_ARG(args[argi]) - 100 + 8;\n      state->bg_index = value;\n      set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value);\n      break;\n\n    default:\n      done = 0;\n      break;\n    }\n\n    if(!done) {\n      DEBUG_LOG(\"libvterm: Unhandled CSI SGR %lu\\n\", arg);\n    }\n\n    while(CSI_ARG_HAS_MORE(args[argi++]));\n  }\n}\n\nINTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount)\n{\n  int argi = 0;\n\n  if(state->pen.bold)\n    args[argi++] = 1;\n\n  if(state->pen.italic)\n    args[argi++] = 3;\n\n  if(state->pen.underline == 1)\n    args[argi++] = 4;\n\n  if(state->pen.blink)\n    args[argi++] = 5;\n\n  if(state->pen.reverse)\n    args[argi++] = 7;\n\n  if(state->pen.strike)\n    args[argi++] = 9;\n\n  if(state->pen.font)\n    args[argi++] = 10 + state->pen.font;\n\n  if(state->pen.underline == 2)\n    args[argi++] = 21;\n\n  if(state->fg_index >= 0 && state->fg_index < 8)\n    args[argi++] = 30 + state->fg_index;\n  else if(state->fg_index >= 8 && state->fg_index < 16)\n    args[argi++] = 90 + state->fg_index - 8;\n  else if(state->fg_index >= 16 && state->fg_index < 256) {\n    args[argi++] = CSI_ARG_FLAG_MORE|38;\n    args[argi++] = CSI_ARG_FLAG_MORE|5;\n    args[argi++] = state->fg_index;\n  }\n  else if(state->fg_index == -1) {\n    // Send palette 2 if the actual FG colour is not default\n    if(state->pen.fg.red   != state->default_fg.red   ||\n       state->pen.fg.green != state->default_fg.green ||\n       state->pen.fg.blue  != state->default_fg.blue  ) {\n      args[argi++] = CSI_ARG_FLAG_MORE|38;\n      args[argi++] = CSI_ARG_FLAG_MORE|2;\n      args[argi++] = CSI_ARG_FLAG_MORE | state->pen.fg.red;\n      args[argi++] = CSI_ARG_FLAG_MORE | state->pen.fg.green;\n      args[argi++] = state->pen.fg.blue;\n    }\n  }\n\n  if(state->bg_index >= 0 && state->bg_index < 8)\n    args[argi++] = 40 + state->bg_index;\n  else if(state->bg_index >= 8 && state->bg_index < 16)\n    args[argi++] = 100 + state->bg_index - 8;\n  else if(state->bg_index >= 16 && state->bg_index < 256) {\n    args[argi++] = CSI_ARG_FLAG_MORE|48;\n    args[argi++] = CSI_ARG_FLAG_MORE|5;\n    args[argi++] = state->bg_index;\n  }\n  else if(state->bg_index == -1) {\n    // Send palette 2 if the actual BG colour is not default\n    if(state->pen.bg.red   != state->default_bg.red   ||\n       state->pen.bg.green != state->default_bg.green ||\n       state->pen.bg.blue  != state->default_bg.blue  ) {\n      args[argi++] = CSI_ARG_FLAG_MORE|48;\n      args[argi++] = CSI_ARG_FLAG_MORE|2;\n      args[argi++] = CSI_ARG_FLAG_MORE | state->pen.bg.red;\n      args[argi++] = CSI_ARG_FLAG_MORE | state->pen.bg.green;\n      args[argi++] = state->pen.bg.blue;\n    }\n  }\n\n  return argi;\n}\n\nint vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val)\n{\n  switch(attr) {\n  case VTERM_ATTR_BOLD:\n    val->boolean = state->pen.bold;\n    return 1;\n\n  case VTERM_ATTR_UNDERLINE:\n    val->number = state->pen.underline;\n    return 1;\n\n  case VTERM_ATTR_ITALIC:\n    val->boolean = state->pen.italic;\n    return 1;\n\n  case VTERM_ATTR_BLINK:\n    val->boolean = state->pen.blink;\n    return 1;\n\n  case VTERM_ATTR_REVERSE:\n    val->boolean = state->pen.reverse;\n    return 1;\n\n  case VTERM_ATTR_STRIKE:\n    val->boolean = state->pen.strike;\n    return 1;\n\n  case VTERM_ATTR_FONT:\n    val->number = state->pen.font;\n    return 1;\n\n  case VTERM_ATTR_FOREGROUND:\n    val->color = state->pen.fg;\n    return 1;\n\n  case VTERM_ATTR_BACKGROUND:\n    val->color = state->pen.bg;\n    return 1;\n\n  case VTERM_N_ATTRS:\n    return 0;\n  }\n\n  return 0;\n}\n"
  },
  {
    "path": "system/fbterm/libvterm/rect.h",
    "content": "/*\n * Some utility functions on VTermRect structures\n */\n\n#define STRFrect \"(%d,%d-%d,%d)\"\n#define ARGSrect(r) (r).start_row, (r).start_col, (r).end_row, (r).end_col\n\n/* Expand dst to contain src as well */\nstatic void rect_expand(VTermRect *dst, VTermRect *src)\n{\n  if(dst->start_row > src->start_row) dst->start_row = src->start_row;\n  if(dst->start_col > src->start_col) dst->start_col = src->start_col;\n  if(dst->end_row   < src->end_row)   dst->end_row   = src->end_row;\n  if(dst->end_col   < src->end_col)   dst->end_col   = src->end_col;\n}\n\n/* Clip the dst to ensure it does not step outside of bounds */\nstatic void rect_clip(VTermRect *dst, VTermRect *bounds)\n{\n  if(dst->start_row < bounds->start_row) dst->start_row = bounds->start_row;\n  if(dst->start_col < bounds->start_col) dst->start_col = bounds->start_col;\n  if(dst->end_row   > bounds->end_row)   dst->end_row   = bounds->end_row;\n  if(dst->end_col   > bounds->end_col)   dst->end_col   = bounds->end_col;\n  /* Ensure it doesn't end up negatively-sized */\n  if(dst->end_row < dst->start_row) dst->end_row = dst->start_row;\n  if(dst->end_col < dst->start_col) dst->end_col = dst->start_col;\n}\n\n/* True if the two rectangles are equal */\nstatic int rect_equal(VTermRect *a, VTermRect *b)\n{\n  return (a->start_row == b->start_row) &&\n         (a->start_col == b->start_col) &&\n         (a->end_row   == b->end_row)   &&\n         (a->end_col   == b->end_col);\n}\n\n/* True if small is contained entirely within big */\nstatic int rect_contains(VTermRect *big, VTermRect *small)\n{\n  if(small->start_row < big->start_row) return 0;\n  if(small->start_col < big->start_col) return 0;\n  if(small->end_row   > big->end_row)   return 0;\n  if(small->end_col   > big->end_col)   return 0;\n  return 1;\n}\n\n/* True if the rectangles overlap at all */\nstatic int rect_intersects(VTermRect *a, VTermRect *b)\n{\n  if(a->start_row > b->end_row || b->start_row > a->end_row)\n    return 0;\n  if(a->start_col > b->end_col || b->start_col > a->end_col)\n    return 0;\n  return 1;\n}\n"
  },
  {
    "path": "system/fbterm/libvterm/screen.c",
    "content": "#include \"vterm_internal.h\"\n\n#include <stdio.h>\n#include <string.h>\n\n#include \"rect.h\"\n#include \"utf8.h\"\n\n#define UNICODE_SPACE 0x20\n#define UNICODE_LINEFEED 0x0a\n\n/* State of the pen at some moment in time, also used in a cell */\ntypedef struct\n{\n  /* After the bitfield */\n  VTermColor   fg, bg;\n\n  unsigned int bold      : 1;\n  unsigned int underline : 2;\n  unsigned int italic    : 1;\n  unsigned int blink     : 1;\n  unsigned int reverse   : 1;\n  unsigned int strike    : 1;\n  unsigned int font      : 4; /* 0 to 9 */\n\n  /* Extra state storage that isn't strictly pen-related */\n  unsigned int protected_cell : 1;\n  unsigned int dwl            : 1; /* on a DECDWL or DECDHL line */\n  unsigned int dhl            : 2; /* on a DECDHL line (1=top 2=bottom) */\n} ScreenPen;\n\n/* Internal representation of a screen cell */\ntypedef struct\n{\n  uint32_t chars[VTERM_MAX_CHARS_PER_CELL];\n  ScreenPen pen;\n} ScreenCell;\n\nstatic int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell);\n\nstruct VTermScreen\n{\n  VTerm *vt;\n  VTermState *state;\n\n  const VTermScreenCallbacks *callbacks;\n  void *cbdata;\n\n  VTermDamageSize damage_merge;\n  /* start_row == -1 => no damage */\n  VTermRect damaged;\n  VTermRect pending_scrollrect;\n  int pending_scroll_downward, pending_scroll_rightward;\n\n  int rows;\n  int cols;\n  int global_reverse;\n\n  /* Primary and Altscreen. buffers[1] is lazily allocated as needed */\n  ScreenCell *buffers[2];\n\n  /* buffer will == buffers[0] or buffers[1], depending on altscreen */\n  ScreenCell *buffer;\n\n  /* buffer for a single screen row used in scrollback storage callbacks */\n  VTermScreenCell *sb_buffer;\n\n  ScreenPen pen;\n};\n\nstatic inline ScreenCell *getcell(const VTermScreen *screen, int row, int col)\n{\n  if(row < 0 || row >= screen->rows)\n    return NULL;\n  if(col < 0 || col >= screen->cols)\n    return NULL;\n  return screen->buffer + (screen->cols * row) + col;\n}\n\nstatic ScreenCell *realloc_buffer(VTermScreen *screen, ScreenCell *buffer, int new_rows, int new_cols)\n{\n  ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols);\n\n  for(int row = 0; row < new_rows; row++) {\n    for(int col = 0; col < new_cols; col++) {\n      ScreenCell *new_cell = new_buffer + row*new_cols + col;\n\n      if(buffer && row < screen->rows && col < screen->cols)\n        *new_cell = buffer[row * screen->cols + col];\n      else {\n        new_cell->chars[0] = 0;\n        new_cell->pen = screen->pen;\n      }\n    }\n  }\n\n  if(buffer)\n    vterm_allocator_free(screen->vt, buffer);\n\n  return new_buffer;\n}\n\nstatic void damagerect(VTermScreen *screen, VTermRect rect)\n{\n  VTermRect emit;\n\n  switch(screen->damage_merge) {\n  case VTERM_DAMAGE_CELL:\n    /* Always emit damage event */\n    emit = rect;\n    break;\n\n  case VTERM_DAMAGE_ROW:\n    /* Emit damage longer than one row. Try to merge with existing damage in\n     * the same row */\n    if(rect.end_row > rect.start_row + 1) {\n      // Bigger than 1 line - flush existing, emit this\n      vterm_screen_flush_damage(screen);\n      emit = rect;\n    }\n    else if(screen->damaged.start_row == -1) {\n      // None stored yet\n      screen->damaged = rect;\n      return;\n    }\n    else if(rect.start_row == screen->damaged.start_row) {\n      // Merge with the stored line\n      if(screen->damaged.start_col > rect.start_col)\n        screen->damaged.start_col = rect.start_col;\n      if(screen->damaged.end_col < rect.end_col)\n        screen->damaged.end_col = rect.end_col;\n      return;\n    }\n    else {\n      // Emit the currently stored line, store a new one\n      emit = screen->damaged;\n      screen->damaged = rect;\n    }\n    break;\n\n  case VTERM_DAMAGE_SCREEN:\n  case VTERM_DAMAGE_SCROLL:\n    /* Never emit damage event */\n    if(screen->damaged.start_row == -1)\n      screen->damaged = rect;\n    else {\n      rect_expand(&screen->damaged, &rect);\n    }\n    return;\n\n  default:\n    DEBUG_LOG(\"TODO: Maybe merge damage for level %d\\n\", screen->damage_merge);\n    return;\n  }\n\n  if(screen->callbacks && screen->callbacks->damage)\n    (*screen->callbacks->damage)(emit, screen->cbdata);\n}\n\nstatic void damagescreen(VTermScreen *screen)\n{\n  VTermRect rect = {\n    .start_row = 0,\n    .end_row   = screen->rows,\n    .start_col = 0,\n    .end_col   = screen->cols,\n  };\n\n  damagerect(screen, rect);\n}\n\nstatic int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)\n{\n  VTermScreen *screen = user;\n  ScreenCell *cell = getcell(screen, pos.row, pos.col);\n\n  if(!cell)\n    return 0;\n\n  int i;\n  for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) {\n    cell->chars[i] = info->chars[i];\n    cell->pen = screen->pen;\n  }\n  if(i < VTERM_MAX_CHARS_PER_CELL)\n    cell->chars[i] = 0;\n\n  for(int col = 1; col < info->width; col++)\n    getcell(screen, pos.row, pos.col + col)->chars[0] = (uint32_t)-1;\n\n  VTermRect rect = {\n    .start_row = pos.row,\n    .end_row   = pos.row+1,\n    .start_col = pos.col,\n    .end_col   = pos.col+info->width,\n  };\n\n  cell->pen.protected_cell = info->protected_cell;\n  cell->pen.dwl            = info->dwl;\n  cell->pen.dhl            = info->dhl;\n\n  damagerect(screen, rect);\n\n  return 1;\n}\n\nstatic int moverect_internal(VTermRect dest, VTermRect src, void *user)\n{\n  VTermScreen *screen = user;\n\n  if(screen->callbacks && screen->callbacks->sb_pushline &&\n     dest.start_row == 0 && dest.start_col == 0 &&  // starts top-left corner\n     dest.end_col == screen->cols &&                // full width\n     screen->buffer == screen->buffers[0]) {        // not altscreen\n    VTermPos pos;\n    for(pos.row = 0; pos.row < src.start_row; pos.row++) {\n      for(pos.col = 0; pos.col < screen->cols; pos.col++)\n        vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col);\n\n      (screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata);\n    }\n  }\n\n  int cols = src.end_col - src.start_col;\n  int downward = src.start_row - dest.start_row;\n\n  int init_row, test_row, inc_row;\n  if(downward < 0) {\n    init_row = dest.end_row - 1;\n    test_row = dest.start_row - 1;\n    inc_row  = -1;\n  }\n  else {\n    init_row = dest.start_row;\n    test_row = dest.end_row;\n    inc_row  = +1;\n  }\n\n  for(int row = init_row; row != test_row; row += inc_row)\n    memmove(getcell(screen, row, dest.start_col),\n            getcell(screen, row + downward, src.start_col),\n            cols * sizeof(ScreenCell));\n\n  return 1;\n}\n\nstatic int moverect_user(VTermRect dest, VTermRect src, void *user)\n{\n  VTermScreen *screen = user;\n\n  if(screen->callbacks && screen->callbacks->moverect) {\n    if(screen->damage_merge != VTERM_DAMAGE_SCROLL)\n      // Avoid an infinite loop\n      vterm_screen_flush_damage(screen);\n\n    if((*screen->callbacks->moverect)(dest, src, screen->cbdata))\n      return 1;\n  }\n\n  damagerect(screen, dest);\n\n  return 1;\n}\n\nstatic int erase_internal(VTermRect rect, int selective, void *user)\n{\n  VTermScreen *screen = user;\n\n  for(int row = rect.start_row; row < screen->state->rows && row < rect.end_row; row++) {\n    const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row);\n\n    for(int col = rect.start_col; col < rect.end_col; col++) {\n      ScreenCell *cell = getcell(screen, row, col);\n\n      if(selective && cell->pen.protected_cell)\n        continue;\n\n      cell->chars[0] = 0;\n      cell->pen = screen->pen;\n      cell->pen.dwl = info->doublewidth;\n      cell->pen.dhl = info->doubleheight;\n    }\n  }\n\n  return 1;\n}\n\nstatic int erase_user(VTermRect rect, int selective, void *user)\n{\n  VTermScreen *screen = user;\n\n  damagerect(screen, rect);\n\n  return 1;\n}\n\nstatic int erase(VTermRect rect, int selective, void *user)\n{\n  erase_internal(rect, selective, user);\n  return erase_user(rect, 0, user);\n}\n\nstatic int scrollrect(VTermRect rect, int downward, int rightward, void *user)\n{\n  VTermScreen *screen = user;\n\n  if(screen->damage_merge != VTERM_DAMAGE_SCROLL) {\n    vterm_scroll_rect(rect, downward, rightward,\n        moverect_internal, erase_internal, screen);\n\n    vterm_screen_flush_damage(screen);\n\n    vterm_scroll_rect(rect, downward, rightward,\n        moverect_user, erase_user, screen);\n\n    return 1;\n  }\n\n  if(screen->damaged.start_row != -1 &&\n     !rect_intersects(&rect, &screen->damaged)) {\n    vterm_screen_flush_damage(screen);\n  }\n\n  if(screen->pending_scrollrect.start_row == -1) {\n    screen->pending_scrollrect = rect;\n    screen->pending_scroll_downward  = downward;\n    screen->pending_scroll_rightward = rightward;\n  }\n  else if(rect_equal(&screen->pending_scrollrect, &rect) &&\n     ((screen->pending_scroll_downward  == 0 && downward  == 0) ||\n      (screen->pending_scroll_rightward == 0 && rightward == 0))) {\n    screen->pending_scroll_downward  += downward;\n    screen->pending_scroll_rightward += rightward;\n  }\n  else {\n    vterm_screen_flush_damage(screen);\n\n    screen->pending_scrollrect = rect;\n    screen->pending_scroll_downward  = downward;\n    screen->pending_scroll_rightward = rightward;\n  }\n\n  vterm_scroll_rect(rect, downward, rightward,\n      moverect_internal, erase_internal, screen);\n\n  if(screen->damaged.start_row == -1)\n    return 1;\n\n  if(rect_contains(&rect, &screen->damaged)) {\n    /* Scroll region entirely contains the damage; just move it */\n    vterm_rect_move(&screen->damaged, -downward, -rightward);\n    rect_clip(&screen->damaged, &rect);\n  }\n  /* There are a number of possible cases here, but lets restrict this to only\n   * the common case where we might actually gain some performance by\n   * optimising it. Namely, a vertical scroll that neatly cuts the damage\n   * region in half.\n   */\n  else if(rect.start_col <= screen->damaged.start_col &&\n          rect.end_col   >= screen->damaged.end_col &&\n          rightward == 0) {\n    if(screen->damaged.start_row >= rect.start_row &&\n       screen->damaged.start_row  < rect.end_row) {\n      screen->damaged.start_row -= downward;\n      if(screen->damaged.start_row < rect.start_row)\n        screen->damaged.start_row = rect.start_row;\n      if(screen->damaged.start_row > rect.end_row)\n        screen->damaged.start_row = rect.end_row;\n    }\n    if(screen->damaged.end_row >= rect.start_row &&\n       screen->damaged.end_row  < rect.end_row) {\n      screen->damaged.end_row -= downward;\n      if(screen->damaged.end_row < rect.start_row)\n        screen->damaged.end_row = rect.start_row;\n      if(screen->damaged.end_row > rect.end_row)\n        screen->damaged.end_row = rect.end_row;\n    }\n  }\n  else {\n    DEBUG_LOG(\"TODO: Just flush and redo damaged=\" STRFrect \" rect=\" STRFrect \"\\n\",\n        ARGSrect(screen->damaged), ARGSrect(rect));\n  }\n\n  return 1;\n}\n\nstatic int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)\n{\n  VTermScreen *screen = user;\n\n  if(screen->callbacks && screen->callbacks->movecursor)\n    return (*screen->callbacks->movecursor)(pos, oldpos, visible, screen->cbdata);\n\n  return 0;\n}\n\nstatic int setpenattr(VTermAttr attr, VTermValue *val, void *user)\n{\n  VTermScreen *screen = user;\n\n  switch(attr) {\n  case VTERM_ATTR_BOLD:\n    screen->pen.bold = val->boolean;\n    return 1;\n  case VTERM_ATTR_UNDERLINE:\n    screen->pen.underline = val->number;\n    return 1;\n  case VTERM_ATTR_ITALIC:\n    screen->pen.italic = val->boolean;\n    return 1;\n  case VTERM_ATTR_BLINK:\n    screen->pen.blink = val->boolean;\n    return 1;\n  case VTERM_ATTR_REVERSE:\n    screen->pen.reverse = val->boolean;\n    return 1;\n  case VTERM_ATTR_STRIKE:\n    screen->pen.strike = val->boolean;\n    return 1;\n  case VTERM_ATTR_FONT:\n    screen->pen.font = val->number;\n    return 1;\n  case VTERM_ATTR_FOREGROUND:\n    screen->pen.fg = val->color;\n    return 1;\n  case VTERM_ATTR_BACKGROUND:\n    screen->pen.bg = val->color;\n    return 1;\n\n  case VTERM_N_ATTRS:\n    return 0;\n  }\n\n  return 0;\n}\n\nstatic int settermprop(VTermProp prop, VTermValue *val, void *user)\n{\n  VTermScreen *screen = user;\n\n  switch(prop) {\n  case VTERM_PROP_ALTSCREEN:\n    if(val->boolean && !screen->buffers[1])\n      return 0;\n\n    screen->buffer = val->boolean ? screen->buffers[1] : screen->buffers[0];\n    /* only send a damage event on disable; because during enable there's an\n     * erase that sends a damage anyway\n     */\n    if(!val->boolean)\n      damagescreen(screen);\n    break;\n  case VTERM_PROP_REVERSE:\n    screen->global_reverse = val->boolean;\n    damagescreen(screen);\n    break;\n  default:\n    ; /* ignore */\n  }\n\n  if(screen->callbacks && screen->callbacks->settermprop)\n    return (*screen->callbacks->settermprop)(prop, val, screen->cbdata);\n\n  return 1;\n}\n\nstatic int bell(void *user)\n{\n  VTermScreen *screen = user;\n\n  if(screen->callbacks && screen->callbacks->bell)\n    return (*screen->callbacks->bell)(screen->cbdata);\n\n  return 0;\n}\n\nstatic int resize(int new_rows, int new_cols, VTermPos *delta, void *user)\n{\n  VTermScreen *screen = user;\n\n  int is_altscreen = (screen->buffers[1] && screen->buffer == screen->buffers[1]);\n\n  int old_rows = screen->rows;\n  int old_cols = screen->cols;\n\n  if(!is_altscreen && new_rows < old_rows) {\n    // Fewer rows - determine if we're going to scroll at all, and if so, push\n    // those lines to scrollback\n    VTermPos pos = { 0, 0 };\n    VTermPos cursor = screen->state->pos;\n    // Find the first blank row after the cursor.\n    for(pos.row = old_rows - 1; pos.row >= new_rows; pos.row--)\n      if(!vterm_screen_is_eol(screen, pos) || cursor.row == pos.row)\n        break;\n\n    int first_blank_row = pos.row + 1;\n    if(first_blank_row > new_rows) {\n      VTermRect rect = {\n        .start_row = 0,\n        .end_row   = old_rows,\n        .start_col = 0,\n        .end_col   = old_cols,\n      };\n      scrollrect(rect, first_blank_row - new_rows, 0, user);\n      vterm_screen_flush_damage(screen);\n\n      delta->row -= first_blank_row - new_rows;\n    }\n  }\n\n  screen->buffers[0] = realloc_buffer(screen, screen->buffers[0], new_rows, new_cols);\n  if(screen->buffers[1])\n    screen->buffers[1] = realloc_buffer(screen, screen->buffers[1], new_rows, new_cols);\n\n  screen->buffer = is_altscreen ? screen->buffers[1] : screen->buffers[0];\n\n  screen->rows = new_rows;\n  screen->cols = new_cols;\n\n  if(screen->sb_buffer)\n    vterm_allocator_free(screen->vt, screen->sb_buffer);\n\n  screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols);\n\n  if(new_cols > old_cols) {\n    VTermRect rect = {\n      .start_row = 0,\n      .end_row   = old_rows,\n      .start_col = old_cols,\n      .end_col   = new_cols,\n    };\n    damagerect(screen, rect);\n  }\n\n  if(new_rows > old_rows) {\n    if(!is_altscreen && screen->callbacks && screen->callbacks->sb_popline) {\n      int rows = new_rows - old_rows;\n      while(rows) {\n        if(!(screen->callbacks->sb_popline(screen->cols, screen->sb_buffer, screen->cbdata)))\n          break;\n\n        VTermRect rect = {\n          .start_row = 0,\n          .end_row   = screen->rows,\n          .start_col = 0,\n          .end_col   = screen->cols,\n        };\n        scrollrect(rect, -1, 0, user);\n\n        VTermPos pos = { 0, 0 };\n        for(pos.col = 0; pos.col < screen->cols; pos.col += screen->sb_buffer[pos.col].width)\n          vterm_screen_set_cell(screen, pos, screen->sb_buffer + pos.col);\n\n        rect.end_row = 1;\n        damagerect(screen, rect);\n\n        vterm_screen_flush_damage(screen);\n\n        rows--;\n        delta->row++;\n      }\n    }\n\n    VTermRect rect = {\n      .start_row = old_rows,\n      .end_row   = new_rows,\n      .start_col = 0,\n      .end_col   = new_cols,\n    };\n    damagerect(screen, rect);\n  }\n\n  if(screen->callbacks && screen->callbacks->resize)\n    return (*screen->callbacks->resize)(new_rows, new_cols, screen->cbdata);\n\n  return 1;\n}\n\nstatic int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user)\n{\n  VTermScreen *screen = user;\n\n  if(newinfo->doublewidth != oldinfo->doublewidth ||\n     newinfo->doubleheight != oldinfo->doubleheight) {\n    for(int col = 0; col < screen->cols; col++) {\n      ScreenCell *cell = getcell(screen, row, col);\n      cell->pen.dwl = newinfo->doublewidth;\n      cell->pen.dhl = newinfo->doubleheight;\n    }\n\n    VTermRect rect = {\n      .start_row = row,\n      .end_row   = row + 1,\n      .start_col = 0,\n      .end_col   = newinfo->doublewidth ? screen->cols / 2 : screen->cols,\n    };\n    damagerect(screen, rect);\n\n    if(newinfo->doublewidth) {\n      rect.start_col = screen->cols / 2;\n      rect.end_col   = screen->cols;\n\n      erase_internal(rect, 0, user);\n    }\n  }\n\n  return 1;\n}\n\nstatic VTermStateCallbacks state_cbs = {\n  .putglyph    = &putglyph,\n  .movecursor  = &movecursor,\n  .scrollrect  = &scrollrect,\n  .erase       = &erase,\n  .setpenattr  = &setpenattr,\n  .settermprop = &settermprop,\n  .bell        = &bell,\n  .resize      = &resize,\n  .setlineinfo = &setlineinfo,\n};\n\nstatic VTermScreen *screen_new(VTerm *vt)\n{\n  VTermState *state = vterm_obtain_state(vt);\n  if(!state)\n    return NULL;\n\n  VTermScreen *screen = vterm_allocator_malloc(vt, sizeof(VTermScreen));\n  int rows, cols;\n\n  vterm_get_size(vt, &rows, &cols);\n\n  screen->vt = vt;\n  screen->state = state;\n\n  screen->damage_merge = VTERM_DAMAGE_CELL;\n  screen->damaged.start_row = -1;\n  screen->pending_scrollrect.start_row = -1;\n\n  screen->rows = rows;\n  screen->cols = cols;\n\n  screen->callbacks = NULL;\n  screen->cbdata    = NULL;\n\n  screen->buffers[0] = realloc_buffer(screen, NULL, rows, cols);\n\n  screen->buffer = screen->buffers[0];\n\n  screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols);\n\n  vterm_state_set_callbacks(screen->state, &state_cbs, screen);\n\n  return screen;\n}\n\nINTERNAL void vterm_screen_free(VTermScreen *screen)\n{\n  vterm_allocator_free(screen->vt, screen->buffers[0]);\n  if(screen->buffers[1])\n    vterm_allocator_free(screen->vt, screen->buffers[1]);\n\n  vterm_allocator_free(screen->vt, screen->sb_buffer);\n\n  vterm_allocator_free(screen->vt, screen);\n}\n\nvoid vterm_screen_reset(VTermScreen *screen, int hard)\n{\n  screen->damaged.start_row = -1;\n  screen->pending_scrollrect.start_row = -1;\n  vterm_state_reset(screen->state, hard);\n  vterm_screen_flush_damage(screen);\n}\n\nstatic size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer, size_t len, const VTermRect rect)\n{\n  size_t outpos = 0;\n  int padding = 0;\n\n#define PUT(c)                                             \\\n  if(utf8) {                                               \\\n    size_t thislen = utf8_seqlen(c);                       \\\n    if(buffer && outpos + thislen <= len)                  \\\n      outpos += fill_utf8((c), (char *)buffer + outpos);   \\\n    else                                                   \\\n      outpos += thislen;                                   \\\n  }                                                        \\\n  else {                                                   \\\n    if(buffer && outpos + 1 <= len)                        \\\n      ((uint32_t*)buffer)[outpos++] = (c);                 \\\n    else                                                   \\\n      outpos++;                                            \\\n  }\n\n  for(int row = rect.start_row; row < rect.end_row; row++) {\n    for(int col = rect.start_col; col < rect.end_col; col++) {\n      ScreenCell *cell = getcell(screen, row, col);\n\n      if(cell->chars[0] == 0)\n        // Erased cell, might need a space\n        padding++;\n      else if(cell->chars[0] == (uint32_t)-1)\n        // Gap behind a double-width char, do nothing\n        ;\n      else {\n        while(padding) {\n          PUT(UNICODE_SPACE);\n          padding--;\n        }\n        for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) {\n          PUT(cell->chars[i]);\n        }\n      }\n    }\n\n    if(row < rect.end_row - 1) {\n      PUT(UNICODE_LINEFEED);\n      padding = 0;\n    }\n  }\n\n  return outpos;\n}\n\nsize_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect)\n{\n  return _get_chars(screen, 0, chars, len, rect);\n}\n\nsize_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect)\n{\n  return _get_chars(screen, 1, str, len, rect);\n}\n\n/* Copy internal to external representation of a screen cell */\nint vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell)\n{\n  ScreenCell *intcell = getcell(screen, pos.row, pos.col);\n  if(!intcell)\n    return 0;\n\n  for(int i = 0; ; i++) {\n    cell->chars[i] = intcell->chars[i];\n    if(!intcell->chars[i])\n      break;\n  }\n\n  cell->attrs.bold      = intcell->pen.bold;\n  cell->attrs.underline = intcell->pen.underline;\n  cell->attrs.italic    = intcell->pen.italic;\n  cell->attrs.blink     = intcell->pen.blink;\n  cell->attrs.reverse   = intcell->pen.reverse ^ screen->global_reverse;\n  cell->attrs.strike    = intcell->pen.strike;\n  cell->attrs.font      = intcell->pen.font;\n\n  cell->attrs.dwl = intcell->pen.dwl;\n  cell->attrs.dhl = intcell->pen.dhl;\n\n  cell->fg = intcell->pen.fg;\n  cell->bg = intcell->pen.bg;\n\n  if(pos.col < (screen->cols - 1) &&\n     getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1)\n    cell->width = 2;\n  else\n    cell->width = 1;\n\n  return 1;\n}\n\n/* Copy external to internal representation of a screen cell */\n/* static because it's only used internally for sb_popline during resize */\nstatic int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell)\n{\n  ScreenCell *intcell = getcell(screen, pos.row, pos.col);\n  if(!intcell)\n    return 0;\n\n  for(int i = 0; ; i++) {\n    intcell->chars[i] = cell->chars[i];\n    if(!cell->chars[i])\n      break;\n  }\n\n  intcell->pen.bold      = cell->attrs.bold;\n  intcell->pen.underline = cell->attrs.underline;\n  intcell->pen.italic    = cell->attrs.italic;\n  intcell->pen.blink     = cell->attrs.blink;\n  intcell->pen.reverse   = cell->attrs.reverse ^ screen->global_reverse;\n  intcell->pen.strike    = cell->attrs.strike;\n  intcell->pen.font      = cell->attrs.font;\n\n  intcell->pen.fg = cell->fg;\n  intcell->pen.bg = cell->bg;\n\n  if(cell->width == 2)\n    getcell(screen, pos.row, pos.col + 1)->chars[0] = (uint32_t)-1;\n\n  return 1;\n}\n\nint vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos)\n{\n  /* This cell is EOL if this and every cell to the right is black */\n  for(; pos.col < screen->cols; pos.col++) {\n    ScreenCell *cell = getcell(screen, pos.row, pos.col);\n    if(cell->chars[0] != 0)\n      return 0;\n  }\n\n  return 1;\n}\n\nVTermScreen *vterm_obtain_screen(VTerm *vt)\n{\n  if(vt->screen)\n    return vt->screen;\n\n  VTermScreen *screen = screen_new(vt);\n  vt->screen = screen;\n\n  return screen;\n}\n\nvoid vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen)\n{\n\n  if(!screen->buffers[1] && altscreen) {\n    int rows, cols;\n    vterm_get_size(screen->vt, &rows, &cols);\n\n    screen->buffers[1] = realloc_buffer(screen, NULL, rows, cols);\n  }\n}\n\nvoid vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user)\n{\n  screen->callbacks = callbacks;\n  screen->cbdata = user;\n}\n\nvoid *vterm_screen_get_cbdata(VTermScreen *screen)\n{\n  return screen->cbdata;\n}\n\nvoid vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user)\n{\n  vterm_state_set_unrecognised_fallbacks(screen->state, fallbacks, user);\n}\n\nvoid *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen)\n{\n  return vterm_state_get_unrecognised_fbdata(screen->state);\n}\n\nvoid vterm_screen_flush_damage(VTermScreen *screen)\n{\n  if(screen->pending_scrollrect.start_row != -1) {\n    vterm_scroll_rect(screen->pending_scrollrect, screen->pending_scroll_downward, screen->pending_scroll_rightward,\n        moverect_user, erase_user, screen);\n\n    screen->pending_scrollrect.start_row = -1;\n  }\n\n  if(screen->damaged.start_row != -1) {\n    if(screen->callbacks && screen->callbacks->damage)\n      (*screen->callbacks->damage)(screen->damaged, screen->cbdata);\n\n    screen->damaged.start_row = -1;\n  }\n}\n\nvoid vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size)\n{\n  vterm_screen_flush_damage(screen);\n  screen->damage_merge = size;\n}\n\nstatic int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b)\n{\n  if((attrs & VTERM_ATTR_BOLD_MASK)       && (a->pen.bold != b->pen.bold))\n    return 1;\n  if((attrs & VTERM_ATTR_UNDERLINE_MASK)  && (a->pen.underline != b->pen.underline))\n    return 1;\n  if((attrs & VTERM_ATTR_ITALIC_MASK)     && (a->pen.italic != b->pen.italic))\n    return 1;\n  if((attrs & VTERM_ATTR_BLINK_MASK)      && (a->pen.blink != b->pen.blink))\n    return 1;\n  if((attrs & VTERM_ATTR_REVERSE_MASK)    && (a->pen.reverse != b->pen.reverse))\n    return 1;\n  if((attrs & VTERM_ATTR_STRIKE_MASK)     && (a->pen.strike != b->pen.strike))\n    return 1;\n  if((attrs & VTERM_ATTR_FONT_MASK)       && (a->pen.font != b->pen.font))\n    return 1;\n  if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_equal(a->pen.fg, b->pen.fg))\n    return 1;\n  if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_equal(a->pen.bg, b->pen.bg))\n    return 1;\n\n  return 0;\n}\n\nint vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs)\n{\n  ScreenCell *target = getcell(screen, pos.row, pos.col);\n\n  // TODO: bounds check\n  extent->start_row = pos.row;\n  extent->end_row   = pos.row + 1;\n\n  if(extent->start_col < 0)\n    extent->start_col = 0;\n  if(extent->end_col < 0)\n    extent->end_col = screen->cols;\n\n  int col;\n\n  for(col = pos.col - 1; col >= extent->start_col; col--)\n    if(attrs_differ(attrs, target, getcell(screen, pos.row, col)))\n      break;\n  extent->start_col = col + 1;\n\n  for(col = pos.col + 1; col < extent->end_col; col++)\n    if(attrs_differ(attrs, target, getcell(screen, pos.row, col)))\n      break;\n  extent->end_col = col - 1;\n\n  return 1;\n}\n"
  },
  {
    "path": "system/fbterm/libvterm/state.c",
    "content": "#include \"vterm_internal.h\"\n\n#include <stdio.h>\n#include <string.h>\n\n#define strneq(a,b,n) (strncmp(a,b,n)==0)\n\n#if defined(DEBUG) && DEBUG > 1\n# define DEBUG_GLYPH_COMBINE\n#endif\n\n/* Some convenient wrappers to make callback functions easier */\n\nstatic void putglyph(VTermState *state, const uint32_t chars[], int width, VTermPos pos)\n{\n  VTermGlyphInfo info = {\n    .chars = chars,\n    .width = width,\n    .protected_cell = state->protected_cell,\n    .dwl = state->lineinfo[pos.row].doublewidth,\n    .dhl = state->lineinfo[pos.row].doubleheight,\n  };\n\n  if(state->callbacks && state->callbacks->putglyph)\n    if((*state->callbacks->putglyph)(&info, pos, state->cbdata))\n      return;\n\n  DEBUG_LOG(\"libvterm: Unhandled putglyph U+%04x at (%d,%d)\\n\", chars[0], pos.col, pos.row);\n}\n\nstatic void updatecursor(VTermState *state, VTermPos *oldpos, int cancel_phantom)\n{\n  if(state->pos.col == oldpos->col && state->pos.row == oldpos->row)\n    return;\n\n  if(cancel_phantom)\n    state->at_phantom = 0;\n\n  if(state->callbacks && state->callbacks->movecursor)\n    if((*state->callbacks->movecursor)(state->pos, *oldpos, state->mode.cursor_visible, state->cbdata))\n      return;\n}\n\nstatic void erase(VTermState *state, VTermRect rect, int selective)\n{\n  if(state->callbacks && state->callbacks->erase)\n    if((*state->callbacks->erase)(rect, selective, state->cbdata))\n      return;\n}\n\nstatic VTermState *vterm_state_new(VTerm *vt)\n{\n  VTermState *state = vterm_allocator_malloc(vt, sizeof(VTermState));\n\n  state->vt = vt;\n\n  state->rows = vt->rows;\n  state->cols = vt->cols;\n\n  state->mouse_col     = 0;\n  state->mouse_row     = 0;\n  state->mouse_buttons = 0;\n\n  state->mouse_protocol = MOUSE_X10;\n\n  state->callbacks = NULL;\n  state->cbdata    = NULL;\n\n  vterm_state_newpen(state);\n\n  state->bold_is_highbright = 0;\n\n  return state;\n}\n\nINTERNAL void vterm_state_free(VTermState *state)\n{\n  vterm_allocator_free(state->vt, state->tabstops);\n  vterm_allocator_free(state->vt, state->lineinfo);\n  vterm_allocator_free(state->vt, state->combine_chars);\n  vterm_allocator_free(state->vt, state);\n}\n\nstatic void scroll(VTermState *state, VTermRect rect, int downward, int rightward)\n{\n  if(!downward && !rightward)\n    return;\n\n  int rows = rect.end_row - rect.start_row;\n  if(downward > rows)\n    downward = rows;\n  else if(downward < -rows)\n    downward = -rows;\n\n  int cols = rect.end_col - rect.start_col;\n  if(rightward > cols)\n    rightward = cols;\n  else if(rightward < -cols)\n    rightward = -cols;\n\n  // Update lineinfo if full line\n  if(rect.start_col == 0 && rect.end_col == state->cols && rightward == 0) {\n    int height = rect.end_row - rect.start_row - abs(downward);\n\n    if(downward > 0)\n      memmove(state->lineinfo + rect.start_row,\n              state->lineinfo + rect.start_row + downward,\n              height * sizeof(state->lineinfo[0]));\n    else\n      memmove(state->lineinfo + rect.start_row - downward,\n              state->lineinfo + rect.start_row,\n              height * sizeof(state->lineinfo[0]));\n  }\n\n  if(state->callbacks && state->callbacks->scrollrect)\n    if((*state->callbacks->scrollrect)(rect, downward, rightward, state->cbdata))\n      return;\n\n  if(state->callbacks)\n    vterm_scroll_rect(rect, downward, rightward,\n        state->callbacks->moverect, state->callbacks->erase, state->cbdata);\n}\n\nstatic void linefeed(VTermState *state)\n{\n  if(state->pos.row == SCROLLREGION_BOTTOM(state) - 1) {\n    VTermRect rect = {\n      .start_row = state->scrollregion_top,\n      .end_row   = SCROLLREGION_BOTTOM(state),\n      .start_col = SCROLLREGION_LEFT(state),\n      .end_col   = SCROLLREGION_RIGHT(state),\n    };\n\n    scroll(state, rect, 1, 0);\n  }\n  else if(state->pos.row < state->rows-1)\n    state->pos.row++;\n}\n\nstatic void grow_combine_buffer(VTermState *state)\n{\n  size_t    new_size = state->combine_chars_size * 2;\n  uint32_t *new_chars = vterm_allocator_malloc(state->vt, new_size * sizeof(new_chars[0]));\n\n  memcpy(new_chars, state->combine_chars, state->combine_chars_size * sizeof(new_chars[0]));\n\n  vterm_allocator_free(state->vt, state->combine_chars);\n\n  state->combine_chars = new_chars;\n  state->combine_chars_size = new_size;\n}\n\nstatic void set_col_tabstop(VTermState *state, int col)\n{\n  unsigned char mask = 1 << (col & 7);\n  state->tabstops[col >> 3] |= mask;\n}\n\nstatic void clear_col_tabstop(VTermState *state, int col)\n{\n  unsigned char mask = 1 << (col & 7);\n  state->tabstops[col >> 3] &= ~mask;\n}\n\nstatic int is_col_tabstop(VTermState *state, int col)\n{\n  unsigned char mask = 1 << (col & 7);\n  return state->tabstops[col >> 3] & mask;\n}\n\nstatic int is_cursor_in_scrollregion(const VTermState *state)\n{\n  if(state->pos.row < state->scrollregion_top ||\n     state->pos.row >= SCROLLREGION_BOTTOM(state))\n    return 0;\n  if(state->pos.col < SCROLLREGION_LEFT(state) ||\n     state->pos.col >= SCROLLREGION_RIGHT(state))\n    return 0;\n\n  return 1;\n}\n\nstatic void tab(VTermState *state, int count, int direction)\n{\n  while(count > 0) {\n    if(direction > 0) {\n      if(state->pos.col >= THISROWWIDTH(state)-1)\n        return;\n\n      state->pos.col++;\n    }\n    else if(direction < 0) {\n      if(state->pos.col < 1)\n        return;\n\n      state->pos.col--;\n    }\n\n    if(is_col_tabstop(state, state->pos.col))\n      count--;\n  }\n}\n\n#define NO_FORCE 0\n#define FORCE    1\n\n#define DWL_OFF 0\n#define DWL_ON  1\n\n#define DHL_OFF    0\n#define DHL_TOP    1\n#define DHL_BOTTOM 2\n\nstatic void set_lineinfo(VTermState *state, int row, int force, int dwl, int dhl)\n{\n  VTermLineInfo info = state->lineinfo[row];\n\n  if(dwl == DWL_OFF)\n    info.doublewidth = DWL_OFF;\n  else if(dwl == DWL_ON)\n    info.doublewidth = DWL_ON;\n  // else -1 to ignore\n\n  if(dhl == DHL_OFF)\n    info.doubleheight = DHL_OFF;\n  else if(dhl == DHL_TOP)\n    info.doubleheight = DHL_TOP;\n  else if(dhl == DHL_BOTTOM)\n    info.doubleheight = DHL_BOTTOM;\n\n  if((state->callbacks &&\n      state->callbacks->setlineinfo &&\n      (*state->callbacks->setlineinfo)(row, &info, state->lineinfo + row, state->cbdata))\n      || force)\n    state->lineinfo[row] = info;\n}\n\nstatic int on_text(const char bytes[], size_t len, void *user)\n{\n  VTermState *state = user;\n\n  VTermPos oldpos = state->pos;\n\n  // We'll have at most len codepoints\n  uint32_t codepoints[len];\n  int npoints = 0;\n  size_t eaten = 0;\n\n  VTermEncodingInstance *encoding =\n    state->gsingle_set     ? &state->encoding[state->gsingle_set] :\n    !(bytes[eaten] & 0x80) ? &state->encoding[state->gl_set] :\n    state->vt->mode.utf8   ? &state->encoding_utf8 :\n                             &state->encoding[state->gr_set];\n\n  (*encoding->enc->decode)(encoding->enc, encoding->data,\n      codepoints, &npoints, state->gsingle_set ? 1 : len,\n      bytes, &eaten, len);\n\n  /* There's a chance an encoding (e.g. UTF-8) hasn't found enough bytes yet\n   * for even a single codepoint\n   */\n  if(!npoints)\n    return eaten;\n\n  if(state->gsingle_set && npoints)\n    state->gsingle_set = 0;\n\n  int i = 0;\n\n  /* This is a combining char. that needs to be merged with the previous\n   * glyph output */\n  if(vterm_unicode_is_combining(codepoints[i])) {\n    /* See if the cursor has moved since */\n    if(state->pos.row == state->combine_pos.row && state->pos.col == state->combine_pos.col + state->combine_width) {\n#ifdef DEBUG_GLYPH_COMBINE\n      int printpos;\n      printf(\"DEBUG: COMBINING SPLIT GLYPH of chars {\");\n      for(printpos = 0; state->combine_chars[printpos]; printpos++)\n        printf(\"U+%04x \", state->combine_chars[printpos]);\n      printf(\"} + {\");\n#endif\n\n      /* Find where we need to append these combining chars */\n      int saved_i = 0;\n      while(state->combine_chars[saved_i])\n        saved_i++;\n\n      /* Add extra ones */\n      while(i < npoints && vterm_unicode_is_combining(codepoints[i])) {\n        if(saved_i >= state->combine_chars_size)\n          grow_combine_buffer(state);\n        state->combine_chars[saved_i++] = codepoints[i++];\n      }\n      if(saved_i >= state->combine_chars_size)\n        grow_combine_buffer(state);\n      state->combine_chars[saved_i] = 0;\n\n#ifdef DEBUG_GLYPH_COMBINE\n      for(; state->combine_chars[printpos]; printpos++)\n        printf(\"U+%04x \", state->combine_chars[printpos]);\n      printf(\"}\\n\");\n#endif\n\n      /* Now render it */\n      putglyph(state, state->combine_chars, state->combine_width, state->combine_pos);\n    }\n    else {\n      DEBUG_LOG(\"libvterm: TODO: Skip over split char+combining\\n\");\n    }\n  }\n\n  for(; i < npoints; i++) {\n    // Try to find combining characters following this\n    int glyph_starts = i;\n    int glyph_ends;\n    for(glyph_ends = i + 1; glyph_ends < npoints; glyph_ends++)\n      if(!vterm_unicode_is_combining(codepoints[glyph_ends]))\n        break;\n\n    int width = 0;\n\n    uint32_t chars[glyph_ends - glyph_starts + 1];\n\n    for( ; i < glyph_ends; i++) {\n      chars[i - glyph_starts] = codepoints[i];\n      int this_width = vterm_unicode_width(codepoints[i]);\n#ifdef DEBUG\n      if(this_width < 0) {\n        fprintf(stderr, \"Text with negative-width codepoint U+%04x\\n\", codepoints[i]);\n        abort();\n      }\n#endif\n      width += this_width;\n    }\n\n    chars[glyph_ends - glyph_starts] = 0;\n    i--;\n\n#ifdef DEBUG_GLYPH_COMBINE\n    int printpos;\n    printf(\"DEBUG: COMBINED GLYPH of %d chars {\", glyph_ends - glyph_starts);\n    for(printpos = 0; printpos < glyph_ends - glyph_starts; printpos++)\n      printf(\"U+%04x \", chars[printpos]);\n    printf(\"}, onscreen width %d\\n\", width);\n#endif\n\n    if(state->at_phantom || state->pos.col + width > THISROWWIDTH(state)) {\n      linefeed(state);\n      state->pos.col = 0;\n      state->at_phantom = 0;\n    }\n\n    if(state->mode.insert) {\n      /* TODO: This will be a little inefficient for large bodies of text, as\n       * it'll have to 'ICH' effectively before every glyph. We should scan\n       * ahead and ICH as many times as required\n       */\n      VTermRect rect = {\n        .start_row = state->pos.row,\n        .end_row   = state->pos.row + 1,\n        .start_col = state->pos.col,\n        .end_col   = THISROWWIDTH(state),\n      };\n      scroll(state, rect, 0, -1);\n    }\n\n    putglyph(state, chars, width, state->pos);\n\n    if(i == npoints - 1) {\n      /* End of the buffer. Save the chars in case we have to combine with\n       * more on the next call */\n      int save_i;\n      for(save_i = 0; chars[save_i]; save_i++) {\n        if(save_i >= state->combine_chars_size)\n          grow_combine_buffer(state);\n        state->combine_chars[save_i] = chars[save_i];\n      }\n      if(save_i >= state->combine_chars_size)\n        grow_combine_buffer(state);\n      state->combine_chars[save_i] = 0;\n      state->combine_width = width;\n      state->combine_pos = state->pos;\n    }\n\n    if(state->pos.col + width >= THISROWWIDTH(state)) {\n      if(state->mode.autowrap)\n        state->at_phantom = 1;\n    }\n    else {\n      state->pos.col += width;\n    }\n  }\n\n  updatecursor(state, &oldpos, 0);\n\n#ifdef DEBUG\n  if(state->pos.row < 0 || state->pos.row >= state->rows ||\n     state->pos.col < 0 || state->pos.col >= state->cols) {\n    fprintf(stderr, \"Position out of bounds after text: (%d,%d)\\n\",\n        state->pos.row, state->pos.col);\n    abort();\n  }\n#endif\n\n  return eaten;\n}\n\nstatic int on_control(unsigned char control, void *user)\n{\n  VTermState *state = user;\n\n  VTermPos oldpos = state->pos;\n\n  switch(control) {\n  case 0x07: // BEL - ECMA-48 8.3.3\n    if(state->callbacks && state->callbacks->bell)\n      (*state->callbacks->bell)(state->cbdata);\n    break;\n\n  case 0x08: // BS - ECMA-48 8.3.5\n    if(state->pos.col > 0)\n      state->pos.col--;\n    break;\n\n  case 0x09: // HT - ECMA-48 8.3.60\n    tab(state, 1, +1);\n    break;\n\n  case 0x0a: // LF - ECMA-48 8.3.74\n  case 0x0b: // VT\n  case 0x0c: // FF\n    linefeed(state);\n    if(state->mode.newline)\n      state->pos.col = 0;\n    break;\n\n  case 0x0d: // CR - ECMA-48 8.3.15\n    state->pos.col = 0;\n    break;\n\n  case 0x0e: // LS1 - ECMA-48 8.3.76\n    state->gl_set = 1;\n    break;\n\n  case 0x0f: // LS0 - ECMA-48 8.3.75\n    state->gl_set = 0;\n    break;\n\n  case 0x84: // IND - DEPRECATED but implemented for completeness\n    linefeed(state);\n    break;\n\n  case 0x85: // NEL - ECMA-48 8.3.86\n    linefeed(state);\n    state->pos.col = 0;\n    break;\n\n  case 0x88: // HTS - ECMA-48 8.3.62\n    set_col_tabstop(state, state->pos.col);\n    break;\n\n  case 0x8d: // RI - ECMA-48 8.3.104\n    if(state->pos.row == state->scrollregion_top) {\n      VTermRect rect = {\n        .start_row = state->scrollregion_top,\n        .end_row   = SCROLLREGION_BOTTOM(state),\n        .start_col = SCROLLREGION_LEFT(state),\n        .end_col   = SCROLLREGION_RIGHT(state),\n      };\n\n      scroll(state, rect, -1, 0);\n    }\n    else if(state->pos.row > 0)\n        state->pos.row--;\n    break;\n\n  case 0x8e: // SS2 - ECMA-48 8.3.141\n    state->gsingle_set = 2;\n    break;\n\n  case 0x8f: // SS3 - ECMA-48 8.3.142\n    state->gsingle_set = 3;\n    break;\n\n  default:\n    if(state->fallbacks && state->fallbacks->control)\n      if((*state->fallbacks->control)(control, state->fbdata))\n        return 1;\n\n    return 0;\n  }\n\n  updatecursor(state, &oldpos, 1);\n\n#ifdef DEBUG\n  if(state->pos.row < 0 || state->pos.row >= state->rows ||\n     state->pos.col < 0 || state->pos.col >= state->cols) {\n    fprintf(stderr, \"Position out of bounds after Ctrl %02x: (%d,%d)\\n\",\n        control, state->pos.row, state->pos.col);\n    abort();\n  }\n#endif\n\n  return 1;\n}\n\nstatic int settermprop_bool(VTermState *state, VTermProp prop, int v)\n{\n  VTermValue val = { .boolean = v };\n  return vterm_state_set_termprop(state, prop, &val);\n}\n\nstatic int settermprop_int(VTermState *state, VTermProp prop, int v)\n{\n  VTermValue val = { .number = v };\n  return vterm_state_set_termprop(state, prop, &val);\n}\n\nstatic int settermprop_string(VTermState *state, VTermProp prop, const char *str, size_t len)\n{\n  char strvalue[len+1];\n  strncpy(strvalue, str, len);\n  strvalue[len] = 0;\n\n  VTermValue val = { .string = strvalue };\n  return vterm_state_set_termprop(state, prop, &val);\n}\n\nstatic void savecursor(VTermState *state, int save)\n{\n  if(save) {\n    state->saved.pos = state->pos;\n    state->saved.mode.cursor_visible = state->mode.cursor_visible;\n    state->saved.mode.cursor_blink   = state->mode.cursor_blink;\n    state->saved.mode.cursor_shape   = state->mode.cursor_shape;\n\n    vterm_state_savepen(state, 1);\n  }\n  else {\n    VTermPos oldpos = state->pos;\n\n    state->pos = state->saved.pos;\n\n    settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, state->saved.mode.cursor_visible);\n    settermprop_bool(state, VTERM_PROP_CURSORBLINK,   state->saved.mode.cursor_blink);\n    settermprop_int (state, VTERM_PROP_CURSORSHAPE,   state->saved.mode.cursor_shape);\n\n    vterm_state_savepen(state, 0);\n\n    updatecursor(state, &oldpos, 1);\n  }\n}\n\nstatic int on_escape(const char *bytes, size_t len, void *user)\n{\n  VTermState *state = user;\n\n  /* Easier to decode this from the first byte, even though the final\n   * byte terminates it\n   */\n  switch(bytes[0]) {\n  case ' ':\n    if(len != 2)\n      return 0;\n\n    switch(bytes[1]) {\n      case 'F': // S7C1T\n        state->vt->mode.ctrl8bit = 0;\n        break;\n\n      case 'G': // S8C1T\n        state->vt->mode.ctrl8bit = 1;\n        break;\n\n      default:\n        return 0;\n    }\n    return 2;\n\n  case '#':\n    if(len != 2)\n      return 0;\n\n    switch(bytes[1]) {\n      case '3': // DECDHL top\n        if(state->mode.leftrightmargin)\n          break;\n        set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_TOP);\n        break;\n\n      case '4': // DECDHL bottom\n        if(state->mode.leftrightmargin)\n          break;\n        set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_BOTTOM);\n        break;\n\n      case '5': // DECSWL\n        if(state->mode.leftrightmargin)\n          break;\n        set_lineinfo(state, state->pos.row, NO_FORCE, DWL_OFF, DHL_OFF);\n        break;\n\n      case '6': // DECDWL\n        if(state->mode.leftrightmargin)\n          break;\n        set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_OFF);\n        break;\n\n      case '8': // DECALN\n      {\n        VTermPos pos;\n        uint32_t E[] = { 'E', 0 };\n        for(pos.row = 0; pos.row < state->rows; pos.row++)\n          for(pos.col = 0; pos.col < ROWWIDTH(state, pos.row); pos.col++)\n            putglyph(state, E, 1, pos);\n        break;\n      }\n\n      default:\n        return 0;\n    }\n    return 2;\n\n  case '(': case ')': case '*': case '+': // SCS\n    if(len != 2)\n      return 0;\n\n    {\n      int setnum = bytes[0] - 0x28;\n      VTermEncoding *newenc = vterm_lookup_encoding(ENC_SINGLE_94, bytes[1]);\n\n      if(newenc) {\n        state->encoding[setnum].enc = newenc;\n\n        if(newenc->init)\n          (*newenc->init)(newenc, state->encoding[setnum].data);\n      }\n    }\n\n    return 2;\n\n  case '7': // DECSC\n    savecursor(state, 1);\n    return 1;\n\n  case '8': // DECRC\n    savecursor(state, 0);\n    return 1;\n\n  case '<': // Ignored by VT100. Used in VT52 mode to switch up to VT100\n    return 1;\n\n  case '=': // DECKPAM\n    state->mode.keypad = 1;\n    return 1;\n\n  case '>': // DECKPNM\n    state->mode.keypad = 0;\n    return 1;\n\n  case 'c': // RIS - ECMA-48 8.3.105\n  {\n    VTermPos oldpos = state->pos;\n    vterm_state_reset(state, 1);\n    if(state->callbacks && state->callbacks->movecursor)\n      (*state->callbacks->movecursor)(state->pos, oldpos, state->mode.cursor_visible, state->cbdata);\n    return 1;\n  }\n\n  case 'n': // LS2 - ECMA-48 8.3.78\n    state->gl_set = 2;\n    return 1;\n\n  case 'o': // LS3 - ECMA-48 8.3.80\n    state->gl_set = 3;\n    return 1;\n\n  case '~': // LS1R - ECMA-48 8.3.77\n    state->gr_set = 1;\n    return 1;\n\n  case '}': // LS2R - ECMA-48 8.3.79\n    state->gr_set = 2;\n    return 1;\n\n  case '|': // LS3R - ECMA-48 8.3.81\n    state->gr_set = 3;\n    return 1;\n\n  default:\n    return 0;\n  }\n}\n\nstatic void set_mode(VTermState *state, int num, int val)\n{\n  switch(num) {\n  case 4: // IRM - ECMA-48 7.2.10\n    state->mode.insert = val;\n    break;\n\n  case 20: // LNM - ANSI X3.4-1977\n    state->mode.newline = val;\n    break;\n\n  default:\n    DEBUG_LOG(\"libvterm: Unknown mode %d\\n\", num);\n    return;\n  }\n}\n\nstatic void set_dec_mode(VTermState *state, int num, int val)\n{\n  switch(num) {\n  case 1:\n    state->mode.cursor = val;\n    break;\n\n  case 5: // DECSCNM - screen mode\n    settermprop_bool(state, VTERM_PROP_REVERSE, val);\n    break;\n\n  case 6: // DECOM - origin mode\n    {\n      VTermPos oldpos = state->pos;\n      state->mode.origin = val;\n      state->pos.row = state->mode.origin ? state->scrollregion_top : 0;\n      state->pos.col = state->mode.origin ? SCROLLREGION_LEFT(state) : 0;\n      updatecursor(state, &oldpos, 1);\n    }\n    break;\n\n  case 7:\n    state->mode.autowrap = val;\n    break;\n\n  case 12:\n    settermprop_bool(state, VTERM_PROP_CURSORBLINK, val);\n    break;\n\n  case 25:\n    settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, val);\n    break;\n\n  case 69: // DECVSSM - vertical split screen mode\n           // DECLRMM - left/right margin mode\n    state->mode.leftrightmargin = val;\n    if(val) {\n      // Setting DECVSSM must clear doublewidth/doubleheight state of every line\n      for(int row = 0; row < state->rows; row++)\n        set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);\n    }\n\n    break;\n\n  case 1000:\n  case 1002:\n  case 1003:\n    settermprop_int(state, VTERM_PROP_MOUSE,\n        !val          ? VTERM_PROP_MOUSE_NONE  :\n        (num == 1000) ? VTERM_PROP_MOUSE_CLICK :\n        (num == 1002) ? VTERM_PROP_MOUSE_DRAG  :\n                        VTERM_PROP_MOUSE_MOVE);\n    break;\n\n  case 1004:\n    state->mode.report_focus = val;\n    break;\n\n  case 1005:\n    state->mouse_protocol = val ? MOUSE_UTF8 : MOUSE_X10;\n    break;\n\n  case 1006:\n    state->mouse_protocol = val ? MOUSE_SGR : MOUSE_X10;\n    break;\n\n  case 1015:\n    state->mouse_protocol = val ? MOUSE_RXVT : MOUSE_X10;\n    break;\n\n  case 1047:\n    settermprop_bool(state, VTERM_PROP_ALTSCREEN, val);\n    break;\n\n  case 1048:\n    savecursor(state, val);\n    break;\n\n  case 1049:\n    settermprop_bool(state, VTERM_PROP_ALTSCREEN, val);\n    savecursor(state, val);\n    break;\n\n  case 2004:\n    state->mode.bracketpaste = val;\n    break;\n\n  default:\n    DEBUG_LOG(\"libvterm: Unknown DEC mode %d\\n\", num);\n    return;\n  }\n}\n\nstatic void request_dec_mode(VTermState *state, int num)\n{\n  int reply;\n\n  switch(num) {\n    case 1:\n      reply = state->mode.cursor;\n      break;\n\n    case 5:\n      reply = state->mode.screen;\n      break;\n\n    case 6:\n      reply = state->mode.origin;\n      break;\n\n    case 7:\n      reply = state->mode.autowrap;\n      break;\n\n    case 12:\n      reply = state->mode.cursor_blink;\n      break;\n\n    case 25:\n      reply = state->mode.cursor_visible;\n      break;\n\n    case 69:\n      reply = state->mode.leftrightmargin;\n      break;\n\n    case 1000:\n      reply = state->mouse_flags == MOUSE_WANT_CLICK;\n      break;\n\n    case 1002:\n      reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_DRAG);\n      break;\n\n    case 1003:\n      reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_MOVE);\n      break;\n\n    case 1004:\n      reply = state->mode.report_focus;\n      break;\n\n    case 1005:\n      reply = state->mouse_protocol == MOUSE_UTF8;\n      break;\n\n    case 1006:\n      reply = state->mouse_protocol == MOUSE_SGR;\n      break;\n\n    case 1015:\n      reply = state->mouse_protocol == MOUSE_RXVT;\n      break;\n\n    case 1047:\n      reply = state->mode.alt_screen;\n      break;\n\n    case 2004:\n      reply = state->mode.bracketpaste;\n      break;\n\n    default:\n      vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, \"?%d;%d$y\", num, 0);\n      return;\n  }\n\n  vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, \"?%d;%d$y\", num, reply ? 1 : 2);\n}\n\nstatic int on_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user)\n{\n  VTermState *state = user;\n  int leader_byte = 0;\n  int intermed_byte = 0;\n\n  if(leader && leader[0]) {\n    if(leader[1]) // longer than 1 char\n      return 0;\n\n    switch(leader[0]) {\n    case '?':\n    case '>':\n      leader_byte = leader[0];\n      break;\n    default:\n      return 0;\n    }\n  }\n\n  if(intermed && intermed[0]) {\n    if(intermed[1]) // longer than 1 char\n      return 0;\n\n    switch(intermed[0]) {\n    case ' ':\n    case '\"':\n    case '$':\n    case '\\'':\n      intermed_byte = intermed[0];\n      break;\n    default:\n      return 0;\n    }\n  }\n\n  VTermPos oldpos = state->pos;\n\n  // Some temporaries for later code\n  int count, val;\n  int row, col;\n  VTermRect rect;\n  int selective;\n\n#define LBOUND(v,min) if((v) < (min)) (v) = (min)\n#define UBOUND(v,max) if((v) > (max)) (v) = (max)\n\n#define LEADER(l,b) ((l << 8) | b)\n#define INTERMED(i,b) ((i << 16) | b)\n\n  switch(intermed_byte << 16 | leader_byte << 8 | command) {\n  case 0x40: // ICH - ECMA-48 8.3.64\n    count = CSI_ARG_COUNT(args[0]);\n\n    if(!is_cursor_in_scrollregion(state))\n      break;\n\n    rect.start_row = state->pos.row;\n    rect.end_row   = state->pos.row + 1;\n    rect.start_col = state->pos.col;\n    if(state->mode.leftrightmargin)\n      rect.end_col = SCROLLREGION_RIGHT(state);\n    else\n      rect.end_col = THISROWWIDTH(state);\n\n    scroll(state, rect, 0, -count);\n\n    break;\n\n  case 0x41: // CUU - ECMA-48 8.3.22\n    count = CSI_ARG_COUNT(args[0]);\n    state->pos.row -= count;\n    state->at_phantom = 0;\n    break;\n\n  case 0x42: // CUD - ECMA-48 8.3.19\n    count = CSI_ARG_COUNT(args[0]);\n    state->pos.row += count;\n    state->at_phantom = 0;\n    break;\n\n  case 0x43: // CUF - ECMA-48 8.3.20\n    count = CSI_ARG_COUNT(args[0]);\n    state->pos.col += count;\n    state->at_phantom = 0;\n    break;\n\n  case 0x44: // CUB - ECMA-48 8.3.18\n    count = CSI_ARG_COUNT(args[0]);\n    state->pos.col -= count;\n    state->at_phantom = 0;\n    break;\n\n  case 0x45: // CNL - ECMA-48 8.3.12\n    count = CSI_ARG_COUNT(args[0]);\n    state->pos.col = 0;\n    state->pos.row += count;\n    state->at_phantom = 0;\n    break;\n\n  case 0x46: // CPL - ECMA-48 8.3.13\n    count = CSI_ARG_COUNT(args[0]);\n    state->pos.col = 0;\n    state->pos.row -= count;\n    state->at_phantom = 0;\n    break;\n\n  case 0x47: // CHA - ECMA-48 8.3.9\n    val = CSI_ARG_OR(args[0], 1);\n    state->pos.col = val-1;\n    state->at_phantom = 0;\n    break;\n\n  case 0x48: // CUP - ECMA-48 8.3.21\n    row = CSI_ARG_OR(args[0], 1);\n    col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]);\n    // zero-based\n    state->pos.row = row-1;\n    state->pos.col = col-1;\n    if(state->mode.origin) {\n      state->pos.row += state->scrollregion_top;\n      state->pos.col += SCROLLREGION_LEFT(state);\n    }\n    state->at_phantom = 0;\n    break;\n\n  case 0x49: // CHT - ECMA-48 8.3.10\n    count = CSI_ARG_COUNT(args[0]);\n    tab(state, count, +1);\n    break;\n\n  case 0x4a: // ED - ECMA-48 8.3.39\n  case LEADER('?', 0x4a): // DECSED - Selective Erase in Display\n    selective = (leader_byte == '?');\n    switch(CSI_ARG(args[0])) {\n    case CSI_ARG_MISSING:\n    case 0:\n      rect.start_row = state->pos.row; rect.end_row = state->pos.row + 1;\n      rect.start_col = state->pos.col; rect.end_col = state->cols;\n      if(rect.end_col > rect.start_col)\n        erase(state, rect, selective);\n\n      rect.start_row = state->pos.row + 1; rect.end_row = state->rows;\n      rect.start_col = 0;\n      for(int row = rect.start_row; row < rect.end_row; row++)\n        set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);\n      if(rect.end_row > rect.start_row)\n        erase(state, rect, selective);\n      break;\n\n    case 1:\n      rect.start_row = 0; rect.end_row = state->pos.row;\n      rect.start_col = 0; rect.end_col = state->cols;\n      for(int row = rect.start_row; row < rect.end_row; row++)\n        set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);\n      if(rect.end_col > rect.start_col)\n        erase(state, rect, selective);\n\n      rect.start_row = state->pos.row; rect.end_row = state->pos.row + 1;\n                          rect.end_col = state->pos.col + 1;\n      if(rect.end_row > rect.start_row)\n        erase(state, rect, selective);\n      break;\n\n    case 2:\n      rect.start_row = 0; rect.end_row = state->rows;\n      rect.start_col = 0; rect.end_col = state->cols;\n      for(int row = rect.start_row; row < rect.end_row; row++)\n        set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);\n      erase(state, rect, selective);\n      break;\n    }\n    break;\n\n  case 0x4b: // EL - ECMA-48 8.3.41\n  case LEADER('?', 0x4b): // DECSEL - Selective Erase in Line\n    selective = (leader_byte == '?');\n    rect.start_row = state->pos.row;\n    rect.end_row   = state->pos.row + 1;\n\n    switch(CSI_ARG(args[0])) {\n    case CSI_ARG_MISSING:\n    case 0:\n      rect.start_col = state->pos.col; rect.end_col = THISROWWIDTH(state); break;\n    case 1:\n      rect.start_col = 0; rect.end_col = state->pos.col + 1; break;\n    case 2:\n      rect.start_col = 0; rect.end_col = THISROWWIDTH(state); break;\n    default:\n      return 0;\n    }\n\n    if(rect.end_col > rect.start_col)\n      erase(state, rect, selective);\n\n    break;\n\n  case 0x4c: // IL - ECMA-48 8.3.67\n    count = CSI_ARG_COUNT(args[0]);\n\n    if(!is_cursor_in_scrollregion(state))\n      break;\n\n    rect.start_row = state->pos.row;\n    rect.end_row   = SCROLLREGION_BOTTOM(state);\n    rect.start_col = SCROLLREGION_LEFT(state);\n    rect.end_col   = SCROLLREGION_RIGHT(state);\n\n    scroll(state, rect, -count, 0);\n\n    break;\n\n  case 0x4d: // DL - ECMA-48 8.3.32\n    count = CSI_ARG_COUNT(args[0]);\n\n    if(!is_cursor_in_scrollregion(state))\n      break;\n\n    rect.start_row = state->pos.row;\n    rect.end_row   = SCROLLREGION_BOTTOM(state);\n    rect.start_col = SCROLLREGION_LEFT(state);\n    rect.end_col   = SCROLLREGION_RIGHT(state);\n\n    scroll(state, rect, count, 0);\n\n    break;\n\n  case 0x50: // DCH - ECMA-48 8.3.26\n    count = CSI_ARG_COUNT(args[0]);\n\n    if(!is_cursor_in_scrollregion(state))\n      break;\n\n    rect.start_row = state->pos.row;\n    rect.end_row   = state->pos.row + 1;\n    rect.start_col = state->pos.col;\n    if(state->mode.leftrightmargin)\n      rect.end_col = SCROLLREGION_RIGHT(state);\n    else\n      rect.end_col = THISROWWIDTH(state);\n\n    scroll(state, rect, 0, count);\n\n    break;\n\n  case 0x53: // SU - ECMA-48 8.3.147\n    count = CSI_ARG_COUNT(args[0]);\n\n    rect.start_row = state->scrollregion_top;\n    rect.end_row   = SCROLLREGION_BOTTOM(state);\n    rect.start_col = SCROLLREGION_LEFT(state);\n    rect.end_col   = SCROLLREGION_RIGHT(state);\n\n    scroll(state, rect, count, 0);\n\n    break;\n\n  case 0x54: // SD - ECMA-48 8.3.113\n    count = CSI_ARG_COUNT(args[0]);\n\n    rect.start_row = state->scrollregion_top;\n    rect.end_row   = SCROLLREGION_BOTTOM(state);\n    rect.start_col = SCROLLREGION_LEFT(state);\n    rect.end_col   = SCROLLREGION_RIGHT(state);\n\n    scroll(state, rect, -count, 0);\n\n    break;\n\n  case 0x58: // ECH - ECMA-48 8.3.38\n    count = CSI_ARG_COUNT(args[0]);\n\n    rect.start_row = state->pos.row;\n    rect.end_row   = state->pos.row + 1;\n    rect.start_col = state->pos.col;\n    rect.end_col   = state->pos.col + count;\n    UBOUND(rect.end_col, THISROWWIDTH(state));\n\n    erase(state, rect, 0);\n    break;\n\n  case 0x5a: // CBT - ECMA-48 8.3.7\n    count = CSI_ARG_COUNT(args[0]);\n    tab(state, count, -1);\n    break;\n\n  case 0x60: // HPA - ECMA-48 8.3.57\n    col = CSI_ARG_OR(args[0], 1);\n    state->pos.col = col-1;\n    state->at_phantom = 0;\n    break;\n\n  case 0x61: // HPR - ECMA-48 8.3.59\n    count = CSI_ARG_COUNT(args[0]);\n    state->pos.col += count;\n    state->at_phantom = 0;\n    break;\n\n  case 0x63: // DA - ECMA-48 8.3.24\n    val = CSI_ARG_OR(args[0], 0);\n    if(val == 0)\n      // DEC VT100 response\n      vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, \"?1;2c\");\n    break;\n\n  case LEADER('>', 0x63): // DEC secondary Device Attributes\n    vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, \">%d;%d;%dc\", 0, 100, 0);\n    break;\n\n  case 0x64: // VPA - ECMA-48 8.3.158\n    row = CSI_ARG_OR(args[0], 1);\n    state->pos.row = row-1;\n    if(state->mode.origin)\n      state->pos.row += state->scrollregion_top;\n    state->at_phantom = 0;\n    break;\n\n  case 0x65: // VPR - ECMA-48 8.3.160\n    count = CSI_ARG_COUNT(args[0]);\n    state->pos.row += count;\n    state->at_phantom = 0;\n    break;\n\n  case 0x66: // HVP - ECMA-48 8.3.63\n    row = CSI_ARG_OR(args[0], 1);\n    col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]);\n    // zero-based\n    state->pos.row = row-1;\n    state->pos.col = col-1;\n    if(state->mode.origin) {\n      state->pos.row += state->scrollregion_top;\n      state->pos.col += SCROLLREGION_LEFT(state);\n    }\n    state->at_phantom = 0;\n    break;\n\n  case 0x67: // TBC - ECMA-48 8.3.154\n    val = CSI_ARG_OR(args[0], 0);\n\n    switch(val) {\n    case 0:\n      clear_col_tabstop(state, state->pos.col);\n      break;\n    case 3:\n    case 5:\n      for(col = 0; col < state->cols; col++)\n        clear_col_tabstop(state, col);\n      break;\n    case 1:\n    case 2:\n    case 4:\n      break;\n    /* TODO: 1, 2 and 4 aren't meaningful yet without line tab stops */\n    default:\n      return 0;\n    }\n    break;\n\n  case 0x68: // SM - ECMA-48 8.3.125\n    if(!CSI_ARG_IS_MISSING(args[0]))\n      set_mode(state, CSI_ARG(args[0]), 1);\n    break;\n\n  case LEADER('?', 0x68): // DEC private mode set\n    if(!CSI_ARG_IS_MISSING(args[0]))\n      set_dec_mode(state, CSI_ARG(args[0]), 1);\n    break;\n\n  case 0x6a: // HPB - ECMA-48 8.3.58\n    count = CSI_ARG_COUNT(args[0]);\n    state->pos.col -= count;\n    state->at_phantom = 0;\n    break;\n\n  case 0x6b: // VPB - ECMA-48 8.3.159\n    count = CSI_ARG_COUNT(args[0]);\n    state->pos.row -= count;\n    state->at_phantom = 0;\n    break;\n\n  case 0x6c: // RM - ECMA-48 8.3.106\n    if(!CSI_ARG_IS_MISSING(args[0]))\n      set_mode(state, CSI_ARG(args[0]), 0);\n    break;\n\n  case LEADER('?', 0x6c): // DEC private mode reset\n    if(!CSI_ARG_IS_MISSING(args[0]))\n      set_dec_mode(state, CSI_ARG(args[0]), 0);\n    break;\n\n  case 0x6d: // SGR - ECMA-48 8.3.117\n    vterm_state_setpen(state, args, argcount);\n    break;\n\n  case 0x6e: // DSR - ECMA-48 8.3.35\n  case LEADER('?', 0x6e): // DECDSR\n    val = CSI_ARG_OR(args[0], 0);\n\n    {\n      char *qmark = (leader_byte == '?') ? \"?\" : \"\";\n\n      switch(val) {\n      case 0: case 1: case 2: case 3: case 4:\n        // ignore - these are replies\n        break;\n      case 5:\n        vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, \"%s0n\", qmark);\n        break;\n      case 6: // CPR - cursor position report\n        vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, \"%s%d;%dR\", qmark, state->pos.row + 1, state->pos.col + 1);\n        break;\n      }\n    }\n    break;\n\n\n  case LEADER('!', 0x70): // DECSTR - DEC soft terminal reset\n    vterm_state_reset(state, 0);\n    break;\n\n  case LEADER('?', INTERMED('$', 0x70)):\n    request_dec_mode(state, CSI_ARG(args[0]));\n    break;\n\n  case INTERMED(' ', 0x71): // DECSCUSR - DEC set cursor shape\n    val = CSI_ARG_OR(args[0], 1);\n\n    switch(val) {\n    case 0: case 1:\n      settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1);\n      settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK);\n      break;\n    case 2:\n      settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0);\n      settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BLOCK);\n      break;\n    case 3:\n      settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1);\n      settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_UNDERLINE);\n      break;\n    case 4:\n      settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0);\n      settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_UNDERLINE);\n      break;\n    case 5:\n      settermprop_bool(state, VTERM_PROP_CURSORBLINK, 1);\n      settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BAR_LEFT);\n      break;\n    case 6:\n      settermprop_bool(state, VTERM_PROP_CURSORBLINK, 0);\n      settermprop_int (state, VTERM_PROP_CURSORSHAPE, VTERM_PROP_CURSORSHAPE_BAR_LEFT);\n      break;\n    }\n\n    break;\n\n  case INTERMED('\"', 0x71): // DECSCA - DEC select character protection attribute\n    val = CSI_ARG_OR(args[0], 0);\n\n    switch(val) {\n    case 0: case 2:\n      state->protected_cell = 0;\n      break;\n    case 1:\n      state->protected_cell = 1;\n      break;\n    }\n\n    break;\n\n  case 0x72: // DECSTBM - DEC custom\n    state->scrollregion_top = CSI_ARG_OR(args[0], 1) - 1;\n    state->scrollregion_bottom = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]);\n    LBOUND(state->scrollregion_top, 0);\n    UBOUND(state->scrollregion_top, state->rows);\n    LBOUND(state->scrollregion_bottom, -1);\n    if(state->scrollregion_top == 0 && state->scrollregion_bottom == state->rows)\n      state->scrollregion_bottom = -1;\n    else\n      UBOUND(state->scrollregion_bottom, state->rows);\n\n    if(SCROLLREGION_BOTTOM(state) <= state->scrollregion_top) {\n      // Invalid\n      state->scrollregion_top    = 0;\n      state->scrollregion_bottom = -1;\n    }\n\n    break;\n\n  case 0x73: // DECSLRM - DEC custom\n    // Always allow setting these margins, just they won't take effect without DECVSSM\n    state->scrollregion_left = CSI_ARG_OR(args[0], 1) - 1;\n    state->scrollregion_right = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]);\n    LBOUND(state->scrollregion_left, 0);\n    UBOUND(state->scrollregion_left, state->cols);\n    LBOUND(state->scrollregion_right, -1);\n    if(state->scrollregion_left == 0 && state->scrollregion_right == state->cols)\n      state->scrollregion_right = -1;\n    else\n      UBOUND(state->scrollregion_right, state->cols);\n\n    if(state->scrollregion_right > -1 &&\n       state->scrollregion_right <= state->scrollregion_left) {\n      // Invalid\n      state->scrollregion_left  = 0;\n      state->scrollregion_right = -1;\n    }\n\n    break;\n\n  case INTERMED('\\'', 0x7D): // DECIC\n    count = CSI_ARG_COUNT(args[0]);\n\n    if(!is_cursor_in_scrollregion(state))\n      break;\n\n    rect.start_row = state->scrollregion_top;\n    rect.end_row   = SCROLLREGION_BOTTOM(state);\n    rect.start_col = state->pos.col;\n    rect.end_col   = SCROLLREGION_RIGHT(state);\n\n    scroll(state, rect, 0, -count);\n\n    break;\n\n  case INTERMED('\\'', 0x7E): // DECDC\n    count = CSI_ARG_COUNT(args[0]);\n\n    if(!is_cursor_in_scrollregion(state))\n      break;\n\n    rect.start_row = state->scrollregion_top;\n    rect.end_row   = SCROLLREGION_BOTTOM(state);\n    rect.start_col = state->pos.col;\n    rect.end_col   = SCROLLREGION_RIGHT(state);\n\n    scroll(state, rect, 0, count);\n\n    break;\n\n  default:\n    if(state->fallbacks && state->fallbacks->csi)\n      if((*state->fallbacks->csi)(leader, args, argcount, intermed, command, state->fbdata))\n        return 1;\n\n    return 0;\n  }\n\n  if(state->mode.origin) {\n    LBOUND(state->pos.row, state->scrollregion_top);\n    UBOUND(state->pos.row, SCROLLREGION_BOTTOM(state)-1);\n    LBOUND(state->pos.col, SCROLLREGION_LEFT(state));\n    UBOUND(state->pos.col, SCROLLREGION_RIGHT(state)-1);\n  }\n  else {\n    LBOUND(state->pos.row, 0);\n    UBOUND(state->pos.row, state->rows-1);\n    LBOUND(state->pos.col, 0);\n    UBOUND(state->pos.col, THISROWWIDTH(state)-1);\n  }\n\n  updatecursor(state, &oldpos, 1);\n\n#ifdef DEBUG\n  if(state->pos.row < 0 || state->pos.row >= state->rows ||\n     state->pos.col < 0 || state->pos.col >= state->cols) {\n    fprintf(stderr, \"Position out of bounds after CSI %c: (%d,%d)\\n\",\n        command, state->pos.row, state->pos.col);\n    abort();\n  }\n\n  if(SCROLLREGION_BOTTOM(state) <= state->scrollregion_top) {\n    fprintf(stderr, \"Scroll region height out of bounds after CSI %c: %d <= %d\\n\",\n        command, SCROLLREGION_BOTTOM(state), state->scrollregion_top);\n    abort();\n  }\n\n  if(SCROLLREGION_RIGHT(state) <= SCROLLREGION_LEFT(state)) {\n    fprintf(stderr, \"Scroll region width out of bounds after CSI %c: %d <= %d\\n\",\n        command, SCROLLREGION_RIGHT(state), SCROLLREGION_LEFT(state));\n    abort();\n  }\n#endif\n\n  return 1;\n}\n\nstatic int on_osc(const char *command, size_t cmdlen, void *user)\n{\n  VTermState *state = user;\n\n  if(cmdlen < 2)\n    return 0;\n\n  if(strneq(command, \"0;\", 2)) {\n    settermprop_string(state, VTERM_PROP_ICONNAME, command + 2, cmdlen - 2);\n    settermprop_string(state, VTERM_PROP_TITLE, command + 2, cmdlen - 2);\n    return 1;\n  }\n  else if(strneq(command, \"1;\", 2)) {\n    settermprop_string(state, VTERM_PROP_ICONNAME, command + 2, cmdlen - 2);\n    return 1;\n  }\n  else if(strneq(command, \"2;\", 2)) {\n    settermprop_string(state, VTERM_PROP_TITLE, command + 2, cmdlen - 2);\n    return 1;\n  }\n  else if(state->fallbacks && state->fallbacks->osc)\n    if((*state->fallbacks->osc)(command, cmdlen, state->fbdata))\n      return 1;\n\n  return 0;\n}\n\nstatic void request_status_string(VTermState *state, const char *command, size_t cmdlen)\n{\n  if(cmdlen == 1)\n    switch(command[0]) {\n      case 'm': // Query SGR\n        {\n          long args[20];\n          int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0]));\n          vterm_push_output_sprintf_ctrl(state->vt, C1_DCS, \"1$r\");\n          for(int argi = 0; argi < argc; argi++)\n            vterm_push_output_sprintf(state->vt,\n                argi == argc - 1             ? \"%d\" :\n                CSI_ARG_HAS_MORE(args[argi]) ? \"%d:\" :\n                                               \"%d;\",\n                CSI_ARG(args[argi]));\n          vterm_push_output_sprintf(state->vt, \"m\");\n          vterm_push_output_sprintf_ctrl(state->vt, C1_ST, \"\");\n        }\n        return;\n      case 'r': // Query DECSTBM\n        vterm_push_output_sprintf_dcs(state->vt, \"1$r%d;%dr\", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state));\n        return;\n      case 's': // Query DECSLRM\n        vterm_push_output_sprintf_dcs(state->vt, \"1$r%d;%ds\", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state));\n        return;\n    }\n\n  if(cmdlen == 2) {\n    if(strneq(command, \" q\", 2)) {\n      int reply = 0;\n      switch(state->mode.cursor_shape) {\n        case VTERM_PROP_CURSORSHAPE_BLOCK:     reply = 2; break;\n        case VTERM_PROP_CURSORSHAPE_UNDERLINE: reply = 4; break;\n        case VTERM_PROP_CURSORSHAPE_BAR_LEFT:  reply = 6; break;\n      }\n      if(state->mode.cursor_blink)\n        reply--;\n      vterm_push_output_sprintf_dcs(state->vt, \"1$r%d q\", reply);\n      return;\n    }\n    else if(strneq(command, \"\\\"q\", 2)) {\n      vterm_push_output_sprintf_dcs(state->vt, \"1$r%d\\\"q\", state->protected_cell ? 1 : 2);\n      return;\n    }\n  }\n\n  vterm_push_output_sprintf_dcs(state->vt, \"0$r%.s\", (int)cmdlen, command);\n}\n\nstatic int on_dcs(const char *command, size_t cmdlen, void *user)\n{\n  VTermState *state = user;\n\n  if(cmdlen >= 2 && strneq(command, \"$q\", 2)) {\n    request_status_string(state, command+2, cmdlen-2);\n    return 1;\n  }\n  else if(state->fallbacks && state->fallbacks->dcs)\n    if((*state->fallbacks->dcs)(command, cmdlen, state->fbdata))\n      return 1;\n\n  return 0;\n}\n\nstatic int on_resize(int rows, int cols, void *user)\n{\n  VTermState *state = user;\n  VTermPos oldpos = state->pos;\n\n  if(cols != state->cols) {\n    unsigned char *newtabstops = vterm_allocator_malloc(state->vt, (cols + 7) / 8);\n\n    /* TODO: This can all be done much more efficiently bytewise */\n    int col;\n    for(col = 0; col < state->cols && col < cols; col++) {\n      unsigned char mask = 1 << (col & 7);\n      if(state->tabstops[col >> 3] & mask)\n        newtabstops[col >> 3] |= mask;\n      else\n        newtabstops[col >> 3] &= ~mask;\n      }\n\n    for( ; col < cols; col++) {\n      unsigned char mask = 1 << (col & 7);\n      if(col % 8 == 0)\n        newtabstops[col >> 3] |= mask;\n      else\n        newtabstops[col >> 3] &= ~mask;\n    }\n\n    vterm_allocator_free(state->vt, state->tabstops);\n    state->tabstops = newtabstops;\n  }\n\n  if(rows != state->rows) {\n    VTermLineInfo *newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo));\n\n    int row;\n    for(row = 0; row < state->rows && row < rows; row++) {\n      newlineinfo[row] = state->lineinfo[row];\n    }\n\n    for( ; row < rows; row++) {\n      newlineinfo[row] = (VTermLineInfo){\n        .doublewidth = 0,\n      };\n    }\n\n    vterm_allocator_free(state->vt, state->lineinfo);\n    state->lineinfo = newlineinfo;\n  }\n\n  state->rows = rows;\n  state->cols = cols;\n\n  if(state->scrollregion_bottom > -1)\n    UBOUND(state->scrollregion_bottom, state->rows);\n  if(state->scrollregion_right > -1)\n    UBOUND(state->scrollregion_right, state->cols);\n\n  VTermPos delta = { 0, 0 };\n\n  if(state->callbacks && state->callbacks->resize)\n    (*state->callbacks->resize)(rows, cols, &delta, state->cbdata);\n\n  if(state->at_phantom && state->pos.col < cols-1) {\n    state->at_phantom = 0;\n    state->pos.col++;\n  }\n\n  state->pos.row += delta.row;\n  state->pos.col += delta.col;\n\n  if(state->pos.row >= rows)\n    state->pos.row = rows - 1;\n  if(state->pos.col >= cols)\n    state->pos.col = cols - 1;\n\n  updatecursor(state, &oldpos, 1);\n\n  return 1;\n}\n\nstatic const VTermParserCallbacks parser_callbacks = {\n  .text    = on_text,\n  .control = on_control,\n  .escape  = on_escape,\n  .csi     = on_csi,\n  .osc     = on_osc,\n  .dcs     = on_dcs,\n  .resize  = on_resize,\n};\n\nVTermState *vterm_obtain_state(VTerm *vt)\n{\n  if(vt->state)\n    return vt->state;\n\n  VTermState *state = vterm_state_new(vt);\n  vt->state = state;\n\n  state->combine_chars_size = 16;\n  state->combine_chars = vterm_allocator_malloc(state->vt, state->combine_chars_size * sizeof(state->combine_chars[0]));\n\n  state->tabstops = vterm_allocator_malloc(state->vt, (state->cols + 7) / 8);\n\n  state->lineinfo = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo));\n\n  state->encoding_utf8.enc = vterm_lookup_encoding(ENC_UTF8, 'u');\n  if(*state->encoding_utf8.enc->init)\n    (*state->encoding_utf8.enc->init)(state->encoding_utf8.enc, state->encoding_utf8.data);\n\n  vterm_parser_set_callbacks(vt, &parser_callbacks, state);\n\n  return state;\n}\n\nvoid vterm_state_reset(VTermState *state, int hard)\n{\n  state->scrollregion_top = 0;\n  state->scrollregion_bottom = -1;\n  state->scrollregion_left = 0;\n  state->scrollregion_right = -1;\n\n  state->mode.keypad          = 0;\n  state->mode.cursor          = 0;\n  state->mode.autowrap        = 1;\n  state->mode.insert          = 0;\n  state->mode.newline         = 0;\n  state->mode.alt_screen      = 0;\n  state->mode.origin          = 0;\n  state->mode.leftrightmargin = 0;\n  state->mode.bracketpaste    = 0;\n  state->mode.report_focus    = 0;\n\n  state->vt->mode.ctrl8bit   = 0;\n\n  for(int col = 0; col < state->cols; col++)\n    if(col % 8 == 0)\n      set_col_tabstop(state, col);\n    else\n      clear_col_tabstop(state, col);\n\n  for(int row = 0; row < state->rows; row++)\n    set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF);\n\n  if(state->callbacks && state->callbacks->initpen)\n    (*state->callbacks->initpen)(state->cbdata);\n\n  vterm_state_resetpen(state);\n\n  VTermEncoding *default_enc = state->vt->mode.utf8 ?\n      vterm_lookup_encoding(ENC_UTF8,      'u') :\n      vterm_lookup_encoding(ENC_SINGLE_94, 'B');\n\n  for(int i = 0; i < 4; i++) {\n    state->encoding[i].enc = default_enc;\n    if(default_enc->init)\n      (*default_enc->init)(default_enc, state->encoding[i].data);\n  }\n\n  state->gl_set = 0;\n  state->gr_set = 1;\n  state->gsingle_set = 0;\n\n  state->protected_cell = 0;\n\n  // Initialise the props\n  settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, 1);\n  settermprop_bool(state, VTERM_PROP_CURSORBLINK,   1);\n  settermprop_int (state, VTERM_PROP_CURSORSHAPE,   VTERM_PROP_CURSORSHAPE_BLOCK);\n\n  if(hard) {\n    state->pos.row = 0;\n    state->pos.col = 0;\n    state->at_phantom = 0;\n\n    VTermRect rect = { 0, state->rows, 0, state->cols };\n    erase(state, rect, 0);\n  }\n}\n\nvoid vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos)\n{\n  *cursorpos = state->pos;\n}\n\nvoid vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user)\n{\n  if(callbacks) {\n    state->callbacks = callbacks;\n    state->cbdata = user;\n\n    if(state->callbacks && state->callbacks->initpen)\n      (*state->callbacks->initpen)(state->cbdata);\n  }\n  else {\n    state->callbacks = NULL;\n    state->cbdata = NULL;\n  }\n}\n\nvoid *vterm_state_get_cbdata(VTermState *state)\n{\n  return state->cbdata;\n}\n\nvoid vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermParserCallbacks *fallbacks, void *user)\n{\n  if(fallbacks) {\n    state->fallbacks = fallbacks;\n    state->fbdata = user;\n  }\n  else {\n    state->fallbacks = NULL;\n    state->fbdata = NULL;\n  }\n}\n\nvoid *vterm_state_get_unrecognised_fbdata(VTermState *state)\n{\n  return state->fbdata;\n}\n\nint vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val)\n{\n  /* Only store the new value of the property if usercode said it was happy.\n   * This is especially important for altscreen switching */\n  if(state->callbacks && state->callbacks->settermprop)\n    if(!(*state->callbacks->settermprop)(prop, val, state->cbdata))\n      return 0;\n\n  switch(prop) {\n  case VTERM_PROP_TITLE:\n  case VTERM_PROP_ICONNAME:\n    // we don't store these, just transparently pass through\n    return 1;\n  case VTERM_PROP_CURSORVISIBLE:\n    state->mode.cursor_visible = val->boolean;\n    return 1;\n  case VTERM_PROP_CURSORBLINK:\n    state->mode.cursor_blink = val->boolean;\n    return 1;\n  case VTERM_PROP_CURSORSHAPE:\n    state->mode.cursor_shape = val->number;\n    return 1;\n  case VTERM_PROP_REVERSE:\n    state->mode.screen = val->boolean;\n    return 1;\n  case VTERM_PROP_ALTSCREEN:\n    state->mode.alt_screen = val->boolean;\n    if(state->mode.alt_screen) {\n      VTermRect rect = {\n        .start_row = 0,\n        .start_col = 0,\n        .end_row = state->rows,\n        .end_col = state->cols,\n      };\n      erase(state, rect, 0);\n    }\n    return 1;\n  case VTERM_PROP_MOUSE:\n    state->mouse_flags = 0;\n    if(val->number)\n      state->mouse_flags |= MOUSE_WANT_CLICK;\n    if(val->number == VTERM_PROP_MOUSE_DRAG)\n      state->mouse_flags |= MOUSE_WANT_DRAG;\n    if(val->number == VTERM_PROP_MOUSE_MOVE)\n      state->mouse_flags |= MOUSE_WANT_MOVE;\n    return 1;\n\n  case VTERM_N_PROPS:\n    return 0;\n  }\n\n  return 0;\n}\n\nvoid vterm_state_focus_in(VTermState *state)\n{\n  if(state->mode.report_focus)\n    vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, \"I\");\n}\n\nvoid vterm_state_focus_out(VTermState *state)\n{\n  if(state->mode.report_focus)\n    vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, \"O\");\n}\n\nconst VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row)\n{\n  return state->lineinfo + row;\n}\n"
  },
  {
    "path": "system/fbterm/libvterm/unicode.c",
    "content": "#include \"vterm_internal.h\"\n\n// ### The following from http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c\n// With modifications:\n//   made functions static\n//   moved 'combining' table to file scope, so other functions can see it\n// ###################################################################\n\n/*\n * This is an implementation of wcwidth() and wcswidth() (defined in\n * IEEE Std 1002.1-2001) for Unicode.\n *\n * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html\n * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html\n *\n * In fixed-width output devices, Latin characters all occupy a single\n * \"cell\" position of equal width, whereas ideographic CJK characters\n * occupy two such cells. Interoperability between terminal-line\n * applications and (teletype-style) character terminals using the\n * UTF-8 encoding requires agreement on which character should advance\n * the cursor by how many cell positions. No established formal\n * standards exist at present on which Unicode character shall occupy\n * how many cell positions on character terminals. These routines are\n * a first attempt of defining such behavior based on simple rules\n * applied to data provided by the Unicode Consortium.\n *\n * For some graphical characters, the Unicode standard explicitly\n * defines a character-cell width via the definition of the East Asian\n * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.\n * In all these cases, there is no ambiguity about which width a\n * terminal shall use. For characters in the East Asian Ambiguous (A)\n * class, the width choice depends purely on a preference of backward\n * compatibility with either historic CJK or Western practice.\n * Choosing single-width for these characters is easy to justify as\n * the appropriate long-term solution, as the CJK practice of\n * displaying these characters as double-width comes from historic\n * implementation simplicity (8-bit encoded characters were displayed\n * single-width and 16-bit ones double-width, even for Greek,\n * Cyrillic, etc.) and not any typographic considerations.\n *\n * Much less clear is the choice of width for the Not East Asian\n * (Neutral) class. Existing practice does not dictate a width for any\n * of these characters. It would nevertheless make sense\n * typographically to allocate two character cells to characters such\n * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be\n * represented adequately with a single-width glyph. The following\n * routines at present merely assign a single-cell width to all\n * neutral characters, in the interest of simplicity. This is not\n * entirely satisfactory and should be reconsidered before\n * establishing a formal standard in this area. At the moment, the\n * decision which Not East Asian (Neutral) characters should be\n * represented by double-width glyphs cannot yet be answered by\n * applying a simple rule from the Unicode database content. Setting\n * up a proper standard for the behavior of UTF-8 character terminals\n * will require a careful analysis not only of each Unicode character,\n * but also of each presentation form, something the author of these\n * routines has avoided to do so far.\n *\n * http://www.unicode.org/unicode/reports/tr11/\n *\n * Markus Kuhn -- 2007-05-26 (Unicode 5.0)\n *\n * Permission to use, copy, modify, and distribute this software\n * for any purpose and without fee is hereby granted. The author\n * disclaims all warranties with regard to this software.\n *\n * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c\n */\n\nstruct interval {\n  int first;\n  int last;\n};\n\n/* sorted list of non-overlapping intervals of non-spacing characters */\n/* generated by \"uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c\" */\nstatic const struct interval combining[] = {\n  { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },\n  { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },\n  { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },\n  { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },\n  { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },\n  { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },\n  { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },\n  { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },\n  { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },\n  { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },\n  { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },\n  { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },\n  { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },\n  { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },\n  { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },\n  { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },\n  { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },\n  { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },\n  { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },\n  { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },\n  { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },\n  { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },\n  { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },\n  { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },\n  { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },\n  { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },\n  { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },\n  { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },\n  { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },\n  { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },\n  { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },\n  { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },\n  { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },\n  { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },\n  { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },\n  { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },\n  { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },\n  { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },\n  { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },\n  { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },\n  { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },\n  { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },\n  { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },\n  { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },\n  { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },\n  { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },\n  { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },\n  { 0xE0100, 0xE01EF }\n};\n\n\n/* auxiliary function for binary search in interval table */\nstatic int bisearch(uint32_t ucs, const struct interval *table, int max) {\n  int min = 0;\n  int mid;\n\n  if (ucs < table[0].first || ucs > table[max].last)\n    return 0;\n  while (max >= min) {\n    mid = (min + max) / 2;\n    if (ucs > table[mid].last)\n      min = mid + 1;\n    else if (ucs < table[mid].first)\n      max = mid - 1;\n    else\n      return 1;\n  }\n\n  return 0;\n}\n\n\n/* The following two functions define the column width of an ISO 10646\n * character as follows:\n *\n *    - The null character (U+0000) has a column width of 0.\n *\n *    - Other C0/C1 control characters and DEL will lead to a return\n *      value of -1.\n *\n *    - Non-spacing and enclosing combining characters (general\n *      category code Mn or Me in the Unicode database) have a\n *      column width of 0.\n *\n *    - SOFT HYPHEN (U+00AD) has a column width of 1.\n *\n *    - Other format characters (general category code Cf in the Unicode\n *      database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.\n *\n *    - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)\n *      have a column width of 0.\n *\n *    - Spacing characters in the East Asian Wide (W) or East Asian\n *      Full-width (F) category as defined in Unicode Technical\n *      Report #11 have a column width of 2.\n *\n *    - All remaining characters (including all printable\n *      ISO 8859-1 and WGL4 characters, Unicode control characters,\n *      etc.) have a column width of 1.\n *\n * This implementation assumes that uint32_t characters are encoded\n * in ISO 10646.\n */\n\n\nstatic int mk_wcwidth(uint32_t ucs)\n{\n  /* test for 8-bit control characters */\n  if (ucs == 0)\n    return 0;\n  if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))\n    return -1;\n\n  /* binary search in table of non-spacing characters */\n  if (bisearch(ucs, combining,\n               sizeof(combining) / sizeof(struct interval) - 1))\n    return 0;\n\n  /* if we arrive here, ucs is not a combining or C0/C1 control character */\n\n  return 1 + \n    (ucs >= 0x1100 &&\n     (ucs <= 0x115f ||                    /* Hangul Jamo init. consonants */\n      ucs == 0x2329 || ucs == 0x232a ||\n      (ucs >= 0x2e80 && ucs <= 0xa4cf &&\n       ucs != 0x303f) ||                  /* CJK ... Yi */\n      (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */\n      (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */\n      (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */\n      (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */\n      (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */\n      (ucs >= 0xffe0 && ucs <= 0xffe6) ||\n      (ucs >= 0x20000 && ucs <= 0x2fffd) ||\n      (ucs >= 0x30000 && ucs <= 0x3fffd)));\n}\n\n\nstatic int mk_wcswidth(const uint32_t *pwcs, size_t n)\n{\n  int w, width = 0;\n\n  for (;*pwcs && n-- > 0; pwcs++)\n    if ((w = mk_wcwidth(*pwcs)) < 0)\n      return -1;\n    else\n      width += w;\n\n  return width;\n}\n\n\n/*\n * The following functions are the same as mk_wcwidth() and\n * mk_wcswidth(), except that spacing characters in the East Asian\n * Ambiguous (A) category as defined in Unicode Technical Report #11\n * have a column width of 2. This variant might be useful for users of\n * CJK legacy encodings who want to migrate to UCS without changing\n * the traditional terminal character-width behaviour. It is not\n * otherwise recommended for general use.\n */\nstatic int mk_wcwidth_cjk(uint32_t ucs)\n{\n  /* sorted list of non-overlapping intervals of East Asian Ambiguous\n   * characters, generated by \"uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c\" */\n  static const struct interval ambiguous[] = {\n    { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },\n    { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },\n    { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },\n    { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },\n    { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },\n    { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },\n    { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },\n    { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },\n    { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },\n    { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },\n    { 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },\n    { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },\n    { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },\n    { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },\n    { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },\n    { 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },\n    { 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },\n    { 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },\n    { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },\n    { 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },\n    { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },\n    { 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },\n    { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },\n    { 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },\n    { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },\n    { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },\n    { 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },\n    { 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },\n    { 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },\n    { 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },\n    { 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },\n    { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },\n    { 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },\n    { 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },\n    { 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },\n    { 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },\n    { 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },\n    { 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },\n    { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },\n    { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },\n    { 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },\n    { 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },\n    { 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },\n    { 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },\n    { 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },\n    { 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },\n    { 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },\n    { 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },\n    { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },\n    { 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },\n    { 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },\n    { 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }\n  };\n\n  /* binary search in table of non-spacing characters */\n  if (bisearch(ucs, ambiguous,\n               sizeof(ambiguous) / sizeof(struct interval) - 1))\n    return 2;\n\n  return mk_wcwidth(ucs);\n}\n\n\nstatic int mk_wcswidth_cjk(const uint32_t *pwcs, size_t n)\n{\n  int w, width = 0;\n\n  for (;*pwcs && n-- > 0; pwcs++)\n    if ((w = mk_wcwidth_cjk(*pwcs)) < 0)\n      return -1;\n    else\n      width += w;\n\n  return width;\n}\n\n// ################################\n// ### The rest added by Paul Evans\n\nINTERNAL int vterm_unicode_width(uint32_t codepoint)\n{\n  return mk_wcwidth(codepoint);\n}\n\nINTERNAL int vterm_unicode_is_combining(uint32_t codepoint)\n{\n  return bisearch(codepoint, combining, sizeof(combining) / sizeof(struct interval) - 1);\n}\n"
  },
  {
    "path": "system/fbterm/libvterm/utf8.h",
    "content": "/* The following functions copied and adapted from libtermkey\n *\n * http://www.leonerd.org.uk/code/libtermkey/\n */\nstatic inline unsigned int utf8_seqlen(long codepoint)\n{\n  if(codepoint < 0x0000080) return 1;\n  if(codepoint < 0x0000800) return 2;\n  if(codepoint < 0x0010000) return 3;\n  if(codepoint < 0x0200000) return 4;\n  if(codepoint < 0x4000000) return 5;\n  return 6;\n}\n\n/* Does NOT NUL-terminate the buffer */\nstatic int fill_utf8(long codepoint, char *str)\n{\n  int nbytes = utf8_seqlen(codepoint);\n\n  // This is easier done backwards\n  int b = nbytes;\n  while(b > 1) {\n    b--;\n    str[b] = 0x80 | (codepoint & 0x3f);\n    codepoint >>= 6;\n  }\n\n  switch(nbytes) {\n    case 1: str[0] =        (codepoint & 0x7f); break;\n    case 2: str[0] = 0xc0 | (codepoint & 0x1f); break;\n    case 3: str[0] = 0xe0 | (codepoint & 0x0f); break;\n    case 4: str[0] = 0xf0 | (codepoint & 0x07); break;\n    case 5: str[0] = 0xf8 | (codepoint & 0x03); break;\n    case 6: str[0] = 0xfc | (codepoint & 0x01); break;\n  }\n\n  return nbytes;\n}\n/* end copy */\n"
  },
  {
    "path": "system/fbterm/libvterm/vterm.c",
    "content": "#include \"vterm_internal.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#include <string.h>\n\n/*****************\n * API functions *\n *****************/\n\nstatic void *default_malloc(size_t size, void *allocdata)\n{\n  void *ptr = malloc(size);\n  if(ptr)\n    memset(ptr, 0, size);\n  return ptr;\n}\n\nstatic void default_free(void *ptr, void *allocdata)\n{\n  free(ptr);\n}\n\nstatic VTermAllocatorFunctions default_allocator = {\n  .malloc = &default_malloc,\n  .free   = &default_free,\n};\n\nVTerm *vterm_new(int rows, int cols)\n{\n  return vterm_new_with_allocator(rows, cols, &default_allocator, NULL);\n}\n\nVTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata)\n{\n  /* Need to bootstrap using the allocator function directly */\n  VTerm *vt = (*funcs->malloc)(sizeof(VTerm), allocdata);\n\n  vt->allocator = funcs;\n  vt->allocdata = allocdata;\n\n  vt->rows = rows;\n  vt->cols = cols;\n\n  vt->parser.state = NORMAL;\n\n  vt->parser.callbacks = NULL;\n  vt->parser.cbdata    = NULL;\n\n  vt->parser.strbuffer_len = 64;\n  vt->parser.strbuffer_cur = 0;\n  vt->parser.strbuffer = vterm_allocator_malloc(vt, vt->parser.strbuffer_len);\n\n  vt->outbuffer_len = 64;\n  vt->outbuffer_cur = 0;\n  vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len);\n\n  return vt;\n}\n\nvoid vterm_free(VTerm *vt)\n{\n  if(vt->screen)\n    vterm_screen_free(vt->screen);\n\n  if(vt->state)\n    vterm_state_free(vt->state);\n\n  vterm_allocator_free(vt, vt->parser.strbuffer);\n  vterm_allocator_free(vt, vt->outbuffer);\n\n  vterm_allocator_free(vt, vt);\n}\n\nINTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size)\n{\n  return (*vt->allocator->malloc)(size, vt->allocdata);\n}\n\nINTERNAL void vterm_allocator_free(VTerm *vt, void *ptr)\n{\n  (*vt->allocator->free)(ptr, vt->allocdata);\n}\n\nvoid vterm_get_size(const VTerm *vt, int *rowsp, int *colsp)\n{\n  if(rowsp)\n    *rowsp = vt->rows;\n  if(colsp)\n    *colsp = vt->cols;\n}\n\nvoid vterm_set_size(VTerm *vt, int rows, int cols)\n{\n  vt->rows = rows;\n  vt->cols = cols;\n\n  if(vt->parser.callbacks && vt->parser.callbacks->resize)\n    (*vt->parser.callbacks->resize)(rows, cols, vt->parser.cbdata);\n}\n\nint vterm_get_utf8(const VTerm *vt)\n{\n  return vt->mode.utf8;\n}\n\nvoid vterm_set_utf8(VTerm *vt, int is_utf8)\n{\n  vt->mode.utf8 = is_utf8;\n}\n\nINTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len)\n{\n  if(len > vt->outbuffer_len - vt->outbuffer_cur) {\n    DEBUG_LOG(\"vterm_push_output(): buffer overflow; truncating output\\n\");\n    len = vt->outbuffer_len - vt->outbuffer_cur;\n  }\n\n  memcpy(vt->outbuffer + vt->outbuffer_cur, bytes, len);\n  vt->outbuffer_cur += len;\n}\n\nstatic int outbuffer_is_full(VTerm *vt)\n{\n  return vt->outbuffer_cur >= vt->outbuffer_len - 1;\n}\n\nINTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args)\n{\n  if(outbuffer_is_full(vt)) {\n    DEBUG_LOG(\"vterm_push_output(): buffer overflow; truncating output\\n\");\n    return;\n  }\n\n  int written = vsnprintf(vt->outbuffer + vt->outbuffer_cur,\n      vt->outbuffer_len - vt->outbuffer_cur,\n      format, args);\n\n  if(written == vt->outbuffer_len - vt->outbuffer_cur) {\n    /* output was truncated */\n    vt->outbuffer_cur = vt->outbuffer_len - 1;\n  }\n  else\n    vt->outbuffer_cur += written;\n}\n\nINTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...)\n{\n  va_list args;\n  va_start(args, format);\n  vterm_push_output_vsprintf(vt, format, args);\n  va_end(args);\n}\n\nINTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...)\n{\n  size_t orig_cur = vt->outbuffer_cur;\n\n  if(ctrl >= 0x80 && !vt->mode.ctrl8bit)\n    vterm_push_output_sprintf(vt, ESC_S \"%c\", ctrl - 0x40);\n  else\n    vterm_push_output_sprintf(vt, \"%c\", ctrl);\n\n  va_list args;\n  va_start(args, fmt);\n  vterm_push_output_vsprintf(vt, fmt, args);\n  va_end(args);\n\n  if(outbuffer_is_full(vt))\n    vt->outbuffer_cur = orig_cur;\n}\n\nINTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...)\n{\n  size_t orig_cur = vt->outbuffer_cur;\n\n  if(!vt->mode.ctrl8bit)\n    vterm_push_output_sprintf(vt, ESC_S \"%c\", C1_DCS - 0x40);\n  else\n    vterm_push_output_sprintf(vt, \"%c\", C1_DCS);\n\n  va_list args;\n  va_start(args, fmt);\n  vterm_push_output_vsprintf(vt, fmt, args);\n  va_end(args);\n\n  vterm_push_output_sprintf_ctrl(vt, C1_ST, \"\");\n\n  if(outbuffer_is_full(vt))\n    vt->outbuffer_cur = orig_cur;\n}\n\nsize_t vterm_output_get_buffer_size(const VTerm *vt)\n{\n  return vt->outbuffer_len;\n}\n\nsize_t vterm_output_get_buffer_current(const VTerm *vt)\n{\n  return vt->outbuffer_cur;\n}\n\nsize_t vterm_output_get_buffer_remaining(const VTerm *vt)\n{\n  return vt->outbuffer_len - vt->outbuffer_cur;\n}\n\nsize_t vterm_output_read(VTerm *vt, char *buffer, size_t len)\n{\n  if(len > vt->outbuffer_cur)\n    len = vt->outbuffer_cur;\n\n  memcpy(buffer, vt->outbuffer, len);\n\n  if(len < vt->outbuffer_cur)\n    memmove(vt->outbuffer, vt->outbuffer + len, vt->outbuffer_cur - len);\n\n  vt->outbuffer_cur -= len;\n\n  return len;\n}\n\nVTermValueType vterm_get_attr_type(VTermAttr attr)\n{\n  switch(attr) {\n    case VTERM_ATTR_BOLD:       return VTERM_VALUETYPE_BOOL;\n    case VTERM_ATTR_UNDERLINE:  return VTERM_VALUETYPE_INT;\n    case VTERM_ATTR_ITALIC:     return VTERM_VALUETYPE_BOOL;\n    case VTERM_ATTR_BLINK:      return VTERM_VALUETYPE_BOOL;\n    case VTERM_ATTR_REVERSE:    return VTERM_VALUETYPE_BOOL;\n    case VTERM_ATTR_STRIKE:     return VTERM_VALUETYPE_BOOL;\n    case VTERM_ATTR_FONT:       return VTERM_VALUETYPE_INT;\n    case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR;\n    case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR;\n\n    case VTERM_N_ATTRS: return 0;\n  }\n  return 0; /* UNREACHABLE */\n}\n\nVTermValueType vterm_get_prop_type(VTermProp prop)\n{\n  switch(prop) {\n    case VTERM_PROP_CURSORVISIBLE: return VTERM_VALUETYPE_BOOL;\n    case VTERM_PROP_CURSORBLINK:   return VTERM_VALUETYPE_BOOL;\n    case VTERM_PROP_ALTSCREEN:     return VTERM_VALUETYPE_BOOL;\n    case VTERM_PROP_TITLE:         return VTERM_VALUETYPE_STRING;\n    case VTERM_PROP_ICONNAME:      return VTERM_VALUETYPE_STRING;\n    case VTERM_PROP_REVERSE:       return VTERM_VALUETYPE_BOOL;\n    case VTERM_PROP_CURSORSHAPE:   return VTERM_VALUETYPE_INT;\n    case VTERM_PROP_MOUSE:         return VTERM_VALUETYPE_INT;\n\n    case VTERM_N_PROPS: return 0;\n  }\n  return 0; /* UNREACHABLE */\n}\n\nvoid vterm_scroll_rect(VTermRect rect,\n    int downward,\n    int rightward,\n    int (*moverect)(VTermRect src, VTermRect dest, void *user),\n    int (*eraserect)(VTermRect rect, int selective, void *user),\n    void *user)\n{\n  VTermRect src;\n  VTermRect dest;\n\n  if(abs(downward)  >= rect.end_row - rect.start_row ||\n     abs(rightward) >= rect.end_col - rect.start_col) {\n    /* Scroll more than area; just erase the lot */\n    (*eraserect)(rect, 0, user);\n    return;\n  }\n\n  if(rightward >= 0) {\n    /* rect: [XXX................]\n     * src:     [----------------]\n     * dest: [----------------]\n     */\n    dest.start_col = rect.start_col;\n    dest.end_col   = rect.end_col   - rightward;\n    src.start_col  = rect.start_col + rightward;\n    src.end_col    = rect.end_col;\n  }\n  else {\n    /* rect: [................XXX]\n     * src:  [----------------]\n     * dest:    [----------------]\n     */\n    int leftward = -rightward;\n    dest.start_col = rect.start_col + leftward;\n    dest.end_col   = rect.end_col;\n    src.start_col  = rect.start_col;\n    src.end_col    = rect.end_col - leftward;\n  }\n\n  if(downward >= 0) {\n    dest.start_row = rect.start_row;\n    dest.end_row   = rect.end_row   - downward;\n    src.start_row  = rect.start_row + downward;\n    src.end_row    = rect.end_row;\n  }\n  else {\n    int upward = -downward;\n    dest.start_row = rect.start_row + upward;\n    dest.end_row   = rect.end_row;\n    src.start_row  = rect.start_row;\n    src.end_row    = rect.end_row - upward;\n  }\n\n  if(moverect)\n    (*moverect)(dest, src, user);\n\n  if(downward > 0)\n    rect.start_row = rect.end_row - downward;\n  else if(downward < 0)\n    rect.end_row = rect.start_row - downward;\n\n  if(rightward > 0)\n    rect.start_col = rect.end_col - rightward;\n  else if(rightward < 0)\n    rect.end_col = rect.start_col - rightward;\n\n  (*eraserect)(rect, 0, user);\n}\n\nvoid vterm_copy_cells(VTermRect dest,\n    VTermRect src,\n    void (*copycell)(VTermPos dest, VTermPos src, void *user),\n    void *user)\n{\n  int downward  = src.start_row - dest.start_row;\n  int rightward = src.start_col - dest.start_col;\n\n  int init_row, test_row, init_col, test_col;\n  int inc_row, inc_col;\n\n  if(downward < 0) {\n    init_row = dest.end_row - 1;\n    test_row = dest.start_row - 1;\n    inc_row = -1;\n  }\n  else /* downward >= 0 */ {\n    init_row = dest.start_row;\n    test_row = dest.end_row;\n    inc_row = +1;\n  }\n\n  if(rightward < 0) {\n    init_col = dest.end_col - 1;\n    test_col = dest.start_col - 1;\n    inc_col = -1;\n  }\n  else /* rightward >= 0 */ {\n    init_col = dest.start_col;\n    test_col = dest.end_col;\n    inc_col = +1;\n  }\n\n  VTermPos pos;\n  for(pos.row = init_row; pos.row != test_row; pos.row += inc_row)\n    for(pos.col = init_col; pos.col != test_col; pos.col += inc_col) {\n      VTermPos srcpos = { pos.row + downward, pos.col + rightward };\n      (*copycell)(pos, srcpos, user);\n    }\n}\n"
  },
  {
    "path": "system/fbterm/libvterm/vterm_internal.h",
    "content": "#ifndef __VTERM_INTERNAL_H__\n#define __VTERM_INTERNAL_H__\n\n#include <vterm.h>\n\n#include <stdarg.h>\n\n#if defined(__GNUC__)\n# define INTERNAL __attribute__((visibility(\"internal\")))\n#else\n# define INTERNAL\n#endif\n\n#ifdef DEBUG\n# define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__)\n#else\n# define DEBUG_LOG(...)\n#endif\n\n#define ESC_S \"\\x1b\"\n\n#define INTERMED_MAX 16\n\n#define CSI_ARGS_MAX 16\n#define CSI_LEADER_MAX 16\n\ntypedef struct VTermEncoding VTermEncoding;\n\ntypedef struct {\n  VTermEncoding *enc;\n\n  // This size should be increased if required by other stateful encodings\n  char           data[4*sizeof(uint32_t)];\n} VTermEncodingInstance;\n\nstruct VTermPen\n{\n  VTermColor fg;\n  VTermColor bg;\n  unsigned int bold:1;\n  unsigned int underline:2;\n  unsigned int italic:1;\n  unsigned int blink:1;\n  unsigned int reverse:1;\n  unsigned int strike:1;\n  unsigned int font:4; /* To store 0-9 */\n};\n\nstatic inline int vterm_color_equal(VTermColor a, VTermColor b)\n{\n  return a.red == b.red && a.green == b.green && a.blue == b.blue;\n}\n\nstruct VTermState\n{\n  VTerm *vt;\n\n  const VTermStateCallbacks *callbacks;\n  void *cbdata;\n\n  const VTermParserCallbacks *fallbacks;\n  void *fbdata;\n\n  int rows;\n  int cols;\n\n  /* Current cursor position */\n  VTermPos pos;\n\n  int at_phantom; /* True if we're on the \"81st\" phantom column to defer a wraparound */\n\n  int scrollregion_top;\n  int scrollregion_bottom; /* -1 means unbounded */\n#define SCROLLREGION_BOTTOM(state) ((state)->scrollregion_bottom > -1 ? (state)->scrollregion_bottom : (state)->rows)\n  int scrollregion_left;\n#define SCROLLREGION_LEFT(state)  ((state)->mode.leftrightmargin ? (state)->scrollregion_left : 0)\n  int scrollregion_right; /* -1 means unbounded */\n#define SCROLLREGION_RIGHT(state) ((state)->mode.leftrightmargin && (state)->scrollregion_right > -1 ? (state)->scrollregion_right : (state)->cols)\n\n  /* Bitvector of tab stops */\n  unsigned char *tabstops;\n\n  VTermLineInfo *lineinfo;\n#define ROWWIDTH(state,row) ((state)->lineinfo[(row)].doublewidth ? ((state)->cols / 2) : (state)->cols)\n#define THISROWWIDTH(state) ROWWIDTH(state, (state)->pos.row)\n\n  /* Mouse state */\n  int mouse_col, mouse_row;\n  int mouse_buttons;\n  int mouse_flags;\n#define MOUSE_WANT_CLICK 0x01\n#define MOUSE_WANT_DRAG  0x02\n#define MOUSE_WANT_MOVE  0x04\n\n  enum { MOUSE_X10, MOUSE_UTF8, MOUSE_SGR, MOUSE_RXVT } mouse_protocol;\n\n  /* Last glyph output, for Unicode recombining purposes */\n  uint32_t *combine_chars;\n  size_t combine_chars_size; // Number of ELEMENTS in the above\n  int combine_width; // The width of the glyph above\n  VTermPos combine_pos;   // Position before movement\n\n  struct {\n    unsigned int keypad:1;\n    unsigned int cursor:1;\n    unsigned int autowrap:1;\n    unsigned int insert:1;\n    unsigned int newline:1;\n    unsigned int cursor_visible:1;\n    unsigned int cursor_blink:1;\n    unsigned int cursor_shape:2;\n    unsigned int alt_screen:1;\n    unsigned int origin:1;\n    unsigned int screen:1;\n    unsigned int leftrightmargin:1;\n    unsigned int bracketpaste:1;\n    unsigned int report_focus:1;\n  } mode;\n\n  VTermEncodingInstance encoding[4], encoding_utf8;\n  int gl_set, gr_set, gsingle_set;\n\n  struct VTermPen pen;\n\n  VTermColor default_fg;\n  VTermColor default_bg;\n  VTermColor colors[16]; // Store the 8 ANSI and the 8 ANSI high-brights only\n\n  int fg_index;\n  int bg_index;\n  int bold_is_highbright;\n\n  unsigned int protected_cell : 1;\n\n  /* Saved state under DEC mode 1048/1049 */\n  struct {\n    VTermPos pos;\n    struct VTermPen pen;\n\n    struct {\n      unsigned int cursor_visible:1;\n      unsigned int cursor_blink:1;\n      unsigned int cursor_shape:2;\n    } mode;\n  } saved;\n};\n\ntypedef enum {\n  VTERM_PARSER_OSC,\n  VTERM_PARSER_DCS,\n\n  VTERM_N_PARSER_TYPES\n} VTermParserStringType;\n\nstruct VTerm\n{\n  VTermAllocatorFunctions *allocator;\n  void *allocdata;\n\n  int rows;\n  int cols;\n\n  struct {\n    unsigned int utf8:1;\n    unsigned int ctrl8bit:1;\n  } mode;\n\n  struct {\n    enum VTermParserState {\n      NORMAL,\n      CSI_LEADER,\n      CSI_ARGS,\n      CSI_INTERMED,\n      ESC,\n      /* below here are the \"string states\" */\n      STRING,\n      ESC_IN_STRING,\n    } state;\n\n    int intermedlen;\n    char intermed[INTERMED_MAX];\n\n    int csi_leaderlen;\n    char csi_leader[CSI_LEADER_MAX];\n\n    int csi_argi;\n    long csi_args[CSI_ARGS_MAX];\n\n    const VTermParserCallbacks *callbacks;\n    void *cbdata;\n\n    VTermParserStringType stringtype;\n    char  *strbuffer;\n    size_t strbuffer_len;\n    size_t strbuffer_cur;\n  } parser;\n\n  /* len == malloc()ed size; cur == number of valid bytes */\n\n  char  *outbuffer;\n  size_t outbuffer_len;\n  size_t outbuffer_cur;\n\n  VTermState *state;\n  VTermScreen *screen;\n};\n\nstruct VTermEncoding {\n  void (*init) (VTermEncoding *enc, void *data);\n  void (*decode)(VTermEncoding *enc, void *data,\n                 uint32_t cp[], int *cpi, int cplen,\n                 const char bytes[], size_t *pos, size_t len);\n};\n\ntypedef enum {\n  ENC_UTF8,\n  ENC_SINGLE_94\n} VTermEncodingType;\n\nvoid *vterm_allocator_malloc(VTerm *vt, size_t size);\nvoid  vterm_allocator_free(VTerm *vt, void *ptr);\n\nvoid vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len);\nvoid vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args);\nvoid vterm_push_output_sprintf(VTerm *vt, const char *format, ...);\nvoid vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...);\nvoid vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...);\n\nvoid vterm_state_free(VTermState *state);\n\nvoid vterm_state_newpen(VTermState *state);\nvoid vterm_state_resetpen(VTermState *state);\nvoid vterm_state_setpen(VTermState *state, const long args[], int argcount);\nint  vterm_state_getpen(VTermState *state, long args[], int argcount);\nvoid vterm_state_savepen(VTermState *state, int save);\n\nenum {\n  C1_SS3 = 0x8f,\n  C1_DCS = 0x90,\n  C1_CSI = 0x9b,\n  C1_ST  = 0x9c,\n};\n\nvoid vterm_state_push_output_sprintf_CSI(VTermState *vts, const char *format, ...);\n\nvoid vterm_screen_free(VTermScreen *screen);\n\nVTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation);\n\nint vterm_unicode_width(uint32_t codepoint);\nint vterm_unicode_is_combining(uint32_t codepoint);\n\n#endif\n"
  },
  {
    "path": "system/fbterm/nanojpeg.c",
    "content": "// NanoJPEG -- KeyJ's Tiny Baseline JPEG Decoder\n// version 1.3.5 (2016-11-14)\n// Copyright (c) 2009-2016 Martin J. Fiedler <martin.fiedler@gmx.net>\n// published under the terms of the MIT license\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to\n// deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n// sell copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n\n\n///////////////////////////////////////////////////////////////////////////////\n// DOCUMENTATION SECTION                                                     //\n// read this if you want to know what this is all about                      //\n///////////////////////////////////////////////////////////////////////////////\n\n// INTRODUCTION\n// ============\n//\n// This is a minimal decoder for baseline JPEG images. It accepts memory dumps\n// of JPEG files as input and generates either 8-bit grayscale or packed 24-bit\n// RGB images as output. It does not parse JFIF or Exif headers; all JPEG files\n// are assumed to be either grayscale or YCbCr. CMYK or other color spaces are\n// not supported. All YCbCr subsampling schemes with power-of-two ratios are\n// supported, as are restart intervals. Progressive or lossless JPEG is not\n// supported.\n// Summed up, NanoJPEG should be able to decode all images from digital cameras\n// and most common forms of other non-progressive JPEG images.\n// The decoder is not optimized for speed, it's optimized for simplicity and\n// small code. Image quality should be at a reasonable level. A bicubic chroma\n// upsampling filter ensures that subsampled YCbCr images are rendered in\n// decent quality. The decoder is not meant to deal with broken JPEG files in\n// a graceful manner; if anything is wrong with the bitstream, decoding will\n// simply fail.\n// The code should work with every modern C compiler without problems and\n// should not emit any warnings. It uses only (at least) 32-bit integer\n// arithmetic and is supposed to be endianness independent and 64-bit clean.\n// However, it is not thread-safe.\n\n\n// COMPILE-TIME CONFIGURATION\n// ==========================\n//\n// The following aspects of NanoJPEG can be controlled with preprocessor\n// defines:\n//\n// _NJ_EXAMPLE_PROGRAM     = Compile a main() function with an example\n//                           program.\n// _NJ_INCLUDE_HEADER_ONLY = Don't compile anything, just act as a header\n//                           file for NanoJPEG. Example:\n//                               #define _NJ_INCLUDE_HEADER_ONLY\n//                               #include \"nanojpeg.c\"\n//                               int main(void) {\n//                                   njInit();\n//                                   // your code here\n//                                   njDone();\n//                               }\n// NJ_USE_LIBC=1           = Use the malloc(), free(), memset() and memcpy()\n//                           functions from the standard C library (default).\n// NJ_USE_LIBC=0           = Don't use the standard C library. In this mode,\n//                           external functions njAlloc(), njFreeMem(),\n//                           njFillMem() and njCopyMem() need to be defined\n//                           and implemented somewhere.\n// NJ_USE_WIN32=0          = Normal mode (default).\n// NJ_USE_WIN32=1          = If compiling with MSVC for Win32 and\n//                           NJ_USE_LIBC=0, NanoJPEG will use its own\n//                           implementations of the required C library\n//                           functions (default if compiling with MSVC and\n//                           NJ_USE_LIBC=0).\n// NJ_CHROMA_FILTER=1      = Use the bicubic chroma upsampling filter\n//                           (default).\n// NJ_CHROMA_FILTER=0      = Use simple pixel repetition for chroma upsampling\n//                           (bad quality, but faster and less code).\n\n\n// API\n// ===\n//\n// For API documentation, read the \"header section\" below.\n\n\n// EXAMPLE\n// =======\n//\n// A few pages below, you can find an example program that uses NanoJPEG to\n// convert JPEG files into PGM or PPM. To compile it, use something like\n//     gcc -O3 -D_NJ_EXAMPLE_PROGRAM -o nanojpeg nanojpeg.c\n// You may also add -std=c99 -Wall -Wextra -pedantic -Werror, if you want :)\n// The only thing you might need is -Wno-shift-negative-value, because this\n// code relies on the target machine using two's complement arithmetic, but\n// the C standard does not, even though *any* practically useful machine\n// nowadays uses two's complement.\n\n\n///////////////////////////////////////////////////////////////////////////////\n// HEADER SECTION                                                            //\n// copy and pase this into nanojpeg.h if you want                            //\n///////////////////////////////////////////////////////////////////////////////\n\n#ifndef _NANOJPEG_H\n#define _NANOJPEG_H\n\n// nj_result_t: Result codes for njDecode().\ntypedef enum _nj_result {\n    NJ_OK = 0,        // no error, decoding successful\n    NJ_NO_JPEG,       // not a JPEG file\n    NJ_UNSUPPORTED,   // unsupported format\n    NJ_OUT_OF_MEM,    // out of memory\n    NJ_INTERNAL_ERR,  // internal error\n    NJ_SYNTAX_ERROR,  // syntax error\n    __NJ_FINISHED,    // used internally, will never be reported\n} nj_result_t;\n\n// njInit: Initialize NanoJPEG.\n// For safety reasons, this should be called at least one time before using\n// using any of the other NanoJPEG functions.\nvoid njInit(void);\n\n// njDecode: Decode a JPEG image.\n// Decodes a memory dump of a JPEG file into internal buffers.\n// Parameters:\n//   jpeg = The pointer to the memory dump.\n//   size = The size of the JPEG file.\n// Return value: The error code in case of failure, or NJ_OK (zero) on success.\nnj_result_t njDecode(const void* jpeg, const int size);\n\n// njGetWidth: Return the width (in pixels) of the most recently decoded\n// image. If njDecode() failed, the result of njGetWidth() is undefined.\nint njGetWidth(void);\n\n// njGetHeight: Return the height (in pixels) of the most recently decoded\n// image. If njDecode() failed, the result of njGetHeight() is undefined.\nint njGetHeight(void);\n\n// njIsColor: Return 1 if the most recently decoded image is a color image\n// (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result\n// of njGetWidth() is undefined.\nint njIsColor(void);\n\n// njGetImage: Returns the decoded image data.\n// Returns a pointer to the most recently image. The memory layout it byte-\n// oriented, top-down, without any padding between lines. Pixels of color\n// images will be stored as three consecutive bytes for the red, green and\n// blue channels. This data format is thus compatible with the PGM or PPM\n// file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8.\n// If njDecode() failed, the result of njGetImage() is undefined.\nunsigned char* njGetImage(void);\n\n// njGetImageSize: Returns the size (in bytes) of the image data returned\n// by njGetImage(). If njDecode() failed, the result of njGetImageSize() is\n// undefined.\nint njGetImageSize(void);\n\n// njDone: Uninitialize NanoJPEG.\n// Resets NanoJPEG's internal state and frees all memory that has been\n// allocated at run-time by NanoJPEG. It is still possible to decode another\n// image after a njDone() call.\nvoid njDone(void);\n\n#endif//_NANOJPEG_H\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CONFIGURATION SECTION                                                     //\n// adjust the default settings for the NJ_ defines here                      //\n///////////////////////////////////////////////////////////////////////////////\n\n#ifndef NJ_USE_LIBC\n    #define NJ_USE_LIBC 1\n#endif\n\n#ifndef NJ_USE_WIN32\n  #ifdef _MSC_VER\n    #define NJ_USE_WIN32 (!NJ_USE_LIBC)\n  #else\n    #define NJ_USE_WIN32 0\n  #endif\n#endif\n\n#ifndef NJ_CHROMA_FILTER\n    #define NJ_CHROMA_FILTER 1\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// EXAMPLE PROGRAM                                                           //\n// just define _NJ_EXAMPLE_PROGRAM to compile this (requires NJ_USE_LIBC)    //\n///////////////////////////////////////////////////////////////////////////////\n\n#ifdef  _NJ_EXAMPLE_PROGRAM\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\nint main(int argc, char* argv[]) {\n    int size;\n    char *buf;\n    FILE *f;\n\n    if (argc < 2) {\n        printf(\"Usage: %s <input.jpg> [<output.ppm>]\\n\", argv[0]);\n        return 2;\n    }\n    f = fopen(argv[1], \"rb\");\n    if (!f) {\n        printf(\"Error opening the input file.\\n\");\n        return 1;\n    }\n    fseek(f, 0, SEEK_END);\n    size = (int) ftell(f);\n    buf = (char*) malloc(size);\n    fseek(f, 0, SEEK_SET);\n    size = (int) fread(buf, 1, size, f);\n    fclose(f);\n\n    njInit();\n    int err = 0;\n    if (err = njDecode(buf, size)) {\n        free((void*)buf);\n        printf(\"Error decoding the input file. %d\\n\", err);\n        return 1;\n    }\n    free((void*)buf);\n\n    f = fopen((argc > 2) ? argv[2] : (njIsColor() ? \"nanojpeg_out.ppm\" : \"nanojpeg_out.pgm\"), \"wb\");\n    if (!f) {\n        printf(\"Error opening the output file.\\n\");\n        return 1;\n    }\n    fprintf(f, \"P%d\\n%d %d\\n255\\n\", njIsColor() ? 6 : 5, njGetWidth(), njGetHeight());\n    fwrite(njGetImage(), 1, njGetImageSize(), f);\n    fclose(f);\n    njDone();\n    return 0;\n}\n\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// IMPLEMENTATION SECTION                                                    //\n// you may stop reading here                                                 //\n///////////////////////////////////////////////////////////////////////////////\n\n#ifndef _NJ_INCLUDE_HEADER_ONLY\n\n#ifdef _MSC_VER\n    #define NJ_INLINE static __inline\n    #define NJ_FORCE_INLINE static __forceinline\n#else\n    #define NJ_INLINE static inline\n    #define NJ_FORCE_INLINE static inline\n#endif\n\n#if NJ_USE_LIBC\n    #include <stdlib.h>\n    #include <string.h>\n    #define njAllocMem malloc\n    #define njFreeMem  free\n    #define njFillMem  memset\n    #define njCopyMem  memcpy\n#elif NJ_USE_WIN32\n    #include <windows.h>\n    #define njAllocMem(size) ((void*) LocalAlloc(LMEM_FIXED, (SIZE_T)(size)))\n    #define njFreeMem(block) ((void) LocalFree((HLOCAL) block))\n    NJ_INLINE void njFillMem(void* block, unsigned char value, int count) { __asm {\n        mov edi, block\n        mov al, value\n        mov ecx, count\n        rep stosb\n    } }\n    NJ_INLINE void njCopyMem(void* dest, const void* src, int count) { __asm {\n        mov edi, dest\n        mov esi, src\n        mov ecx, count\n        rep movsb\n    } }\n#else\n    extern void* njAllocMem(int size);\n    extern void njFreeMem(void* block);\n    extern void njFillMem(void* block, unsigned char byte, int size);\n    extern void njCopyMem(void* dest, const void* src, int size);\n#endif\n\ntypedef struct _nj_code {\n    unsigned char bits, code;\n} nj_vlc_code_t;\n\ntypedef struct _nj_cmp {\n    int cid;\n    int ssx, ssy;\n    int width, height;\n    int stride;\n    int qtsel;\n    int actabsel, dctabsel;\n    int dcpred;\n    unsigned char *pixels;\n} nj_component_t;\n\ntypedef struct _nj_ctx {\n    nj_result_t error;\n    const unsigned char *pos;\n    int size;\n    int length;\n    int width, height;\n    int mbwidth, mbheight;\n    int mbsizex, mbsizey;\n    int ncomp;\n    nj_component_t comp[3];\n    int qtused, qtavail;\n    unsigned char qtab[4][64];\n    nj_vlc_code_t vlctab[4][65536];\n    int buf, bufbits;\n    int block[64];\n    int rstinterval;\n    unsigned char *rgb;\n} nj_context_t;\n\nstatic nj_context_t nj;\n\nstatic const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18,\n11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35,\n42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45,\n38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 };\n\nNJ_FORCE_INLINE unsigned char njClip(const int x) {\n    return (x < 0) ? 0 : ((x > 0xFF) ? 0xFF : (unsigned char) x);\n}\n\n#define W1 2841\n#define W2 2676\n#define W3 2408\n#define W5 1609\n#define W6 1108\n#define W7 565\n\nNJ_INLINE void njRowIDCT(int* blk) {\n    int x0, x1, x2, x3, x4, x5, x6, x7, x8;\n    if (!((x1 = blk[4] << 11)\n        | (x2 = blk[6])\n        | (x3 = blk[2])\n        | (x4 = blk[1])\n        | (x5 = blk[7])\n        | (x6 = blk[5])\n        | (x7 = blk[3])))\n    {\n        blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = blk[0] << 3;\n        return;\n    }\n    x0 = (blk[0] << 11) + 128;\n    x8 = W7 * (x4 + x5);\n    x4 = x8 + (W1 - W7) * x4;\n    x5 = x8 - (W1 + W7) * x5;\n    x8 = W3 * (x6 + x7);\n    x6 = x8 - (W3 - W5) * x6;\n    x7 = x8 - (W3 + W5) * x7;\n    x8 = x0 + x1;\n    x0 -= x1;\n    x1 = W6 * (x3 + x2);\n    x2 = x1 - (W2 + W6) * x2;\n    x3 = x1 + (W2 - W6) * x3;\n    x1 = x4 + x6;\n    x4 -= x6;\n    x6 = x5 + x7;\n    x5 -= x7;\n    x7 = x8 + x3;\n    x8 -= x3;\n    x3 = x0 + x2;\n    x0 -= x2;\n    x2 = (181 * (x4 + x5) + 128) >> 8;\n    x4 = (181 * (x4 - x5) + 128) >> 8;\n    blk[0] = (x7 + x1) >> 8;\n    blk[1] = (x3 + x2) >> 8;\n    blk[2] = (x0 + x4) >> 8;\n    blk[3] = (x8 + x6) >> 8;\n    blk[4] = (x8 - x6) >> 8;\n    blk[5] = (x0 - x4) >> 8;\n    blk[6] = (x3 - x2) >> 8;\n    blk[7] = (x7 - x1) >> 8;\n}\n\nNJ_INLINE void njColIDCT(const int* blk, unsigned char *out, int stride) {\n    int x0, x1, x2, x3, x4, x5, x6, x7, x8;\n    if (!((x1 = blk[8*4] << 8)\n        | (x2 = blk[8*6])\n        | (x3 = blk[8*2])\n        | (x4 = blk[8*1])\n        | (x5 = blk[8*7])\n        | (x6 = blk[8*5])\n        | (x7 = blk[8*3])))\n    {\n        x1 = njClip(((blk[0] + 32) >> 6) + 128);\n        for (x0 = 8;  x0;  --x0) {\n            *out = (unsigned char) x1;\n            out += stride;\n        }\n        return;\n    }\n    x0 = (blk[0] << 8) + 8192;\n    x8 = W7 * (x4 + x5) + 4;\n    x4 = (x8 + (W1 - W7) * x4) >> 3;\n    x5 = (x8 - (W1 + W7) * x5) >> 3;\n    x8 = W3 * (x6 + x7) + 4;\n    x6 = (x8 - (W3 - W5) * x6) >> 3;\n    x7 = (x8 - (W3 + W5) * x7) >> 3;\n    x8 = x0 + x1;\n    x0 -= x1;\n    x1 = W6 * (x3 + x2) + 4;\n    x2 = (x1 - (W2 + W6) * x2) >> 3;\n    x3 = (x1 + (W2 - W6) * x3) >> 3;\n    x1 = x4 + x6;\n    x4 -= x6;\n    x6 = x5 + x7;\n    x5 -= x7;\n    x7 = x8 + x3;\n    x8 -= x3;\n    x3 = x0 + x2;\n    x0 -= x2;\n    x2 = (181 * (x4 + x5) + 128) >> 8;\n    x4 = (181 * (x4 - x5) + 128) >> 8;\n    *out = njClip(((x7 + x1) >> 14) + 128);  out += stride;\n    *out = njClip(((x3 + x2) >> 14) + 128);  out += stride;\n    *out = njClip(((x0 + x4) >> 14) + 128);  out += stride;\n    *out = njClip(((x8 + x6) >> 14) + 128);  out += stride;\n    *out = njClip(((x8 - x6) >> 14) + 128);  out += stride;\n    *out = njClip(((x0 - x4) >> 14) + 128);  out += stride;\n    *out = njClip(((x3 - x2) >> 14) + 128);  out += stride;\n    *out = njClip(((x7 - x1) >> 14) + 128);\n}\n\n#define njThrow(e) do { nj.error = e; return; } while (0)\n#define njCheckError() do { if (nj.error) return; } while (0)\n\nstatic int njShowBits(int bits) {\n    unsigned char newbyte;\n    if (!bits) return 0;\n    while (nj.bufbits < bits) {\n        if (nj.size <= 0) {\n            nj.buf = (nj.buf << 8) | 0xFF;\n            nj.bufbits += 8;\n            continue;\n        }\n        newbyte = *nj.pos++;\n        nj.size--;\n        nj.bufbits += 8;\n        nj.buf = (nj.buf << 8) | newbyte;\n        if (newbyte == 0xFF) {\n            if (nj.size) {\n                unsigned char marker = *nj.pos++;\n                nj.size--;\n                switch (marker) {\n                    case 0x00:\n                    case 0xFF:\n                        break;\n                    case 0xD9: nj.size = 0; break;\n                    default:\n                        if ((marker & 0xF8) != 0xD0)\n                            nj.error = NJ_SYNTAX_ERROR;\n                        else {\n                            nj.buf = (nj.buf << 8) | marker;\n                            nj.bufbits += 8;\n                        }\n                }\n            } else\n                nj.error = NJ_SYNTAX_ERROR;\n        }\n    }\n    return (nj.buf >> (nj.bufbits - bits)) & ((1 << bits) - 1);\n}\n\nNJ_INLINE void njSkipBits(int bits) {\n    if (nj.bufbits < bits)\n        (void) njShowBits(bits);\n    nj.bufbits -= bits;\n}\n\nNJ_INLINE int njGetBits(int bits) {\n    int res = njShowBits(bits);\n    njSkipBits(bits);\n    return res;\n}\n\nNJ_INLINE void njByteAlign(void) {\n    nj.bufbits &= 0xF8;\n}\n\nstatic void njSkip(int count) {\n    nj.pos += count;\n    nj.size -= count;\n    nj.length -= count;\n    if (nj.size < 0) nj.error = NJ_SYNTAX_ERROR;\n}\n\nNJ_INLINE unsigned short njDecode16(const unsigned char *pos) {\n    return (pos[0] << 8) | pos[1];\n}\n\nstatic void njDecodeLength(void) {\n    if (nj.size < 2) njThrow(NJ_SYNTAX_ERROR);\n    nj.length = njDecode16(nj.pos);\n    if (nj.length > nj.size) njThrow(NJ_SYNTAX_ERROR);\n    njSkip(2);\n}\n\nNJ_INLINE void njSkipMarker(void) {\n    njDecodeLength();\n    njSkip(nj.length);\n}\n\nNJ_INLINE void njDecodeSOF(void) {\n    int i, ssxmax = 0, ssymax = 0;\n    nj_component_t* c;\n    njDecodeLength();\n    njCheckError();\n    if (nj.length < 9) njThrow(NJ_SYNTAX_ERROR);\n    if (nj.pos[0] != 8) njThrow(NJ_UNSUPPORTED);\n    nj.height = njDecode16(nj.pos+1);\n    nj.width = njDecode16(nj.pos+3);\n    if (!nj.width || !nj.height) njThrow(NJ_SYNTAX_ERROR);\n    nj.ncomp = nj.pos[5];\n    njSkip(6);\n    switch (nj.ncomp) {\n        case 1:\n        case 3:\n            break;\n        default:\n            njThrow(NJ_UNSUPPORTED);\n    }\n    if (nj.length < (nj.ncomp * 3)) njThrow(NJ_SYNTAX_ERROR);\n    for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) {\n        c->cid = nj.pos[0];\n        if (!(c->ssx = nj.pos[1] >> 4)) njThrow(NJ_SYNTAX_ERROR);\n        if (c->ssx & (c->ssx - 1)) njThrow(NJ_UNSUPPORTED);  // non-power of two\n        if (!(c->ssy = nj.pos[1] & 15)) njThrow(NJ_SYNTAX_ERROR);\n        if (c->ssy & (c->ssy - 1)) njThrow(NJ_UNSUPPORTED);  // non-power of two\n        if ((c->qtsel = nj.pos[2]) & 0xFC) njThrow(NJ_SYNTAX_ERROR);\n        njSkip(3);\n        nj.qtused |= 1 << c->qtsel;\n        if (c->ssx > ssxmax) ssxmax = c->ssx;\n        if (c->ssy > ssymax) ssymax = c->ssy;\n    }\n    if (nj.ncomp == 1) {\n        c = nj.comp;\n        c->ssx = c->ssy = ssxmax = ssymax = 1;\n    }\n    nj.mbsizex = ssxmax << 3;\n    nj.mbsizey = ssymax << 3;\n    nj.mbwidth = (nj.width + nj.mbsizex - 1) / nj.mbsizex;\n    nj.mbheight = (nj.height + nj.mbsizey - 1) / nj.mbsizey;\n    for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) {\n        c->width = (nj.width * c->ssx + ssxmax - 1) / ssxmax;\n        c->height = (nj.height * c->ssy + ssymax - 1) / ssymax;\n        c->stride = nj.mbwidth * c->ssx << 3;\n        if (((c->width < 3) && (c->ssx != ssxmax)) || ((c->height < 3) && (c->ssy != ssymax))) njThrow(NJ_UNSUPPORTED);\n        if (!(c->pixels = (unsigned char*) njAllocMem(c->stride * nj.mbheight * c->ssy << 3))) njThrow(NJ_OUT_OF_MEM);\n    }\n    if (nj.ncomp == 3) {\n        nj.rgb = (unsigned char*) njAllocMem(nj.width * nj.height * nj.ncomp);\n        if (!nj.rgb) njThrow(NJ_OUT_OF_MEM);\n    }\n    njSkip(nj.length);\n}\n\nNJ_INLINE void njDecodeDHT(void) {\n    int codelen, currcnt, remain, spread, i, j;\n    nj_vlc_code_t *vlc;\n    static unsigned char counts[16];\n    njDecodeLength();\n    njCheckError();\n    while (nj.length >= 17) {\n        i = nj.pos[0];\n        if (i & 0xEC) njThrow(NJ_SYNTAX_ERROR);\n        if (i & 0x02) njThrow(NJ_UNSUPPORTED);\n        i = (i | (i >> 3)) & 3;  // combined DC/AC + tableid value\n        for (codelen = 1;  codelen <= 16;  ++codelen)\n            counts[codelen - 1] = nj.pos[codelen];\n        njSkip(17);\n        vlc = &nj.vlctab[i][0];\n        remain = spread = 65536;\n        for (codelen = 1;  codelen <= 16;  ++codelen) {\n            spread >>= 1;\n            currcnt = counts[codelen - 1];\n            if (!currcnt) continue;\n            if (nj.length < currcnt) njThrow(NJ_SYNTAX_ERROR);\n            remain -= currcnt << (16 - codelen);\n            if (remain < 0) njThrow(NJ_SYNTAX_ERROR);\n            for (i = 0;  i < currcnt;  ++i) {\n                register unsigned char code = nj.pos[i];\n                for (j = spread;  j;  --j) {\n                    vlc->bits = (unsigned char) codelen;\n                    vlc->code = code;\n                    ++vlc;\n                }\n            }\n            njSkip(currcnt);\n        }\n        while (remain--) {\n            vlc->bits = 0;\n            ++vlc;\n        }\n    }\n    if (nj.length) njThrow(NJ_SYNTAX_ERROR);\n}\n\nNJ_INLINE void njDecodeDQT(void) {\n    int i;\n    unsigned char *t;\n    njDecodeLength();\n    njCheckError();\n    while (nj.length >= 65) {\n        i = nj.pos[0];\n        if (i & 0xFC) njThrow(NJ_SYNTAX_ERROR);\n        nj.qtavail |= 1 << i;\n        t = &nj.qtab[i][0];\n        for (i = 0;  i < 64;  ++i)\n            t[i] = nj.pos[i + 1];\n        njSkip(65);\n    }\n    if (nj.length) njThrow(NJ_SYNTAX_ERROR);\n}\n\nNJ_INLINE void njDecodeDRI(void) {\n    njDecodeLength();\n    njCheckError();\n    if (nj.length < 2) njThrow(NJ_SYNTAX_ERROR);\n    nj.rstinterval = njDecode16(nj.pos);\n    njSkip(nj.length);\n}\n\nstatic int njGetVLC(nj_vlc_code_t* vlc, unsigned char* code) {\n    int value = njShowBits(16);\n    int bits = vlc[value].bits;\n    if (!bits) { nj.error = NJ_SYNTAX_ERROR; return 0; }\n    njSkipBits(bits);\n    value = vlc[value].code;\n    if (code) *code = (unsigned char) value;\n    bits = value & 15;\n    if (!bits) return 0;\n    value = njGetBits(bits);\n    if (value < (1 << (bits - 1)))\n        value += ((-1U) << bits) + 1;\n    return value;\n}\n\nNJ_INLINE void njDecodeBlock(nj_component_t* c, unsigned char* out) {\n    unsigned char code = 0;\n    int value, coef = 0;\n    njFillMem(nj.block, 0, sizeof(nj.block));\n    c->dcpred += njGetVLC(&nj.vlctab[c->dctabsel][0], NULL);\n    nj.block[0] = (c->dcpred) * nj.qtab[c->qtsel][0];\n    do {\n        value = njGetVLC(&nj.vlctab[c->actabsel][0], &code);\n        if (!code) break;  // EOB\n        if (!(code & 0x0F) && (code != 0xF0)) njThrow(NJ_SYNTAX_ERROR);\n        coef += (code >> 4) + 1;\n        if (coef > 63) njThrow(NJ_SYNTAX_ERROR);\n        nj.block[(int) njZZ[coef]] = value * nj.qtab[c->qtsel][coef];\n    } while (coef < 63);\n    for (coef = 0;  coef < 64;  coef += 8)\n        njRowIDCT(&nj.block[coef]);\n    for (coef = 0;  coef < 8;  ++coef)\n        njColIDCT(&nj.block[coef], &out[coef], c->stride);\n}\n\nNJ_INLINE void njDecodeScan(void) {\n    int i, mbx, mby, sbx, sby;\n    int rstcount = nj.rstinterval, nextrst = 0;\n    nj_component_t* c;\n    njDecodeLength();\n    njCheckError();\n    if (nj.length < (4 + 2 * nj.ncomp)) njThrow(NJ_SYNTAX_ERROR);\n    if (nj.pos[0] != nj.ncomp) njThrow(NJ_UNSUPPORTED);\n    njSkip(1);\n    for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) {\n        if (nj.pos[0] != c->cid) njThrow(NJ_SYNTAX_ERROR);\n        if (nj.pos[1] & 0xEE) njThrow(NJ_SYNTAX_ERROR);\n        c->dctabsel = nj.pos[1] >> 4;\n        c->actabsel = (nj.pos[1] & 1) | 2;\n        njSkip(2);\n    }\n    if (nj.pos[0] || (nj.pos[1] != 63) || nj.pos[2]) njThrow(NJ_UNSUPPORTED);\n    njSkip(nj.length);\n    for (mbx = mby = 0;;) {\n        for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c)\n            for (sby = 0;  sby < c->ssy;  ++sby)\n                for (sbx = 0;  sbx < c->ssx;  ++sbx) {\n                    njDecodeBlock(c, &c->pixels[((mby * c->ssy + sby) * c->stride + mbx * c->ssx + sbx) << 3]);\n                    njCheckError();\n                }\n        if (++mbx >= nj.mbwidth) {\n            mbx = 0;\n            if (++mby >= nj.mbheight) break;\n        }\n        if (nj.rstinterval && !(--rstcount)) {\n            njByteAlign();\n            i = njGetBits(16);\n            if (((i & 0xFFF8) != 0xFFD0) || ((i & 7) != nextrst)) njThrow(NJ_SYNTAX_ERROR);\n            nextrst = (nextrst + 1) & 7;\n            rstcount = nj.rstinterval;\n            for (i = 0;  i < 3;  ++i)\n                nj.comp[i].dcpred = 0;\n        }\n    }\n    nj.error = __NJ_FINISHED;\n}\n\n#if NJ_CHROMA_FILTER\n\n#define CF4A (-9)\n#define CF4B (111)\n#define CF4C (29)\n#define CF4D (-3)\n#define CF3A (28)\n#define CF3B (109)\n#define CF3C (-9)\n#define CF3X (104)\n#define CF3Y (27)\n#define CF3Z (-3)\n#define CF2A (139)\n#define CF2B (-11)\n#define CF(x) njClip(((x) + 64) >> 7)\n\nNJ_INLINE void njUpsampleH(nj_component_t* c) {\n    const int xmax = c->width - 3;\n    unsigned char *out, *lin, *lout;\n    int x, y;\n    out = (unsigned char*) njAllocMem((c->width * c->height) << 1);\n    if (!out) njThrow(NJ_OUT_OF_MEM);\n    lin = c->pixels;\n    lout = out;\n    for (y = c->height;  y;  --y) {\n        lout[0] = CF(CF2A * lin[0] + CF2B * lin[1]);\n        lout[1] = CF(CF3X * lin[0] + CF3Y * lin[1] + CF3Z * lin[2]);\n        lout[2] = CF(CF3A * lin[0] + CF3B * lin[1] + CF3C * lin[2]);\n        for (x = 0;  x < xmax;  ++x) {\n            lout[(x << 1) + 3] = CF(CF4A * lin[x] + CF4B * lin[x + 1] + CF4C * lin[x + 2] + CF4D * lin[x + 3]);\n            lout[(x << 1) + 4] = CF(CF4D * lin[x] + CF4C * lin[x + 1] + CF4B * lin[x + 2] + CF4A * lin[x + 3]);\n        }\n        lin += c->stride;\n        lout += c->width << 1;\n        lout[-3] = CF(CF3A * lin[-1] + CF3B * lin[-2] + CF3C * lin[-3]);\n        lout[-2] = CF(CF3X * lin[-1] + CF3Y * lin[-2] + CF3Z * lin[-3]);\n        lout[-1] = CF(CF2A * lin[-1] + CF2B * lin[-2]);\n    }\n    c->width <<= 1;\n    c->stride = c->width;\n    njFreeMem((void*)c->pixels);\n    c->pixels = out;\n}\n\nNJ_INLINE void njUpsampleV(nj_component_t* c) {\n    const int w = c->width, s1 = c->stride, s2 = s1 + s1;\n    unsigned char *out, *cin, *cout;\n    int x, y;\n    out = (unsigned char*) njAllocMem((c->width * c->height) << 1);\n    if (!out) njThrow(NJ_OUT_OF_MEM);\n    for (x = 0;  x < w;  ++x) {\n        cin = &c->pixels[x];\n        cout = &out[x];\n        *cout = CF(CF2A * cin[0] + CF2B * cin[s1]);  cout += w;\n        *cout = CF(CF3X * cin[0] + CF3Y * cin[s1] + CF3Z * cin[s2]);  cout += w;\n        *cout = CF(CF3A * cin[0] + CF3B * cin[s1] + CF3C * cin[s2]);  cout += w;\n        cin += s1;\n        for (y = c->height - 3;  y;  --y) {\n            *cout = CF(CF4A * cin[-s1] + CF4B * cin[0] + CF4C * cin[s1] + CF4D * cin[s2]);  cout += w;\n            *cout = CF(CF4D * cin[-s1] + CF4C * cin[0] + CF4B * cin[s1] + CF4A * cin[s2]);  cout += w;\n            cin += s1;\n        }\n        cin += s1;\n        *cout = CF(CF3A * cin[0] + CF3B * cin[-s1] + CF3C * cin[-s2]);  cout += w;\n        *cout = CF(CF3X * cin[0] + CF3Y * cin[-s1] + CF3Z * cin[-s2]);  cout += w;\n        *cout = CF(CF2A * cin[0] + CF2B * cin[-s1]);\n    }\n    c->height <<= 1;\n    c->stride = c->width;\n    njFreeMem((void*) c->pixels);\n    c->pixels = out;\n}\n\n#else\n\nNJ_INLINE void njUpsample(nj_component_t* c) {\n    int x, y, xshift = 0, yshift = 0;\n    unsigned char *out, *lin, *lout;\n    while (c->width < nj.width) { c->width <<= 1; ++xshift; }\n    while (c->height < nj.height) { c->height <<= 1; ++yshift; }\n    out = (unsigned char*) njAllocMem(c->width * c->height);\n    if (!out) njThrow(NJ_OUT_OF_MEM);\n    lin = c->pixels;\n    lout = out;\n    for (y = 0;  y < c->height;  ++y) {\n        lin = &c->pixels[(y >> yshift) * c->stride];\n        for (x = 0;  x < c->width;  ++x)\n            lout[x] = lin[x >> xshift];\n        lout += c->width;\n    }\n    c->stride = c->width;\n    njFreeMem((void*) c->pixels);\n    c->pixels = out;\n}\n\n#endif\n\nNJ_INLINE void njConvert(void) {\n    int i;\n    nj_component_t* c;\n    for (i = 0, c = nj.comp;  i < nj.ncomp;  ++i, ++c) {\n        #if NJ_CHROMA_FILTER\n            while ((c->width < nj.width) || (c->height < nj.height)) {\n                if (c->width < nj.width) njUpsampleH(c);\n                njCheckError();\n                if (c->height < nj.height) njUpsampleV(c);\n                njCheckError();\n            }\n        #else\n            if ((c->width < nj.width) || (c->height < nj.height))\n                njUpsample(c);\n        #endif\n        if ((c->width < nj.width) || (c->height < nj.height)) njThrow(NJ_INTERNAL_ERR);\n    }\n    if (nj.ncomp == 3) {\n        // convert to RGB\n        int x, yy;\n        unsigned char *prgb = nj.rgb;\n        const unsigned char *py  = nj.comp[0].pixels;\n        const unsigned char *pcb = nj.comp[1].pixels;\n        const unsigned char *pcr = nj.comp[2].pixels;\n        for (yy = nj.height;  yy;  --yy) {\n            for (x = 0;  x < nj.width;  ++x) {\n                register int y = py[x] << 8;\n                register int cb = pcb[x] - 128;\n                register int cr = pcr[x] - 128;\n                *prgb++ = njClip((y            + 359 * cr + 128) >> 8);\n                *prgb++ = njClip((y -  88 * cb - 183 * cr + 128) >> 8);\n                *prgb++ = njClip((y + 454 * cb            + 128) >> 8);\n            }\n            py += nj.comp[0].stride;\n            pcb += nj.comp[1].stride;\n            pcr += nj.comp[2].stride;\n        }\n    } else if (nj.comp[0].width != nj.comp[0].stride) {\n        // grayscale -> only remove stride\n        unsigned char *pin = &nj.comp[0].pixels[nj.comp[0].stride];\n        unsigned char *pout = &nj.comp[0].pixels[nj.comp[0].width];\n        int y;\n        for (y = nj.comp[0].height - 1;  y;  --y) {\n            njCopyMem(pout, pin, nj.comp[0].width);\n            pin += nj.comp[0].stride;\n            pout += nj.comp[0].width;\n        }\n        nj.comp[0].stride = nj.comp[0].width;\n    }\n}\n\nvoid njInit(void) {\n    njFillMem(&nj, 0, sizeof(nj_context_t));\n}\n\nvoid njDone(void) {\n    int i;\n    for (i = 0;  i < 3;  ++i)\n        if (nj.comp[i].pixels) njFreeMem((void*) nj.comp[i].pixels);\n    if (nj.rgb) njFreeMem((void*) nj.rgb);\n    njInit();\n}\n\nnj_result_t njDecode(const void* jpeg, const int size) {\n    njDone();\n    nj.pos = (const unsigned char*) jpeg;\n    nj.size = size & 0x7FFFFFFF;\n    if (nj.size < 2) return NJ_NO_JPEG;\n    if ((nj.pos[0] ^ 0xFF) | (nj.pos[1] ^ 0xD8)) return NJ_NO_JPEG;\n    njSkip(2);\n    while (!nj.error) {\n        if ((nj.size < 2) || (nj.pos[0] != 0xFF)) return NJ_SYNTAX_ERROR;\n        njSkip(2);\n        switch (nj.pos[-1]) {\n            case 0xC0: njDecodeSOF();  break;\n            case 0xC4: njDecodeDHT();  break;\n            case 0xDB: njDecodeDQT();  break;\n            case 0xDD: njDecodeDRI();  break;\n            case 0xDA: njDecodeScan(); break;\n            case 0xFE: njSkipMarker(); break;\n            default:\n                if ((nj.pos[-1] & 0xF0) == 0xE0)\n                    njSkipMarker();\n                else\n                    return NJ_UNSUPPORTED;\n        }\n    }\n    if (nj.error != __NJ_FINISHED) return nj.error;\n    nj.error = NJ_OK;\n    njConvert();\n    return nj.error;\n}\n\nint njGetWidth(void)            { return nj.width; }\nint njGetHeight(void)           { return nj.height; }\nint njIsColor(void)             { return (nj.ncomp != 1); }\nunsigned char* njGetImage(void) { return (nj.ncomp == 1) ? nj.comp[0].pixels : nj.rgb; }\nint njGetImageSize(void)        { return nj.width * nj.height * nj.ncomp; }\n\n#endif // _NJ_INCLUDE_HEADER_ONLY\n"
  },
  {
    "path": "system/kilo/Build.mk",
    "content": "obj-y += kilo.o\n"
  },
  {
    "path": "system/kilo/LICENSE",
    "content": "Copyright (c) 2016, Salvatore Sanfilippo <antirez at gmail dot com>\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice,\n  this list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "system/kilo/Makefile",
    "content": "export\n\nMAKEFLAGS += --no-print-directory\n\nPDIR := $(SRC_DIR)/system/kilo\n\ninclude Build.mk\n\nall: builtin.o kilo\n\nkilo: builtin.o\n\t$(LD) $(LDFLAGS) $< $(LDLIBS) -o $@;\n\nbuiltin.o: $(obj-y) $(dirs-y)\n\t@echo -e \"  LD      \" builtin.o;\n\t@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; \n\n.PHONY: $(dirs-y)\n$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))\n\t@echo -e \"  MK      \" $@\n\t@$(MAKE) -C $@ $(param)\n\n%.o:%.c\n\t@echo -e \"  CC      \" $@;\n\t@ $(CC) $(CFLAGS) -c $< -o $@\n\n.PHONY: clean\nclean: param = clean\nclean: $(dirs-y)\n\t$(RM) -f kilo builtin.o $(obj-y)\n"
  },
  {
    "path": "system/kilo/README.md",
    "content": "Kilo\n===\n\nKilo is a small text editor in less than 1K lines of code (counted with cloc).\n\nA screencast is available here: https://asciinema.org/a/90r2i9bq8po03nazhqtsifksb\n\nUsage: kilo `<filename>`\n\nKeys:\n\n    CTRL-S: Save\n    CTRL-Q: Quit\n    CTRL-F: Find string in file (ESC to exit search, arrows to navigate)\n\nKilo does not depend on any library (not even curses). It uses fairly standard\nVT100 (and similar terminals) escape sequences. The project is in alpha\nstage and was written in just a few hours taking code from my other two\nprojects, load81 and linenoise.\n\nPeople are encouraged to use it as a starting point to write other editors\nor command line interfaces that are more advanced than the usual REPL\nstyle CLI.\n\nKilo was written by Salvatore Sanfilippo aka antirez and is released\nunder the BSD 2 clause license.\n"
  },
  {
    "path": "system/kilo/kilo.c",
    "content": "/* Kilo -- A very simple editor in less than 1-kilo lines of code (as counted\n *         by \"cloc\"). Does not depend on libcurses, directly emits VT100\n *         escapes on the terminal.\n *\n * -----------------------------------------------------------------------\n *\n * Copyright (C) 2016 Salvatore Sanfilippo <antirez at gmail dot com>\n *\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *  *  Redistributions of source code must retain the above copyright\n *     notice, this list of conditions and the following disclaimer.\n *\n *  *  Redistributions in binary form must reproduce the above copyright\n *     notice, this list of conditions and the following disclaimer in the\n *     documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#define KILO_VERSION \"0.0.1\"\n\n#define _BSD_SOURCE\n#define _GNU_SOURCE\n\n#include <termios.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <errno.h>\n#include <string.h>\n#include <stdlib.h>\n#include <ctype.h>\n#include <sys/types.h>\n#include <sys/ioctl.h>\n#include <sys/time.h>\n#include <unistd.h>\n#include <stdarg.h>\n#include <fcntl.h>\n\n/* XXX Thses functions are not provided by libc */\nint tcgetattr(int fd, struct termios *tios)\n{\n    return ioctl(fd, TCGETS, tios);\n}\n\nint tcsetattr(int fd, int req, struct termios *tios)\n{\n    return ioctl(fd, TCSETS, tios);\n}\n\nssize_t __getline(char **lineptr, size_t *n, FILE *stream);\nssize_t getline(char **lineptr, size_t *n, FILE *stream)\n{\n    return __getline(lineptr, n, stream);\n}\n\n/* XXX fix libc already! */\n#define isatty(...) (1)\n\n/* Syntax highlight types */\n#define HL_NORMAL 0\n#define HL_NONPRINT 1\n#define HL_COMMENT 2   /* Single line comment. */\n#define HL_MLCOMMENT 3 /* Multi-line comment. */\n#define HL_KEYWORD1 4\n#define HL_KEYWORD2 5\n#define HL_STRING 6\n#define HL_NUMBER 7\n#define HL_MATCH 8      /* Search match. */\n\n#define HL_HIGHLIGHT_STRINGS (1<<0)\n#define HL_HIGHLIGHT_NUMBERS (1<<1)\n\nstruct editorSyntax {\n    char **filematch;\n    char **keywords;\n    char singleline_comment_start[2];\n    char multiline_comment_start[3];\n    char multiline_comment_end[3];\n    int flags;\n};\n\n/* This structure represents a single line of the file we are editing. */\ntypedef struct erow {\n    int idx;            /* Row index in the file, zero-based. */\n    int size;           /* Size of the row, excluding the null term. */\n    int rsize;          /* Size of the rendered row. */\n    char *chars;        /* Row content. */\n    char *render;       /* Row content \"rendered\" for screen (for TABs). */\n    unsigned char *hl;  /* Syntax highlight type for each character in render.*/\n    int hl_oc;          /* Row had open comment at end in last syntax highlight\n                           check. */\n} erow;\n\ntypedef struct hlcolor {\n    int r,g,b;\n} hlcolor;\n\nstruct editorConfig {\n    int cx,cy;  /* Cursor x and y position in characters */\n    int rowoff;     /* Offset of row displayed. */\n    int coloff;     /* Offset of column displayed. */\n    int screenrows; /* Number of rows that we can show */\n    int screencols; /* Number of cols that we can show */\n    int numrows;    /* Number of rows */\n    int rawmode;    /* Is terminal raw mode enabled? */\n    erow *row;      /* Rows */\n    int dirty;      /* File modified but not saved. */\n    char *filename; /* Currently open filename */\n    char statusmsg[80];\n    time_t statusmsg_time;\n    struct editorSyntax *syntax;    /* Current syntax highlight, or NULL. */\n};\n\nstatic struct editorConfig E;\n\nenum KEY_ACTION{\n        KEY_NULL = 0,       /* NULL */\n        CTRL_C = 3,         /* Ctrl-c */\n        CTRL_D = 4,         /* Ctrl-d */\n        CTRL_F = 6,         /* Ctrl-f */\n        CTRL_H = 8,         /* Ctrl-h */\n        TAB = 9,            /* Tab */\n        CTRL_L = 12,        /* Ctrl+l */\n        ENTER = 13,         /* Enter */\n        CTRL_Q = 17,        /* Ctrl-q */\n        CTRL_S = 19,        /* Ctrl-s */\n        CTRL_U = 21,        /* Ctrl-u */\n        ESC = 27,           /* Escape */\n        BACKSPACE =  127,   /* Backspace */\n        /* The following are just soft codes, not really reported by the\n         * terminal directly. */\n        ARROW_LEFT = 1000,\n        ARROW_RIGHT,\n        ARROW_UP,\n        ARROW_DOWN,\n        DEL_KEY,\n        HOME_KEY,\n        END_KEY,\n        PAGE_UP,\n        PAGE_DOWN\n};\n\nvoid editorSetStatusMessage(const char *fmt, ...);\n\n/* =========================== Syntax highlights DB =========================\n *\n * In order to add a new syntax, define two arrays with a list of file name\n * matches and keywords. The file name matches are used in order to match\n * a given syntax with a given file name: if a match pattern starts with a\n * dot, it is matched as the last past of the filename, for example \".c\".\n * Otherwise the pattern is just searched inside the filenme, like \"Makefile\").\n *\n * The list of keywords to highlight is just a list of words, however if they\n * a trailing '|' character is added at the end, they are highlighted in\n * a different color, so that you can have two different sets of keywords.\n *\n * Finally add a stanza in the HLDB global variable with two two arrays\n * of strings, and a set of flags in order to enable highlighting of\n * comments and numbers.\n *\n * The characters for single and multi line comments must be exactly two\n * and must be provided as well (see the C language example).\n *\n * There is no support to highlight patterns currently. */\n\n/* C / C++ */\nchar *C_HL_extensions[] = {\".c\",\".cpp\",NULL};\nchar *C_HL_keywords[] = {\n        /* A few C / C++ keywords */\n        \"switch\",\"if\",\"while\",\"for\",\"break\",\"continue\",\"return\",\"else\",\n        \"struct\",\"union\",\"typedef\",\"static\",\"enum\",\"class\",\n        /* C types */\n        \"int|\",\"long|\",\"double|\",\"float|\",\"char|\",\"unsigned|\",\"signed|\",\n        \"void|\",NULL\n};\n\n/* Here we define an array of syntax highlights by extensions, keywords,\n * comments delimiters and flags. */\nstruct editorSyntax HLDB[] = {\n    {\n        /* C / C++ */\n        C_HL_extensions,\n        C_HL_keywords,\n        \"//\",\"/*\",\"*/\",\n        HL_HIGHLIGHT_STRINGS | HL_HIGHLIGHT_NUMBERS\n    }\n};\n\n#define HLDB_ENTRIES (sizeof(HLDB)/sizeof(HLDB[0]))\n\n/* ======================= Low level terminal handling ====================== */\n\nstatic struct termios orig_termios; /* In order to restore at exit.*/\n\nvoid disableRawMode(int fd) {\n    /* Don't even check the return value as it's too late. */\n    if (E.rawmode) {\n        tcsetattr(fd,TCSAFLUSH,&orig_termios);\n        E.rawmode = 0;\n    }\n}\n\n/* Called at exit to avoid remaining in raw mode. */\nvoid editorAtExit(void) {\n    disableRawMode(STDIN_FILENO);\n}\n\n/* Raw mode: 1960 magic shit. */\nint enableRawMode(int fd) {\n    struct termios raw;\n\n    if (E.rawmode) return 0; /* Already enabled. */\n    if (!isatty(STDIN_FILENO)) goto fatal;\n    atexit(editorAtExit);\n    if (tcgetattr(fd,&orig_termios) == -1) goto fatal;\n\n    raw = orig_termios;  /* modify the original mode */\n    /* input modes: no break, no CR to NL, no parity check, no strip char,\n     * no start/stop output control. */\n    raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);\n    /* output modes - disable post processing */\n    raw.c_oflag &= ~(OPOST);\n    /* control modes - set 8 bit chars */\n    raw.c_cflag |= (CS8);\n    /* local modes - choing off, canonical off, no extended functions,\n     * no signal chars (^Z,^C) */\n    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);\n    /* control chars - set return condition: min number of bytes and timer. */\n    raw.c_cc[VMIN] = 0; /* Return each byte, or zero for timeout. */\n    raw.c_cc[VTIME] = 1; /* 100 ms timeout (unit is tens of second). */\n\n    /* put terminal in raw mode after flushing */\n    if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;\n    E.rawmode = 1;\n    return 0;\n\nfatal:\n    errno = ENOTTY;\n    return -1;\n}\n\n/* Read a key from the terminal put in raw mode, trying to handle\n * escape sequences. */\nint editorReadKey(int fd) {\n    int nread;\n    char c, seq[3];\n    while ((nread = read(fd,&c,1)) == 0);\n    if (nread == -1) exit(1);\n\n    while(1) {\n        switch(c) {\n        case ESC:    /* escape sequence */\n            /* If this is just an ESC, we'll timeout here. */\n            if (read(fd,seq,1) == 0) return ESC;\n            if (read(fd,seq+1,1) == 0) return ESC;\n\n            /* ESC [ sequences. */\n            if (seq[0] == '[') {\n                if (seq[1] >= '0' && seq[1] <= '9') {\n                    /* Extended escape, read additional byte. */\n                    if (read(fd,seq+2,1) == 0) return ESC;\n                    if (seq[2] == '~') {\n                        switch(seq[1]) {\n                        case '3': return DEL_KEY;\n                        case '5': return PAGE_UP;\n                        case '6': return PAGE_DOWN;\n                        }\n                    }\n                } else {\n                    switch(seq[1]) {\n                    case 'A': return ARROW_UP;\n                    case 'B': return ARROW_DOWN;\n                    case 'C': return ARROW_RIGHT;\n                    case 'D': return ARROW_LEFT;\n                    case 'H': return HOME_KEY;\n                    case 'F': return END_KEY;\n                    }\n                }\n            }\n\n            /* ESC O sequences. */\n            else if (seq[0] == 'O') {\n                switch(seq[1]) {\n                case 'H': return HOME_KEY;\n                case 'F': return END_KEY;\n                }\n            }\n            break;\n        default:\n            return c;\n        }\n    }\n}\n\n/* Use the ESC [6n escape sequence to query the horizontal cursor position\n * and return it. On error -1 is returned, on success the position of the\n * cursor is stored at *rows and *cols and 0 is returned. */\nint getCursorPosition(int ifd, int ofd, int *rows, int *cols) {\n    char buf[32];\n    unsigned int i = 0;\n\n    /* Report cursor location */\n    if (write(ofd, \"\\x1b[6n\", 4) != 4) return -1;\n\n    /* Read the response: ESC [ rows ; cols R */\n    while (i < sizeof(buf)-1) {\n        if (read(ifd,buf+i,1) != 1) break;\n        if (buf[i] == 'R') break;\n        i++;\n    }\n    buf[i] = '\\0';\n\n    /* Parse it. */\n    if (buf[0] != ESC || buf[1] != '[') return -1;\n    if (sscanf(buf+2,\"%d;%d\",rows,cols) != 2) return -1;\n    return 0;\n}\n\n/* Try to get the number of columns in the current terminal. If the ioctl()\n * call fails the function will try to query the terminal itself.\n * Returns 0 on success, -1 on error. */\nint getWindowSize(int ifd, int ofd, int *rows, int *cols) {\n    struct winsize ws;\n\n    if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {\n        /* ioctl() failed. Try to query the terminal itself. */\n        int orig_row, orig_col, retval;\n\n        /* Get the initial position so we can restore it later. */\n        retval = getCursorPosition(ifd,ofd,&orig_row,&orig_col);\n        if (retval == -1) goto failed;\n\n        /* Go to right/bottom margin and get position. */\n        if (write(ofd,\"\\x1b[999C\\x1b[999B\",12) != 12) goto failed;\n        retval = getCursorPosition(ifd,ofd,rows,cols);\n        if (retval == -1) goto failed;\n\n        /* Restore position. */\n        char seq[32];\n        snprintf(seq,32,\"\\x1b[%d;%dH\",orig_row,orig_col);\n        if (write(ofd,seq,strlen(seq)) == -1) {\n            /* Can't recover... */\n        }\n        return 0;\n    } else {\n        *cols = ws.ws_col;\n        *rows = ws.ws_row;\n        return 0;\n    }\n\nfailed:\n    return -1;\n}\n\n/* ====================== Syntax highlight color scheme  ==================== */\n\nint is_separator(int c) {\n    return c == '\\0' || isspace(c) || strchr(\",.()+-/*=~%[];\",c) != NULL;\n}\n\n/* Return true if the specified row last char is part of a multi line comment\n * that starts at this row or at one before, and does not end at the end\n * of the row but spawns to the next row. */\nint editorRowHasOpenComment(erow *row) {\n    if (row->hl && row->rsize && row->hl[row->rsize-1] == HL_MLCOMMENT &&\n        (row->rsize < 2 || (row->render[row->rsize-2] != '*' ||\n                            row->render[row->rsize-1] != '/'))) return 1;\n    return 0;\n}\n\n/* Set every byte of row->hl (that corresponds to every character in the line)\n * to the right syntax highlight type (HL_* defines). */\nvoid editorUpdateSyntax(erow *row) {\n    row->hl = realloc(row->hl,row->rsize);\n    memset(row->hl,HL_NORMAL,row->rsize);\n\n    if (E.syntax == NULL) return; /* No syntax, everything is HL_NORMAL. */\n\n    int i, prev_sep, in_string, in_comment;\n    char *p;\n    char **keywords = E.syntax->keywords;\n    char *scs = E.syntax->singleline_comment_start;\n    char *mcs = E.syntax->multiline_comment_start;\n    char *mce = E.syntax->multiline_comment_end;\n\n    /* Point to the first non-space char. */\n    p = row->render;\n    i = 0; /* Current char offset */\n    while(*p && isspace(*p)) {\n        p++;\n        i++;\n    }\n    prev_sep = 1; /* Tell the parser if 'i' points to start of word. */\n    in_string = 0; /* Are we inside \"\" or '' ? */\n    in_comment = 0; /* Are we inside multi-line comment? */\n\n    /* If the previous line has an open comment, this line starts\n     * with an open comment state. */\n    if (row->idx > 0 && editorRowHasOpenComment(&E.row[row->idx-1]))\n        in_comment = 1;\n\n    while(*p) {\n        /* Handle // comments. */\n        if (prev_sep && *p == scs[0] && *(p+1) == scs[1]) {\n            /* From here to end is a comment */\n            memset(row->hl+i,HL_COMMENT,row->size-i);\n            return;\n        }\n\n        /* Handle multi line comments. */\n        if (in_comment) {\n            row->hl[i] = HL_MLCOMMENT;\n            if (*p == mce[0] && *(p+1) == mce[1]) {\n                row->hl[i+1] = HL_MLCOMMENT;\n                p += 2; i += 2;\n                in_comment = 0;\n                prev_sep = 1;\n                continue;\n            } else {\n                prev_sep = 0;\n                p++; i++;\n                continue;\n            }\n        } else if (*p == mcs[0] && *(p+1) == mcs[1]) {\n            row->hl[i] = HL_MLCOMMENT;\n            row->hl[i+1] = HL_MLCOMMENT;\n            p += 2; i += 2;\n            in_comment = 1;\n            prev_sep = 0;\n            continue;\n        }\n\n        /* Handle \"\" and '' */\n        if (in_string) {\n            row->hl[i] = HL_STRING;\n            if (*p == '\\\\') {\n                row->hl[i+1] = HL_STRING;\n                p += 2; i += 2;\n                prev_sep = 0;\n                continue;\n            }\n            if (*p == in_string) in_string = 0;\n            p++; i++;\n            continue;\n        } else {\n            if (*p == '\"' || *p == '\\'') {\n                in_string = *p;\n                row->hl[i] = HL_STRING;\n                p++; i++;\n                prev_sep = 0;\n                continue;\n            }\n        }\n\n        /* Handle non printable chars. */\n        if (!isprint(*p)) {\n            row->hl[i] = HL_NONPRINT;\n            p++; i++;\n            prev_sep = 0;\n            continue;\n        }\n\n        /* Handle numbers */\n        if ((isdigit(*p) && (prev_sep || row->hl[i-1] == HL_NUMBER)) ||\n            (*p == '.' && i >0 && row->hl[i-1] == HL_NUMBER)) {\n            row->hl[i] = HL_NUMBER;\n            p++; i++;\n            prev_sep = 0;\n            continue;\n        }\n\n        /* Handle keywords and lib calls */\n        if (prev_sep) {\n            int j;\n            for (j = 0; keywords[j]; j++) {\n                int klen = strlen(keywords[j]);\n                int kw2 = keywords[j][klen-1] == '|';\n                if (kw2) klen--;\n\n                if (!memcmp(p,keywords[j],klen) &&\n                    is_separator(*(p+klen)))\n                {\n                    /* Keyword */\n                    memset(row->hl+i,kw2 ? HL_KEYWORD2 : HL_KEYWORD1,klen);\n                    p += klen;\n                    i += klen;\n                    break;\n                }\n            }\n            if (keywords[j] != NULL) {\n                prev_sep = 0;\n                continue; /* We had a keyword match */\n            }\n        }\n\n        /* Not special chars */\n        prev_sep = is_separator(*p);\n        p++; i++;\n    }\n\n    /* Propagate syntax change to the next row if the open commen\n     * state changed. This may recursively affect all the following rows\n     * in the file. */\n    int oc = editorRowHasOpenComment(row);\n    if (row->hl_oc != oc && row->idx+1 < E.numrows)\n        editorUpdateSyntax(&E.row[row->idx+1]);\n    row->hl_oc = oc;\n}\n\n/* Maps syntax highlight token types to terminal colors. */\nint editorSyntaxToColor(int hl) {\n    switch(hl) {\n    case HL_COMMENT:\n    case HL_MLCOMMENT: return 36;     /* cyan */\n    case HL_KEYWORD1: return 33;    /* yellow */\n    case HL_KEYWORD2: return 32;    /* green */\n    case HL_STRING: return 35;      /* magenta */\n    case HL_NUMBER: return 31;      /* red */\n    case HL_MATCH: return 34;      /* blu */\n    default: return 37;             /* white */\n    }\n}\n\n/* Select the syntax highlight scheme depending on the filename,\n * setting it in the global state E.syntax. */\nvoid editorSelectSyntaxHighlight(char *filename) {\n    for (unsigned int j = 0; j < HLDB_ENTRIES; j++) {\n        struct editorSyntax *s = HLDB+j;\n        unsigned int i = 0;\n        while(s->filematch[i]) {\n            char *p;\n            int patlen = strlen(s->filematch[i]);\n            if ((p = strstr(filename,s->filematch[i])) != NULL) {\n                if (s->filematch[i][0] != '.' || p[patlen] == '\\0') {\n                    E.syntax = s;\n                    return;\n                }\n            }\n            i++;\n        }\n    }\n}\n\n/* ======================= Editor rows implementation ======================= */\n\n/* Update the rendered version and the syntax highlight of a row. */\nvoid editorUpdateRow(erow *row) {\n    int tabs = 0, nonprint = 0, j, idx;\n\n   /* Create a version of the row we can directly print on the screen,\n     * respecting tabs, substituting non printable characters with '?'. */\n    free(row->render);\n    for (j = 0; j < row->size; j++)\n        if (row->chars[j] == TAB) tabs++;\n\n    row->render = malloc(row->size + tabs*8 + nonprint*9 + 1);\n    idx = 0;\n    for (j = 0; j < row->size; j++) {\n        if (row->chars[j] == TAB) {\n            row->render[idx++] = ' ';\n            while((idx+1) % 8 != 0) row->render[idx++] = ' ';\n        } else {\n            row->render[idx++] = row->chars[j];\n        }\n    }\n    row->rsize = idx;\n    row->render[idx] = '\\0';\n\n    /* Update the syntax highlighting attributes of the row. */\n    editorUpdateSyntax(row);\n}\n\n/* Insert a row at the specified position, shifting the other rows on the bottom\n * if required. */\nvoid editorInsertRow(int at, char *s, size_t len) {\n    if (at > E.numrows) return;\n    E.row = realloc(E.row,sizeof(erow)*(E.numrows+1));\n    if (at != E.numrows) {\n        memmove(E.row+at+1,E.row+at,sizeof(E.row[0])*(E.numrows-at));\n        for (int j = at+1; j <= E.numrows; j++) E.row[j].idx++;\n    }\n    E.row[at].size = len;\n    E.row[at].chars = malloc(len+1);\n    memcpy(E.row[at].chars,s,len+1);\n    E.row[at].hl = NULL;\n    E.row[at].hl_oc = 0;\n    E.row[at].render = NULL;\n    E.row[at].rsize = 0;\n    E.row[at].idx = at;\n    editorUpdateRow(E.row+at);\n    E.numrows++;\n    E.dirty++;\n}\n\n/* Free row's heap allocated stuff. */\nvoid editorFreeRow(erow *row) {\n    free(row->render);\n    free(row->chars);\n    free(row->hl);\n}\n\n/* Remove the row at the specified position, shifting the remainign on the\n * top. */\nvoid editorDelRow(int at) {\n    erow *row;\n\n    if (at >= E.numrows) return;\n    row = E.row+at;\n    editorFreeRow(row);\n    memmove(E.row+at,E.row+at+1,sizeof(E.row[0])*(E.numrows-at-1));\n    for (int j = at; j < E.numrows-1; j++) E.row[j].idx++;\n    E.numrows--;\n    E.dirty++;\n}\n\n/* Turn the editor rows into a single heap-allocated string.\n * Returns the pointer to the heap-allocated string and populate the\n * integer pointed by 'buflen' with the size of the string, escluding\n * the final nulterm. */\nchar *editorRowsToString(int *buflen) {\n    char *buf = NULL, *p;\n    int totlen = 0;\n    int j;\n\n    /* Compute count of bytes */\n    for (j = 0; j < E.numrows; j++)\n        totlen += E.row[j].size+1; /* +1 is for \"\\n\" at end of every row */\n    *buflen = totlen;\n    totlen++; /* Also make space for nulterm */\n\n    p = buf = malloc(totlen);\n    for (j = 0; j < E.numrows; j++) {\n        memcpy(p,E.row[j].chars,E.row[j].size);\n        p += E.row[j].size;\n        *p = '\\n';\n        p++;\n    }\n    *p = '\\0';\n    return buf;\n}\n\n/* Insert a character at the specified position in a row, moving the remaining\n * chars on the right if needed. */\nvoid editorRowInsertChar(erow *row, int at, int c) {\n    if (at > row->size) {\n        /* Pad the string with spaces if the insert location is outside the\n         * current length by more than a single character. */\n        int padlen = at-row->size;\n        /* In the next line +2 means: new char and null term. */\n        row->chars = realloc(row->chars,row->size+padlen+2);\n        memset(row->chars+row->size,' ',padlen);\n        row->chars[row->size+padlen+1] = '\\0';\n        row->size += padlen+1;\n    } else {\n        /* If we are in the middle of the string just make space for 1 new\n         * char plus the (already existing) null term. */\n        row->chars = realloc(row->chars,row->size+2);\n        memmove(row->chars+at+1,row->chars+at,row->size-at+1);\n        row->size++;\n    }\n    row->chars[at] = c;\n    editorUpdateRow(row);\n    E.dirty++;\n}\n\n/* Append the string 's' at the end of a row */\nvoid editorRowAppendString(erow *row, char *s, size_t len) {\n    row->chars = realloc(row->chars,row->size+len+1);\n    memcpy(row->chars+row->size,s,len);\n    row->size += len;\n    row->chars[row->size] = '\\0';\n    editorUpdateRow(row);\n    E.dirty++;\n}\n\n/* Delete the character at offset 'at' from the specified row. */\nvoid editorRowDelChar(erow *row, int at) {\n    if (row->size <= at) return;\n    memmove(row->chars+at,row->chars+at+1,row->size-at);\n    editorUpdateRow(row);\n    row->size--;\n    E.dirty++;\n}\n\n/* Insert the specified char at the current prompt position. */\nvoid editorInsertChar(int c) {\n    int filerow = E.rowoff+E.cy;\n    int filecol = E.coloff+E.cx;\n    erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];\n\n    /* If the row where the cursor is currently located does not exist in our\n     * logical representaion of the file, add enough empty rows as needed. */\n    if (!row) {\n        while(E.numrows <= filerow)\n            editorInsertRow(E.numrows,\"\",0);\n    }\n    row = &E.row[filerow];\n    editorRowInsertChar(row,filecol,c);\n    if (E.cx == E.screencols-1)\n        E.coloff++;\n    else\n        E.cx++;\n    E.dirty++;\n}\n\n/* Inserting a newline is slightly complex as we have to handle inserting a\n * newline in the middle of a line, splitting the line as needed. */\nvoid editorInsertNewline(void) {\n    int filerow = E.rowoff+E.cy;\n    int filecol = E.coloff+E.cx;\n    erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];\n\n    if (!row) {\n        if (filerow == E.numrows) {\n            editorInsertRow(filerow,\"\",0);\n            goto fixcursor;\n        }\n        return;\n    }\n    /* If the cursor is over the current line size, we want to conceptually\n     * think it's just over the last character. */\n    if (filecol >= row->size) filecol = row->size;\n    if (filecol == 0) {\n        editorInsertRow(filerow,\"\",0);\n    } else {\n        /* We are in the middle of a line. Split it between two rows. */\n        editorInsertRow(filerow+1,row->chars+filecol,row->size-filecol);\n        row = &E.row[filerow];\n        row->chars[filecol] = '\\0';\n        row->size = filecol;\n        editorUpdateRow(row);\n    }\nfixcursor:\n    if (E.cy == E.screenrows-1) {\n        E.rowoff++;\n    } else {\n        E.cy++;\n    }\n    E.cx = 0;\n    E.coloff = 0;\n}\n\n/* Delete the char at the current prompt position. */\nvoid editorDelChar() {\n    int filerow = E.rowoff+E.cy;\n    int filecol = E.coloff+E.cx;\n    erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];\n\n    if (!row || (filecol == 0 && filerow == 0)) return;\n    if (filecol == 0) {\n        /* Handle the case of column 0, we need to move the current line\n         * on the right of the previous one. */\n        filecol = E.row[filerow-1].size;\n        editorRowAppendString(&E.row[filerow-1],row->chars,row->size);\n        editorDelRow(filerow);\n        row = NULL;\n        if (E.cy == 0)\n            E.rowoff--;\n        else\n            E.cy--;\n        E.cx = filecol;\n        if (E.cx >= E.screencols) {\n            int shift = (E.screencols-E.cx)+1;\n            E.cx -= shift;\n            E.coloff += shift;\n        }\n    } else {\n        editorRowDelChar(row,filecol-1);\n        if (E.cx == 0 && E.coloff)\n            E.coloff--;\n        else\n            E.cx--;\n    }\n    if (row) editorUpdateRow(row);\n    E.dirty++;\n}\n\n/* Load the specified program in the editor memory and returns 0 on success\n * or 1 on error. */\nint editorOpen(char *filename) {\n    FILE *fp;\n\n    E.dirty = 0;\n    free(E.filename);\n    E.filename = strdup(filename);\n\n    fp = fopen(filename,\"r\");\n    if (!fp) {\n        if (errno != ENOENT) {\n            perror(\"Opening file\");\n            exit(1);\n        }\n        return 1;\n    }\n\n    char *line = NULL;\n    size_t linecap = 0;\n    ssize_t linelen;\n    while((linelen = getline(&line,&linecap,fp)) != -1) {\n        if (linelen && (line[linelen-1] == '\\n' || line[linelen-1] == '\\r'))\n            line[--linelen] = '\\0';\n        editorInsertRow(E.numrows,line,linelen);\n    }\n    free(line);\n    fclose(fp);\n    E.dirty = 0;\n    return 0;\n}\n\n/* Save the current file on disk. Return 0 on success, 1 on error. */\nint editorSave(void) {\n    int len;\n    char *buf = editorRowsToString(&len);\n    int fd = open(E.filename,O_RDWR|O_CREAT,0644);\n    if (fd == -1) goto writeerr;\n\n    /* Use truncate + a single write(2) call in order to make saving\n     * a bit safer, under the limits of what we can do in a small editor. */\n    //if (ftruncate(fd,len) == -1) goto writeerr;\n    if (write(fd,buf,len) != len) goto writeerr;\n\n    close(fd);\n    free(buf);\n    E.dirty = 0;\n    editorSetStatusMessage(\"%d bytes written on disk\", len);\n    return 0;\n\nwriteerr:\n    free(buf);\n    if (fd != -1) close(fd);\n    editorSetStatusMessage(\"Can't save! I/O error: %s\",strerror(errno));\n    return 1;\n}\n\n/* ============================= Terminal update ============================ */\n\n/* We define a very simple \"append buffer\" structure, that is an heap\n * allocated string where we can append to. This is useful in order to\n * write all the escape sequences in a buffer and flush them to the standard\n * output in a single call, to avoid flickering effects. */\nstruct abuf {\n    char *b;\n    int len;\n};\n\n#define ABUF_INIT {NULL,0}\n\nvoid abAppend(struct abuf *ab, const char *s, int len) {\n    char *new = realloc(ab->b,ab->len+len);\n\n    if (new == NULL) return;\n    memcpy(new+ab->len,s,len);\n    ab->b = new;\n    ab->len += len;\n}\n\nvoid abFree(struct abuf *ab) {\n    free(ab->b);\n}\n\n/* This function writes the whole screen using VT100 escape characters\n * starting from the logical state of the editor in the global state 'E'. */\nvoid editorRefreshScreen(void) {\n    int y;\n    erow *r;\n    char buf[32];\n    struct abuf ab = ABUF_INIT;\n\n    abAppend(&ab,\"\\x1b[?25l\",6); /* Hide cursor. */\n    abAppend(&ab,\"\\x1b[H\",3); /* Go home. */\n    for (y = 0; y < E.screenrows; y++) {\n        int filerow = E.rowoff+y;\n\n        if (filerow >= E.numrows) {\n            if (E.numrows == 0 && y == E.screenrows/3) {\n                char welcome[80];\n                int welcomelen = snprintf(welcome,sizeof(welcome),\n                    \"Kilo editor -- verison %s\\x1b[0K\\r\\n\", KILO_VERSION);\n                int padding = (E.screencols-welcomelen)/2;\n                if (padding) {\n                    abAppend(&ab,\"~\",1);\n                    padding--;\n                }\n                while(padding--) abAppend(&ab,\" \",1);\n                abAppend(&ab,welcome,welcomelen);\n            } else {\n                abAppend(&ab,\"~\\x1b[0K\\r\\n\",7);\n            }\n            continue;\n        }\n\n        r = &E.row[filerow];\n\n        int len = r->rsize - E.coloff;\n        int current_color = -1;\n        if (len > 0) {\n            if (len > E.screencols) len = E.screencols;\n            char *c = r->render+E.coloff;\n            unsigned char *hl = r->hl+E.coloff;\n            int j;\n            for (j = 0; j < len; j++) {\n                if (hl[j] == HL_NONPRINT) {\n                    char sym;\n                    abAppend(&ab,\"\\x1b[7m\",4);\n                    if (c[j] <= 26)\n                        sym = '@'+c[j];\n                    else\n                        sym = '?';\n                    abAppend(&ab,&sym,1);\n                    abAppend(&ab,\"\\x1b[0m\",4);\n                } else if (hl[j] == HL_NORMAL) {\n                    if (current_color != -1) {\n                        abAppend(&ab,\"\\x1b[39m\",5);\n                        current_color = -1;\n                    }\n                    abAppend(&ab,c+j,1);\n                } else {\n                    int color = editorSyntaxToColor(hl[j]);\n                    if (color != current_color) {\n                        char buf[16];\n                        int clen = snprintf(buf,sizeof(buf),\"\\x1b[%dm\",color);\n                        current_color = color;\n                        abAppend(&ab,buf,clen);\n                    }\n                    abAppend(&ab,c+j,1);\n                }\n            }\n        }\n        abAppend(&ab,\"\\x1b[39m\",5);\n        abAppend(&ab,\"\\x1b[0K\",4);\n        abAppend(&ab,\"\\r\\n\",2);\n    }\n\n    /* Create a two rows status. First row: */\n    abAppend(&ab,\"\\x1b[0K\",4);\n    abAppend(&ab,\"\\x1b[7m\",4);\n    char status[80], rstatus[80];\n    int len = snprintf(status, sizeof(status), \"%.20s - %d lines %s\",\n        E.filename, E.numrows, E.dirty ? \"(modified)\" : \"\");\n    int rlen = snprintf(rstatus, sizeof(rstatus),\n        \"%d/%d\",E.rowoff+E.cy+1,E.numrows);\n    if (len > E.screencols) len = E.screencols;\n    abAppend(&ab,status,len);\n    while(len < E.screencols) {\n        if (E.screencols - len == rlen) {\n            abAppend(&ab,rstatus,rlen);\n            break;\n        } else {\n            abAppend(&ab,\" \",1);\n            len++;\n        }\n    }\n    abAppend(&ab,\"\\x1b[0m\\r\\n\",6);\n\n    /* Second row depends on E.statusmsg and the status message update time. */\n    abAppend(&ab,\"\\x1b[0K\",4);\n    int msglen = strlen(E.statusmsg);\n    if (msglen && time(NULL)-E.statusmsg_time < 5)\n        abAppend(&ab,E.statusmsg,msglen <= E.screencols ? msglen : E.screencols);\n\n    /* Put cursor at its current position. Note that the horizontal position\n     * at which the cursor is displayed may be different compared to 'E.cx'\n     * because of TABs. */\n    int j;\n    int cx = 1;\n    int filerow = E.rowoff+E.cy;\n    erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];\n    if (row) {\n        for (j = E.coloff; j < (E.cx+E.coloff); j++) {\n            if (j < row->size && row->chars[j] == TAB) cx += 7-((cx)%8);\n            cx++;\n        }\n    }\n    snprintf(buf,sizeof(buf),\"\\x1b[%d;%dH\",E.cy+1,cx);\n    abAppend(&ab,buf,strlen(buf));\n    abAppend(&ab,\"\\x1b[?25h\",6); /* Show cursor. */\n    write(STDOUT_FILENO,ab.b,ab.len);\n    abFree(&ab);\n}\n\n/* Set an editor status message for the second line of the status, at the\n * end of the screen. */\nvoid editorSetStatusMessage(const char *fmt, ...) {\n    va_list ap;\n    va_start(ap,fmt);\n    vsnprintf(E.statusmsg,sizeof(E.statusmsg),fmt,ap);\n    va_end(ap);\n    E.statusmsg_time = time(NULL);\n}\n\n/* =============================== Find mode ================================ */\n\n#define KILO_QUERY_LEN 256\n\nvoid editorFind(int fd) {\n    char query[KILO_QUERY_LEN+1] = {0};\n    int qlen = 0;\n    int last_match = -1; /* Last line where a match was found. -1 for none. */\n    int find_next = 0; /* if 1 search next, if -1 search prev. */\n    int saved_hl_line = -1;  /* No saved HL */\n    char *saved_hl = NULL;\n\n#define FIND_RESTORE_HL do { \\\n    if (saved_hl) { \\\n        memcpy(E.row[saved_hl_line].hl,saved_hl, E.row[saved_hl_line].rsize); \\\n        saved_hl = NULL; \\\n    } \\\n} while (0)\n\n    /* Save the cursor position in order to restore it later. */\n    int saved_cx = E.cx, saved_cy = E.cy;\n    int saved_coloff = E.coloff, saved_rowoff = E.rowoff;\n\n    while(1) {\n        editorSetStatusMessage(\n            \"Search: %s (Use ESC/Arrows/Enter)\", query);\n        editorRefreshScreen();\n\n        int c = editorReadKey(fd);\n        if (c == DEL_KEY || c == CTRL_H || c == BACKSPACE) {\n            if (qlen != 0) query[--qlen] = '\\0';\n            last_match = -1;\n        } else if (c == ESC || c == ENTER) {\n            if (c == ESC) {\n                E.cx = saved_cx; E.cy = saved_cy;\n                E.coloff = saved_coloff; E.rowoff = saved_rowoff;\n            }\n            FIND_RESTORE_HL;\n            editorSetStatusMessage(\"\");\n            return;\n        } else if (c == ARROW_RIGHT || c == ARROW_DOWN) {\n            find_next = 1;\n        } else if (c == ARROW_LEFT || c == ARROW_UP) {\n            find_next = -1;\n        } else if (isprint(c)) {\n            if (qlen < KILO_QUERY_LEN) {\n                query[qlen++] = c;\n                query[qlen] = '\\0';\n                last_match = -1;\n            }\n        }\n\n        /* Search occurrence. */\n        if (last_match == -1) find_next = 1;\n        if (find_next) {\n            char *match = NULL;\n            int match_offset = 0;\n            int i, current = last_match;\n\n            for (i = 0; i < E.numrows; i++) {\n                current += find_next;\n                if (current == -1) current = E.numrows-1;\n                else if (current == E.numrows) current = 0;\n                match = strstr(E.row[current].render,query);\n                if (match) {\n                    match_offset = match-E.row[current].render;\n                    break;\n                }\n            }\n            find_next = 0;\n\n            /* Highlight */\n            FIND_RESTORE_HL;\n\n            if (match) {\n                erow *row = &E.row[current];\n                last_match = current;\n                if (row->hl) {\n                    saved_hl_line = current;\n                    saved_hl = malloc(row->rsize);\n                    memcpy(saved_hl,row->hl,row->rsize);\n                    memset(row->hl+match_offset,HL_MATCH,qlen);\n                }\n                E.cy = 0;\n                E.cx = match_offset;\n                E.rowoff = current;\n                E.coloff = 0;\n                /* Scroll horizontally as needed. */\n                if (E.cx > E.screencols) {\n                    int diff = E.cx - E.screencols;\n                    E.cx -= diff;\n                    E.coloff += diff;\n                }\n            }\n        }\n    }\n}\n\n/* ========================= Editor events handling  ======================== */\n\n/* Handle cursor position change because arrow keys were pressed. */\nvoid editorMoveCursor(int key) {\n    int filerow = E.rowoff+E.cy;\n    int filecol = E.coloff+E.cx;\n    int rowlen;\n    erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];\n\n    switch(key) {\n    case ARROW_LEFT:\n        if (E.cx == 0) {\n            if (E.coloff) {\n                E.coloff--;\n            } else {\n                if (filerow > 0) {\n                    E.cy--;\n                    E.cx = E.row[filerow-1].size;\n                    if (E.cx > E.screencols-1) {\n                        E.coloff = E.cx-E.screencols+1;\n                        E.cx = E.screencols-1;\n                    }\n                }\n            }\n        } else {\n            E.cx -= 1;\n        }\n        break;\n    case ARROW_RIGHT:\n        if (row && filecol < row->size) {\n            if (E.cx == E.screencols-1) {\n                E.coloff++;\n            } else {\n                E.cx += 1;\n            }\n        } else if (row && filecol == row->size) {\n            E.cx = 0;\n            E.coloff = 0;\n            if (E.cy == E.screenrows-1) {\n                E.rowoff++;\n            } else {\n                E.cy += 1;\n            }\n        }\n        break;\n    case ARROW_UP:\n        if (E.cy == 0) {\n            if (E.rowoff) E.rowoff--;\n        } else {\n            E.cy -= 1;\n        }\n        break;\n    case ARROW_DOWN:\n        if (filerow < E.numrows) {\n            if (E.cy == E.screenrows-1) {\n                E.rowoff++;\n            } else {\n                E.cy += 1;\n            }\n        }\n        break;\n    }\n    /* Fix cx if the current line has not enough chars. */\n    filerow = E.rowoff+E.cy;\n    filecol = E.coloff+E.cx;\n    row = (filerow >= E.numrows) ? NULL : &E.row[filerow];\n    rowlen = row ? row->size : 0;\n    if (filecol > rowlen) {\n        E.cx -= filecol-rowlen;\n        if (E.cx < 0) {\n            E.coloff += E.cx;\n            E.cx = 0;\n        }\n    }\n}\n\n/* Process events arriving from the standard input, which is, the user\n * is typing stuff on the terminal. */\n#define KILO_QUIT_TIMES 3\nvoid editorProcessKeypress(int fd) {\n    /* When the file is modified, requires Ctrl-q to be pressed N times\n     * before actually quitting. */\n    static int quit_times = KILO_QUIT_TIMES;\n\n    int c = editorReadKey(fd);\n    switch(c) {\n    case ENTER:         /* Enter */\n        editorInsertNewline();\n        break;\n    case CTRL_C:        /* Ctrl-c */\n        /* We ignore ctrl-c, it can't be so simple to lose the changes\n         * to the edited file. */\n        break;\n    case CTRL_Q:        /* Ctrl-q */\n        /* Quit if the file was already saved. */\n        if (E.dirty && quit_times) {\n            editorSetStatusMessage(\"WARNING!!! File has unsaved changes. \"\n                \"Press Ctrl-Q %d more times to quit.\", quit_times);\n            quit_times--;\n            return;\n        }\n        exit(0);\n        break;\n    case CTRL_S:        /* Ctrl-s */\n        editorSave();\n        break;\n    case CTRL_F:\n        editorFind(fd);\n        break;\n    case BACKSPACE:     /* Backspace */\n    case CTRL_H:        /* Ctrl-h */\n    case DEL_KEY:\n        editorDelChar();\n        break;\n    case PAGE_UP:\n    case PAGE_DOWN:\n        if (c == PAGE_UP && E.cy != 0)\n            E.cy = 0;\n        else if (c == PAGE_DOWN && E.cy != E.screenrows-1)\n            E.cy = E.screenrows-1;\n        {\n        int times = E.screenrows;\n        while(times--)\n            editorMoveCursor(c == PAGE_UP ? ARROW_UP:\n                                            ARROW_DOWN);\n        }\n        break;\n\n    case ARROW_UP:\n    case ARROW_DOWN:\n    case ARROW_LEFT:\n    case ARROW_RIGHT:\n        editorMoveCursor(c);\n        break;\n    case CTRL_L: /* ctrl+l, clear screen */\n        /* Just refresht the line as side effect. */\n        break;\n    case ESC:\n        /* Nothing to do for ESC in this mode. */\n        break;\n    default:\n        editorInsertChar(c);\n        break;\n    }\n\n    quit_times = KILO_QUIT_TIMES; /* Reset it to the original value. */\n}\n\nint editorFileWasModified(void) {\n    return E.dirty;\n}\n\nvoid initEditor(void) {\n    E.cx = 0;\n    E.cy = 0;\n    E.rowoff = 0;\n    E.coloff = 0;\n    E.numrows = 0;\n    E.row = NULL;\n    E.dirty = 0;\n    E.filename = NULL;\n    E.syntax = NULL;\n    if (getWindowSize(STDIN_FILENO,STDOUT_FILENO,\n                      &E.screenrows,&E.screencols) == -1)\n    {\n        perror(\"Unable to query the screen for size (columns / rows)\");\n        exit(1);\n    }\n    E.screenrows -= 2; /* Get room for status bar. */\n}\n\nint main(int argc, char **argv) {\n    if (argc != 2) {\n        fprintf(stderr,\"Usage: kilo <filename>\\n\");\n        exit(1);\n    }\n\n    initEditor();\n    editorSelectSyntaxHighlight(argv[1]);\n    editorOpen(argv[1]);\n    enableRawMode(STDIN_FILENO);\n    editorSetStatusMessage(\n        \"HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find\");\n    while(1) {\n        editorRefreshScreen();\n        editorProcessKeypress(STDIN_FILENO);\n    }\n    return 0;\n}\n"
  },
  {
    "path": "system/scripts/gen.pl",
    "content": "my $dir_name = $ENV{'PWD'};\n$dir_name =~ s/\\S*\\///g;\n\nprint \"include Build.mk\\n\";\nprint 'all: builtin.o $(elf)', \"\\n\";\n\nprint 'builtin.o: $(obj-y) $(dirs-y)', \"\\n\";\nprint \"\\t\", '@echo -e \"  LD      \" ', \"builtin.o;\\n\\t\",\n\t\t'@$(LD) $(LDFLAGS) -r $(obj-y) $(patsubst %/,%/builtin.o, $(dirs-y)) -o builtin.o; ', \"\\n\";\n\nprint '.PHONY: $(dirs-y)', \"\\n\";\nprint '$(dirs-y): $(patsubst %/,%/Makefile, $(dirs-y))', \"\\n\";\nprint \"\\t\", '@echo -e \"  MK      \" $@', \"\\n\\t\", '@$(MAKE) -C $@ $(param)', \"\\n\";\n\nprint '$(patsubst %/,%/Makefile, $(dirs-y)): $(patsubst %/,%/Build.mk, $(dirs-y))', \"\\n\";\nprint \"\\t\", '@echo -e \"  PL      \" Makefile', \"\\n\\t\", '@cd $(dir $@) && $(PERL) $(PDIR)/scripts/gen.pl > Makefile', \"\\n\";\n\nprint \"%.o:%.c\\n\", \"\\t\", '@echo -e \"  CC      \" $@;', \"\\n\\t\", '@ $(CC) $(CFLAGS) -c $< -o $@', \"\\n\";\nprint \"%.o:%.S\\n\", \"\\t\", '@echo -e \"  AS      \" $@;', \"\\n\\t\", '@ $(AS) $(ASFLAGS) -c $< -o $@', \"\\n\";\nprint \"%.elf:\\n\", \"\\t\",  '@echo -e \"  ELF     \" $@;', \"\\n\\t\", '@ $(CC) $(CFLAGS) -Wl,-Tlink.ld -lgcc -o $@', \"\\n\";\n\nprint '.PHONY: clean', \"\\n\", 'clean: param = clean', \"\\n\", 'clean: $(dirs-y)', \"\\n\\t\",\n\t'$(RM) $(obj-y) $(elf)', \" builtin.o\\n\";\n\nprint \".PHONY: distclean\\n\", \"distclean: param = distclean\\n\", 'distclean: $(dirs-y) clean', \"\\n\\t\",\n\t'$(RM) Makefile', \"\\n\";\n"
  }
]