├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── crc32.c ├── crc32.h ├── portable_endian.h ├── tl-parser-tree.h ├── tl-parser.c ├── tl-parser.h ├── tl-tl.h ├── tlc.c ├── wgetopt.c └── wgetopt.h /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | config.h 3 | dep 4 | objs 5 | bin 6 | autom4te.cache 7 | config.log 8 | config.status 9 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0 FATAL_ERROR) 2 | project(tl-parser LANGUAGES C) 3 | 4 | set(SOURCES crc32.h crc32.c tlc.c tl-parser.c tl-parser.h tl-parser-tree.h tl-tl.h portable_endian.h) 5 | 6 | if (WIN32) 7 | add_definitions("-D_CRT_SECURE_NO_WARNINGS") 8 | list(APPEND SOURCES wgetopt.c wgetopt.h) 9 | if (MSVC) 10 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8") 11 | endif() 12 | endif() 13 | 14 | add_executable(${PROJECT_NAME} ${SOURCES}) 15 | if (NOT WIN32) 16 | target_link_libraries(${PROJECT_NAME} m) 17 | endif() 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Parse tl scheme to tlo file. Formely part of telegram-cli 2 | -------------------------------------------------------------------------------- /crc32.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of VK/KittenPHP-DB-Engine Library. 3 | 4 | VK/KittenPHP-DB-Engine Library is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | VK/KittenPHP-DB-Engine Library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with VK/KittenPHP-DB-Engine Library. If not, see . 16 | 17 | Copyright 2009-2012 Vkontakte Ltd 18 | 2009-2012 Nikolai Durov 19 | 2009-2012 Andrei Lopatin 20 | 2012 Anton Maydell 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "crc32.h" 28 | 29 | unsigned int crc32_table[256] = 30 | { 31 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 32 | 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 33 | 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 34 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 35 | 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 36 | 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 37 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 38 | 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 39 | 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 40 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 41 | 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 42 | 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 43 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 44 | 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 45 | 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 46 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 47 | 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 48 | 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 49 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 50 | 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 51 | 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 52 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 53 | 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 54 | 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 55 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 56 | 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 57 | 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 58 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 59 | 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 60 | 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 61 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 62 | 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 63 | 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 64 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 65 | 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 66 | 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 67 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 68 | 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 69 | 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 70 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 71 | 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 72 | 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 73 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 74 | 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 75 | 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 76 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 77 | 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 78 | 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 79 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 80 | 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 81 | 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 82 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 83 | 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 84 | 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 85 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 86 | 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 87 | 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 88 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 89 | 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 90 | 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 91 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 92 | 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 93 | 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 94 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 95 | }; 96 | 97 | unsigned int crc32_table2[256] = 98 | { 99 | 0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 100 | 0x646cc504, 0x7d77f445, 0x565aa786, 0x4f4196c7, 101 | 0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, 102 | 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf, 103 | 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, 104 | 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 105 | 0x821b9859, 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 106 | 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, 0xcd5a0e9e, 107 | 0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, 108 | 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, 109 | 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 110 | 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d, 111 | 0xdf4636f3, 0xc65d07b2, 0xed705471, 0xf46b6530, 112 | 0xbb2af3f7, 0xa231c2b6, 0x891c9175, 0x9007a034, 113 | 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, 114 | 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 115 | 0xf0794f05, 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 116 | 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2, 117 | 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, 0x138d96ce, 118 | 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, 119 | 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 120 | 0xded79850, 0xc7cca911, 0xece1fad2, 0xf5facb93, 121 | 0x7262d75c, 0x6b79e61d, 0x4054b5de, 0x594f849f, 122 | 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b, 123 | 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, 124 | 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 125 | 0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 126 | 0xc94824ab, 0xd05315ea, 0xfb7e4629, 0xe2657768, 127 | 0x2f3f79f6, 0x362448b7, 0x1d091b74, 0x04122a35, 128 | 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, 129 | 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 130 | 0x838a36fa, 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 131 | 0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, 132 | 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c, 133 | 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, 134 | 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 135 | 0x71418a1a, 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 136 | 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, 0x3e001cdd, 137 | 0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, 138 | 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, 139 | 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 140 | 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 141 | 0x66de36e1, 0x7fc507a0, 0x54e85463, 0x4df36522, 142 | 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, 0x299fa026, 143 | 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, 144 | 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 145 | 0x2c1c24b0, 0x350715f1, 0x1e2a4632, 0x07317773, 146 | 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277, 147 | 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, 148 | 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, 149 | 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 150 | 0x674f9842, 0x7e54a903, 0x5579fac0, 0x4c62cb81, 151 | 0x8138c51f, 0x9823f45e, 0xb30ea79d, 0xaa1596dc, 152 | 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8, 153 | 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, 154 | 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 155 | 0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, 156 | 0x3a1236e8, 0x230907a9, 0x0824546a, 0x113f652b, 157 | 0x96a779e4, 0x8fbc48a5, 0xa4911b66, 0xbd8a2a27, 158 | 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, 159 | 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 160 | 0x70d024b9, 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 161 | 0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, 162 | 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, 0x9324fd72, 163 | }; 164 | 165 | unsigned int crc32_table1[256] = 166 | { 167 | 0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 168 | 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 169 | 0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, 170 | 0x091af964, 0x08d89353, 0x0a9e2d0a, 0x0b5c473d, 171 | 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, 172 | 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 173 | 0x1235f2c8, 0x13f798ff, 0x11b126a6, 0x10734c91, 174 | 0x153c5a14, 0x14fe3023, 0x16b88e7a, 0x177ae44d, 175 | 0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, 176 | 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, 177 | 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 178 | 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd, 179 | 0x246be590, 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, 180 | 0x23624d4c, 0x22a0277b, 0x20e69922, 0x2124f315, 181 | 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, 182 | 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 183 | 0x709a8dc0, 0x7158e7f7, 0x731e59ae, 0x72dc3399, 184 | 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45, 185 | 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, 186 | 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, 187 | 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 188 | 0x6bb5866c, 0x6a77ec5b, 0x68315202, 0x69f33835, 189 | 0x62af7f08, 0x636d153f, 0x612bab66, 0x60e9c151, 190 | 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d, 191 | 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, 192 | 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 193 | 0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, 194 | 0x41cd3244, 0x400f5873, 0x4249e62a, 0x438b8c1d, 195 | 0x54f16850, 0x55330267, 0x5775bc3e, 0x56b7d609, 196 | 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, 197 | 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 198 | 0x5deb9134, 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 199 | 0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, 200 | 0xe63cb35c, 0xe7fed96b, 0xe5b86732, 0xe47a0d05, 201 | 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, 202 | 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 203 | 0xfd13b8f0, 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 204 | 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, 0xf85cae75, 205 | 0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, 206 | 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, 207 | 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 208 | 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 209 | 0xd76b0cd8, 0xd6a966ef, 0xd4efd8b6, 0xd52db281, 210 | 0xd062a404, 0xd1a0ce33, 0xd3e6706a, 0xd2241a5d, 211 | 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, 212 | 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 213 | 0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 214 | 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d, 215 | 0x91af9640, 0x906dfc77, 0x922b422e, 0x93e92819, 216 | 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, 217 | 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 218 | 0x98b56f24, 0x99770513, 0x9b31bb4a, 0x9af3d17d, 219 | 0x8d893530, 0x8c4b5f07, 0x8e0de15e, 0x8fcf8b69, 220 | 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5, 221 | 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, 222 | 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 223 | 0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 224 | 0xaeeb787c, 0xaf29124b, 0xad6fac12, 0xacadc625, 225 | 0xa7f18118, 0xa633eb2f, 0xa4755576, 0xa5b73f41, 226 | 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, 227 | 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 228 | 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, 0xb08b6555, 229 | 0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, 230 | 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed, 231 | }; 232 | 233 | unsigned int crc32_table0[256] = { 234 | 0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 235 | 0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9, 236 | 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, 237 | 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, 0x58631056, 238 | 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, 239 | 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 240 | 0x95ad7f70, 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 241 | 0x1acfe827, 0xa2738f42, 0xb0c620ac, 0x087a47c9, 242 | 0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, 243 | 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, 244 | 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 245 | 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68, 246 | 0xf02bf8a1, 0x48979fc4, 0x5a22302a, 0xe29e574f, 247 | 0x7f496ff6, 0xc7f50893, 0xd540a77d, 0x6dfcc018, 248 | 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, 249 | 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 250 | 0x9b14583d, 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 251 | 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084, 252 | 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, 253 | 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, 254 | 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 255 | 0x446f98f5, 0xfcd3ff90, 0xee66507e, 0x56da371b, 256 | 0x0eb9274d, 0xb6054028, 0xa4b0efc6, 0x1c0c88a3, 257 | 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4, 258 | 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, 259 | 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 260 | 0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, 261 | 0x71f048bb, 0xc94c2fde, 0xdbf98030, 0x6345e755, 262 | 0x6b3fa09c, 0xd383c7f9, 0xc1366817, 0x798a0f72, 263 | 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, 264 | 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 265 | 0x21e91f24, 0x99557841, 0x8be0d7af, 0x335cb0ca, 266 | 0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, 267 | 0x623b216c, 0xda874609, 0xc832e9e7, 0x708e8e82, 268 | 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, 269 | 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 270 | 0xbd40e1a4, 0x05fc86c1, 0x1749292f, 0xaff54e4a, 271 | 0x322276f3, 0x8a9e1196, 0x982bbe78, 0x2097d91d, 272 | 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, 273 | 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, 274 | 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 275 | 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 276 | 0x88df31ea, 0x3063568f, 0x22d6f961, 0x9a6a9e04, 277 | 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, 0x15080953, 278 | 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, 279 | 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 280 | 0xd8c66675, 0x607a0110, 0x72cfaefe, 0xca73c99b, 281 | 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc, 282 | 0x764dee06, 0xcef18963, 0xdc44268d, 0x64f841e8, 283 | 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, 284 | 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 285 | 0x3c9b51be, 0x842736db, 0x96929935, 0x2e2efe50, 286 | 0x2654b999, 0x9ee8defc, 0x8c5d7112, 0x34e11677, 287 | 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120, 288 | 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, 289 | 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 290 | 0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 291 | 0x591dd66f, 0xe1a1b10a, 0xf3141ee4, 0x4ba87981, 292 | 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, 0x017ec639, 293 | 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, 294 | 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 295 | 0x090481f0, 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 296 | 0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, 297 | 0xccb0a91f, 0x740cce7a, 0x66b96194, 0xde0506f1, 298 | }; 299 | 300 | static unsigned int crc32_partial (const void *data, int len, unsigned crc) { 301 | const int *p = (const int *) data; 302 | int x; 303 | #define DO_ONE(v) crc ^= v; crc = crc32_table0[crc & 0xff] ^ crc32_table1[(crc & 0xff00) >> 8] ^ crc32_table2[(crc & 0xff0000) >> 16] ^ crc32_table[crc >> 24]; 304 | #define DO_FOUR(p) DO_ONE((p)[0]); DO_ONE((p)[1]); DO_ONE((p)[2]); DO_ONE((p)[3]); 305 | 306 | for (x = (len >> 5); x > 0; x--) { 307 | DO_FOUR (p); 308 | DO_FOUR (p + 4); 309 | p += 8; 310 | } 311 | if (len & 16) { 312 | DO_FOUR (p); 313 | p += 4; 314 | } 315 | if (len & 8) { 316 | DO_ONE (p[0]); 317 | DO_ONE (p[1]); 318 | p += 2; 319 | } 320 | if (len & 4) { 321 | DO_ONE (*p++); 322 | } 323 | /* 324 | for (x = (len >> 2) & 7; x > 0; x--) { 325 | DO_ONE (*p++); 326 | } 327 | */ 328 | #undef DO_ONE 329 | #undef DO_FOUR 330 | const char *q = (const char *) p; 331 | if (len & 2) { 332 | crc = crc32_table[(crc ^ q[0]) & 0xff] ^ (crc >> 8); 333 | crc = crc32_table[(crc ^ q[1]) & 0xff] ^ (crc >> 8); 334 | q += 2; 335 | } 336 | if (len & 1) { 337 | crc = crc32_table[(crc ^ *q++) & 0xff] ^ (crc >> 8); 338 | } 339 | return crc; 340 | } 341 | 342 | unsigned int compute_crc32 (const void *data, int len) { 343 | return crc32_partial (data, len, -1) ^ -1; 344 | } 345 | 346 | -------------------------------------------------------------------------------- /crc32.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of VK/KittenPHP-DB-Engine Library. 3 | 4 | VK/KittenPHP-DB-Engine Library is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | VK/KittenPHP-DB-Engine Library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with VK/KittenPHP-DB-Engine Library. If not, see . 16 | 17 | Copyright 2009-2012 Vkontakte Ltd 18 | 2009-2012 Nikolai Durov 19 | 2009-2012 Andrei Lopatin 20 | 2012 Anton Maydell 21 | */ 22 | 23 | #ifndef __CRC32_H__ 24 | #define __CRC32_H__ 25 | 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | unsigned int compute_crc32 (const void *data, int len); 32 | 33 | #ifdef __cplusplus 34 | } 35 | #endif 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /portable_endian.h: -------------------------------------------------------------------------------- 1 | // "License": Public Domain 2 | // I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like. 3 | // In case there are jurisdictions that don't support putting things in the public domain you can also consider it to 4 | // be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it 5 | // an example on how to get the endian conversion functions on different platforms. 6 | 7 | /* Originally cloned from https://gist.github.com/PkmX/63dd23f28ba885be53a5 8 | * Commit was: 1eca2ab34f2301b9641aa73d1016b951fff3fc39 9 | * Re-published at https://github.com/BenWiederhake/portable-endian.h to provide a means to submit patches and report issues. */ 10 | 11 | #ifndef PORTABLE_ENDIAN_H__ 12 | #define PORTABLE_ENDIAN_H__ 13 | 14 | #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) 15 | 16 | # define __WINDOWS__ 17 | 18 | #endif 19 | 20 | #if defined(__linux__) || defined(__CYGWIN__) 21 | 22 | # include 23 | 24 | #elif defined(__APPLE__) 25 | 26 | # include 27 | 28 | # define htobe16(x) OSSwapHostToBigInt16(x) 29 | # define htole16(x) OSSwapHostToLittleInt16(x) 30 | # define be16toh(x) OSSwapBigToHostInt16(x) 31 | # define le16toh(x) OSSwapLittleToHostInt16(x) 32 | 33 | # define htobe32(x) OSSwapHostToBigInt32(x) 34 | # define htole32(x) OSSwapHostToLittleInt32(x) 35 | # define be32toh(x) OSSwapBigToHostInt32(x) 36 | # define le32toh(x) OSSwapLittleToHostInt32(x) 37 | 38 | # define htobe64(x) OSSwapHostToBigInt64(x) 39 | # define htole64(x) OSSwapHostToLittleInt64(x) 40 | # define be64toh(x) OSSwapBigToHostInt64(x) 41 | # define le64toh(x) OSSwapLittleToHostInt64(x) 42 | 43 | # define __BYTE_ORDER BYTE_ORDER 44 | # define __BIG_ENDIAN BIG_ENDIAN 45 | # define __LITTLE_ENDIAN LITTLE_ENDIAN 46 | # define __PDP_ENDIAN PDP_ENDIAN 47 | 48 | #elif defined(__OpenBSD__) 49 | 50 | # include 51 | 52 | #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) 53 | 54 | # include 55 | 56 | # define be16toh(x) betoh16(x) 57 | # define le16toh(x) letoh16(x) 58 | 59 | # define be32toh(x) betoh32(x) 60 | # define le32toh(x) letoh32(x) 61 | 62 | # define be64toh(x) betoh64(x) 63 | # define le64toh(x) letoh64(x) 64 | 65 | #elif defined(__WINDOWS__) 66 | 67 | # include 68 | #ifdef __MINGW32__ 69 | # include 70 | #endif 71 | 72 | # if BYTE_ORDER == LITTLE_ENDIAN 73 | 74 | # define htobe16(x) htons(x) 75 | # define htole16(x) (x) 76 | # define be16toh(x) ntohs(x) 77 | # define le16toh(x) (x) 78 | 79 | # define htobe32(x) htonl(x) 80 | # define htole32(x) (x) 81 | # define be32toh(x) ntohl(x) 82 | # define le32toh(x) (x) 83 | 84 | # define htobe64(x) htonll(x) 85 | # define htole64(x) (x) 86 | # define be64toh(x) ntohll(x) 87 | # define le64toh(x) (x) 88 | 89 | # elif BYTE_ORDER == BIG_ENDIAN 90 | 91 | /* that would be xbox 360 */ 92 | # define htobe16(x) (x) 93 | # define htole16(x) __builtin_bswap16(x) 94 | # define be16toh(x) (x) 95 | # define le16toh(x) __builtin_bswap16(x) 96 | 97 | # define htobe32(x) (x) 98 | # define htole32(x) __builtin_bswap32(x) 99 | # define be32toh(x) (x) 100 | # define le32toh(x) __builtin_bswap32(x) 101 | 102 | # define htobe64(x) (x) 103 | # define htole64(x) __builtin_bswap64(x) 104 | # define be64toh(x) (x) 105 | # define le64toh(x) __builtin_bswap64(x) 106 | 107 | # else 108 | 109 | # error byte order not supported 110 | 111 | # endif 112 | 113 | # define __BYTE_ORDER BYTE_ORDER 114 | # define __BIG_ENDIAN BIG_ENDIAN 115 | # define __LITTLE_ENDIAN LITTLE_ENDIAN 116 | # define __PDP_ENDIAN PDP_ENDIAN 117 | 118 | #else 119 | 120 | # error platform not supported 121 | 122 | #endif 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /tl-parser-tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of tgl-library 3 | 4 | This library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either 7 | version 2.1 of the License, or (at your option) any later version. 8 | 9 | This library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this library; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | 18 | Copyright Vitaly Valtman 2013-2014 19 | */ 20 | #ifndef __TREE_H__ 21 | #define __TREE_H__ 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #pragma pack(push,4) 28 | #define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \ 29 | struct tree_ ## X_NAME { \ 30 | struct tree_ ## X_NAME *left, *right;\ 31 | X_TYPE x;\ 32 | int y;\ 33 | };\ 34 | \ 35 | static struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\ 36 | struct tree_ ## X_NAME *T = malloc (sizeof (*T));\ 37 | T->x = x;\ 38 | T->y = y;\ 39 | T->left = T->right = 0;\ 40 | return T;\ 41 | }\ 42 | \ 43 | static void delete_tree_node_ ## X_NAME (struct tree_ ## X_NAME *T) {\ 44 | free (T);\ 45 | }\ 46 | \ 47 | static void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## X_NAME **L, struct tree_ ## X_NAME **R) {\ 48 | if (!T) {\ 49 | *L = *R = 0;\ 50 | } else {\ 51 | int c = X_CMP (x, T->x);\ 52 | if (c < 0) {\ 53 | tree_split_ ## X_NAME (T->left, x, L, &T->left);\ 54 | *R = T;\ 55 | } else {\ 56 | tree_split_ ## X_NAME (T->right, x, &T->right, R);\ 57 | *L = T;\ 58 | }\ 59 | }\ 60 | }\ 61 | \ 62 | static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) __attribute__ ((warn_unused_result,unused));\ 63 | static struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) {\ 64 | if (!T) {\ 65 | return new_tree_node_ ## X_NAME (x, y);\ 66 | } else {\ 67 | if (y > T->y) {\ 68 | struct tree_ ## X_NAME *N = new_tree_node_ ## X_NAME (x, y);\ 69 | tree_split_ ## X_NAME (T, x, &N->left, &N->right);\ 70 | return N;\ 71 | } else {\ 72 | int c = X_CMP (x, T->x);\ 73 | assert (c);\ 74 | if (c < 0) { \ 75 | T->left = tree_insert_ ## X_NAME (T->left, x, y);\ 76 | } else { \ 77 | T->right = tree_insert_ ## X_NAME (T->right, x, y);\ 78 | } \ 79 | return T; \ 80 | }\ 81 | }\ 82 | }\ 83 | \ 84 | static struct tree_ ## X_NAME *tree_merge_ ## X_NAME (struct tree_ ## X_NAME *L, struct tree_ ## X_NAME *R) {\ 85 | if (!L || !R) {\ 86 | return L ? L : R;\ 87 | } else {\ 88 | if (L->y > R->y) {\ 89 | L->right = tree_merge_ ## X_NAME (L->right, R);\ 90 | return L;\ 91 | } else {\ 92 | R->left = tree_merge_ ## X_NAME (L, R->left);\ 93 | return R;\ 94 | }\ 95 | }\ 96 | }\ 97 | \ 98 | static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((warn_unused_result,unused));\ 99 | static struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ 100 | assert (T);\ 101 | int c = X_CMP (x, T->x);\ 102 | if (!c) {\ 103 | struct tree_ ## X_NAME *N = tree_merge_ ## X_NAME (T->left, T->right);\ 104 | delete_tree_node_ ## X_NAME (T);\ 105 | return N;\ 106 | } else {\ 107 | if (c < 0) { \ 108 | T->left = tree_delete_ ## X_NAME (T->left, x); \ 109 | } else { \ 110 | T->right = tree_delete_ ## X_NAME (T->right, x); \ 111 | } \ 112 | return T; \ 113 | }\ 114 | }\ 115 | \ 116 | static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *t) __attribute__ ((unused));\ 117 | static X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *T) {\ 118 | if (!T) { return X_UNSET; } \ 119 | while (T->left) { T = T->left; }\ 120 | return T->x; \ 121 | } \ 122 | \ 123 | static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) __attribute__ ((unused));\ 124 | static X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\ 125 | int c;\ 126 | while (T && (c = X_CMP (x, T->x))) {\ 127 | T = (c < 0 ? T->left : T->right);\ 128 | }\ 129 | return T ? T->x : X_UNSET;\ 130 | }\ 131 | \ 132 | static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) __attribute__ ((unused));\ 133 | static void tree_act_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE)) {\ 134 | if (!T) { return; } \ 135 | tree_act_ ## X_NAME (T->left, act); \ 136 | act (T->x); \ 137 | tree_act_ ## X_NAME (T->right, act); \ 138 | }\ 139 | \ 140 | static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) __attribute__ ((unused));\ 141 | static void tree_act_ex_ ## X_NAME (struct tree_ ## X_NAME *T, void (*act)(X_TYPE, void *), void *extra) {\ 142 | if (!T) { return; } \ 143 | tree_act_ex_ ## X_NAME (T->left, act, extra); \ 144 | act (T->x, extra); \ 145 | tree_act_ex_ ## X_NAME (T->right, act, extra); \ 146 | }\ 147 | \ 148 | static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ 149 | static int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \ 150 | if (!T) { return 0; }\ 151 | return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \ 152 | }\ 153 | static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ 154 | static void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \ 155 | if (!T) { return; }\ 156 | if (T->left) { \ 157 | assert (T->left->y <= T->y);\ 158 | assert (X_CMP (T->left->x, T->x) < 0); \ 159 | }\ 160 | if (T->right) { \ 161 | assert (T->right->y <= T->y);\ 162 | assert (X_CMP (T->right->x, T->x) > 0); \ 163 | }\ 164 | tree_check_ ## X_NAME (T->left); \ 165 | tree_check_ ## X_NAME (T->right); \ 166 | }\ 167 | static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) __attribute__ ((unused));\ 168 | static struct tree_ ## X_NAME *tree_clear_ ## X_NAME (struct tree_ ## X_NAME *T) { \ 169 | if (!T) { return 0; }\ 170 | tree_clear_ ## X_NAME (T->left); \ 171 | tree_clear_ ## X_NAME (T->right); \ 172 | delete_tree_node_ ## X_NAME (T); \ 173 | return 0; \ 174 | } \ 175 | 176 | #define int_cmp(a,b) ((a) - (b)) 177 | #pragma pack(pop) 178 | #endif 179 | -------------------------------------------------------------------------------- /tl-parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of tl-parser 3 | 4 | tl-parser is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | tl-parser is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this tl-parser. If not, see . 16 | 17 | Copyright Vitaly Valtman 2014 18 | 19 | It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) 20 | Copyright 2012-2013 Vkontakte Ltd 21 | 2012-2013 Vitaliy Valtman 22 | 23 | */ 24 | 25 | #define _FILE_OFFSET_BITS 64 26 | 27 | #ifndef _WIN32 28 | #include 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include "portable_endian.h" 40 | #include "tl-parser-tree.h" 41 | #include "tl-parser.h" 42 | #include "crc32.h" 43 | #include "tl-tl.h" 44 | 45 | extern int verbosity; 46 | extern int schema_version; 47 | extern int output_expressions; 48 | 49 | 50 | int total_types_num; 51 | int total_constructors_num; 52 | int total_functions_num; 53 | 54 | 55 | /*char *tstrdup (const char *s) { 56 | assert (s); 57 | char *r = talloc (strlen (s) + 1); 58 | memcpy (r, s, strlen (s) + 1); 59 | return r; 60 | }*/ 61 | 62 | #define talloc(a) malloc(a) 63 | #define tfree(a,b) free (a) 64 | #define talloc0(a) calloc(a,1) 65 | #define tstrdup(a) strdup(a) 66 | 67 | typedef char error_int_must_be_4_byte[(sizeof (int) == 4) ? 1 : -1]; 68 | typedef char error_long_long_must_be_8_byte[(sizeof (long long) == 8) ? 1 : -1]; 69 | 70 | char curch; 71 | struct parse parse; 72 | 73 | struct tree *tree; 74 | 75 | struct tree *tree_alloc (void) { 76 | struct tree *T = talloc (sizeof (*T)); 77 | assert (T); 78 | memset (T, 0, sizeof (*T)); 79 | return T; 80 | } 81 | 82 | void tree_add_child (struct tree *P, struct tree *C) { 83 | if (P->nc == P->size) { 84 | void **t = talloc (sizeof (void *) * (++P->size)); 85 | memcpy (t, P->c, sizeof (void *) * (P->size - 1)); 86 | if (P->c) { 87 | tfree (P->c, sizeof (void *) * (P->size - 1)); 88 | } 89 | P->c = (void *)t; 90 | assert (P->c); 91 | } 92 | P->c[P->nc ++] = C; 93 | } 94 | 95 | void tree_delete (struct tree *T) { 96 | assert (T); 97 | int i; 98 | for (i = 0; i < T->nc; i++) { 99 | assert (T->c[i]); 100 | tree_delete (T->c[i]); 101 | } 102 | if (T->c) { 103 | tfree (T->c, sizeof (void *) * T->nc); 104 | } 105 | tfree (T, sizeof (*T)); 106 | } 107 | 108 | void tree_del_child (struct tree *P) { 109 | assert (P->nc); 110 | tree_delete (P->c[--P->nc]); 111 | } 112 | 113 | 114 | char nextch (void) { 115 | if (parse.pos < parse.len - 1) { 116 | curch = parse.text[++parse.pos]; 117 | } else { 118 | curch = 0; 119 | } 120 | if (curch == 10) { 121 | parse.line ++; 122 | parse.line_pos = 0; 123 | } else { 124 | if (curch) { 125 | parse.line_pos ++; 126 | } 127 | } 128 | return curch; 129 | } 130 | 131 | 132 | struct parse save_parse (void) { 133 | return parse; 134 | } 135 | 136 | void load_parse (struct parse _parse) { 137 | parse = _parse; 138 | curch = parse.pos > parse.len ? 0: parse.text[parse.pos] ; 139 | } 140 | 141 | int is_whitespace (char c) { 142 | return (c <= 32); 143 | } 144 | 145 | int is_uletter (char c) { 146 | return (c >= 'A' && c <= 'Z'); 147 | } 148 | 149 | int is_lletter (char c) { 150 | return (c >= 'a' && c <= 'z'); 151 | } 152 | 153 | int is_letter (char c) { 154 | return is_uletter (c) || is_lletter (c); 155 | } 156 | 157 | int is_digit (char c) { 158 | return (c >= '0' && c <= '9'); 159 | } 160 | 161 | int is_hexdigit (char c) { 162 | return is_digit (c) || (c >= 'a' && c <= 'f'); 163 | } 164 | 165 | int is_ident_char (char c) { 166 | return is_digit (c) || is_letter (c) || c == '_'; 167 | } 168 | 169 | int last_error_pos; 170 | int last_error_line; 171 | int last_error_line_pos; 172 | char *last_error; 173 | 174 | void parse_error (const char *e) { 175 | if (parse.pos > last_error_pos) { 176 | last_error_pos = parse.pos; 177 | last_error_line = parse.line; 178 | last_error_line_pos = parse.line_pos; 179 | if (last_error) { 180 | tfree (last_error, strlen (last_error) + 1); 181 | } 182 | last_error = tstrdup (e); 183 | } 184 | } 185 | 186 | void tl_print_parse_error (void) { 187 | fprintf (stderr, "Error near line %d pos %d: `%s`\n", last_error_line + 1, last_error_line_pos + 1, last_error); 188 | } 189 | 190 | char *parse_lex (void) { 191 | while (1) { 192 | while (curch && is_whitespace (curch)) { nextch (); } 193 | if (curch == '/' && nextch () == '/') { 194 | while (nextch () != 10); 195 | nextch (); 196 | } else { 197 | break; 198 | } 199 | } 200 | if (!curch) { 201 | parse.lex.len = 0; 202 | parse.lex.type = lex_eof; 203 | return (parse.lex.ptr = 0); 204 | } 205 | char *p = parse.text + parse.pos; 206 | parse.lex.flags = 0; 207 | switch (curch) { 208 | case '-': 209 | if (nextch () != '-' || nextch () != '-') { 210 | parse_error ("Can not parse triple minus"); 211 | parse.lex.type = lex_error; 212 | return (parse.lex.ptr = (void *)-1); 213 | } else { 214 | parse.lex.len = 3; 215 | parse.lex.type = lex_triple_minus; 216 | nextch (); 217 | return (parse.lex.ptr = p); 218 | } 219 | case ':': 220 | case ';': 221 | case '(': 222 | case ')': 223 | case '[': 224 | case ']': 225 | case '{': 226 | case '}': 227 | case '=': 228 | case '#': 229 | case '?': 230 | case '%': 231 | case '<': 232 | case '>': 233 | case '+': 234 | case ',': 235 | case '*': 236 | case '_': 237 | case '!': 238 | case '.': 239 | nextch (); 240 | parse.lex.len = 1; 241 | parse.lex.type = lex_char; 242 | return (parse.lex.ptr = p); 243 | case 'a': 244 | case 'b': 245 | case 'c': 246 | case 'd': 247 | case 'e': 248 | case 'f': 249 | case 'g': 250 | case 'h': 251 | case 'i': 252 | case 'j': 253 | case 'k': 254 | case 'l': 255 | case 'm': 256 | case 'n': 257 | case 'o': 258 | case 'p': 259 | case 'q': 260 | case 'r': 261 | case 's': 262 | case 't': 263 | case 'u': 264 | case 'v': 265 | case 'w': 266 | case 'x': 267 | case 'y': 268 | case 'z': 269 | case 'A': 270 | case 'B': 271 | case 'C': 272 | case 'D': 273 | case 'E': 274 | case 'F': 275 | case 'G': 276 | case 'H': 277 | case 'I': 278 | case 'J': 279 | case 'K': 280 | case 'L': 281 | case 'M': 282 | case 'N': 283 | case 'O': 284 | case 'P': 285 | case 'Q': 286 | case 'R': 287 | case 'S': 288 | case 'T': 289 | case 'U': 290 | case 'V': 291 | case 'W': 292 | case 'X': 293 | case 'Y': 294 | case 'Z': 295 | parse.lex.flags = 0; 296 | if (is_uletter (curch)) { 297 | while (is_ident_char (nextch ())); 298 | parse.lex.len = parse.text + parse.pos - p; 299 | parse.lex.ptr = p; 300 | if (parse.lex.len == 5 && !memcmp (parse.lex.ptr, "Final", 5)) { 301 | parse.lex.type = lex_final; 302 | } else if (parse.lex.len == 3 && !memcmp (parse.lex.ptr, "New", 3)) { 303 | parse.lex.type = lex_new; 304 | } else if (parse.lex.len == 5 && !memcmp (parse.lex.ptr, "Empty", 5)) { 305 | parse.lex.type = lex_empty; 306 | } else { 307 | parse.lex.type = lex_uc_ident; 308 | } 309 | return (parse.lex.ptr = p); 310 | } 311 | while (is_ident_char (nextch ())); 312 | if (curch == '.' && !is_letter (parse.text[parse.pos + 1])) { 313 | parse.lex.len = parse.text + parse.pos - p; 314 | parse.lex.type = lex_lc_ident; 315 | return (parse.lex.ptr = p); 316 | } 317 | while (curch == '.') { 318 | parse.lex.flags |= 1; 319 | nextch (); 320 | if (is_uletter (curch)) { 321 | while (is_ident_char (nextch ())); 322 | parse.lex.len = parse.text + parse.pos - p; 323 | parse.lex.type = lex_uc_ident; 324 | return (parse.lex.ptr = p); 325 | } 326 | if (is_lletter (curch)) { 327 | while (is_ident_char (nextch ())); 328 | } else { 329 | parse_error ("Expected letter"); 330 | parse.lex.type = lex_error; 331 | return (parse.lex.ptr = (void *)-1); 332 | } 333 | } 334 | if (curch == '#') { 335 | parse.lex.flags |= 2; 336 | int i; 337 | int ok = 1; 338 | for (i = 0; i < 8; i++) { 339 | if (!is_hexdigit (nextch())) { 340 | if (curch == ' ' && i >= 5) { 341 | ok = 2; 342 | break; 343 | } else { 344 | parse_error ("Hex digit expected"); 345 | parse.lex.type = lex_error; 346 | return (parse.lex.ptr = (void *)-1); 347 | } 348 | } 349 | } 350 | if (ok == 1) { 351 | nextch (); 352 | } 353 | } 354 | parse.lex.len = parse.text + parse.pos - p; 355 | parse.lex.type = lex_lc_ident; 356 | return (parse.lex.ptr = p); 357 | case '0': 358 | case '1': 359 | case '2': 360 | case '3': 361 | case '4': 362 | case '5': 363 | case '6': 364 | case '7': 365 | case '8': 366 | case '9': 367 | while (is_digit (nextch ())); 368 | parse.lex.len = parse.text + parse.pos - p; 369 | parse.lex.type = lex_num; 370 | return (parse.lex.ptr = p); 371 | default: 372 | parse_error ("Unknown lexem"); 373 | parse.lex.type = lex_error; 374 | return (parse.lex.ptr = (void *)-1); 375 | } 376 | 377 | } 378 | 379 | int expect (char *s) { 380 | if (!parse.lex.ptr || parse.lex.ptr == (void *)-1 || parse.lex.type == lex_error || parse.lex.type == lex_none || parse.lex.len != (int)strlen (s) || memcmp (s, parse.lex.ptr, parse.lex.len)) { 381 | static char buf[1000]; 382 | sprintf (buf, "Expected %s", s); 383 | parse_error (buf); 384 | return -1; 385 | } else { 386 | parse_lex (); 387 | } 388 | return 1; 389 | } 390 | 391 | struct parse *tl_init_parse_file (const char *fname) { 392 | int fd = open (fname, O_RDONLY); 393 | if (fd < 0) { 394 | fprintf (stderr, "Error %m\n"); 395 | assert (0); 396 | return 0; 397 | } 398 | long long size = lseek (fd, 0, SEEK_END); 399 | if (size <= 0) { 400 | fprintf (stderr, "size is %lld. Too small.\n", size); 401 | return 0; 402 | } 403 | static struct parse save; 404 | save.text = talloc (size); 405 | lseek (fd, 0, SEEK_SET); 406 | save.len = read (fd, save.text, size); 407 | assert (save.len == size); 408 | save.pos = 0; 409 | save.line = 0; 410 | save.line_pos = 0; 411 | save.lex.ptr = save.text; 412 | save.lex.len = 0; 413 | save.lex.type = lex_none; 414 | return &save; 415 | } 416 | 417 | #define PARSE_INIT(_type) struct parse save = save_parse (); struct tree *T = tree_alloc (); T->type = (_type); T->lex_line = parse.line; T->lex_line_pos = parse.line_pos; struct tree *S __attribute__ ((unused)); 418 | #define PARSE_FAIL load_parse (save); tree_delete (T); return 0; 419 | #define PARSE_OK return T; 420 | #define PARSE_TRY_PES(x) if (!(S = x ())) { PARSE_FAIL; } { tree_add_child (T, S); } 421 | #define PARSE_TRY_OPT(x) if ((S = x ())) { tree_add_child (T, S); PARSE_OK } 422 | #define PARSE_TRY(x) S = x (); 423 | #define PARSE_ADD(_type) S = tree_alloc (); S->type = _type; tree_add_child (T, S); 424 | #define EXPECT(s) if (expect (s) < 0) { PARSE_FAIL; } 425 | #define LEX_CHAR(c) (parse.lex.type == lex_char && *parse.lex.ptr == c) 426 | struct tree *parse_args (void); 427 | struct tree *parse_expr (void); 428 | 429 | struct tree *parse_boxed_type_ident (void) { 430 | PARSE_INIT (type_boxed_type_ident); 431 | if (parse.lex.type != lex_uc_ident) { 432 | parse_error ("Can not parse boxed type"); 433 | PARSE_FAIL; 434 | } else { 435 | T->text = parse.lex.ptr; 436 | T->len = parse.lex.len; 437 | T->flags = parse.lex.flags; 438 | parse_lex (); 439 | PARSE_OK; 440 | } 441 | } 442 | 443 | struct tree *parse_full_combinator_id (void) { 444 | PARSE_INIT (type_full_combinator_id); 445 | if (parse.lex.type == lex_lc_ident || LEX_CHAR('_')) { 446 | T->text = parse.lex.ptr; 447 | T->len = parse.lex.len; 448 | T->flags = parse.lex.flags; 449 | parse_lex (); 450 | PARSE_OK; 451 | } else { 452 | parse_error ("Can not parse full combinator id"); 453 | PARSE_FAIL; 454 | } 455 | } 456 | 457 | struct tree *parse_combinator_id (void) { 458 | PARSE_INIT (type_combinator_id); 459 | if (parse.lex.type == lex_lc_ident && !(parse.lex.flags & 2)) { 460 | T->text = parse.lex.ptr; 461 | T->len = parse.lex.len; 462 | T->flags = parse.lex.flags; 463 | parse_lex (); 464 | PARSE_OK; 465 | } else { 466 | parse_error ("Can not parse combinator id"); 467 | PARSE_FAIL; 468 | } 469 | } 470 | 471 | struct tree *parse_var_ident (void) { 472 | PARSE_INIT (type_var_ident); 473 | if ((parse.lex.type == lex_lc_ident || parse.lex.type == lex_uc_ident) && !(parse.lex.flags & 3)) { 474 | T->text = parse.lex.ptr; 475 | T->len = parse.lex.len; 476 | T->flags = parse.lex.flags; 477 | parse_lex (); 478 | PARSE_OK; 479 | } else { 480 | parse_error ("Can not parse var ident"); 481 | PARSE_FAIL; 482 | } 483 | } 484 | 485 | struct tree *parse_var_ident_opt (void) { 486 | PARSE_INIT (type_var_ident_opt); 487 | if ((parse.lex.type == lex_lc_ident || parse.lex.type == lex_uc_ident)&& !(parse.lex.flags & 3)) { 488 | T->text = parse.lex.ptr; 489 | T->len = parse.lex.len; 490 | T->flags = parse.lex.flags; 491 | parse_lex (); 492 | PARSE_OK; 493 | } else if (LEX_CHAR ('_')) { 494 | T->text = parse.lex.ptr; 495 | T->len = parse.lex.len; 496 | T->flags = parse.lex.flags; 497 | parse_lex (); 498 | PARSE_OK; 499 | } else { 500 | parse_error ("Can not parse var ident opt"); 501 | PARSE_FAIL; 502 | } 503 | } 504 | 505 | struct tree *parse_nat_const (void) { 506 | PARSE_INIT (type_nat_const); 507 | if (parse.lex.type == lex_num) { 508 | T->text = parse.lex.ptr; 509 | T->len = parse.lex.len; 510 | T->flags = parse.lex.flags; 511 | parse_lex (); 512 | PARSE_OK; 513 | } else { 514 | parse_error ("Can not parse nat const"); 515 | PARSE_FAIL; 516 | } 517 | } 518 | 519 | struct tree *parse_type_ident (void) { 520 | PARSE_INIT (type_type_ident); 521 | if (parse.lex.type == lex_uc_ident && !(parse.lex.flags & 2)) { 522 | T->text = parse.lex.ptr; 523 | T->len = parse.lex.len; 524 | T->flags = parse.lex.flags; 525 | parse_lex (); 526 | PARSE_OK; 527 | } else if (parse.lex.type == lex_lc_ident && !(parse.lex.flags & 2)) { 528 | T->text = parse.lex.ptr; 529 | T->len = parse.lex.len; 530 | T->flags = parse.lex.flags; 531 | parse_lex (); 532 | PARSE_OK; 533 | } else if (LEX_CHAR ('#')) { 534 | T->text = parse.lex.ptr; 535 | T->len = parse.lex.len; 536 | T->flags = parse.lex.flags; 537 | parse_lex (); 538 | PARSE_OK; 539 | } else { 540 | parse_error ("Can not parse type ident"); 541 | PARSE_FAIL; 542 | } 543 | } 544 | 545 | struct tree *parse_term (void) { 546 | PARSE_INIT (type_term); 547 | while (LEX_CHAR ('%')) { 548 | EXPECT ("%") 549 | PARSE_ADD (type_percent); 550 | } 551 | if (LEX_CHAR ('(')) { 552 | EXPECT ("("); 553 | PARSE_TRY_PES (parse_expr); 554 | EXPECT (")"); 555 | PARSE_OK; 556 | } 557 | PARSE_TRY (parse_type_ident); 558 | if (S) { 559 | tree_add_child (T, S); 560 | if (LEX_CHAR ('<')) { 561 | EXPECT ("<"); 562 | while (1) { 563 | PARSE_TRY_PES (parse_expr); 564 | if (LEX_CHAR ('>')) { break; } 565 | EXPECT (","); 566 | } 567 | EXPECT (">"); 568 | } 569 | PARSE_OK; 570 | } 571 | PARSE_TRY_OPT (parse_type_ident); 572 | PARSE_TRY_OPT (parse_var_ident); 573 | PARSE_TRY_OPT (parse_nat_const); 574 | PARSE_FAIL; 575 | } 576 | 577 | struct tree *parse_nat_term (void) { 578 | PARSE_INIT (type_nat_term); 579 | PARSE_TRY_PES (parse_term); 580 | PARSE_OK; 581 | } 582 | 583 | struct tree *parse_subexpr (void) { 584 | PARSE_INIT (type_subexpr); 585 | int was_term = 0; 586 | int cc = 0; 587 | 588 | while (1) { 589 | PARSE_TRY (parse_nat_const); 590 | if (S) { 591 | tree_add_child (T, S); 592 | } else if (!was_term) { 593 | was_term = 1; 594 | PARSE_TRY (parse_term); 595 | if (S) { 596 | tree_add_child (T, S); 597 | } else { 598 | break; 599 | } 600 | } 601 | cc ++; 602 | if (!LEX_CHAR ('+')) { 603 | break; 604 | } 605 | EXPECT ("+"); 606 | } 607 | if (!cc) { 608 | PARSE_FAIL; 609 | } else { 610 | PARSE_OK; 611 | } 612 | } 613 | 614 | struct tree *parse_expr (void) { 615 | PARSE_INIT (type_expr); 616 | int cc = 0; 617 | while (1) { 618 | PARSE_TRY (parse_subexpr); 619 | if (S) { 620 | tree_add_child (T, S); 621 | cc ++; 622 | } else { 623 | if (cc < 1) { PARSE_FAIL; } 624 | else { PARSE_OK; } 625 | } 626 | } 627 | } 628 | 629 | 630 | 631 | struct tree *parse_final_empty (void) { 632 | PARSE_INIT (type_final_empty); 633 | EXPECT ("Empty"); 634 | PARSE_TRY_PES (parse_boxed_type_ident); 635 | PARSE_OK; 636 | } 637 | 638 | struct tree *parse_final_new (void) { 639 | PARSE_INIT (type_final_new); 640 | EXPECT ("New"); 641 | PARSE_TRY_PES (parse_boxed_type_ident); 642 | PARSE_OK; 643 | } 644 | 645 | struct tree *parse_final_final (void) { 646 | PARSE_INIT (type_final_final); 647 | EXPECT ("Final"); 648 | PARSE_TRY_PES (parse_boxed_type_ident); 649 | PARSE_OK; 650 | } 651 | 652 | struct tree *parse_partial_comb_app_decl (void) { 653 | PARSE_INIT (type_partial_comb_app_decl); 654 | PARSE_TRY_PES (parse_combinator_id); 655 | while (1) { 656 | PARSE_TRY_PES (parse_subexpr); 657 | if (LEX_CHAR (';')) { break; } 658 | } 659 | PARSE_OK; 660 | } 661 | 662 | struct tree *parse_partial_type_app_decl (void) { 663 | PARSE_INIT (type_partial_type_app_decl); 664 | PARSE_TRY_PES (parse_boxed_type_ident); 665 | if (LEX_CHAR ('<')) { 666 | EXPECT ("<"); 667 | while (1) { 668 | PARSE_TRY_PES (parse_expr); 669 | if (LEX_CHAR ('>')) { break; } 670 | EXPECT (","); 671 | } 672 | EXPECT (">"); 673 | PARSE_OK; 674 | } else { 675 | while (1) { 676 | PARSE_TRY_PES (parse_subexpr); 677 | if (LEX_CHAR (';')) { break; } 678 | } 679 | PARSE_OK; 680 | } 681 | } 682 | 683 | 684 | 685 | 686 | struct tree *parse_multiplicity (void) { 687 | PARSE_INIT (type_multiplicity); 688 | PARSE_TRY_PES (parse_nat_term); 689 | PARSE_OK; 690 | } 691 | 692 | 693 | struct tree *parse_type_term (void) { 694 | PARSE_INIT (type_type_term); 695 | PARSE_TRY_PES (parse_term); 696 | PARSE_OK; 697 | } 698 | 699 | struct tree *parse_optional_arg_def (void) { 700 | PARSE_INIT (type_optional_arg_def); 701 | PARSE_TRY_PES (parse_var_ident); 702 | EXPECT ("."); 703 | PARSE_TRY_PES (parse_nat_const); 704 | EXPECT ("?"); 705 | PARSE_OK; 706 | } 707 | 708 | struct tree *parse_args4 (void) { 709 | PARSE_INIT (type_args4); 710 | struct parse so = save_parse (); 711 | PARSE_TRY (parse_optional_arg_def); 712 | if (S) { 713 | tree_add_child (T, S); 714 | } else { 715 | load_parse (so); 716 | } 717 | if (LEX_CHAR ('!')) { 718 | PARSE_ADD (type_exclam); 719 | EXPECT ("!"); 720 | } 721 | PARSE_TRY_PES (parse_type_term); 722 | PARSE_OK; 723 | } 724 | 725 | struct tree *parse_args3 (void) { 726 | PARSE_INIT (type_args3); 727 | PARSE_TRY_PES (parse_var_ident_opt); 728 | EXPECT (":"); 729 | struct parse so = save_parse (); 730 | PARSE_TRY (parse_optional_arg_def); 731 | if (S) { 732 | tree_add_child (T, S); 733 | } else { 734 | load_parse (so); 735 | } 736 | if (LEX_CHAR ('!')) { 737 | PARSE_ADD (type_exclam); 738 | EXPECT ("!"); 739 | } 740 | PARSE_TRY_PES (parse_type_term); 741 | PARSE_OK; 742 | } 743 | 744 | struct tree *parse_args2 (void) { 745 | PARSE_INIT (type_args2); 746 | PARSE_TRY (parse_var_ident_opt); 747 | if (S && LEX_CHAR (':')) { 748 | tree_add_child (T, S); 749 | EXPECT (":"); 750 | } else { 751 | load_parse (save); 752 | } 753 | struct parse so = save_parse (); 754 | PARSE_TRY (parse_optional_arg_def); 755 | if (S) { 756 | tree_add_child (T, S); 757 | } else { 758 | load_parse (so); 759 | } 760 | struct parse save2 = save_parse (); 761 | PARSE_TRY (parse_multiplicity); 762 | if (S && LEX_CHAR ('*')) { 763 | tree_add_child (T, S); 764 | EXPECT ("*"); 765 | } else { 766 | load_parse (save2); 767 | } 768 | EXPECT ("["); 769 | while (1) { 770 | if (LEX_CHAR (']')) { break; } 771 | PARSE_TRY_PES (parse_args); 772 | } 773 | EXPECT ("]"); 774 | PARSE_OK; 775 | } 776 | 777 | struct tree *parse_args1 (void) { 778 | PARSE_INIT (type_args1); 779 | EXPECT ("("); 780 | while (1) { 781 | PARSE_TRY_PES (parse_var_ident_opt); 782 | if (LEX_CHAR(':')) { break; } 783 | } 784 | EXPECT (":"); 785 | struct parse so = save_parse (); 786 | PARSE_TRY (parse_optional_arg_def); 787 | if (S) { 788 | tree_add_child (T, S); 789 | } else { 790 | load_parse (so); 791 | } 792 | if (LEX_CHAR ('!')) { 793 | PARSE_ADD (type_exclam); 794 | EXPECT ("!"); 795 | } 796 | PARSE_TRY_PES (parse_type_term); 797 | EXPECT (")"); 798 | PARSE_OK; 799 | } 800 | 801 | struct tree *parse_args (void) { 802 | PARSE_INIT (type_args); 803 | PARSE_TRY_OPT (parse_args1); 804 | PARSE_TRY_OPT (parse_args2); 805 | PARSE_TRY_OPT (parse_args3); 806 | PARSE_TRY_OPT (parse_args4); 807 | PARSE_FAIL; 808 | } 809 | 810 | struct tree *parse_opt_args (void) { 811 | PARSE_INIT (type_opt_args); 812 | while (1) { 813 | PARSE_TRY_PES (parse_var_ident); 814 | if (parse.lex.type == lex_char && *parse.lex.ptr == ':') { break;} 815 | } 816 | EXPECT (":"); 817 | PARSE_TRY_PES (parse_type_term); 818 | PARSE_OK; 819 | } 820 | 821 | struct tree *parse_final_decl (void) { 822 | PARSE_INIT (type_final_decl); 823 | PARSE_TRY_OPT (parse_final_new); 824 | PARSE_TRY_OPT (parse_final_final); 825 | PARSE_TRY_OPT (parse_final_empty); 826 | PARSE_FAIL; 827 | } 828 | 829 | struct tree *parse_partial_app_decl (void) { 830 | PARSE_INIT (type_partial_app_decl); 831 | PARSE_TRY_OPT (parse_partial_type_app_decl); 832 | PARSE_TRY_OPT (parse_partial_comb_app_decl); 833 | PARSE_FAIL; 834 | } 835 | 836 | struct tree *parse_result_type (void) { 837 | PARSE_INIT (type_result_type); 838 | PARSE_TRY_PES (parse_boxed_type_ident); 839 | if (LEX_CHAR ('<')) { 840 | EXPECT ("<"); 841 | while (1) { 842 | PARSE_TRY_PES (parse_expr); 843 | if (LEX_CHAR ('>')) { break; } 844 | EXPECT (","); 845 | } 846 | EXPECT (">"); 847 | PARSE_OK; 848 | } else { 849 | while (1) { 850 | if (LEX_CHAR (';')) { PARSE_OK; } 851 | PARSE_TRY_PES (parse_subexpr); 852 | } 853 | } 854 | } 855 | 856 | struct tree *parse_combinator_decl (void) { 857 | PARSE_INIT (type_combinator_decl); 858 | PARSE_TRY_PES (parse_full_combinator_id) 859 | while (1) { 860 | if (LEX_CHAR ('{')) { 861 | parse_lex (); 862 | PARSE_TRY_PES (parse_opt_args); 863 | EXPECT ("}"); 864 | } else { 865 | break; 866 | } 867 | } 868 | while (1) { 869 | if (LEX_CHAR ('=')) { break; } 870 | PARSE_TRY_PES (parse_args); 871 | } 872 | EXPECT ("="); 873 | PARSE_ADD (type_equals); 874 | 875 | PARSE_TRY_PES (parse_result_type); 876 | PARSE_OK; 877 | } 878 | 879 | struct tree *parse_builtin_combinator_decl (void) { 880 | PARSE_INIT (type_builtin_combinator_decl); 881 | PARSE_TRY_PES (parse_full_combinator_id) 882 | EXPECT ("?"); 883 | EXPECT ("="); 884 | PARSE_TRY_PES (parse_boxed_type_ident); 885 | PARSE_OK; 886 | } 887 | 888 | struct tree *parse_declaration (void) { 889 | PARSE_INIT (type_declaration); 890 | PARSE_TRY_OPT (parse_combinator_decl); 891 | PARSE_TRY_OPT (parse_partial_app_decl); 892 | PARSE_TRY_OPT (parse_final_decl); 893 | PARSE_TRY_OPT (parse_builtin_combinator_decl); 894 | PARSE_FAIL; 895 | } 896 | 897 | struct tree *parse_constr_declarations (void) { 898 | PARSE_INIT (type_constr_declarations); 899 | if (parse.lex.type == lex_triple_minus || parse.lex.type == lex_eof) { PARSE_OK; } 900 | while (1) { 901 | PARSE_TRY_PES (parse_declaration); 902 | EXPECT (";"); 903 | if (parse.lex.type == lex_eof || parse.lex.type == lex_triple_minus) { PARSE_OK; } 904 | } 905 | } 906 | 907 | struct tree *parse_fun_declarations (void) { 908 | PARSE_INIT (type_fun_declarations); 909 | if (parse.lex.type == lex_triple_minus || parse.lex.type == lex_eof) { PARSE_OK; } 910 | while (1) { 911 | PARSE_TRY_PES (parse_declaration); 912 | EXPECT (";"); 913 | if (parse.lex.type == lex_eof || parse.lex.type == lex_triple_minus) { PARSE_OK; } 914 | } 915 | } 916 | 917 | struct tree *parse_program (void) { 918 | PARSE_INIT (type_tl_program); 919 | while (1) { 920 | PARSE_TRY_PES (parse_constr_declarations); 921 | if (parse.lex.type == lex_eof) { PARSE_OK; } 922 | if (parse.lex.type == lex_error || expect ("---") < 0 || expect ("functions") < 0 || expect ("---") < 0) { PARSE_FAIL; } 923 | 924 | PARSE_TRY_PES (parse_fun_declarations); 925 | if (parse.lex.type == lex_eof) { PARSE_OK; } 926 | if (parse.lex.type == lex_error || expect ("---") < 0 || expect ("types") < 0 || expect ("---") < 0) { PARSE_FAIL; } 927 | } 928 | } 929 | 930 | struct tree *tl_parse_lex (struct parse *_parse) { 931 | assert (_parse); 932 | load_parse (*_parse); 933 | if (parse.lex.type == lex_none) { 934 | parse_lex (); 935 | } 936 | if (parse.lex.type == lex_error) { 937 | return 0; 938 | } 939 | return parse_program (); 940 | } 941 | 942 | int mystrcmp2 (const char *b, int len, const char *a) { 943 | int c = strncmp (b, a, len); 944 | return c ? a[len] ? -1 : 0 : c; 945 | } 946 | 947 | char *mystrdup (const char *a, int len) { 948 | char *z = talloc (len + 1); 949 | memcpy (z, a, len); 950 | z[len] = 0; 951 | return z; 952 | } 953 | 954 | struct tl_program *tl_program_cur; 955 | #define TL_TRY_PES(x) if (!(x)) { return 0; } 956 | 957 | #define tl_type_cmp(a,b) (strcmp (a->id, b->id)) 958 | DEFINE_TREE (tl_type,struct tl_type *,tl_type_cmp,0) 959 | struct tree_tl_type *tl_type_tree; 960 | 961 | DEFINE_TREE (tl_constructor,struct tl_constructor *,tl_type_cmp,0) 962 | struct tree_tl_constructor *tl_constructor_tree; 963 | struct tree_tl_constructor *tl_function_tree; 964 | 965 | DEFINE_TREE (tl_var,struct tl_var *,tl_type_cmp,0) 966 | 967 | struct tl_var_value { 968 | struct tl_combinator_tree *ptr; 969 | struct tl_combinator_tree *val; 970 | int num_val; 971 | }; 972 | 973 | #define tl_var_value_cmp(a,b) (((char *)a.ptr) - ((char *)b.ptr)) 974 | struct tl_var_value empty; 975 | DEFINE_TREE (var_value, struct tl_var_value, tl_var_value_cmp, empty) 976 | //tree_tl_var_t *tl_var_tree; 977 | 978 | DEFINE_TREE (tl_field,char *,strcmp, 0) 979 | //tree_tl_field_t *tl_field_tree; 980 | #define TL_FAIL return 0; 981 | #define TL_INIT(x) struct tl_combinator_tree *x = 0; 982 | #define TL_TRY(f,x) { struct tl_combinator_tree *_t = f; if (!_t) { TL_FAIL;} x = tl_union (x, _t); if (!x) { TL_FAIL; }} 983 | #define TL_ERROR(...) fprintf (stderr, __VA_ARGS__); 984 | #define TL_WARNING(...) fprintf (stderr, __VA_ARGS__); 985 | 986 | void tl_set_var_value (struct tree_var_value **T, struct tl_combinator_tree *var, struct tl_combinator_tree *value) { 987 | struct tl_var_value t = {.ptr = var, .val = value, .num_val = 0}; 988 | if (tree_lookup_var_value (*T, t).ptr) { 989 | *T = tree_delete_var_value (*T, t); 990 | } 991 | *T = tree_insert_var_value (*T, t, lrand48 ()); 992 | } 993 | 994 | void tl_set_var_value_num (struct tree_var_value **T, struct tl_combinator_tree *var, struct tl_combinator_tree *value, long long num_value) { 995 | struct tl_var_value t = {.ptr = var, .val = value, .num_val = num_value}; 996 | if (tree_lookup_var_value (*T, t).ptr) { 997 | *T = tree_delete_var_value (*T, t); 998 | } 999 | *T = tree_insert_var_value (*T, t, lrand48 ()); 1000 | } 1001 | 1002 | struct tl_combinator_tree *tl_get_var_value (struct tree_var_value **T, struct tl_combinator_tree *var) { 1003 | struct tl_var_value t = {.ptr = var, .val = 0, .num_val = 0}; 1004 | struct tl_var_value r = tree_lookup_var_value (*T, t); 1005 | return r.ptr ? r.val : 0; 1006 | } 1007 | 1008 | int tl_get_var_value_num (struct tree_var_value **T, struct tl_combinator_tree *var) { 1009 | struct tl_var_value t = {.ptr = var, .val = 0}; 1010 | struct tl_var_value r = tree_lookup_var_value (*T, t); 1011 | return r.ptr ? r.num_val : 0; 1012 | } 1013 | 1014 | int namespace_level; 1015 | 1016 | struct tree_tl_var *vars[10]; 1017 | struct tree_tl_field *fields[10]; 1018 | struct tl_var *last_num_var[10]; 1019 | 1020 | int tl_is_type_name (const char *id, int len) { 1021 | if (len == 1 && *id == '#') { return 1;} 1022 | int ok = id[0] >= 'A' && id[0] <= 'Z'; 1023 | int i; 1024 | for (i = 0; i < len - 1; i++) if (id[i] == '.') { 1025 | ok = id[i + 1] >= 'A' && id[i + 1] <= 'Z'; 1026 | } 1027 | return ok; 1028 | } 1029 | 1030 | int tl_add_field (char *id) { 1031 | assert (namespace_level < 10); 1032 | assert (namespace_level >= 0); 1033 | if (tree_lookup_tl_field (fields[namespace_level], id)) { 1034 | return 0; 1035 | } 1036 | fields[namespace_level] = tree_insert_tl_field (fields[namespace_level], id, lrand48 ()); 1037 | return 1; 1038 | } 1039 | 1040 | void tl_clear_fields (void) { 1041 | // tree_act_tl_field (fields[namespace_level], (void *)free); 1042 | fields[namespace_level] = tree_clear_tl_field (fields[namespace_level]); 1043 | } 1044 | 1045 | struct tl_var *tl_add_var (char *id, struct tl_combinator_tree *ptr, int type) { 1046 | struct tl_var *v = talloc (sizeof (*v)); 1047 | v->id = tstrdup (id); 1048 | v->type = type; 1049 | v->ptr = ptr; 1050 | v->flags = 0; 1051 | if (tree_lookup_tl_var (vars[namespace_level], v)) { 1052 | return 0; 1053 | } 1054 | vars[namespace_level] = tree_insert_tl_var (vars[namespace_level], v, lrand48 ()); 1055 | if (type) { 1056 | last_num_var[namespace_level] = v; 1057 | } 1058 | return v; 1059 | } 1060 | 1061 | void tl_del_var (struct tl_var *v) { 1062 | // free (v->id); 1063 | tfree (v, sizeof (*v)); 1064 | } 1065 | 1066 | void tl_clear_vars (void) { 1067 | tree_act_tl_var (vars[namespace_level], tl_del_var); 1068 | vars[namespace_level] = tree_clear_tl_var (vars[namespace_level]); 1069 | last_num_var[namespace_level] = 0; 1070 | } 1071 | 1072 | struct tl_var *tl_get_last_num_var (void) { 1073 | return last_num_var[namespace_level]; 1074 | } 1075 | 1076 | struct tl_var *tl_get_var (char *_id, int len) { 1077 | char *id = mystrdup (_id, len); 1078 | struct tl_var v = {.id = id}; 1079 | int i; 1080 | for (i = namespace_level; i >= 0; i--) { 1081 | struct tl_var *w = tree_lookup_tl_var (vars[i], &v); 1082 | if (w) { 1083 | tfree (id, len + 1); 1084 | return w; 1085 | } 1086 | } 1087 | tfree (id, len + 1); 1088 | return 0; 1089 | } 1090 | 1091 | void namespace_push (void) { 1092 | namespace_level ++; 1093 | assert (namespace_level < 10); 1094 | tl_clear_vars (); 1095 | tl_clear_fields (); 1096 | } 1097 | 1098 | void namespace_pop (void) { 1099 | namespace_level --; 1100 | assert (namespace_level >= 0); 1101 | } 1102 | 1103 | struct tl_type *tl_get_type (const char *_id, int len) { 1104 | char *id = mystrdup (_id, len); 1105 | struct tl_type _t = {.id = id}; 1106 | struct tl_type *r = tree_lookup_tl_type (tl_type_tree, &_t); 1107 | tfree (id, len + 1); 1108 | return r; 1109 | } 1110 | 1111 | struct tl_type *tl_add_type (const char *_id, int len, int params_num, long long params_types) { 1112 | char *id = talloc (len + 1); 1113 | memcpy (id, _id, len); 1114 | id[len] = 0; 1115 | struct tl_type _t = {.id = id}; 1116 | struct tl_type *_r = 0; 1117 | if ((_r = tree_lookup_tl_type (tl_type_tree, &_t))) { 1118 | tfree (id, len + 1); 1119 | if (params_num >= 0 && (_r->params_num != params_num || _r->params_types != params_types)) { 1120 | TL_ERROR ("Wrong params_num or types for type %s\n", _r->id); 1121 | return 0; 1122 | } 1123 | return _r; 1124 | } 1125 | struct tl_type *t = talloc (sizeof (*t)); 1126 | t->id = id; 1127 | t->print_id = tstrdup (t->id); 1128 | int i; 1129 | for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') { 1130 | t->print_id[i] = '$'; 1131 | } 1132 | t->name = 0; 1133 | t->constructors_num = 0; 1134 | t->constructors = 0; 1135 | t->flags = 0; 1136 | t->real_id = 0; 1137 | if (params_num >= 0) { 1138 | assert (params_num <= 64); 1139 | t->params_num = params_num; 1140 | t->params_types = params_types; 1141 | } else { 1142 | t->flags |= 4; 1143 | t->params_num = -1; 1144 | } 1145 | tl_type_tree = tree_insert_tl_type (tl_type_tree, t, lrand48 ()); 1146 | total_types_num ++; 1147 | return t; 1148 | } 1149 | 1150 | void tl_add_type_param (struct tl_type *t, int x) { 1151 | assert (t->flags & 4); 1152 | assert (t->params_num <= 64); 1153 | if (x) { 1154 | t->params_types |= (1ull << (t->params_num ++)); 1155 | } else { 1156 | t->params_num ++; 1157 | } 1158 | } 1159 | 1160 | int tl_type_set_params (struct tl_type *t, int x, long long y) { 1161 | if (t->flags & 4) { 1162 | t->params_num = x; 1163 | t->params_types = y; 1164 | t->flags &= ~4; 1165 | } else { 1166 | if (t->params_num != x || t->params_types != y) { 1167 | fprintf (stderr, "Wrong num of params (type %s)\n", t->id); 1168 | return 0; 1169 | } 1170 | } 1171 | return 1; 1172 | } 1173 | 1174 | void tl_type_finalize (struct tl_type *t) { 1175 | t->flags &= ~4; 1176 | } 1177 | 1178 | struct tl_constructor *tl_get_constructor (const char *_id, int len) { 1179 | char *id = mystrdup (_id, len); 1180 | struct tl_constructor _t = {.id = id}; 1181 | struct tl_constructor *r = tree_lookup_tl_constructor (tl_constructor_tree, &_t); 1182 | tfree (id, len + 1); 1183 | return r; 1184 | } 1185 | 1186 | struct tl_constructor *tl_add_constructor (struct tl_type *a, const char *_id, int len, int force_magic) { 1187 | assert (a); 1188 | if (a->flags & 1) { 1189 | TL_ERROR ("New constructor for type `%s` after final statement\n", a->id); 1190 | return 0; 1191 | } 1192 | int x = 0; 1193 | while (x < len && (_id[x] != '#' || force_magic)) { x++; } 1194 | char *id = talloc (x + 1); 1195 | memcpy (id, _id, x); 1196 | id[x] = 0; 1197 | 1198 | unsigned magic = 0; 1199 | if (x < len) { 1200 | assert (len - x >= 6 && len - x <= 9); 1201 | int i; 1202 | for (i = 1; i < len - x; i++) { 1203 | magic = (magic << 4) + (_id[x + i] <= '9' ? _id[x + i] - '0' : _id[x + i] - 'a' + 10); 1204 | } 1205 | assert (magic && magic != (unsigned)-1); 1206 | } 1207 | 1208 | len = x; 1209 | if (*id != '_') { 1210 | struct tl_constructor _t = {.id = id}; 1211 | if (tree_lookup_tl_constructor (tl_constructor_tree, &_t)) { 1212 | TL_ERROR ("Duplicate constructor id `%s`\n", id); 1213 | tfree (id, len + 1); 1214 | return 0; 1215 | } 1216 | } else { 1217 | assert (len == 1); 1218 | } 1219 | 1220 | struct tl_constructor *t = talloc (sizeof (*t)); 1221 | t->type = a; 1222 | t->name = magic; 1223 | t->id = id; 1224 | t->print_id = tstrdup (id); 1225 | t->real_id = 0; 1226 | 1227 | int i; 1228 | for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') { 1229 | t->print_id[i] = '$'; 1230 | } 1231 | 1232 | t->left = t->right = 0; 1233 | a->constructors = realloc (a->constructors, sizeof (void *) * (a->constructors_num + 1)); 1234 | assert (a->constructors); 1235 | a->constructors[a->constructors_num ++] = t; 1236 | if (*id != '_') { 1237 | tl_constructor_tree = tree_insert_tl_constructor (tl_constructor_tree, t, lrand48 ()); 1238 | } else { 1239 | a->flags |= FLAG_DEFAULT_CONSTRUCTOR; 1240 | } 1241 | total_constructors_num ++; 1242 | return t; 1243 | } 1244 | 1245 | struct tl_constructor *tl_get_function (const char *_id, int len) { 1246 | char *id = mystrdup (_id, len); 1247 | struct tl_constructor _t = {.id = id}; 1248 | struct tl_constructor *r = tree_lookup_tl_constructor (tl_function_tree, &_t); 1249 | tfree (id, len + 1); 1250 | return r; 1251 | } 1252 | 1253 | struct tl_constructor *tl_add_function (struct tl_type *a, const char *_id, int len, int force_magic) { 1254 | // assert (a); 1255 | int x = 0; 1256 | while (x < len && ((_id[x] != '#') || force_magic)) { x++; } 1257 | char *id = talloc (x + 1); 1258 | memcpy (id, _id, x); 1259 | id[x] = 0; 1260 | 1261 | unsigned magic = 0; 1262 | if (x < len) { 1263 | assert (len - x >= 6 && len - x <= 9); 1264 | int i; 1265 | for (i = 1; i < len - x; i++) { 1266 | magic = (magic << 4) + (_id[x + i] <= '9' ? _id[x + i] - '0' : _id[x + i] - 'a' + 10); 1267 | } 1268 | assert (magic && magic != (unsigned)-1); 1269 | } 1270 | 1271 | len = x; 1272 | 1273 | struct tl_constructor _t = {.id = id}; 1274 | if (tree_lookup_tl_constructor (tl_function_tree, &_t)) { 1275 | TL_ERROR ("Duplicate function id `%s`\n", id); 1276 | tfree (id, len + 1); 1277 | return 0; 1278 | } 1279 | 1280 | struct tl_constructor *t = talloc (sizeof (*t)); 1281 | t->type = a; 1282 | t->name = magic; 1283 | t->id = id; 1284 | t->print_id = tstrdup (id); 1285 | t->real_id = 0; 1286 | 1287 | int i; 1288 | for (i = 0; i < len; i++) if (t->print_id[i] == '.' || t->print_id[i] == '#' || t->print_id[i] == ' ') { 1289 | t->print_id[i] = '$'; 1290 | } 1291 | 1292 | t->left = t->right = 0; 1293 | tl_function_tree = tree_insert_tl_constructor (tl_function_tree, t, lrand48 ()); 1294 | total_functions_num ++; 1295 | return t; 1296 | } 1297 | 1298 | static char buf[(1 << 20)]; 1299 | int buf_pos; 1300 | 1301 | struct tl_combinator_tree *alloc_ctree_node (void) { 1302 | struct tl_combinator_tree *T = talloc (sizeof (*T)); 1303 | assert (T); 1304 | memset (T, 0, sizeof (*T)); 1305 | return T; 1306 | } 1307 | 1308 | struct tl_combinator_tree *tl_tree_dup (struct tl_combinator_tree *T) { 1309 | if (!T) { return 0; } 1310 | struct tl_combinator_tree *S = talloc (sizeof (*S)); 1311 | memcpy (S, T, sizeof (*S)); 1312 | S->left = tl_tree_dup (T->left); 1313 | S->right = tl_tree_dup (T->right); 1314 | return S; 1315 | } 1316 | 1317 | struct tl_type *tl_tree_get_type (struct tl_combinator_tree *T) { 1318 | assert (T->type == type_type); 1319 | if (T->act == act_array) { return 0;} 1320 | while (T->left) { 1321 | T = T->left; 1322 | if (T->act == act_array) { return 0;} 1323 | assert (T->type == type_type); 1324 | } 1325 | assert (T->act == act_type || T->act == act_var || T->act == act_array); 1326 | return T->act == act_type ? T->data : 0; 1327 | } 1328 | 1329 | void tl_tree_set_len (struct tl_combinator_tree *T) { 1330 | TL_INIT (H); 1331 | H = T; 1332 | while (H->left) { 1333 | H->left->type_len = H->type_len + 1; 1334 | H = H->left; 1335 | } 1336 | assert (H->type == type_type); 1337 | struct tl_type *t = H->data; 1338 | assert (t); 1339 | assert (H->type_len == t->params_num); 1340 | } 1341 | 1342 | void tl_buf_reset (void) { 1343 | buf_pos = 0; 1344 | } 1345 | 1346 | void tl_buf_add_string (char *s, int len) { 1347 | if (len < 0) { len = strlen (s); } 1348 | buf[buf_pos ++] = ' '; 1349 | memcpy (buf + buf_pos, s, len); buf_pos += len; 1350 | buf[buf_pos] = 0; 1351 | } 1352 | 1353 | void tl_buf_add_string_nospace (char *s, int len) { 1354 | if (len < 0) { len = strlen (s); } 1355 | // if (buf_pos) { buf[buf_pos ++] = ' '; } 1356 | memcpy (buf + buf_pos, s, len); buf_pos += len; 1357 | buf[buf_pos] = 0; 1358 | } 1359 | 1360 | void tl_buf_add_string_q (char *s, int len, int x) { 1361 | if (x) { 1362 | tl_buf_add_string (s, len); 1363 | } else { 1364 | tl_buf_add_string_nospace (s, len); 1365 | } 1366 | } 1367 | 1368 | 1369 | void tl_buf_add_tree (struct tl_combinator_tree *T, int x) { 1370 | if (!T) { return; } 1371 | assert (T != (void *)-1l && T != (void *)-2l); 1372 | switch (T->act) { 1373 | case act_question_mark: 1374 | tl_buf_add_string_q ("?", -1, x); 1375 | return; 1376 | case act_type: 1377 | if ((T->flags & 1) && !(T->flags & 4)) { 1378 | tl_buf_add_string_q ("%", -1, x); 1379 | x = 0; 1380 | } 1381 | if (T->flags & 2) { 1382 | tl_buf_add_string_q ((char *)T->data, -1, x); 1383 | } else { 1384 | struct tl_type *t = T->data; 1385 | if (T->flags & 4) { 1386 | assert (t->constructors_num == 1); 1387 | tl_buf_add_string_q (t->constructors[0]->real_id ? t->constructors[0]->real_id : t->constructors[0]->id, -1, x); 1388 | } else { 1389 | tl_buf_add_string_q (t->real_id ? t->real_id : t->id, -1, x); 1390 | } 1391 | } 1392 | return; 1393 | case act_field: 1394 | if (T->data) { 1395 | tl_buf_add_string_q ((char *)T->data, -1, x); 1396 | x = 0; 1397 | tl_buf_add_string_q (":", -1, 0); 1398 | } 1399 | tl_buf_add_tree (T->left, x); 1400 | tl_buf_add_tree (T->right, 1); 1401 | return; 1402 | case act_union: 1403 | tl_buf_add_tree (T->left, x); 1404 | tl_buf_add_tree (T->right, 1); 1405 | return; 1406 | case act_var: 1407 | { 1408 | if (T->data == (void *)-1l) { return; } 1409 | struct tl_combinator_tree *v = T->data; 1410 | tl_buf_add_string_q ((char *)v->data, -1, x); 1411 | if (T->type == type_num && T->type_flags) { 1412 | static char _buf[30]; 1413 | sprintf (_buf, "+%lld", T->type_flags); 1414 | tl_buf_add_string_q (_buf, -1, 0); 1415 | } 1416 | } 1417 | return; 1418 | case act_arg: 1419 | tl_buf_add_tree (T->left, x); 1420 | tl_buf_add_tree (T->right, 1); 1421 | return; 1422 | case act_array: 1423 | if (T->left && !(T->left->flags & 128)) { 1424 | tl_buf_add_tree (T->left, x); 1425 | x = 0; 1426 | tl_buf_add_string_q ("*", -1, x); 1427 | } 1428 | tl_buf_add_string_q ("[", -1, x); 1429 | tl_buf_add_tree (T->right, 1); 1430 | tl_buf_add_string_q ("]", -1, 1); 1431 | return; 1432 | case act_plus: 1433 | tl_buf_add_tree (T->left, x); 1434 | tl_buf_add_string_q ("+", -1, 0); 1435 | tl_buf_add_tree (T->right, 0); 1436 | return; 1437 | case act_nat_const: 1438 | { 1439 | static char _buf[30]; 1440 | snprintf (_buf, 29, "%lld", T->type_flags); 1441 | tl_buf_add_string_q (_buf, -1, x); 1442 | return; 1443 | } 1444 | case act_opt_field: 1445 | { 1446 | struct tl_combinator_tree *v = T->left->data; 1447 | tl_buf_add_string_q ((char *)v->data, -1, x); 1448 | tl_buf_add_string_q (".", -1, 0); 1449 | static char _buf[30]; 1450 | sprintf (_buf, "%lld", T->left->type_flags); 1451 | tl_buf_add_string_q (_buf, -1, 0); 1452 | tl_buf_add_string_q ("?", -1, 0); 1453 | tl_buf_add_tree (T->right, 0); 1454 | return; 1455 | } 1456 | 1457 | default: 1458 | fprintf (stderr, "%s %s\n", TL_ACT (T->act), TL_TYPE (T->type)); 1459 | assert (0); 1460 | return; 1461 | } 1462 | } 1463 | 1464 | int tl_count_combinator_name (struct tl_constructor *c) { 1465 | assert (c); 1466 | tl_buf_reset (); 1467 | tl_buf_add_string_nospace (c->real_id ? c->real_id : c->id, -1); 1468 | tl_buf_add_tree (c->left, 1); 1469 | tl_buf_add_string ("=", -1); 1470 | tl_buf_add_tree (c->right, 1); 1471 | //fprintf (stderr, "%.*s\n", buf_pos, buf); 1472 | if (!c->name) { 1473 | c->name = compute_crc32 (buf, buf_pos); 1474 | } 1475 | return c->name; 1476 | } 1477 | 1478 | int tl_print_combinator (struct tl_constructor *c) { 1479 | tl_buf_reset (); 1480 | tl_buf_add_string_nospace (c->real_id ? c->real_id : c->id, -1); 1481 | static char _buf[10]; 1482 | sprintf (_buf, "#%08x", c->name); 1483 | tl_buf_add_string_nospace (_buf, -1); 1484 | tl_buf_add_tree (c->left, 1); 1485 | tl_buf_add_string ("=", -1); 1486 | tl_buf_add_tree (c->right, 1); 1487 | if (output_expressions >= 1) { 1488 | fprintf (stderr, "%.*s\n", buf_pos, buf); 1489 | } 1490 | /* if (!c->name) { 1491 | c->name = compute_crc32 (buf, buf_pos); 1492 | }*/ 1493 | return c->name; 1494 | } 1495 | 1496 | int _tl_finish_subtree (struct tl_combinator_tree *R, int x, long long y) { 1497 | assert (R->type == type_type); 1498 | assert (R->type_len < 0); 1499 | assert (R->act == act_arg || R->act == act_type); 1500 | R->type_len = x; 1501 | R->type_flags = y; 1502 | if (R->act == act_type) { 1503 | struct tl_type *t = R->data; 1504 | assert (t); 1505 | return tl_type_set_params (t, x, y); 1506 | } 1507 | assert ((R->right->type == type_type && R->right->type_len == 0) || R->right->type == type_num || R->right->type == type_num_value); 1508 | return _tl_finish_subtree (R->left, x + 1, y * 2 + (R->right->type == type_num || R->right->type == type_num_value)); 1509 | } 1510 | 1511 | int tl_finish_subtree (struct tl_combinator_tree *R) { 1512 | assert (R); 1513 | if (R->type != type_type) { 1514 | return 1; 1515 | } 1516 | if (R->type_len >= 0) { 1517 | if (R->type_len > 0) { 1518 | TL_ERROR ("Not enough params\n"); 1519 | return 0; 1520 | } 1521 | return 1; 1522 | } 1523 | return _tl_finish_subtree (R, 0, 0); 1524 | } 1525 | 1526 | struct tl_combinator_tree *tl_union (struct tl_combinator_tree *L, struct tl_combinator_tree *R) { 1527 | if (!L) { return R; } 1528 | if (!R) { return L; } 1529 | TL_INIT (v); 1530 | v = alloc_ctree_node (); 1531 | v->left = L; 1532 | v->right = R; 1533 | switch (L->type) { 1534 | case type_num: 1535 | if (R->type != type_num_value) { 1536 | TL_ERROR ("Union: type mistmatch\n"); 1537 | return 0; 1538 | } 1539 | tfree (v, sizeof (*v)); 1540 | L->type_flags += R->type_flags; 1541 | return L; 1542 | case type_num_value: 1543 | if (R->type != type_num_value && R->type != type_num) { 1544 | TL_ERROR ("Union: type mistmatch\n"); 1545 | return 0; 1546 | } 1547 | tfree (v, sizeof (*v)); 1548 | R->type_flags += L->type_flags; 1549 | return R; 1550 | case type_list_item: 1551 | case type_list: 1552 | if (R->type != type_list_item) { 1553 | TL_ERROR ("Union: type mistmatch\n"); 1554 | return 0; 1555 | } 1556 | v->type = type_list; 1557 | v->act = act_union; 1558 | return v; 1559 | case type_type: 1560 | if (L->type_len == 0) { 1561 | TL_ERROR ("Arguments number exceeds type arity\n"); 1562 | return 0; 1563 | } 1564 | if (R->type != type_num && R->type != type_type && R->type != type_num_value) { 1565 | TL_ERROR ("Union: type mistmatch\n"); 1566 | return 0; 1567 | } 1568 | if (R->type_len < 0) { 1569 | if (!tl_finish_subtree (R)) { 1570 | return 0; 1571 | } 1572 | } 1573 | if (R->type_len > 0) { 1574 | TL_ERROR ("Argument type must have full number of arguments\n"); 1575 | return 0; 1576 | } 1577 | if (L->type_len > 0 && ((L->type_flags & 1) != (R->type == type_num || R->type == type_num_value))) { 1578 | TL_ERROR ("Argument types mistmatch: L->type_flags = %lld, R->type = %s\n", L->flags, TL_TYPE (R->type)); 1579 | return 0; 1580 | } 1581 | v->type = type_type; 1582 | v->act = act_arg; 1583 | v->type_len = L->type_len > 0 ? L->type_len - 1 : -1; 1584 | v->type_flags = L->type_flags >> 1; 1585 | return v; 1586 | default: 1587 | assert (0); 1588 | return 0; 1589 | } 1590 | } 1591 | 1592 | struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s); 1593 | struct tl_combinator_tree *tl_parse_term (struct tree *T, int s) { 1594 | assert (T->type == type_term); 1595 | int i = 0; 1596 | while (i < T->nc && T->c[i]->type == type_percent) { i ++; s ++; } 1597 | assert (i < T->nc); 1598 | TL_INIT (L); 1599 | while (i < T->nc) { 1600 | TL_TRY (tl_parse_any_term (T->c[i], s), L); 1601 | s = 0; 1602 | i ++; 1603 | } 1604 | return L; 1605 | } 1606 | 1607 | 1608 | struct tl_combinator_tree *tl_parse_type_term (struct tree *T, int s) { 1609 | assert (T->type == type_type_term); 1610 | assert (T->nc == 1); 1611 | struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s); 1612 | if (!Z || Z->type != type_type) { if (Z) { TL_ERROR ("type_term: found type %s\n", TL_TYPE (Z->type)); } TL_FAIL; } 1613 | return Z; 1614 | } 1615 | 1616 | struct tl_combinator_tree *tl_parse_nat_term (struct tree *T, int s) { 1617 | assert (T->type == type_nat_term); 1618 | assert (T->nc == 1); 1619 | struct tl_combinator_tree *Z = tl_parse_term (T->c[0], s); 1620 | if (!Z || (Z->type != type_num && Z->type != type_num_value)) { if (Z) { TL_ERROR ("nat_term: found type %s\n", TL_TYPE (Z->type)); }TL_FAIL; } 1621 | return Z; 1622 | } 1623 | 1624 | struct tl_combinator_tree *tl_parse_subexpr (struct tree *T, int s) { 1625 | assert (T->type == type_subexpr); 1626 | assert (T->nc >= 1); 1627 | int i; 1628 | TL_INIT (L); 1629 | for (i = 0; i < T->nc; i++) { 1630 | TL_TRY (tl_parse_any_term (T->c[i], s), L); 1631 | s = 0; 1632 | } 1633 | return L; 1634 | } 1635 | 1636 | struct tl_combinator_tree *tl_parse_expr (struct tree *T, int s) { 1637 | assert (T->type == type_expr); 1638 | assert (T->nc >= 1); 1639 | int i; 1640 | TL_INIT (L); 1641 | for (i = 0; i < T->nc; i++) { 1642 | TL_TRY (tl_parse_subexpr (T->c[i], s), L); 1643 | s = 0; 1644 | } 1645 | return L; 1646 | } 1647 | 1648 | struct tl_combinator_tree *tl_parse_nat_const (struct tree *T, int s) { 1649 | assert (T->type == type_nat_const); 1650 | assert (!T->nc); 1651 | if (s > 0) { 1652 | TL_ERROR ("Nat const can not preceed with %%\n"); 1653 | TL_FAIL; 1654 | } 1655 | assert (T->type == type_nat_const); 1656 | assert (!T->nc); 1657 | TL_INIT (L); 1658 | L = alloc_ctree_node (); 1659 | L->act = act_nat_const; 1660 | L->type = type_num_value; 1661 | int i; 1662 | long long x = 0; 1663 | for (i = 0; i < T->len; i++) { 1664 | x = x * 10 + T->text[i] - '0'; 1665 | } 1666 | L->type_flags = x; 1667 | return L; 1668 | } 1669 | 1670 | struct tl_combinator_tree *tl_parse_ident (struct tree *T, int s) { 1671 | assert (T->type == type_type_ident || T->type == type_var_ident || T->type == type_boxed_type_ident); 1672 | assert (!T->nc); 1673 | struct tl_var *v = tl_get_var (T->text, T->len); 1674 | TL_INIT (L); 1675 | if (v) { 1676 | L = alloc_ctree_node (); 1677 | L->act = act_var; 1678 | L->type = v->type ? type_num : type_type; 1679 | if (L->type == type_num && s) { 1680 | TL_ERROR ("Nat var can not preceed with %%\n"); 1681 | TL_FAIL; 1682 | } else { 1683 | if (s) { 1684 | L->flags |= 1; 1685 | } 1686 | } 1687 | L->type_len = 0; 1688 | L->type_flags = 0; 1689 | L->data = v->ptr; 1690 | return L; 1691 | } 1692 | 1693 | /* if (!mystrcmp2 (T->text, T->len, "#") || !mystrcmp2 (T->text, T->len, "Type")) { 1694 | L = alloc_ctree_node (); 1695 | L->act = act_type; 1696 | L->flags |= 2; 1697 | L->data = tl_get_type (T->text, T->len); 1698 | assert (L->data); 1699 | L->type = type_type; 1700 | L->type_len = 0; 1701 | L->type_flags = 0; 1702 | return L; 1703 | }*/ 1704 | 1705 | struct tl_constructor *c = tl_get_constructor (T->text, T->len); 1706 | if (c) { 1707 | assert (c->type); 1708 | if (c->type->constructors_num != 1) { 1709 | TL_ERROR ("Constructor can be used only if it is the only constructor of the type\n"); 1710 | return 0; 1711 | } 1712 | c->type->flags |= 1; 1713 | L = alloc_ctree_node (); 1714 | L->act = act_type; 1715 | L->flags |= 5; 1716 | L->data = c->type; 1717 | L->type = type_type; 1718 | L->type_len = c->type->params_num; 1719 | L->type_flags = c->type->params_types; 1720 | return L; 1721 | } 1722 | int x = tl_is_type_name (T->text, T->len); 1723 | if (x) { 1724 | struct tl_type *t = tl_add_type (T->text, T->len, -1, 0); 1725 | L = alloc_ctree_node (); 1726 | if (s) { 1727 | L->flags |= 1; 1728 | t->flags |= 8; 1729 | } 1730 | L->act = act_type; 1731 | L->data = t; 1732 | L->type = type_type; 1733 | L->type_len = t->params_num; 1734 | L->type_flags = t->params_types; 1735 | return L; 1736 | } else { 1737 | TL_ERROR ("Not a type/var ident `%.*s`\n", T->len, T->text); 1738 | return 0; 1739 | } 1740 | } 1741 | 1742 | struct tl_combinator_tree *tl_parse_any_term (struct tree *T, int s) { 1743 | switch (T->type) { 1744 | case type_type_term: 1745 | return tl_parse_type_term (T, s); 1746 | case type_nat_term: 1747 | return tl_parse_nat_term (T, s); 1748 | case type_term: 1749 | return tl_parse_term (T, s); 1750 | case type_expr: 1751 | return tl_parse_expr (T, s); 1752 | case type_subexpr: 1753 | return tl_parse_subexpr (T, s); 1754 | case type_nat_const: 1755 | return tl_parse_nat_const (T, s); 1756 | case type_type_ident: 1757 | case type_var_ident: 1758 | return tl_parse_ident (T, s); 1759 | default: 1760 | fprintf (stderr, "type = %d\n", T->type); 1761 | assert (0); 1762 | return 0; 1763 | } 1764 | } 1765 | 1766 | struct tl_combinator_tree *tl_parse_multiplicity (struct tree *T) { 1767 | assert (T->type == type_multiplicity); 1768 | assert (T->nc == 1); 1769 | return tl_parse_nat_term (T->c[0], 0); 1770 | } 1771 | 1772 | struct tl_combinator_tree *tl_parse_opt_args (struct tree *T) { 1773 | assert (T); 1774 | assert (T->type == type_opt_args); 1775 | assert (T->nc >= 2); 1776 | TL_INIT (R); 1777 | TL_TRY (tl_parse_type_term (T->c[T->nc - 1], 0), R); 1778 | assert (R->type == type_type && !R->type_len); 1779 | assert (tl_finish_subtree (R)); 1780 | struct tl_type *t = tl_tree_get_type (R); 1781 | //assert (t); 1782 | int tt = -1; 1783 | if (t && !strcmp (t->id, "#")) { 1784 | tt = 1; 1785 | } else if (t && !strcmp (t->id, "Type")) { 1786 | tt = 0; 1787 | } 1788 | if (tt < 0) { 1789 | TL_ERROR ("Optargs can be only of type # or Type\n"); 1790 | TL_FAIL; 1791 | } 1792 | 1793 | int i; 1794 | for (i = 0; i < T->nc - 1; i++) { 1795 | if (T->c[i]->type != type_var_ident) { 1796 | TL_ERROR ("Variable name expected\n"); 1797 | TL_FAIL; 1798 | } 1799 | if (T->c[i]->len == 1 && *T->c[i]->text == '_') { 1800 | TL_ERROR ("Variables can not be unnamed\n"); 1801 | TL_FAIL; 1802 | } 1803 | } 1804 | TL_INIT (H); 1805 | // for (i = T->nc - 2; i >= (T->nc >= 2 ? 0 : -1); i--) { 1806 | for (i = 0; i <= T->nc - 2; i++) { 1807 | TL_INIT (S); S = alloc_ctree_node (); 1808 | S->left = (i == T->nc - 2) ? R : tl_tree_dup (R) ; S->right = 0; 1809 | S->type = type_list_item; 1810 | S->type_len = 0; 1811 | S->act = act_field; 1812 | S->data = i >= 0 ? mystrdup (T->c[i]->text, T->c[i]->len) : 0; 1813 | if (tt >= 0) { 1814 | assert (S->data); 1815 | tl_add_var (S->data, S, tt); 1816 | } 1817 | S->flags = 33; 1818 | H = tl_union (H, S); 1819 | } 1820 | return H; 1821 | } 1822 | 1823 | struct tl_combinator_tree *tl_parse_args (struct tree *T); 1824 | struct tl_combinator_tree *tl_parse_args2 (struct tree *T) { 1825 | assert (T); 1826 | assert (T->type == type_args2); 1827 | assert (T->nc >= 1); 1828 | TL_INIT (R); 1829 | TL_INIT (L); 1830 | int x = 0; 1831 | char *field_name = 0; 1832 | if (T->c[x]->type == type_var_ident_opt || T->c[x]->type == type_var_ident) { 1833 | field_name = mystrdup (T->c[x]->text, T->c[x]->len); 1834 | if (!tl_add_field (field_name)) { 1835 | TL_ERROR ("Duplicate field name %s\n", field_name); 1836 | TL_FAIL; 1837 | } 1838 | x ++; 1839 | } 1840 | //fprintf (stderr, "%d %d\n", x, T->nc); 1841 | if (T->c[x]->type == type_multiplicity) { 1842 | L = tl_parse_multiplicity (T->c[x]); 1843 | if (!L) { TL_FAIL;} 1844 | x ++; 1845 | } else { 1846 | struct tl_var *v = tl_get_last_num_var (); 1847 | if (!v) { 1848 | TL_ERROR ("Expected multiplicity or nat var\n"); 1849 | TL_FAIL; 1850 | } 1851 | L = alloc_ctree_node (); 1852 | L->act = act_var; 1853 | L->type = type_num; 1854 | L->flags |= 128; 1855 | L->type_len = 0; 1856 | L->type_flags = 0; 1857 | L->data = v->ptr; 1858 | ((struct tl_combinator_tree *)(v->ptr))->flags |= 256; 1859 | } 1860 | namespace_push (); 1861 | while (x < T->nc) { 1862 | TL_TRY (tl_parse_args (T->c[x]), R); 1863 | x ++; 1864 | } 1865 | namespace_pop (); 1866 | struct tl_combinator_tree *S = alloc_ctree_node (); 1867 | S->type = type_type; 1868 | S->type_len = 0; 1869 | S->act = act_array; 1870 | S->left = L; 1871 | S->right = R; 1872 | //S->data = field_name; 1873 | 1874 | struct tl_combinator_tree *H = alloc_ctree_node (); 1875 | H->type = type_list_item; 1876 | H->act = act_field; 1877 | H->left = S; 1878 | H->right = 0; 1879 | H->data = field_name; 1880 | H->type_len = 0; 1881 | 1882 | return H; 1883 | } 1884 | 1885 | void tl_mark_vars (struct tl_combinator_tree *T); 1886 | struct tl_combinator_tree *tl_parse_args134 (struct tree *T) { 1887 | assert (T); 1888 | assert (T->type == type_args1 || T->type == type_args3 || T->type == type_args4); 1889 | assert (T->nc >= 1); 1890 | TL_INIT (R); 1891 | TL_TRY (tl_parse_type_term (T->c[T->nc - 1], 0), R); 1892 | assert (tl_finish_subtree (R)); 1893 | assert (R->type == type_type && !R->type_len); 1894 | struct tl_type *t = tl_tree_get_type (R); 1895 | //assert (t); 1896 | int tt = -1; 1897 | if (t && !strcmp (t->id, "#")) { 1898 | tt = 1; 1899 | } else if (t && !strcmp (t->id, "Type")) { 1900 | tt = 0; 1901 | } 1902 | 1903 | /* if (tt >= 0 && T->nc == 1) { 1904 | TL_ERROR ("Variables can not be unnamed (type %d)\n", tt); 1905 | }*/ 1906 | int last = T->nc - 2; 1907 | int excl = 0; 1908 | if (last >= 0 && T->c[last]->type == type_exclam) { 1909 | excl ++; 1910 | tl_mark_vars (R); 1911 | last --; 1912 | } 1913 | if (last >= 0 && T->c[last]->type == type_optional_arg_def) { 1914 | assert (T->c[last]->nc == 2); 1915 | TL_INIT (E); E = alloc_ctree_node (); 1916 | E->type = type_type; 1917 | E->act = act_opt_field; 1918 | E->left = tl_parse_ident (T->c[last]->c[0], 0); 1919 | int i; 1920 | long long x = 0; 1921 | for (i = 0; i < T->c[last]->c[1]->len; i++) { 1922 | x = x * 10 + T->c[last]->c[1]->text[i] - '0'; 1923 | } 1924 | E->left->type_flags = x; 1925 | E->type_flags = R->type_flags; 1926 | E->type_len = R->type_len; 1927 | E->right = R; 1928 | R = E; 1929 | last --; 1930 | } 1931 | int i; 1932 | for (i = 0; i < last; i++) { 1933 | if (T->c[i]->type != type_var_ident && T->c[i]->type != type_var_ident_opt) { 1934 | TL_ERROR ("Variable name expected\n"); 1935 | TL_FAIL; 1936 | } 1937 | /* if (tt >= 0 && (T->nc == 1 || (T->c[i]->len == 1 && *T->c[i]->text == '_'))) { 1938 | TL_ERROR ("Variables can not be unnamed\n"); 1939 | TL_FAIL; 1940 | }*/ 1941 | } 1942 | TL_INIT (H); 1943 | // for (i = T->nc - 2; i >= (T->nc >= 2 ? 0 : -1); i--) { 1944 | for (i = (last >= 0 ? 0 : -1); i <= last; i++) { 1945 | TL_INIT (S); S = alloc_ctree_node (); 1946 | S->left = (i == last) ? R : tl_tree_dup (R) ; S->right = 0; 1947 | S->type = type_list_item; 1948 | S->type_len = 0; 1949 | S->act = act_field; 1950 | S->data = i >= 0 ? mystrdup (T->c[i]->text, T->c[i]->len) : 0; 1951 | if (excl) { 1952 | S->flags |= FLAG_EXCL; 1953 | } 1954 | if (S->data && (T->c[i]->len >= 2 || *T->c[i]->text != '_')) { 1955 | if (!tl_add_field (S->data)) { 1956 | TL_ERROR ("Duplicate field name %s\n", (char *)S->data); 1957 | TL_FAIL; 1958 | } 1959 | } 1960 | if (tt >= 0) { 1961 | //assert (S->data); 1962 | char *name = S->data; 1963 | if (!name) { 1964 | static char s[20]; 1965 | sprintf (s, "%lld", lrand48 () * (1ll << 32) + lrand48 ()); 1966 | name = s; 1967 | } 1968 | struct tl_var *v = tl_add_var (name, S, tt); 1969 | if (!v) {TL_FAIL;} 1970 | v->flags |= 2; 1971 | } 1972 | 1973 | H = tl_union (H, S); 1974 | } 1975 | return H; 1976 | } 1977 | 1978 | 1979 | struct tl_combinator_tree *tl_parse_args (struct tree *T) { 1980 | assert (T->type == type_args); 1981 | assert (T->nc == 1); 1982 | switch (T->c[0]->type) { 1983 | case type_args1: 1984 | return tl_parse_args134 (T->c[0]); 1985 | case type_args2: 1986 | return tl_parse_args2 (T->c[0]); 1987 | case type_args3: 1988 | return tl_parse_args134 (T->c[0]); 1989 | case type_args4: 1990 | return tl_parse_args134 (T->c[0]); 1991 | default: 1992 | assert (0); 1993 | return 0; 1994 | } 1995 | } 1996 | 1997 | void tl_mark_vars (struct tl_combinator_tree *T) { 1998 | if (!T) { return; } 1999 | if (T->act == act_var) { 2000 | char *id = ((struct tl_combinator_tree *)(T->data))->data; 2001 | struct tl_var *v = tl_get_var (id, strlen (id)); 2002 | assert (v); 2003 | v->flags |= 1; 2004 | } 2005 | tl_mark_vars (T->left); 2006 | tl_mark_vars (T->right); 2007 | } 2008 | 2009 | struct tl_combinator_tree *tl_parse_result_type (struct tree *T) { 2010 | assert (T->type == type_result_type); 2011 | assert (T->nc >= 1); 2012 | assert (T->nc <= 64); 2013 | 2014 | TL_INIT (L); 2015 | 2016 | if (tl_get_var (T->c[0]->text, T->c[0]->len)) { 2017 | if (T->nc != 1) { 2018 | TL_ERROR ("Variable can not take params\n"); 2019 | TL_FAIL; 2020 | } 2021 | L = alloc_ctree_node (); 2022 | L->act = act_var; 2023 | L->type = type_type; 2024 | struct tl_var *v = tl_get_var (T->c[0]->text, T->c[0]->len); 2025 | if (v->type) { 2026 | TL_ERROR ("Type mistmatch\n"); 2027 | TL_FAIL; 2028 | } 2029 | L->data = v->ptr; 2030 | // assert (v->ptr); 2031 | } else { 2032 | L = alloc_ctree_node (); 2033 | L->act = act_type; 2034 | L->type = type_type; 2035 | struct tl_type *t = tl_add_type (T->c[0]->text, T->c[0]->len, -1, 0); 2036 | assert (t); 2037 | L->type_len = t->params_num; 2038 | L->type_flags = t->params_types; 2039 | L->data = t; 2040 | 2041 | int i; 2042 | for (i = 1; i < T->nc; i++) { 2043 | TL_TRY (tl_parse_any_term (T->c[i], 0), L); 2044 | assert (L->right); 2045 | assert (L->right->type == type_num || L->right->type == type_num_value || (L->right->type == type_type && L->right->type_len == 0)); 2046 | } 2047 | } 2048 | 2049 | if (!tl_finish_subtree (L)) { 2050 | TL_FAIL; 2051 | } 2052 | 2053 | tl_mark_vars (L); 2054 | return L; 2055 | } 2056 | 2057 | int __ok; 2058 | void tl_var_check_used (struct tl_var *v) { 2059 | __ok = __ok && (v->flags & 3); 2060 | } 2061 | 2062 | int tl_parse_combinator_decl (struct tree *T, int fun) { 2063 | assert (T->type == type_combinator_decl); 2064 | assert (T->nc >= 3); 2065 | namespace_level = 0; 2066 | tl_clear_vars (); 2067 | tl_clear_fields (); 2068 | TL_INIT (L); 2069 | TL_INIT (R); 2070 | 2071 | int i = 1; 2072 | while (i < T->nc - 2 && T->c[i]->type == type_opt_args) { 2073 | TL_TRY (tl_parse_opt_args (T->c[i]), L); 2074 | i++; 2075 | } 2076 | while (i < T->nc - 2 && T->c[i]->type == type_args) { 2077 | TL_TRY (tl_parse_args (T->c[i]), L); 2078 | i++; 2079 | } 2080 | assert (i == T->nc - 2 && T->c[i]->type == type_equals); 2081 | i ++; 2082 | 2083 | R = tl_parse_result_type (T->c[i]); 2084 | if (!R) { TL_FAIL; } 2085 | 2086 | struct tl_type *t = tl_tree_get_type (R); 2087 | if (!fun && !t) { 2088 | TL_ERROR ("Only functions can return variables\n"); 2089 | } 2090 | assert (t || fun); 2091 | 2092 | assert (namespace_level == 0); 2093 | __ok = 1; 2094 | tree_act_tl_var (vars[0], tl_var_check_used); 2095 | if (!__ok) { 2096 | TL_ERROR ("Not all variables are used in right side\n"); 2097 | TL_FAIL; 2098 | } 2099 | 2100 | if (tl_get_constructor (T->c[0]->text, T->c[0]->len) || tl_get_function (T->c[0]->text, T->c[0]->len)) { 2101 | TL_ERROR ("Duplicate combinator id %.*s\n", T->c[0]->len, T->c[0]->text); 2102 | return 0; 2103 | } 2104 | struct tl_constructor *c = !fun ? tl_add_constructor (t, T->c[0]->text, T->c[0]->len, 0) : tl_add_function (t, T->c[0]->text, T->c[0]->len, 0); 2105 | if (!c) { TL_FAIL; } 2106 | c->left = L; 2107 | c->right = R; 2108 | 2109 | if (!c->name) { 2110 | tl_count_combinator_name (c); 2111 | } 2112 | tl_print_combinator (c); 2113 | 2114 | return 1; 2115 | } 2116 | 2117 | void change_var_ptrs (struct tl_combinator_tree *O, struct tl_combinator_tree *D, struct tree_var_value **V) { 2118 | if (!O || !D) { 2119 | assert (!O && !D); 2120 | return; 2121 | } 2122 | if (O->act == act_field) { 2123 | struct tl_type *t = tl_tree_get_type (O->left); 2124 | if (t && (!strcmp (t->id, "#") || !strcmp (t->id, "Type"))) { 2125 | tl_set_var_value (V, O, D); 2126 | } 2127 | } 2128 | if (O->act == act_var) { 2129 | assert (D->data == O->data); 2130 | D->data = tl_get_var_value (V, O->data); 2131 | assert (D->data); 2132 | } 2133 | change_var_ptrs (O->left, D->left, V); 2134 | change_var_ptrs (O->right, D->right, V); 2135 | } 2136 | 2137 | struct tl_combinator_tree *change_first_var (struct tl_combinator_tree *O, struct tl_combinator_tree **X, struct tl_combinator_tree *Y) { 2138 | if (!O) { return (void *)-2l; }; 2139 | if (O->act == act_field && !*X) { 2140 | struct tl_type *t = tl_tree_get_type (O->left); 2141 | if (t && !strcmp (t->id, "#")) { 2142 | if (Y->type != type_num && Y->type != type_num_value) { 2143 | TL_ERROR ("change_var: Type mistmatch\n"); 2144 | return 0; 2145 | } else { 2146 | *X = O; 2147 | return (void *)-1l; 2148 | } 2149 | } 2150 | if (t && !strcmp (t->id, "Type")) { 2151 | if (Y->type != type_type || Y->type_len != 0) { 2152 | TL_ERROR ("change_var: Type mistmatch\n"); 2153 | return 0; 2154 | } else { 2155 | *X = O; 2156 | return (void *)-1l; 2157 | } 2158 | } 2159 | } 2160 | if (O->act == act_var) { 2161 | if (O->data == *X) { 2162 | struct tl_combinator_tree *R = tl_tree_dup (Y); 2163 | if (O->type == type_num || O->type == type_num_value) { R->type_flags += O->type_flags; } 2164 | return R; 2165 | } 2166 | } 2167 | struct tl_combinator_tree *t; 2168 | t = change_first_var (O->left, X, Y); 2169 | if (!t) { return 0;} 2170 | if (t == (void *)-1l) { 2171 | t = change_first_var (O->right, X, Y); 2172 | if (!t) { return 0;} 2173 | if (t == (void *)-1l) { return (void *)-1l; } 2174 | if (t != (void *)-2l) { return t;} 2175 | return (void *)-1l; 2176 | } 2177 | if (t != (void *)-2l) { 2178 | O->left = t; 2179 | } 2180 | t = change_first_var (O->right, X, Y); 2181 | if (!t) { return 0;} 2182 | if (t == (void *)-1l) { 2183 | return O->left; 2184 | } 2185 | if (t != (void *)-2l) { 2186 | O->right = t; 2187 | } 2188 | return O; 2189 | } 2190 | 2191 | 2192 | int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T); 2193 | struct tree_var_value **_T; 2194 | int __tok; 2195 | void check_nat_val (struct tl_var_value v) { 2196 | if (!__tok) { return; } 2197 | long long x = v.num_val; 2198 | struct tl_combinator_tree *L = v.val; 2199 | if (L->type == type_type) { return;} 2200 | while (1) { 2201 | if (L->type == type_num_value) { 2202 | if (x + L->type_flags < 0) { 2203 | __tok = 0; 2204 | return; 2205 | } else { 2206 | return; 2207 | } 2208 | } 2209 | assert (L->type == type_num); 2210 | x += L->type_flags; 2211 | x += tl_get_var_value_num (_T, L->data); 2212 | L = tl_get_var_value (_T, L->data); 2213 | if (!L) { return;} 2214 | } 2215 | } 2216 | 2217 | int check_constructors_equal (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T) { 2218 | if (!uniformize (L, R, T)) { return 0; } 2219 | __tok = 1; 2220 | _T = T; 2221 | tree_act_var_value (*T, check_nat_val); 2222 | return __tok; 2223 | } 2224 | 2225 | struct tl_combinator_tree *reduce_type (struct tl_combinator_tree *A, struct tl_type *t) { 2226 | assert (A); 2227 | if (A->type_len == t->params_num) { 2228 | assert (A->type_flags == t->params_types); 2229 | A->act = act_type; 2230 | A->type = type_type; 2231 | A->left = A->right = 0; 2232 | A->data = t; 2233 | return A; 2234 | } 2235 | A->left = reduce_type (A->left, t); 2236 | return A; 2237 | } 2238 | 2239 | struct tl_combinator_tree *change_value_var (struct tl_combinator_tree *O, struct tree_var_value **X) { 2240 | if (!O) { return (void *)-2l; }; 2241 | while (O->act == act_var) { 2242 | assert (O->data); 2243 | if (!tl_get_var_value (X, O->data)) { 2244 | break; 2245 | } 2246 | if (O->type == type_type) { 2247 | O = tl_tree_dup (tl_get_var_value (X, O->data)); 2248 | } else { 2249 | long long n = tl_get_var_value_num (X, O->data); 2250 | struct tl_combinator_tree *T = tl_get_var_value (X, O->data); 2251 | O->data = T->data; 2252 | O->type = T->type; 2253 | O->act = T->act; 2254 | O->type_flags = O->type_flags + n + T->type_flags; 2255 | } 2256 | } 2257 | if (O->act == act_field) { 2258 | if (tl_get_var_value (X, O)) { return (void *)-1l; } 2259 | } 2260 | struct tl_combinator_tree *t; 2261 | t = change_value_var (O->left, X); 2262 | if (!t) { return 0;} 2263 | if (t == (void *)-1l) { 2264 | t = change_value_var (O->right, X); 2265 | if (!t) { return 0;} 2266 | if (t == (void *)-1l) { return (void *)-1l; } 2267 | if (t != (void *)-2l) { return t;} 2268 | return (void *)-1l; 2269 | } 2270 | if (t != (void *)-2l) { 2271 | O->left = t; 2272 | } 2273 | t = change_value_var (O->right, X); 2274 | if (!t) { return 0;} 2275 | if (t == (void *)-1l) { 2276 | return O->left; 2277 | } 2278 | if (t != (void *)-2l) { 2279 | O->right = t; 2280 | } 2281 | return O; 2282 | } 2283 | 2284 | int tl_parse_partial_type_app_decl (struct tree *T) { 2285 | assert (T->type == type_partial_type_app_decl); 2286 | assert (T->nc >= 1); 2287 | 2288 | assert (T->c[0]->type == type_boxed_type_ident); 2289 | struct tl_type *t = tl_get_type (T->c[0]->text, T->c[0]->len); 2290 | if (!t) { 2291 | TL_ERROR ("Can not make partial app for unknown type\n"); 2292 | return 0; 2293 | } 2294 | 2295 | tl_type_finalize (t); 2296 | 2297 | struct tl_combinator_tree *L = tl_parse_ident (T->c[0], 0); 2298 | assert (L); 2299 | int i; 2300 | tl_buf_reset (); 2301 | int cc = T->nc - 1; 2302 | for (i = 1; i < T->nc; i++) { 2303 | TL_TRY (tl_parse_any_term (T->c[i], 0), L); 2304 | tl_buf_add_tree (L->right, 1); 2305 | } 2306 | 2307 | while (L->type_len) { 2308 | struct tl_combinator_tree *C = alloc_ctree_node (); 2309 | C->act = act_var; 2310 | C->type = (L->type_flags & 1) ? type_num : type_type; 2311 | C->type_len = 0; 2312 | C->type_flags = 0; 2313 | C->data = (void *)-1l; 2314 | L = tl_union (L, C); 2315 | if (!L) { return 0; } 2316 | } 2317 | 2318 | 2319 | static char _buf[100000]; 2320 | snprintf (_buf, 100000, "%s%.*s", t->id, buf_pos, buf); 2321 | struct tl_type *nt = tl_add_type (_buf, strlen (_buf), t->params_num - cc, t->params_types >> cc); 2322 | assert (nt); 2323 | //snprintf (_buf, 100000, "%s #", t->id); 2324 | //nt->real_id = strdup (_buf); 2325 | 2326 | for (i = 0; i < t->constructors_num; i++) { 2327 | struct tl_constructor *c = t->constructors[i]; 2328 | struct tree_var_value *V = 0; 2329 | TL_INIT (A); 2330 | TL_INIT (B); 2331 | A = tl_tree_dup (c->left); 2332 | B = tl_tree_dup (c->right); 2333 | 2334 | struct tree_var_value *W = 0; 2335 | change_var_ptrs (c->left, A, &W); 2336 | change_var_ptrs (c->right, B, &W); 2337 | 2338 | 2339 | if (!check_constructors_equal (B, L, &V)) { continue; } 2340 | B = reduce_type (B, nt); 2341 | A = change_value_var (A, &V); 2342 | if (A == (void *)-1l) { A = 0;} 2343 | B = change_value_var (B, &V); 2344 | assert (B != (void *)-1l); 2345 | snprintf (_buf, 100000, "%s%.*s", c->id, buf_pos, buf); 2346 | 2347 | struct tl_constructor *r = tl_add_constructor (nt, _buf, strlen (_buf), 1); 2348 | snprintf (_buf, 100000, "%s", c->id); 2349 | r->real_id = tstrdup (_buf); 2350 | 2351 | r->left = A; 2352 | r->right = B; 2353 | if (!r->name) { 2354 | tl_count_combinator_name (r); 2355 | } 2356 | tl_print_combinator (r); 2357 | } 2358 | 2359 | return 1; 2360 | } 2361 | 2362 | int tl_parse_partial_comb_app_decl (struct tree *T, int fun) { 2363 | assert (T->type == type_partial_comb_app_decl); 2364 | 2365 | struct tl_constructor *c = !fun ? tl_get_constructor (T->c[0]->text, T->c[0]->len) : tl_get_function (T->c[0]->text, T->c[0]->len); 2366 | if (!c) { 2367 | TL_ERROR ("Can not make partial app for undefined combinator\n"); 2368 | return 0; 2369 | } 2370 | 2371 | //TL_INIT (K); 2372 | //static char buf[1000]; 2373 | //int x = sprintf (buf, "%s", c->id); 2374 | TL_INIT (L); 2375 | TL_INIT (R); 2376 | L = tl_tree_dup (c->left); 2377 | R = tl_tree_dup (c->right); 2378 | 2379 | 2380 | struct tree_var_value *V = 0; 2381 | change_var_ptrs (c->left, L, &V); 2382 | change_var_ptrs (c->right, R, &V); 2383 | V = tree_clear_var_value (V); 2384 | 2385 | int i; 2386 | tl_buf_reset (); 2387 | for (i = 1; i < T->nc; i++) { 2388 | TL_INIT (X); 2389 | TL_INIT (Z); 2390 | X = tl_parse_any_term (T->c[i], 0); 2391 | struct tl_combinator_tree *K = 0; 2392 | if (!(Z = change_first_var (L, &K, X))) { 2393 | TL_FAIL; 2394 | } 2395 | L = Z; 2396 | if (!K) { 2397 | TL_ERROR ("Partial app: not enougth variables (i = %d)\n", i); 2398 | TL_FAIL; 2399 | } 2400 | if (!(Z = change_first_var (R, &K, X))) { 2401 | TL_FAIL; 2402 | } 2403 | assert (Z == R); 2404 | tl_buf_add_tree (X, 1); 2405 | } 2406 | 2407 | static char _buf[100000]; 2408 | snprintf (_buf, 100000, "%s%.*s", c->id, buf_pos, buf); 2409 | // fprintf (stderr, "Local id: %s\n", _buf); 2410 | 2411 | struct tl_constructor *r = !fun ? tl_add_constructor (c->type, _buf, strlen (_buf), 1) : tl_add_function (c->type, _buf, strlen (_buf), 1); 2412 | r->left = L; 2413 | r->right = R; 2414 | snprintf (_buf, 100000, "%s", c->id); 2415 | r->real_id = tstrdup (_buf); 2416 | if (!r->name) { 2417 | tl_count_combinator_name (r); 2418 | } 2419 | tl_print_combinator (r); 2420 | return 1; 2421 | } 2422 | 2423 | 2424 | int tl_parse_partial_app_decl (struct tree *T, int fun) { 2425 | assert (T->type == type_partial_app_decl); 2426 | assert (T->nc == 1); 2427 | if (T->c[0]->type == type_partial_comb_app_decl) { 2428 | return tl_parse_partial_comb_app_decl (T->c[0], fun); 2429 | } else { 2430 | if (fun) { 2431 | TL_ERROR ("Partial type app in functions block\n"); 2432 | TL_FAIL; 2433 | } 2434 | return tl_parse_partial_type_app_decl (T->c[0]); 2435 | } 2436 | } 2437 | 2438 | int tl_parse_final_final (struct tree *T) { 2439 | assert (T->type == type_final_final); 2440 | assert (T->nc == 1); 2441 | struct tl_type *R; 2442 | if ((R = tl_get_type (T->c[0]->text, T->c[0]->len))) { 2443 | R->flags |= 1; 2444 | return 1; 2445 | } else { 2446 | TL_ERROR ("Final statement for type `%.*s` before declaration\n", T->c[0]->len, T->c[0]->text); 2447 | TL_FAIL; 2448 | } 2449 | } 2450 | 2451 | int tl_parse_final_new (struct tree *T) { 2452 | assert (T->type == type_final_new); 2453 | assert (T->nc == 1); 2454 | if (tl_get_type (T->c[0]->text, T->c[0]->len)) { 2455 | TL_ERROR ("New statement: type `%.*s` already declared\n", T->c[0]->len, T->c[0]->text); 2456 | TL_FAIL; 2457 | } else { 2458 | return 1; 2459 | } 2460 | } 2461 | 2462 | int tl_parse_final_empty (struct tree *T) { 2463 | assert (T->type == type_final_empty); 2464 | assert (T->nc == 1); 2465 | if (tl_get_type (T->c[0]->text, T->c[0]->len)) { 2466 | TL_ERROR ("New statement: type `%.*s` already declared\n", T->c[0]->len, T->c[0]->text); 2467 | TL_FAIL; 2468 | } 2469 | struct tl_type *t = tl_add_type (T->c[0]->text, T->c[0]->len, 0, 0); 2470 | assert (t); 2471 | t->flags |= 1 | FLAG_EMPTY; 2472 | return 1; 2473 | } 2474 | 2475 | int tl_parse_final_decl (struct tree *T, int fun) { 2476 | assert (T->type == type_final_decl); 2477 | assert (!fun); 2478 | assert (T->nc == 1); 2479 | switch (T->c[0]->type) { 2480 | case type_final_new: 2481 | return tl_parse_final_new (T->c[0]); 2482 | case type_final_final: 2483 | return tl_parse_final_final (T->c[0]); 2484 | case type_final_empty: 2485 | return tl_parse_final_empty (T->c[0]); 2486 | default: 2487 | assert (0); 2488 | return 0; 2489 | } 2490 | } 2491 | 2492 | int tl_parse_builtin_combinator_decl (struct tree *T, int fun) { 2493 | if (fun) { 2494 | TL_ERROR ("Builtin type can not be described in function block\n"); 2495 | return -1; 2496 | } 2497 | assert (T->type == type_builtin_combinator_decl); 2498 | assert (T->nc == 2); 2499 | assert (T->c[0]->type == type_full_combinator_id); 2500 | assert (T->c[1]->type == type_boxed_type_ident); 2501 | 2502 | 2503 | if ((!mystrcmp2 (T->c[0]->text, T->c[0]->len, "int") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Int")) || 2504 | (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "long") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Long")) || 2505 | (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "double") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Double")) || 2506 | (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "object") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Object")) || 2507 | (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "function") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "Function")) || 2508 | (!mystrcmp2 (T->c[0]->text, T->c[0]->len, "string") && !mystrcmp2 (T->c[1]->text, T->c[1]->len, "String"))) { 2509 | struct tl_type *t = tl_add_type (T->c[1]->text, T->c[1]->len, 0, 0); 2510 | if (!t) { 2511 | return 0; 2512 | } 2513 | struct tl_constructor *c = tl_add_constructor (t, T->c[0]->text, T->c[0]->len, 0); 2514 | if (!c) { 2515 | return 0; 2516 | } 2517 | 2518 | c->left = alloc_ctree_node (); 2519 | c->left->act = act_question_mark; 2520 | c->left->type = type_list_item; 2521 | 2522 | c->right = alloc_ctree_node (); 2523 | c->right->act = act_type; 2524 | c->right->data = t; 2525 | c->right->type = type_type; 2526 | 2527 | if (!c->name) { 2528 | tl_count_combinator_name (c); 2529 | } 2530 | tl_print_combinator (c); 2531 | } else { 2532 | TL_ERROR ("Unknown builting type `%.*s`\n", T->c[0]->len, T->c[0]->text); 2533 | return 0; 2534 | } 2535 | 2536 | return 1; 2537 | } 2538 | 2539 | int tl_parse_declaration (struct tree *T, int fun) { 2540 | assert (T->type == type_declaration); 2541 | assert (T->nc == 1); 2542 | switch (T->c[0]->type) { 2543 | case type_combinator_decl: 2544 | return tl_parse_combinator_decl (T->c[0], fun); 2545 | case type_partial_app_decl: 2546 | return tl_parse_partial_app_decl (T->c[0], fun); 2547 | case type_final_decl: 2548 | return tl_parse_final_decl (T->c[0], fun); 2549 | case type_builtin_combinator_decl: 2550 | return tl_parse_builtin_combinator_decl (T->c[0], fun); 2551 | default: 2552 | assert (0); 2553 | return 0; 2554 | } 2555 | } 2556 | 2557 | int tl_parse_constr_declarations (struct tree *T) { 2558 | assert (T->type == type_constr_declarations); 2559 | int i; 2560 | for (i = 0; i < T->nc; i++) { 2561 | TL_TRY_PES (tl_parse_declaration (T->c[i], 0)); 2562 | } 2563 | return 1; 2564 | } 2565 | 2566 | int tl_parse_fun_declarations (struct tree *T) { 2567 | assert (T->type == type_fun_declarations); 2568 | int i; 2569 | for (i = 0; i < T->nc; i++) { 2570 | TL_TRY_PES (tl_parse_declaration (T->c[i], 1)); 2571 | } 2572 | return 1; 2573 | } 2574 | 2575 | int tl_tree_lookup_value (struct tl_combinator_tree *L, void *var, struct tree_var_value **T) { 2576 | if (!L) { 2577 | return -1; 2578 | } 2579 | if (L->act == act_var && L->data == var) { 2580 | return 0; 2581 | } 2582 | if (L->act == act_var) { 2583 | struct tl_combinator_tree *E = tl_get_var_value (T, L->data); 2584 | if (!E) { return -1;} 2585 | else { return tl_tree_lookup_value (E, var, T); } 2586 | } 2587 | if (tl_tree_lookup_value (L->left, var, T) >= 0) { return 1; } 2588 | if (tl_tree_lookup_value (L->right, var, T) >= 0) { return 1; } 2589 | return -1; 2590 | } 2591 | 2592 | int tl_tree_lookup_value_nat (struct tl_combinator_tree *L, void *var, long long x, struct tree_var_value **T) { 2593 | assert (L); 2594 | if (L->type == type_num_value) { return -1; } 2595 | assert (L->type == type_num); 2596 | assert (L->act == act_var); 2597 | if (L->data == var) { 2598 | return x == L->type_flags ? 0 : 1; 2599 | } else { 2600 | if (!tl_get_var_value (T, L->data)) { 2601 | return -1; 2602 | } 2603 | return tl_tree_lookup_value_nat (tl_get_var_value (T, L->data), var, x + tl_get_var_value_num (T, L->data), T); 2604 | } 2605 | 2606 | } 2607 | 2608 | int uniformize (struct tl_combinator_tree *L, struct tl_combinator_tree *R, struct tree_var_value **T) { 2609 | if (!L || !R) { 2610 | assert (!L && !R); 2611 | return 1; 2612 | } 2613 | if (R->act == act_var) { 2614 | struct tl_combinator_tree *_ = R; R = L; L = _; 2615 | } 2616 | 2617 | if (L->type == type_type) { 2618 | if (R->type != type_type || L->type_len != R->type_len || L->type_flags != R->type_flags) { 2619 | return 0; 2620 | } 2621 | if (R->data == (void *)-1l || L->data == (void *)-1l) { return 1;} 2622 | if (L->act == act_var) { 2623 | int x = tl_tree_lookup_value (R, L->data, T); 2624 | if (x > 0) { 2625 | // if (tl_tree_lookup_value (R, L->data, T) > 0) { 2626 | return 0; 2627 | } 2628 | if (x == 0) { 2629 | return 1; 2630 | } 2631 | struct tl_combinator_tree *E = tl_get_var_value (T, L->data); 2632 | if (!E) { 2633 | tl_set_var_value (T, L->data, R); 2634 | return 1; 2635 | } else { 2636 | return uniformize (E, R, T); 2637 | } 2638 | } else { 2639 | if (L->act != R->act || L->data != R->data) { 2640 | return 0; 2641 | } 2642 | return uniformize (L->left, R->left, T) && uniformize (L->right, R->right, T); 2643 | } 2644 | } else { 2645 | assert (L->type == type_num || L->type == type_num_value); 2646 | if (R->type != type_num && R->type != type_num_value) { 2647 | return 0; 2648 | } 2649 | assert (R->type == type_num || R->type == type_num_value); 2650 | if (R->data == (void *)-1l || L->data == (void *)-1l) { return 1;} 2651 | long long x = 0; 2652 | struct tl_combinator_tree *K = L; 2653 | while (1) { 2654 | x += K->type_flags; 2655 | if (K->type == type_num_value) { 2656 | break; 2657 | } 2658 | if (!tl_get_var_value (T, K->data)) { 2659 | int s = tl_tree_lookup_value_nat (R, K->data, K->type_flags, T); 2660 | if (s > 0) { 2661 | return 0; 2662 | } 2663 | if (s == 0) { 2664 | return 1; 2665 | } 2666 | /*tl_set_var_value_num (T, K->data, R, -x); 2667 | return 1;*/ 2668 | break; 2669 | } 2670 | x += tl_get_var_value_num (T, K->data); 2671 | K = tl_get_var_value (T, K->data); 2672 | } 2673 | long long y = 0; 2674 | struct tl_combinator_tree *M = R; 2675 | while (1) { 2676 | y += M->type_flags; 2677 | if (M->type == type_num_value) { 2678 | break; 2679 | } 2680 | if (!tl_get_var_value (T, M->data)) { 2681 | int s = tl_tree_lookup_value_nat (L, M->data, M->type_flags, T); 2682 | if (s > 0) { 2683 | return 0; 2684 | } 2685 | if (s == 0) { 2686 | return 1; 2687 | } 2688 | /*tl_set_var_value_num (T, M->data, L, -y); 2689 | return 1;*/ 2690 | break; 2691 | } 2692 | y += tl_get_var_value_num (T, M->data); 2693 | M = tl_get_var_value (T, M->data); 2694 | } 2695 | if (K->type == type_num_value && M->type == type_num_value) { 2696 | return x == y; 2697 | } 2698 | if (M->type == type_num_value) { 2699 | tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags)); 2700 | return 1; 2701 | } else if (K->type == type_num_value) { 2702 | tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags)); 2703 | return 1; 2704 | } else { 2705 | if (x >= y) { 2706 | tl_set_var_value_num (T, K->data, M, -(x - y + M->type_flags)); 2707 | } else { 2708 | tl_set_var_value_num (T, M->data, K, -(y - x + K->type_flags)); 2709 | } 2710 | return 1; 2711 | } 2712 | } 2713 | return 0; 2714 | } 2715 | 2716 | 2717 | void tl_type_check (struct tl_type *t) { 2718 | if (!__ok) return; 2719 | if (!strcmp (t->id, "#")) { t->name = 0x70659eff; return; } 2720 | if (!strcmp (t->id, "Type")) { t->name = 0x2cecf817; return; } 2721 | if (t->constructors_num <= 0 && !(t->flags & FLAG_EMPTY)) { 2722 | TL_ERROR ("Type %s has no constructors\n", t->id); 2723 | __ok = 0; 2724 | return; 2725 | } 2726 | int i, j; 2727 | t->name = 0; 2728 | for (i = 0; i < t->constructors_num; i++) { 2729 | t->name ^= t->constructors[i]->name; 2730 | } 2731 | for (i = 0; i < t->constructors_num; i++) { 2732 | for (j = i + 1; j < t->constructors_num; j++) { 2733 | struct tree_var_value *v = 0; 2734 | if (check_constructors_equal (t->constructors[i]->right, t->constructors[j]->right, &v)) { 2735 | t->flags |= 16; 2736 | } 2737 | } 2738 | } 2739 | if ((t->flags & 24) == 24) { 2740 | TL_WARNING ("Warning: Type %s has overlapping costructors, but it is used with `%%`\n", t->id); 2741 | } 2742 | int z = 0; 2743 | int sid = 0; 2744 | for (i = 0; i < t->constructors_num; i++) if (*t->constructors[i]->id == '_') { 2745 | z ++; 2746 | sid = i; 2747 | } 2748 | if (z > 1) { 2749 | TL_ERROR ("Type %s has %d default constructors\n", t->id, z); 2750 | __ok = 0; 2751 | return; 2752 | } 2753 | if (z == 1 && (t->flags & 8)) { 2754 | TL_ERROR ("Type %s has default constructors and used bare\n", t->id); 2755 | __ok = 0; 2756 | return; 2757 | } 2758 | if (z) { 2759 | struct tl_constructor *c; 2760 | c = t->constructors[sid]; 2761 | t->constructors[sid] = t->constructors[t->constructors_num - 1]; 2762 | t->constructors[t->constructors_num - 1] = c; 2763 | } 2764 | } 2765 | 2766 | struct tl_program *tl_parse (struct tree *T) { 2767 | assert (T); 2768 | assert (T->type == type_tl_program); 2769 | int i; 2770 | tl_program_cur = talloc (sizeof (*tl_program_cur)); 2771 | tl_add_type ("#", 1, 0, 0); 2772 | tl_add_type ("Type", 4, 0, 0); 2773 | for (i = 0; i < T->nc; i++) { 2774 | if (T->c[i]->type == type_constr_declarations) { TL_TRY_PES (tl_parse_constr_declarations (T->c[i])); } 2775 | else { TL_TRY_PES (tl_parse_fun_declarations (T->c[i])) } 2776 | } 2777 | __ok = 1; 2778 | tree_act_tl_type (tl_type_tree, tl_type_check); 2779 | if (!__ok) { 2780 | return 0; 2781 | } 2782 | return tl_program_cur; 2783 | } 2784 | 2785 | int __f; 2786 | int num = 0; 2787 | 2788 | void wint (int a) { 2789 | // printf ("%d ", a); 2790 | a = htole32 (a); 2791 | assert (write (__f, &a, 4) == 4); 2792 | } 2793 | 2794 | void wdata (const void *x, int len) { 2795 | assert (write (__f, x, len) == len); 2796 | } 2797 | 2798 | void wstr (const char *s) { 2799 | if (s) { 2800 | // printf ("\"%s\" ", s); 2801 | int x = strlen (s); 2802 | if (x <= 254) { 2803 | unsigned char x_c = (unsigned char)x; 2804 | assert (write (__f, &x_c, 1) == 1); 2805 | } else { 2806 | fprintf (stderr, "String is too big...\n"); 2807 | assert (0); 2808 | } 2809 | wdata (s, x); 2810 | x ++; // The header, containing the length, which is 1 byte 2811 | int t = 0; 2812 | if (x & 3) { 2813 | // Let's hope it's truly zero on every platform 2814 | wdata (&t, 4 - (x & 3)); 2815 | } 2816 | } else { 2817 | // printf (" "); 2818 | wint (0); 2819 | } 2820 | } 2821 | 2822 | void wll (long long a) { 2823 | // printf ("%lld ", a); 2824 | a = htole64 (a); 2825 | assert (write (__f, &a, 8) == 8); 2826 | } 2827 | 2828 | int count_list_size (struct tl_combinator_tree *T) { 2829 | assert (T->type == type_list || T->type == type_list_item); 2830 | if (T->type == type_list_item) { 2831 | return 1; 2832 | } else { 2833 | return count_list_size (T->left) + count_list_size (T->right); 2834 | } 2835 | } 2836 | 2837 | void write_type_flags (long long flags) { 2838 | int new_flags = 0; 2839 | if (flags & 1) { 2840 | new_flags |= FLAG_BARE; 2841 | } 2842 | if (flags & FLAG_DEFAULT_CONSTRUCTOR) { 2843 | new_flags |= FLAG_DEFAULT_CONSTRUCTOR; 2844 | } 2845 | wint (new_flags); 2846 | } 2847 | 2848 | void write_field_flags (long long flags) { 2849 | int new_flags = 0; 2850 | //fprintf (stderr, "%lld\n", flags); 2851 | if (flags & 1) { 2852 | new_flags |= FLAG_BARE; 2853 | } 2854 | if (flags & 32) { 2855 | new_flags |= FLAG_OPT_VAR; 2856 | } 2857 | if (flags & FLAG_EXCL) { 2858 | new_flags |= FLAG_EXCL; 2859 | } 2860 | if (flags & FLAG_OPT_FIELD) { 2861 | // new_flags |= FLAG_OPT_FIELD; 2862 | new_flags |= 2; 2863 | } 2864 | if (flags & (1 << 21)) { 2865 | new_flags |= 4; 2866 | } 2867 | wint (new_flags); 2868 | } 2869 | 2870 | void write_var_type_flags (long long flags) { 2871 | int new_flags = 0; 2872 | if (flags & 1) { 2873 | new_flags |= FLAG_BARE; 2874 | } 2875 | if (new_flags & FLAG_BARE) { 2876 | TL_ERROR ("Sorry, bare vars are not (yet ?) supported.\n"); 2877 | assert (!(new_flags & FLAG_BARE)); 2878 | } 2879 | wint (new_flags); 2880 | } 2881 | 2882 | void write_tree (struct tl_combinator_tree *T, int extra, struct tree_var_value **v, int *last_var); 2883 | void write_args (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) { 2884 | assert (T->type == type_list || T->type == type_list_item); 2885 | if (T->type == type_list) { 2886 | assert (T->act == act_union); 2887 | assert (T->left); 2888 | assert (T->right); 2889 | write_args (T->left, v, last_var); 2890 | write_args (T->right, v, last_var); 2891 | return; 2892 | } 2893 | wint (TLS_ARG_V2); 2894 | assert (T->act == act_field); 2895 | assert (T->left); 2896 | wstr (T->data && strcmp (T->data, "_") ? T->data : 0); 2897 | long long f = T->flags; 2898 | if (T->left->act == act_opt_field) { 2899 | f |= (1 << 20); 2900 | } 2901 | if (T->left->act == act_type && T->left->data && (!strcmp (((struct tl_type *)T->left->data)->id, "#") || !strcmp (((struct tl_type *)T->left->data)->id, "Type"))) { 2902 | write_field_flags (f | (1 << 21)); 2903 | wint (*last_var); 2904 | *last_var = (*last_var) + 1; 2905 | tl_set_var_value_num (v, T, 0, (*last_var) - 1); 2906 | } else { 2907 | write_field_flags (f); 2908 | } 2909 | write_tree (T->left, 0, v, last_var); 2910 | } 2911 | 2912 | void write_array (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) { 2913 | wint (TLS_ARRAY); 2914 | write_tree (T->left, 0, v, last_var); 2915 | write_tree (T->right, 0, v, last_var); 2916 | } 2917 | 2918 | void write_type_rec (struct tl_combinator_tree *T, int cc, struct tree_var_value **v, int *last_var) { 2919 | if (T->act == act_arg) { 2920 | write_type_rec (T->left, cc + 1, v, last_var); 2921 | if (T->right->type == type_num_value || T->right->type == type_num) { 2922 | wint (TLS_EXPR_NAT); 2923 | } else { 2924 | wint (TLS_EXPR_TYPE); 2925 | } 2926 | write_tree (T->right, 0, v, last_var); 2927 | } else { 2928 | assert (T->act == act_var || T->act == act_type); 2929 | if (T->act == act_var) { 2930 | assert (!cc); 2931 | wint (TLS_TYPE_VAR); 2932 | wint (tl_get_var_value_num (v, T->data)); 2933 | write_var_type_flags (T->flags); 2934 | //wint (T->flags); 2935 | } else { 2936 | wint (TLS_TYPE_EXPR); 2937 | struct tl_type *t = T->data; 2938 | wint (t->name); 2939 | write_type_flags (T->flags); 2940 | // wint (T->flags); 2941 | wint (cc); 2942 | // fprintf (stderr, "cc = %d\n", cc); 2943 | } 2944 | } 2945 | } 2946 | 2947 | void write_opt_type (struct tl_combinator_tree *T, struct tree_var_value **v, int *last_var) { 2948 | wint (tl_get_var_value_num (v, T->left->data)); 2949 | wint (T->left->type_flags); 2950 | // write_tree (T->right, 0, v, last_var); 2951 | assert (T); 2952 | T = T->right; 2953 | switch (T->type) { 2954 | case type_type: 2955 | if (T->act == act_array) { 2956 | write_array (T, v, last_var); 2957 | } else if (T->act == act_type || T->act == act_var || T->act == act_arg) { 2958 | write_type_rec (T, 0, v, last_var); 2959 | } else { 2960 | assert (0); 2961 | } 2962 | break; 2963 | default: 2964 | assert (0); 2965 | } 2966 | } 2967 | 2968 | void write_tree (struct tl_combinator_tree *T, int extra, struct tree_var_value **v, int *last_var) { 2969 | assert (T); 2970 | switch (T->type) { 2971 | case type_list_item: 2972 | case type_list: 2973 | if (extra) { 2974 | wint (TLS_COMBINATOR_RIGHT_V2); 2975 | } 2976 | wint (count_list_size (T)); 2977 | write_args (T, v, last_var); 2978 | break; 2979 | case type_num_value: 2980 | wint ((int)TLS_NAT_CONST); 2981 | wint (T->type_flags); 2982 | break; 2983 | case type_num: 2984 | wint ((int)TLS_NAT_VAR); 2985 | wint (T->type_flags); 2986 | wint (tl_get_var_value_num (v, T->data)); 2987 | break; 2988 | case type_type: 2989 | if (T->act == act_array) { 2990 | write_array (T, v, last_var); 2991 | } else if (T->act == act_type || T->act == act_var || T->act == act_arg) { 2992 | write_type_rec (T, 0, v, last_var); 2993 | } else { 2994 | assert (T->act == act_opt_field); 2995 | write_opt_type (T, v, last_var); 2996 | } 2997 | break; 2998 | default: 2999 | assert (0); 3000 | } 3001 | } 3002 | 3003 | void write_type (struct tl_type *t) { 3004 | wint (TLS_TYPE); 3005 | wint (t->name); 3006 | wstr (t->id); 3007 | wint (t->constructors_num); 3008 | wint (t->flags); 3009 | wint (t->params_num); 3010 | wll (t->params_types); 3011 | } 3012 | 3013 | int is_builtin_type (const char *id) { 3014 | return !strcmp (id, "int") || !strcmp (id, "long") || !strcmp (id, "double") || !strcmp (id, "string") 3015 | || !strcmp(id, "object") || !strcmp(id, "function"); 3016 | } 3017 | 3018 | void write_combinator (struct tl_constructor *c) { 3019 | wint (c->name); 3020 | wstr (c->id); 3021 | wint (c->type ? c->type->name : 0); 3022 | struct tree_var_value *T = 0; 3023 | int x = 0; 3024 | assert (c->right); 3025 | if (c->left) { 3026 | if (is_builtin_type (c->id)) { 3027 | wint (TLS_COMBINATOR_LEFT_BUILTIN); 3028 | } else { 3029 | wint (TLS_COMBINATOR_LEFT); 3030 | // FIXME: What is that? 3031 | // wint (count_list_size (c->left)); 3032 | write_tree (c->left, 0, &T, &x); 3033 | } 3034 | } else { 3035 | wint (TLS_COMBINATOR_LEFT); 3036 | wint (0); 3037 | } 3038 | wint (TLS_COMBINATOR_RIGHT_V2); 3039 | write_tree (c->right, 1, &T, &x); 3040 | } 3041 | 3042 | void write_constructor (struct tl_constructor *c) { 3043 | wint (TLS_COMBINATOR); 3044 | write_combinator (c); 3045 | } 3046 | 3047 | void write_function (struct tl_constructor *c) { 3048 | wint (TLS_COMBINATOR); 3049 | write_combinator (c); 3050 | } 3051 | 3052 | void write_type_constructors (struct tl_type *t) { 3053 | int i; 3054 | for (i = 0; i < t->constructors_num; i++) { 3055 | write_constructor (t->constructors[i]); 3056 | } 3057 | } 3058 | 3059 | void write_types (int f) { 3060 | __f = f; 3061 | wint (TLS_SCHEMA_V2); 3062 | wint (0); 3063 | #ifdef TL_PARSER_NEED_TIME 3064 | wint (time (0)); 3065 | #else 3066 | /* Make the tlo reproducible by default. Rationale: https://wiki.debian.org/ReproducibleBuilds/Howto#Introduction */ 3067 | wint (0); 3068 | #endif 3069 | num = 0; 3070 | wint (total_types_num); 3071 | tree_act_tl_type (tl_type_tree, write_type); 3072 | wint (total_constructors_num); 3073 | tree_act_tl_type (tl_type_tree, write_type_constructors); 3074 | wint (total_functions_num); 3075 | tree_act_tl_constructor (tl_function_tree, write_function); 3076 | } 3077 | -------------------------------------------------------------------------------- /tl-parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of tgl-libary/tlc 3 | 4 | Tgl-library/tlc is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | Tgl-library/tlc is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this tgl-library/tlc. If not, see . 16 | 17 | Copyright Vitaly Valtman 2014 18 | 19 | It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) 20 | Copyright 2012-2013 Vkontakte Ltd 21 | 2012-2013 Vitaliy Valtman 22 | 23 | */ 24 | 25 | #ifndef __TL_PARSER_NEW_H__ 26 | #define __TL_PARSER_NEW_H__ 27 | enum lex_type { 28 | lex_error, 29 | lex_char, 30 | lex_triple_minus, 31 | lex_uc_ident, 32 | lex_lc_ident, 33 | lex_eof, 34 | lex_final, 35 | lex_new, 36 | lex_none, 37 | lex_num, 38 | lex_empty 39 | }; 40 | 41 | 42 | struct curlex { 43 | char *ptr; 44 | int len; 45 | enum lex_type type; 46 | int flags; 47 | }; 48 | 49 | struct parse { 50 | char *text; 51 | int pos; 52 | int len; 53 | int line; 54 | int line_pos; 55 | struct curlex lex; 56 | }; 57 | 58 | 59 | enum tree_type { 60 | type_tl_program, 61 | type_fun_declarations, 62 | type_constr_declarations, 63 | type_declaration, 64 | type_combinator_decl, 65 | type_equals, 66 | type_partial_app_decl, 67 | type_final_decl, 68 | type_full_combinator_id, 69 | type_opt_args, 70 | type_args, 71 | type_args1, 72 | type_args2, 73 | type_args3, 74 | type_args4, 75 | type_boxed_type_ident, 76 | type_subexpr, 77 | type_partial_comb_app_decl, 78 | type_partial_type_app_decl, 79 | type_final_new, 80 | type_final_final, 81 | type_final_empty, 82 | // type_type, 83 | type_var_ident, 84 | type_var_ident_opt, 85 | type_multiplicity, 86 | type_type_term, 87 | type_term, 88 | type_percent, 89 | type_result_type, 90 | type_expr, 91 | type_nat_term, 92 | type_combinator_id, 93 | type_nat_const, 94 | type_type_ident, 95 | type_builtin_combinator_decl, 96 | type_exclam, 97 | type_optional_arg_def 98 | }; 99 | 100 | struct tree { 101 | char *text; 102 | int len; 103 | enum tree_type type; 104 | int lex_line; 105 | int lex_line_pos; 106 | int flags; 107 | int size; 108 | int nc; 109 | struct tree **c; 110 | }; 111 | 112 | 113 | #define TL_ACT(x) (x == act_var ? "act_var" : x == act_field ? "act_field" : x == act_plus ? "act_plus" : x == act_type ? "act_type" : x == act_nat_const ? "act_nat_const" : x == act_array ? "act_array" : x == act_question_mark ? "act_question_mark" : \ 114 | x == act_union ? "act_union" : x == act_arg ? "act_arg" : x == act_opt_field ? "act_opt_field" : "act_unknown") 115 | 116 | #define TL_TYPE(x) (x == type_num ? "type_num" : x == type_type ? "type_type" : x == type_list_item ? "type_list_item" : x == type_list ? "type_list" : x == type_num_value ? "type_num_value" : "type_unknown") 117 | enum combinator_tree_action { 118 | act_var, 119 | act_field, 120 | act_plus, 121 | act_type, 122 | act_nat_const, 123 | act_array, 124 | act_question_mark, 125 | act_union, 126 | act_arg, 127 | act_opt_field 128 | }; 129 | 130 | enum combinator_tree_type { 131 | type_num, 132 | type_num_value, 133 | type_type, 134 | type_list_item, 135 | type_list 136 | }; 137 | 138 | struct tl_combinator_tree { 139 | enum combinator_tree_action act; 140 | struct tl_combinator_tree *left, *right; 141 | char *name; 142 | void *data; 143 | long long flags; 144 | enum combinator_tree_type type; 145 | int type_len; 146 | long long type_flags; 147 | }; 148 | 149 | 150 | struct tl_program { 151 | int types_num; 152 | int functions_num; 153 | int constructors_num; 154 | struct tl_type **types; 155 | struct tl_function **functions; 156 | // struct tl_constuctor **constructors; 157 | }; 158 | 159 | struct tl_type { 160 | char *id; 161 | char *print_id; 162 | char *real_id; 163 | unsigned name; 164 | int flags; 165 | 166 | int params_num; 167 | long long params_types; 168 | 169 | int constructors_num; 170 | struct tl_constructor **constructors; 171 | }; 172 | 173 | struct tl_constructor { 174 | char *id; 175 | char *print_id; 176 | char *real_id; 177 | unsigned name; 178 | struct tl_type *type; 179 | 180 | struct tl_combinator_tree *left; 181 | struct tl_combinator_tree *right; 182 | }; 183 | 184 | struct tl_var { 185 | char *id; 186 | struct tl_combinator_tree *ptr; 187 | int type; 188 | int flags; 189 | }; 190 | 191 | struct parse *tl_init_parse_file (const char *fname); 192 | struct tree *tl_parse_lex (struct parse *P); 193 | void tl_print_parse_error (void); 194 | struct tl_program *tl_parse (struct tree *T); 195 | 196 | void write_types (int f); 197 | 198 | #define FLAG_BARE 1 199 | #define FLAG_OPT_VAR (1 << 17) 200 | #define FLAG_EXCL (1 << 18) 201 | #define FLAG_OPT_FIELD (1 << 20) 202 | #define FLAG_IS_VAR (1 << 21) 203 | #define FLAG_DEFAULT_CONSTRUCTOR (1 << 25) 204 | #define FLAG_EMPTY (1 << 10) 205 | 206 | #ifdef NDEBUG 207 | #undef assert 208 | #define assert(x) if (!(x)) { fprintf(stderr, "Assertion error!\n"); abort(); } 209 | #endif 210 | 211 | #ifdef _WIN32 212 | #include 213 | #include "wgetopt.h" 214 | 215 | #define __attribute__(x) 216 | 217 | #define lrand48() rand() 218 | #define strdup _strdup 219 | #define lseek _lseek 220 | #define open _open 221 | #define close _close 222 | #define write _write 223 | #define read _read 224 | #endif 225 | 226 | #endif 227 | -------------------------------------------------------------------------------- /tl-tl.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of VK/KittenPHP-DB-Engine. 3 | 4 | VK/KittenPHP-DB-Engine is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | VK/KittenPHP-DB-Engine is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with VK/KittenPHP-DB-Engine. If not, see . 16 | 17 | This program is released under the GPL with the additional exemption 18 | that compiling, linking, and/or using OpenSSL is allowed. 19 | You are free to remove this exemption from derived works. 20 | 21 | Copyright 2012-2013 Vkontakte Ltd 22 | 2012-2013 Vitaliy Valtman 23 | */ 24 | 25 | #ifndef __TL_TL_H__ 26 | #define __TL_TL_H__ 27 | 28 | // Current tl-tl schema is V2 29 | // See https://core.telegram.org/mtproto/TL-tl 30 | 31 | #define TLS_SCHEMA_V2 0x3a2f9be2 32 | #define TLS_TYPE 0x12eb4386 33 | #define TLS_COMBINATOR 0x5c0a1ed5 34 | #define TLS_COMBINATOR_LEFT_BUILTIN 0xcd211f63 35 | #define TLS_COMBINATOR_LEFT 0x4c12c6d9 36 | #define TLS_COMBINATOR_RIGHT_V2 0x2c064372 37 | #define TLS_ARG_V2 0x29dfe61b 38 | 39 | #define TLS_EXPR_TYPE 0xecc9da78 40 | #define TLS_EXPR_NAT 0xdcb49bd8 41 | 42 | #define TLS_NAT_CONST 0xdcb49bd8 43 | #define TLS_NAT_VAR 0x4e8a14f0 44 | #define TLS_TYPE_VAR 0x0142ceae 45 | #define TLS_ARRAY 0xd9fb20de 46 | #define TLS_TYPE_EXPR 0xc1863d08 47 | 48 | /* Deprecated (old versions), read-only */ 49 | #define TLS_TREE_NAT_CONST 0xc09f07d7 50 | #define TLS_TREE_NAT_VAR 0x90ea6f58 51 | #define TLS_TREE_TYPE_VAR 0x1caa237a 52 | #define TLS_TREE_ARRAY 0x80479360 53 | #define TLS_TREE_TYPE 0x10f32190 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /tlc.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of tl-parser 3 | 4 | tl-parser is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | tl-parser is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this tl-parser. If not, see . 16 | 17 | Copyright Vitaly Valtman 2014 18 | 19 | It is derivative work of VK/KittenPHP-DB-Engine (https://github.com/vk-com/kphp-kdb/) 20 | Copyright 2012-2013 Vkontakte Ltd 21 | 2012-2013 Vitaliy Valtman 22 | 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "tl-parser.h" 30 | 31 | #ifndef _WIN32 32 | #include 33 | #endif 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | 41 | #ifdef HAVE_EXECINFO_H 42 | #include 43 | #endif 44 | #include 45 | 46 | int verbosity; 47 | int output_expressions; 48 | void usage (void) { 49 | printf ("usage: tl-parser [-v] [-h] \n" 50 | "\tTL compiler\n" 51 | "\t-v\toutput statistical and debug information into stderr\n" 52 | "\t-E\twhenever is possible output to stdout expressions\n" 53 | "\t-e \texport serialized schema to file\n" 54 | ); 55 | exit (2); 56 | } 57 | 58 | int vkext_write (const char *filename) { 59 | #ifdef _WIN32 60 | int f = _open(filename, _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY, 0640); 61 | #else 62 | int f = open (filename, O_CREAT | O_WRONLY | O_TRUNC, 0640); 63 | #endif 64 | assert (f >= 0); 65 | write_types (f); 66 | close (f); 67 | return 0; 68 | } 69 | 70 | void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2))); 71 | void logprintf (const char *format __attribute__ ((unused)), ...) { 72 | va_list ap; 73 | va_start (ap, format); 74 | vfprintf (stderr, format, ap); 75 | va_end (ap); 76 | } 77 | 78 | void hexdump (int *in_ptr, int *in_end) { 79 | int *ptr = in_ptr; 80 | while (ptr < in_end) { printf (" %08x", *(ptr ++)); } 81 | printf ("\n"); 82 | } 83 | 84 | #ifdef HAVE_EXECINFO_H 85 | void print_backtrace (void) { 86 | void *buffer[255]; 87 | const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *)); 88 | backtrace_symbols_fd (buffer, calls, 1); 89 | } 90 | #else 91 | void print_backtrace (void) { 92 | if (write (1, "No libexec. Backtrace disabled\n", 32) < 0) { 93 | // Sad thing 94 | } 95 | } 96 | #endif 97 | 98 | void sig_segv_handler (int signum __attribute__ ((unused))) { 99 | if (write (1, "SIGSEGV received\n", 18) < 0) { 100 | // Sad thing 101 | } 102 | print_backtrace (); 103 | exit (EXIT_FAILURE); 104 | } 105 | 106 | void sig_abrt_handler (int signum __attribute__ ((unused))) { 107 | if (write (1, "SIGABRT received\n", 18) < 0) { 108 | // Sad thing 109 | } 110 | print_backtrace (); 111 | exit (EXIT_FAILURE); 112 | } 113 | 114 | int main (int argc, char **argv) { 115 | signal (SIGSEGV, sig_segv_handler); 116 | signal (SIGABRT, sig_abrt_handler); 117 | int i; 118 | char *vkext_file = 0; 119 | while ((i = getopt (argc, argv, "Ehve:w:")) != -1) { 120 | switch (i) { 121 | case 'E': 122 | output_expressions++; 123 | break; 124 | case 'h': 125 | usage (); 126 | return 2; 127 | case 'e': 128 | vkext_file = optarg; 129 | break; 130 | case 'v': 131 | verbosity++; 132 | break; 133 | } 134 | } 135 | 136 | if (argc != optind + 1) { 137 | usage (); 138 | } 139 | 140 | 141 | struct parse *P = tl_init_parse_file (argv[optind]); 142 | if (!P) { 143 | return 0; 144 | } 145 | struct tree *T; 146 | if (!(T = tl_parse_lex (P))) { 147 | fprintf (stderr, "Error in parse:\n"); 148 | tl_print_parse_error (); 149 | return 0; 150 | } else { 151 | if (verbosity) { 152 | fprintf (stderr, "Parse ok\n"); 153 | } 154 | if (!tl_parse (T)) { 155 | if (verbosity) { 156 | fprintf (stderr, "Fail\n"); 157 | } 158 | return 1; 159 | } else { 160 | if (verbosity) { 161 | fprintf (stderr, "Ok\n"); 162 | } 163 | } 164 | } 165 | if (vkext_file) { 166 | vkext_write (vkext_file); 167 | } 168 | return 0; 169 | } 170 | -------------------------------------------------------------------------------- /wgetopt.c: -------------------------------------------------------------------------------- 1 | /* Getopt for GNU. 2 | NOTE: getopt is now part of the C library, so if you don't know what 3 | "Keep this file name-space clean" means, talk to drepper@gnu.org 4 | before changing it! 5 | Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 6 | Free Software Foundation, Inc. 7 | This file is part of the GNU C Library. 8 | 9 | The GNU C Library is free software; you can redistribute it and/or 10 | modify it under the terms of the GNU Lesser General Public 11 | License as published by the Free Software Foundation; either 12 | version 2.1 of the License, or (at your option) any later version. 13 | 14 | The GNU C Library is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | Lesser General Public License for more details. 18 | 19 | You should have received a copy of the GNU Lesser General Public 20 | License along with the GNU C Library; if not, write to the Free 21 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 22 | 02111-1307 USA. */ 23 | 24 | /* This tells Alpha OSF/1 not to define a getopt prototype in . 25 | Ditto for AIX 3.2 and . */ 26 | #ifndef _NO_PROTO 27 | # define _NO_PROTO 28 | #endif 29 | 30 | #ifdef HAVE_CONFIG_H 31 | # include 32 | #endif 33 | 34 | #if !defined __STDC__ || !__STDC__ 35 | /* This is a separate conditional since some stdc systems 36 | reject `defined (const)'. */ 37 | # ifndef const 38 | # define const 39 | # endif 40 | #endif 41 | 42 | #include 43 | 44 | /* Comment out all this code if we are using the GNU C Library, and are not 45 | actually compiling the library itself. This code is part of the GNU C 46 | Library, but also included in many other GNU distributions. Compiling 47 | and linking in this code is a waste when using the GNU C library 48 | (especially if it is a shared library). Rather than having every GNU 49 | program understand `configure --with-gnu-libc' and omit the object files, 50 | it is simpler to just do this in the source for each such file. */ 51 | 52 | #define GETOPT_INTERFACE_VERSION 2 53 | #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 54 | # include 55 | # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION 56 | # define ELIDE_CODE 57 | # endif 58 | #endif 59 | 60 | #ifndef ELIDE_CODE 61 | 62 | 63 | /* This needs to come after some library #include 64 | to get __GNU_LIBRARY__ defined. */ 65 | #ifdef __GNU_LIBRARY__ 66 | /* Don't include stdlib.h for non-GNU C libraries because some of them 67 | contain conflicting prototypes for getopt. */ 68 | # include 69 | # include 70 | #endif /* GNU C library. */ 71 | 72 | #ifdef VMS 73 | # include 74 | # if HAVE_STRING_H - 0 75 | # include 76 | # endif 77 | #endif 78 | 79 | #ifndef _ 80 | /* This is for other GNU distributions with internationalized messages. */ 81 | # if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC 82 | # include 83 | # ifndef _ 84 | # define _(msgid) gettext (msgid) 85 | # endif 86 | # else 87 | # define _(msgid) (msgid) 88 | # endif 89 | # if defined _LIBC && defined USE_IN_LIBIO 90 | # include 91 | # endif 92 | #endif 93 | 94 | /* This version of `getopt' appears to the caller like standard Unix `getopt' 95 | but it behaves differently for the user, since it allows the user 96 | to intersperse the options with the other arguments. 97 | 98 | As `getopt' works, it permutes the elements of ARGV so that, 99 | when it is done, all the options precede everything else. Thus 100 | all application programs are extended to handle flexible argument order. 101 | 102 | Setting the environment variable POSIXLY_CORRECT disables permutation. 103 | Then the behavior is completely standard. 104 | 105 | GNU application programs can use a third alternative mode in which 106 | they can distinguish the relative order of options and other arguments. */ 107 | 108 | #include "wgetopt.h" 109 | 110 | /* For communication from `getopt' to the caller. 111 | When `getopt' finds an option that takes an argument, 112 | the argument value is returned here. 113 | Also, when `ordering' is RETURN_IN_ORDER, 114 | each non-option ARGV-element is returned here. */ 115 | 116 | char *optarg; 117 | 118 | /* Index in ARGV of the next element to be scanned. 119 | This is used for communication to and from the caller 120 | and for communication between successive calls to `getopt'. 121 | 122 | On entry to `getopt', zero means this is the first call; initialize. 123 | 124 | When `getopt' returns -1, this is the index of the first of the 125 | non-option elements that the caller should itself scan. 126 | 127 | Otherwise, `optind' communicates from one call to the next 128 | how much of ARGV has been scanned so far. */ 129 | 130 | /* 1003.2 says this must be 1 before any call. */ 131 | int optind = 1; 132 | 133 | /* Formerly, initialization of getopt depended on optind==0, which 134 | causes problems with re-calling getopt as programs generally don't 135 | know that. */ 136 | 137 | int __getopt_initialized; 138 | 139 | /* The next char to be scanned in the option-element 140 | in which the last option character we returned was found. 141 | This allows us to pick up the scan where we left off. 142 | 143 | If this is zero, or a null string, it means resume the scan 144 | by advancing to the next ARGV-element. */ 145 | 146 | static char *nextchar; 147 | 148 | /* Callers store zero here to inhibit the error message 149 | for unrecognized options. */ 150 | 151 | int opterr = 1; 152 | 153 | /* Set to an option character which was unrecognized. 154 | This must be initialized on some systems to avoid linking in the 155 | system's own getopt implementation. */ 156 | 157 | int optopt = '?'; 158 | 159 | /* Describe how to deal with options that follow non-option ARGV-elements. 160 | 161 | If the caller did not specify anything, 162 | the default is REQUIRE_ORDER if the environment variable 163 | POSIXLY_CORRECT is defined, PERMUTE otherwise. 164 | 165 | REQUIRE_ORDER means don't recognize them as options; 166 | stop option processing when the first non-option is seen. 167 | This is what Unix does. 168 | This mode of operation is selected by either setting the environment 169 | variable POSIXLY_CORRECT, or using `+' as the first character 170 | of the list of option characters. 171 | 172 | PERMUTE is the default. We permute the contents of ARGV as we scan, 173 | so that eventually all the non-options are at the end. This allows options 174 | to be given in any order, even with programs that were not written to 175 | expect this. 176 | 177 | RETURN_IN_ORDER is an option available to programs that were written 178 | to expect options and other ARGV-elements in any order and that care about 179 | the ordering of the two. We describe each non-option ARGV-element 180 | as if it were the argument of an option with character code 1. 181 | Using `-' as the first character of the list of option characters 182 | selects this mode of operation. 183 | 184 | The special argument `--' forces an end of option-scanning regardless 185 | of the value of `ordering'. In the case of RETURN_IN_ORDER, only 186 | `--' can cause `getopt' to return -1 with `optind' != ARGC. */ 187 | 188 | static enum 189 | { 190 | REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER 191 | } ordering; 192 | 193 | /* Value of POSIXLY_CORRECT environment variable. */ 194 | static char *posixly_correct; 195 | 196 | #ifdef __GNU_LIBRARY__ 197 | /* We want to avoid inclusion of string.h with non-GNU libraries 198 | because there are many ways it can cause trouble. 199 | On some systems, it contains special magic macros that don't work 200 | in GCC. */ 201 | # include 202 | # define my_index strchr 203 | #else 204 | 205 | #define HAVE_STRING_H 1 206 | # if HAVE_STRING_H 207 | # include 208 | # else 209 | # include 210 | # endif 211 | 212 | /* Avoid depending on library functions or files 213 | whose names are inconsistent. */ 214 | 215 | #ifndef getenv 216 | extern char *getenv(); 217 | #endif 218 | 219 | static char * 220 | my_index(str, chr) 221 | const char *str; 222 | int chr; 223 | { 224 | while (*str) 225 | { 226 | if (*str == chr) 227 | return (char *)str; 228 | str++; 229 | } 230 | return 0; 231 | } 232 | 233 | /* If using GCC, we can safely declare strlen this way. 234 | If not using GCC, it is ok not to declare it. */ 235 | #ifdef __GNUC__ 236 | /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. 237 | That was relevant to code that was here before. */ 238 | # if (!defined __STDC__ || !__STDC__) && !defined strlen 239 | /* gcc with -traditional declares the built-in strlen to return int, 240 | and has done so at least since version 2.4.5. -- rms. */ 241 | extern int strlen(const char *); 242 | # endif /* not __STDC__ */ 243 | #endif /* __GNUC__ */ 244 | 245 | #endif /* not __GNU_LIBRARY__ */ 246 | 247 | /* Handle permutation of arguments. */ 248 | 249 | /* Describe the part of ARGV that contains non-options that have 250 | been skipped. `first_nonopt' is the index in ARGV of the first of them; 251 | `last_nonopt' is the index after the last of them. */ 252 | 253 | static int first_nonopt; 254 | static int last_nonopt; 255 | 256 | #ifdef _LIBC 257 | /* Stored original parameters. 258 | XXX This is no good solution. We should rather copy the args so 259 | that we can compare them later. But we must not use malloc(3). */ 260 | extern int __libc_argc; 261 | extern char **__libc_argv; 262 | 263 | /* Bash 2.0 gives us an environment variable containing flags 264 | indicating ARGV elements that should not be considered arguments. */ 265 | 266 | # ifdef USE_NONOPTION_FLAGS 267 | /* Defined in getopt_init.c */ 268 | extern char *__getopt_nonoption_flags; 269 | 270 | static int nonoption_flags_max_len; 271 | static int nonoption_flags_len; 272 | # endif 273 | 274 | # ifdef USE_NONOPTION_FLAGS 275 | # define SWAP_FLAGS(ch1, ch2) \ 276 | if (nonoption_flags_len > 0) \ 277 | { \ 278 | char __tmp = __getopt_nonoption_flags[ch1]; \ 279 | __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ 280 | __getopt_nonoption_flags[ch2] = __tmp; \ 281 | } 282 | # else 283 | # define SWAP_FLAGS(ch1, ch2) 284 | # endif 285 | #else /* !_LIBC */ 286 | # define SWAP_FLAGS(ch1, ch2) 287 | #endif /* _LIBC */ 288 | 289 | /* Exchange two adjacent subsequences of ARGV. 290 | One subsequence is elements [first_nonopt,last_nonopt) 291 | which contains all the non-options that have been skipped so far. 292 | The other is elements [last_nonopt,optind), which contains all 293 | the options processed since those non-options were skipped. 294 | 295 | `first_nonopt' and `last_nonopt' are relocated so that they describe 296 | the new indices of the non-options in ARGV after they are moved. */ 297 | 298 | #if defined __STDC__ && __STDC__ 299 | static void exchange(char **); 300 | #endif 301 | 302 | static void 303 | exchange(argv) 304 | char **argv; 305 | { 306 | int bottom = first_nonopt; 307 | int middle = last_nonopt; 308 | int top = optind; 309 | char *tem; 310 | 311 | /* Exchange the shorter segment with the far end of the longer segment. 312 | That puts the shorter segment into the right place. 313 | It leaves the longer segment in the right place overall, 314 | but it consists of two parts that need to be swapped next. */ 315 | 316 | #if defined _LIBC && defined USE_NONOPTION_FLAGS 317 | /* First make sure the handling of the `__getopt_nonoption_flags' 318 | string can work normally. Our top argument must be in the range 319 | of the string. */ 320 | if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) 321 | { 322 | /* We must extend the array. The user plays games with us and 323 | presents new arguments. */ 324 | char *new_str = malloc(top + 1); 325 | if (new_str == NULL) 326 | nonoption_flags_len = nonoption_flags_max_len = 0; 327 | else 328 | { 329 | memset(__mempcpy(new_str, __getopt_nonoption_flags, 330 | nonoption_flags_max_len), 331 | '\0', top + 1 - nonoption_flags_max_len); 332 | nonoption_flags_max_len = top + 1; 333 | __getopt_nonoption_flags = new_str; 334 | } 335 | } 336 | #endif 337 | 338 | while (top > middle && middle > bottom) 339 | { 340 | if (top - middle > middle - bottom) 341 | { 342 | /* Bottom segment is the short one. */ 343 | int len = middle - bottom; 344 | register int i; 345 | 346 | /* Swap it with the top part of the top segment. */ 347 | for (i = 0; i < len; i++) 348 | { 349 | tem = argv[bottom + i]; 350 | argv[bottom + i] = argv[top - (middle - bottom) + i]; 351 | argv[top - (middle - bottom) + i] = tem; 352 | SWAP_FLAGS(bottom + i, top - (middle - bottom) + i); 353 | } 354 | /* Exclude the moved bottom segment from further swapping. */ 355 | top -= len; 356 | } 357 | else 358 | { 359 | /* Top segment is the short one. */ 360 | int len = top - middle; 361 | register int i; 362 | 363 | /* Swap it with the bottom part of the bottom segment. */ 364 | for (i = 0; i < len; i++) 365 | { 366 | tem = argv[bottom + i]; 367 | argv[bottom + i] = argv[middle + i]; 368 | argv[middle + i] = tem; 369 | SWAP_FLAGS(bottom + i, middle + i); 370 | } 371 | /* Exclude the moved top segment from further swapping. */ 372 | bottom += len; 373 | } 374 | } 375 | 376 | /* Update records for the slots the non-options now occupy. */ 377 | 378 | first_nonopt += (optind - last_nonopt); 379 | last_nonopt = optind; 380 | } 381 | 382 | /* Initialize the internal data when the first call is made. */ 383 | 384 | #if defined __STDC__ && __STDC__ 385 | static const char *_getopt_initialize(int, char *const *, const char *); 386 | #endif 387 | static const char * 388 | _getopt_initialize(argc, argv, optstring) 389 | int argc; 390 | char *const *argv; 391 | const char *optstring; 392 | { 393 | /* Start processing options with ARGV-element 1 (since ARGV-element 0 394 | is the program name); the sequence of previously skipped 395 | non-option ARGV-elements is empty. */ 396 | 397 | first_nonopt = last_nonopt = optind; 398 | 399 | nextchar = NULL; 400 | 401 | posixly_correct = getenv("POSIXLY_CORRECT"); 402 | 403 | /* Determine how to handle the ordering of options and nonoptions. */ 404 | 405 | if (optstring[0] == '-') 406 | { 407 | ordering = RETURN_IN_ORDER; 408 | ++optstring; 409 | } 410 | else if (optstring[0] == '+') 411 | { 412 | ordering = REQUIRE_ORDER; 413 | ++optstring; 414 | } 415 | else if (posixly_correct != NULL) 416 | ordering = REQUIRE_ORDER; 417 | else 418 | ordering = PERMUTE; 419 | 420 | #if defined _LIBC && defined USE_NONOPTION_FLAGS 421 | if (posixly_correct == NULL 422 | && argc == __libc_argc && argv == __libc_argv) 423 | { 424 | if (nonoption_flags_max_len == 0) 425 | { 426 | if (__getopt_nonoption_flags == NULL 427 | || __getopt_nonoption_flags[0] == '\0') 428 | nonoption_flags_max_len = -1; 429 | else 430 | { 431 | const char *orig_str = __getopt_nonoption_flags; 432 | int len = nonoption_flags_max_len = strlen(orig_str); 433 | if (nonoption_flags_max_len < argc) 434 | nonoption_flags_max_len = argc; 435 | __getopt_nonoption_flags = 436 | (char *)malloc(nonoption_flags_max_len); 437 | if (__getopt_nonoption_flags == NULL) 438 | nonoption_flags_max_len = -1; 439 | else 440 | memset(__mempcpy(__getopt_nonoption_flags, orig_str, len), 441 | '\0', nonoption_flags_max_len - len); 442 | } 443 | } 444 | nonoption_flags_len = nonoption_flags_max_len; 445 | } 446 | else 447 | nonoption_flags_len = 0; 448 | #endif 449 | 450 | return optstring; 451 | } 452 | 453 | /* Scan elements of ARGV (whose length is ARGC) for option characters 454 | given in OPTSTRING. 455 | 456 | If an element of ARGV starts with '-', and is not exactly "-" or "--", 457 | then it is an option element. The characters of this element 458 | (aside from the initial '-') are option characters. If `getopt' 459 | is called repeatedly, it returns successively each of the option characters 460 | from each of the option elements. 461 | 462 | If `getopt' finds another option character, it returns that character, 463 | updating `optind' and `nextchar' so that the next call to `getopt' can 464 | resume the scan with the following option character or ARGV-element. 465 | 466 | If there are no more option characters, `getopt' returns -1. 467 | Then `optind' is the index in ARGV of the first ARGV-element 468 | that is not an option. (The ARGV-elements have been permuted 469 | so that those that are not options now come last.) 470 | 471 | OPTSTRING is a string containing the legitimate option characters. 472 | If an option character is seen that is not listed in OPTSTRING, 473 | return '?' after printing an error message. If you set `opterr' to 474 | zero, the error message is suppressed but we still return '?'. 475 | 476 | If a char in OPTSTRING is followed by a colon, that means it wants an arg, 477 | so the following text in the same ARGV-element, or the text of the following 478 | ARGV-element, is returned in `optarg'. Two colons mean an option that 479 | wants an optional arg; if there is text in the current ARGV-element, 480 | it is returned in `optarg', otherwise `optarg' is set to zero. 481 | 482 | If OPTSTRING starts with `-' or `+', it requests different methods of 483 | handling the non-option ARGV-elements. 484 | See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. 485 | 486 | Long-named options begin with `--' instead of `-'. 487 | Their names may be abbreviated as long as the abbreviation is unique 488 | or is an exact match for some defined option. If they have an 489 | argument, it follows the option name in the same ARGV-element, separated 490 | from the option name by a `=', or else the in next ARGV-element. 491 | When `getopt' finds a long-named option, it returns 0 if that option's 492 | `flag' field is nonzero, the value of the option's `val' field 493 | if the `flag' field is zero. 494 | 495 | The elements of ARGV aren't really const, because we permute them. 496 | But we pretend they're const in the prototype to be compatible 497 | with other systems. 498 | 499 | LONGOPTS is a vector of `struct option' terminated by an 500 | element containing a name which is zero. 501 | 502 | LONGIND returns the index in LONGOPT of the long-named option found. 503 | It is only valid when a long-named option has been found by the most 504 | recent call. 505 | 506 | If LONG_ONLY is nonzero, '-' as well as '--' can introduce 507 | long-named options. */ 508 | 509 | int 510 | _getopt_internal(argc, argv, optstring, longopts, longind, long_only) 511 | int argc; 512 | char *const *argv; 513 | const char *optstring; 514 | const struct option *longopts; 515 | int *longind; 516 | int long_only; 517 | { 518 | int print_errors = opterr; 519 | if (optstring[0] == ':') 520 | print_errors = 0; 521 | 522 | if (argc < 1) 523 | return -1; 524 | 525 | optarg = NULL; 526 | 527 | if (optind == 0 || !__getopt_initialized) 528 | { 529 | if (optind == 0) 530 | optind = 1; /* Don't scan ARGV[0], the program name. */ 531 | optstring = _getopt_initialize(argc, argv, optstring); 532 | __getopt_initialized = 1; 533 | } 534 | 535 | /* Test whether ARGV[optind] points to a non-option argument. 536 | Either it does not have option syntax, or there is an environment flag 537 | from the shell indicating it is not an option. The later information 538 | is only used when the used in the GNU libc. */ 539 | #if defined _LIBC && defined USE_NONOPTION_FLAGS 540 | # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ 541 | || (optind < nonoption_flags_len \ 542 | && __getopt_nonoption_flags[optind] == '1')) 543 | #else 544 | # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') 545 | #endif 546 | 547 | if (nextchar == NULL || *nextchar == '\0') 548 | { 549 | /* Advance to the next ARGV-element. */ 550 | 551 | /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been 552 | moved back by the user (who may also have changed the arguments). */ 553 | if (last_nonopt > optind) 554 | last_nonopt = optind; 555 | if (first_nonopt > optind) 556 | first_nonopt = optind; 557 | 558 | if (ordering == PERMUTE) 559 | { 560 | /* If we have just processed some options following some non-options, 561 | exchange them so that the options come first. */ 562 | 563 | if (first_nonopt != last_nonopt && last_nonopt != optind) 564 | exchange((char **)argv); 565 | else if (last_nonopt != optind) 566 | first_nonopt = optind; 567 | 568 | /* Skip any additional non-options 569 | and extend the range of non-options previously skipped. */ 570 | 571 | while (optind < argc && NONOPTION_P) 572 | optind++; 573 | last_nonopt = optind; 574 | } 575 | 576 | /* The special ARGV-element `--' means premature end of options. 577 | Skip it like a null option, 578 | then exchange with previous non-options as if it were an option, 579 | then skip everything else like a non-option. */ 580 | 581 | if (optind != argc && !strcmp(argv[optind], "--")) 582 | { 583 | optind++; 584 | 585 | if (first_nonopt != last_nonopt && last_nonopt != optind) 586 | exchange((char **)argv); 587 | else if (first_nonopt == last_nonopt) 588 | first_nonopt = optind; 589 | last_nonopt = argc; 590 | 591 | optind = argc; 592 | } 593 | 594 | /* If we have done all the ARGV-elements, stop the scan 595 | and back over any non-options that we skipped and permuted. */ 596 | 597 | if (optind == argc) 598 | { 599 | /* Set the next-arg-index to point at the non-options 600 | that we previously skipped, so the caller will digest them. */ 601 | if (first_nonopt != last_nonopt) 602 | optind = first_nonopt; 603 | return -1; 604 | } 605 | 606 | /* If we have come to a non-option and did not permute it, 607 | either stop the scan or describe it to the caller and pass it by. */ 608 | 609 | if (NONOPTION_P) 610 | { 611 | if (ordering == REQUIRE_ORDER) 612 | return -1; 613 | optarg = argv[optind++]; 614 | return 1; 615 | } 616 | 617 | /* We have found another option-ARGV-element. 618 | Skip the initial punctuation. */ 619 | 620 | nextchar = (argv[optind] + 1 621 | + (longopts != NULL && argv[optind][1] == '-')); 622 | } 623 | 624 | /* Decode the current option-ARGV-element. */ 625 | 626 | /* Check whether the ARGV-element is a long option. 627 | 628 | If long_only and the ARGV-element has the form "-f", where f is 629 | a valid short option, don't consider it an abbreviated form of 630 | a long option that starts with f. Otherwise there would be no 631 | way to give the -f short option. 632 | 633 | On the other hand, if there's a long option "fubar" and 634 | the ARGV-element is "-fu", do consider that an abbreviation of 635 | the long option, just like "--fu", and not "-f" with arg "u". 636 | 637 | This distinction seems to be the most useful approach. */ 638 | 639 | if (longopts != NULL 640 | && (argv[optind][1] == '-' 641 | || (long_only && (argv[optind][2] || !my_index(optstring, argv[optind][1]))))) 642 | { 643 | char *nameend; 644 | const struct option *p; 645 | const struct option *pfound = NULL; 646 | int exact = 0; 647 | int ambig = 0; 648 | int indfound = -1; 649 | int option_index; 650 | 651 | for (nameend = nextchar; *nameend && *nameend != '='; nameend++) 652 | /* Do nothing. */; 653 | 654 | /* Test all long options for either exact match 655 | or abbreviated matches. */ 656 | for (p = longopts, option_index = 0; p->name; p++, option_index++) 657 | if (!strncmp(p->name, nextchar, nameend - nextchar)) 658 | { 659 | if ((unsigned int)(nameend - nextchar) 660 | == (unsigned int)strlen(p->name)) 661 | { 662 | /* Exact match found. */ 663 | pfound = p; 664 | indfound = option_index; 665 | exact = 1; 666 | break; 667 | } 668 | else if (pfound == NULL) 669 | { 670 | /* First nonexact match found. */ 671 | pfound = p; 672 | indfound = option_index; 673 | } 674 | else if (long_only 675 | || pfound->has_arg != p->has_arg 676 | || pfound->flag != p->flag 677 | || pfound->val != p->val) 678 | /* Second or later nonexact match found. */ 679 | ambig = 1; 680 | } 681 | 682 | if (ambig && !exact) 683 | { 684 | if (print_errors) 685 | { 686 | #if defined _LIBC && defined USE_IN_LIBIO 687 | char *buf; 688 | 689 | __asprintf(&buf, _("%s: option `%s' is ambiguous\n"), 690 | argv[0], argv[optind]); 691 | 692 | if (_IO_fwide(stderr, 0) > 0) 693 | __fwprintf(stderr, L"%s", buf); 694 | else 695 | fputs(buf, stderr); 696 | 697 | free(buf); 698 | #else 699 | fprintf(stderr, _("%s: option `%s' is ambiguous\n"), 700 | argv[0], argv[optind]); 701 | #endif 702 | } 703 | nextchar += strlen(nextchar); 704 | optind++; 705 | optopt = 0; 706 | return '?'; 707 | } 708 | 709 | if (pfound != NULL) 710 | { 711 | option_index = indfound; 712 | optind++; 713 | if (*nameend) 714 | { 715 | /* Don't test has_arg with >, because some C compilers don't 716 | allow it to be used on enums. */ 717 | if (pfound->has_arg) 718 | optarg = nameend + 1; 719 | else 720 | { 721 | if (print_errors) 722 | { 723 | #if defined _LIBC && defined USE_IN_LIBIO 724 | char *buf; 725 | #endif 726 | 727 | if (argv[optind - 1][1] == '-') 728 | { 729 | /* --option */ 730 | #if defined _LIBC && defined USE_IN_LIBIO 731 | __asprintf(&buf, _("\ 732 | %s: option `--%s' doesn't allow an argument\n"), 733 | argv[0], pfound->name); 734 | #else 735 | fprintf(stderr, _("\ 736 | %s: option `--%s' doesn't allow an argument\n"), 737 | argv[0], pfound->name); 738 | #endif 739 | } 740 | else 741 | { 742 | /* +option or -option */ 743 | #if defined _LIBC && defined USE_IN_LIBIO 744 | __asprintf(&buf, _("\ 745 | %s: option `%c%s' doesn't allow an argument\n"), 746 | argv[0], argv[optind - 1][0], 747 | pfound->name); 748 | #else 749 | fprintf(stderr, _("\ 750 | %s: option `%c%s' doesn't allow an argument\n"), 751 | argv[0], argv[optind - 1][0], pfound->name); 752 | #endif 753 | } 754 | 755 | #if defined _LIBC && defined USE_IN_LIBIO 756 | if (_IO_fwide(stderr, 0) > 0) 757 | __fwprintf(stderr, L"%s", buf); 758 | else 759 | fputs(buf, stderr); 760 | 761 | free(buf); 762 | #endif 763 | } 764 | 765 | nextchar += strlen(nextchar); 766 | 767 | optopt = pfound->val; 768 | return '?'; 769 | } 770 | } 771 | else if (pfound->has_arg == 1) 772 | { 773 | if (optind < argc) 774 | optarg = argv[optind++]; 775 | else 776 | { 777 | if (print_errors) 778 | { 779 | #if defined _LIBC && defined USE_IN_LIBIO 780 | char *buf; 781 | 782 | __asprintf(&buf, 783 | _("%s: option `%s' requires an argument\n"), 784 | argv[0], argv[optind - 1]); 785 | 786 | if (_IO_fwide(stderr, 0) > 0) 787 | __fwprintf(stderr, L"%s", buf); 788 | else 789 | fputs(buf, stderr); 790 | 791 | free(buf); 792 | #else 793 | fprintf(stderr, 794 | _("%s: option `%s' requires an argument\n"), 795 | argv[0], argv[optind - 1]); 796 | #endif 797 | } 798 | nextchar += strlen(nextchar); 799 | optopt = pfound->val; 800 | return optstring[0] == ':' ? ':' : '?'; 801 | } 802 | } 803 | nextchar += strlen(nextchar); 804 | if (longind != NULL) 805 | *longind = option_index; 806 | if (pfound->flag) 807 | { 808 | *(pfound->flag) = pfound->val; 809 | return 0; 810 | } 811 | return pfound->val; 812 | } 813 | 814 | /* Can't find it as a long option. If this is not getopt_long_only, 815 | or the option starts with '--' or is not a valid short 816 | option, then it's an error. 817 | Otherwise interpret it as a short option. */ 818 | if (!long_only || argv[optind][1] == '-' 819 | || my_index(optstring, *nextchar) == NULL) 820 | { 821 | if (print_errors) 822 | { 823 | #if defined _LIBC && defined USE_IN_LIBIO 824 | char *buf; 825 | #endif 826 | 827 | if (argv[optind][1] == '-') 828 | { 829 | /* --option */ 830 | #if defined _LIBC && defined USE_IN_LIBIO 831 | __asprintf(&buf, _("%s: unrecognized option `--%s'\n"), 832 | argv[0], nextchar); 833 | #else 834 | fprintf(stderr, _("%s: unrecognized option `--%s'\n"), 835 | argv[0], nextchar); 836 | #endif 837 | } 838 | else 839 | { 840 | /* +option or -option */ 841 | #if defined _LIBC && defined USE_IN_LIBIO 842 | __asprintf(&buf, _("%s: unrecognized option `%c%s'\n"), 843 | argv[0], argv[optind][0], nextchar); 844 | #else 845 | fprintf(stderr, _("%s: unrecognized option `%c%s'\n"), 846 | argv[0], argv[optind][0], nextchar); 847 | #endif 848 | } 849 | 850 | #if defined _LIBC && defined USE_IN_LIBIO 851 | if (_IO_fwide(stderr, 0) > 0) 852 | __fwprintf(stderr, L"%s", buf); 853 | else 854 | fputs(buf, stderr); 855 | 856 | free(buf); 857 | #endif 858 | } 859 | nextchar = (char *) ""; 860 | optind++; 861 | optopt = 0; 862 | return '?'; 863 | } 864 | } 865 | 866 | /* Look at and handle the next short option-character. */ 867 | 868 | { 869 | char c = *nextchar++; 870 | char *temp = my_index(optstring, c); 871 | 872 | /* Increment `optind' when we start to process its last character. */ 873 | if (*nextchar == '\0') 874 | ++optind; 875 | 876 | if (temp == NULL || c == ':') 877 | { 878 | if (print_errors) 879 | { 880 | #if defined _LIBC && defined USE_IN_LIBIO 881 | char *buf; 882 | #endif 883 | 884 | if (posixly_correct) 885 | { 886 | /* 1003.2 specifies the format of this message. */ 887 | #if defined _LIBC && defined USE_IN_LIBIO 888 | __asprintf(&buf, _("%s: illegal option -- %c\n"), 889 | argv[0], c); 890 | #else 891 | fprintf(stderr, _("%s: illegal option -- %c\n"), argv[0], c); 892 | #endif 893 | } 894 | else 895 | { 896 | #if defined _LIBC && defined USE_IN_LIBIO 897 | __asprintf(&buf, _("%s: invalid option -- %c\n"), 898 | argv[0], c); 899 | #else 900 | fprintf(stderr, _("%s: invalid option -- %c\n"), argv[0], c); 901 | #endif 902 | } 903 | 904 | #if defined _LIBC && defined USE_IN_LIBIO 905 | if (_IO_fwide(stderr, 0) > 0) 906 | __fwprintf(stderr, L"%s", buf); 907 | else 908 | fputs(buf, stderr); 909 | 910 | free(buf); 911 | #endif 912 | } 913 | optopt = c; 914 | return '?'; 915 | } 916 | /* Convenience. Treat POSIX -W foo same as long option --foo */ 917 | if (temp[0] == 'W' && temp[1] == ';') 918 | { 919 | char *nameend; 920 | const struct option *p; 921 | const struct option *pfound = NULL; 922 | int exact = 0; 923 | int ambig = 0; 924 | int indfound = 0; 925 | int option_index; 926 | 927 | /* This is an option that requires an argument. */ 928 | if (*nextchar != '\0') 929 | { 930 | optarg = nextchar; 931 | /* If we end this ARGV-element by taking the rest as an arg, 932 | we must advance to the next element now. */ 933 | optind++; 934 | } 935 | else if (optind == argc) 936 | { 937 | if (print_errors) 938 | { 939 | /* 1003.2 specifies the format of this message. */ 940 | #if defined _LIBC && defined USE_IN_LIBIO 941 | char *buf; 942 | 943 | __asprintf(&buf, _("%s: option requires an argument -- %c\n"), 944 | argv[0], c); 945 | 946 | if (_IO_fwide(stderr, 0) > 0) 947 | __fwprintf(stderr, L"%s", buf); 948 | else 949 | fputs(buf, stderr); 950 | 951 | free(buf); 952 | #else 953 | fprintf(stderr, _("%s: option requires an argument -- %c\n"), 954 | argv[0], c); 955 | #endif 956 | } 957 | optopt = c; 958 | if (optstring[0] == ':') 959 | c = ':'; 960 | else 961 | c = '?'; 962 | return c; 963 | } 964 | else 965 | /* We already incremented `optind' once; 966 | increment it again when taking next ARGV-elt as argument. */ 967 | optarg = argv[optind++]; 968 | 969 | /* optarg is now the argument, see if it's in the 970 | table of longopts. */ 971 | 972 | for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) 973 | /* Do nothing. */; 974 | 975 | /* Test all long options for either exact match 976 | or abbreviated matches. */ 977 | for (p = longopts, option_index = 0; p->name; p++, option_index++) 978 | if (!strncmp(p->name, nextchar, nameend - nextchar)) 979 | { 980 | if ((unsigned int)(nameend - nextchar) == strlen(p->name)) 981 | { 982 | /* Exact match found. */ 983 | pfound = p; 984 | indfound = option_index; 985 | exact = 1; 986 | break; 987 | } 988 | else if (pfound == NULL) 989 | { 990 | /* First nonexact match found. */ 991 | pfound = p; 992 | indfound = option_index; 993 | } 994 | else 995 | /* Second or later nonexact match found. */ 996 | ambig = 1; 997 | } 998 | if (ambig && !exact) 999 | { 1000 | if (print_errors) 1001 | { 1002 | #if defined _LIBC && defined USE_IN_LIBIO 1003 | char *buf; 1004 | 1005 | __asprintf(&buf, _("%s: option `-W %s' is ambiguous\n"), 1006 | argv[0], argv[optind]); 1007 | 1008 | if (_IO_fwide(stderr, 0) > 0) 1009 | __fwprintf(stderr, L"%s", buf); 1010 | else 1011 | fputs(buf, stderr); 1012 | 1013 | free(buf); 1014 | #else 1015 | fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"), 1016 | argv[0], argv[optind]); 1017 | #endif 1018 | } 1019 | nextchar += strlen(nextchar); 1020 | optind++; 1021 | return '?'; 1022 | } 1023 | if (pfound != NULL) 1024 | { 1025 | option_index = indfound; 1026 | if (*nameend) 1027 | { 1028 | /* Don't test has_arg with >, because some C compilers don't 1029 | allow it to be used on enums. */ 1030 | if (pfound->has_arg) 1031 | optarg = nameend + 1; 1032 | else 1033 | { 1034 | if (print_errors) 1035 | { 1036 | #if defined _LIBC && defined USE_IN_LIBIO 1037 | char *buf; 1038 | 1039 | __asprintf(&buf, _("\ 1040 | %s: option `-W %s' doesn't allow an argument\n"), 1041 | argv[0], pfound->name); 1042 | 1043 | if (_IO_fwide(stderr, 0) > 0) 1044 | __fwprintf(stderr, L"%s", buf); 1045 | else 1046 | fputs(buf, stderr); 1047 | 1048 | free(buf); 1049 | #else 1050 | fprintf(stderr, _("\ 1051 | %s: option `-W %s' doesn't allow an argument\n"), 1052 | argv[0], pfound->name); 1053 | #endif 1054 | } 1055 | 1056 | nextchar += strlen(nextchar); 1057 | return '?'; 1058 | } 1059 | } 1060 | else if (pfound->has_arg == 1) 1061 | { 1062 | if (optind < argc) 1063 | optarg = argv[optind++]; 1064 | else 1065 | { 1066 | if (print_errors) 1067 | { 1068 | #if defined _LIBC && defined USE_IN_LIBIO 1069 | char *buf; 1070 | 1071 | __asprintf(&buf, _("\ 1072 | %s: option `%s' requires an argument\n"), 1073 | argv[0], argv[optind - 1]); 1074 | 1075 | if (_IO_fwide(stderr, 0) > 0) 1076 | __fwprintf(stderr, L"%s", buf); 1077 | else 1078 | fputs(buf, stderr); 1079 | 1080 | free(buf); 1081 | #else 1082 | fprintf(stderr, 1083 | _("%s: option `%s' requires an argument\n"), 1084 | argv[0], argv[optind - 1]); 1085 | #endif 1086 | } 1087 | nextchar += strlen(nextchar); 1088 | return optstring[0] == ':' ? ':' : '?'; 1089 | } 1090 | } 1091 | nextchar += strlen(nextchar); 1092 | if (longind != NULL) 1093 | *longind = option_index; 1094 | if (pfound->flag) 1095 | { 1096 | *(pfound->flag) = pfound->val; 1097 | return 0; 1098 | } 1099 | return pfound->val; 1100 | } 1101 | nextchar = NULL; 1102 | return 'W'; /* Let the application handle it. */ 1103 | } 1104 | if (temp[1] == ':') 1105 | { 1106 | if (temp[2] == ':') 1107 | { 1108 | /* This is an option that accepts an argument optionally. */ 1109 | if (*nextchar != '\0') 1110 | { 1111 | optarg = nextchar; 1112 | optind++; 1113 | } 1114 | else 1115 | optarg = NULL; 1116 | nextchar = NULL; 1117 | } 1118 | else 1119 | { 1120 | /* This is an option that requires an argument. */ 1121 | if (*nextchar != '\0') 1122 | { 1123 | optarg = nextchar; 1124 | /* If we end this ARGV-element by taking the rest as an arg, 1125 | we must advance to the next element now. */ 1126 | optind++; 1127 | } 1128 | else if (optind == argc) 1129 | { 1130 | if (print_errors) 1131 | { 1132 | /* 1003.2 specifies the format of this message. */ 1133 | #if defined _LIBC && defined USE_IN_LIBIO 1134 | char *buf; 1135 | 1136 | __asprintf(&buf, 1137 | _("%s: option requires an argument -- %c\n"), 1138 | argv[0], c); 1139 | 1140 | if (_IO_fwide(stderr, 0) > 0) 1141 | __fwprintf(stderr, L"%s", buf); 1142 | else 1143 | fputs(buf, stderr); 1144 | 1145 | free(buf); 1146 | #else 1147 | fprintf(stderr, 1148 | _("%s: option requires an argument -- %c\n"), 1149 | argv[0], c); 1150 | #endif 1151 | } 1152 | optopt = c; 1153 | if (optstring[0] == ':') 1154 | c = ':'; 1155 | else 1156 | c = '?'; 1157 | } 1158 | else 1159 | /* We already incremented `optind' once; 1160 | increment it again when taking next ARGV-elt as argument. */ 1161 | optarg = argv[optind++]; 1162 | nextchar = NULL; 1163 | } 1164 | } 1165 | return c; 1166 | } 1167 | } 1168 | 1169 | int 1170 | getopt(argc, argv, optstring) 1171 | int argc; 1172 | char *const *argv; 1173 | const char *optstring; 1174 | { 1175 | return _getopt_internal(argc, argv, optstring, 1176 | (const struct option *) 0, 1177 | (int *)0, 1178 | 0); 1179 | } 1180 | 1181 | 1182 | 1183 | 1184 | int 1185 | getopt_long(int argc, char *const *argv, const char *options, 1186 | const struct option *long_options, int *opt_index) 1187 | { 1188 | return _getopt_internal(argc, argv, options, long_options, opt_index, 0, 0); 1189 | } 1190 | 1191 | int 1192 | getopt_long_only(int argc, char *const *argv, const char *options, 1193 | const struct option *long_options, int *opt_index) 1194 | { 1195 | return _getopt_internal(argc, argv, options, long_options, opt_index, 1, 0); 1196 | } 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | #endif /* Not ELIDE_CODE. */ 1203 | 1204 | #ifdef TEST 1205 | 1206 | /* Compile with -DTEST to make an executable for use in testing 1207 | the above definition of `getopt'. */ 1208 | 1209 | int 1210 | main(argc, argv) 1211 | int argc; 1212 | char **argv; 1213 | { 1214 | int c; 1215 | int digit_optind = 0; 1216 | 1217 | while (1) 1218 | { 1219 | int this_option_optind = optind ? optind : 1; 1220 | 1221 | c = getopt(argc, argv, "abc:d:0123456789"); 1222 | if (c == -1) 1223 | break; 1224 | 1225 | switch (c) 1226 | { 1227 | case '0': 1228 | case '1': 1229 | case '2': 1230 | case '3': 1231 | case '4': 1232 | case '5': 1233 | case '6': 1234 | case '7': 1235 | case '8': 1236 | case '9': 1237 | if (digit_optind != 0 && digit_optind != this_option_optind) 1238 | printf("digits occur in two different argv-elements.\n"); 1239 | digit_optind = this_option_optind; 1240 | printf("option %c\n", c); 1241 | break; 1242 | 1243 | case 'a': 1244 | printf("option a\n"); 1245 | break; 1246 | 1247 | case 'b': 1248 | printf("option b\n"); 1249 | break; 1250 | 1251 | case 'c': 1252 | printf("option c with value `%s'\n", optarg); 1253 | break; 1254 | 1255 | case '?': 1256 | break; 1257 | 1258 | default: 1259 | printf("?? getopt returned character code 0%o ??\n", c); 1260 | } 1261 | } 1262 | 1263 | if (optind < argc) 1264 | { 1265 | printf("non-option ARGV-elements: "); 1266 | while (optind < argc) 1267 | printf("%s ", argv[optind++]); 1268 | printf("\n"); 1269 | } 1270 | 1271 | exit(0); 1272 | } 1273 | 1274 | #endif /* TEST */ 1275 | -------------------------------------------------------------------------------- /wgetopt.h: -------------------------------------------------------------------------------- 1 | /* Declarations for getopt. 2 | Copyright (C) 1989-1994,1996-1999,2001,2003,2004,2009,2010 3 | Free Software Foundation, Inc. 4 | This file is part of the GNU C Library. 5 | 6 | The GNU C Library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | The GNU C Library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with the GNU C Library; if not, write to the Free 18 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 19 | 02111-1307 USA. */ 20 | 21 | #ifndef _GETOPT_H 22 | 23 | #ifndef __need_getopt 24 | # define _GETOPT_H 1 25 | #endif 26 | 27 | /* If __GNU_LIBRARY__ is not already defined, either we are being used 28 | standalone, or this is the first header included in the source file. 29 | If we are being used with glibc, we need to include , but 30 | that does not exist if we are standalone. So: if __GNU_LIBRARY__ is 31 | not defined, include , which will pull in for us 32 | if it's from glibc. (Why ctype.h? It's guaranteed to exist and it 33 | doesn't flood the namespace with stuff the way some other headers do.) */ 34 | #if !defined __GNU_LIBRARY__ 35 | # include 36 | #endif 37 | 38 | #ifndef __THROW 39 | # ifndef __GNUC_PREREQ 40 | # define __GNUC_PREREQ(maj, min) (0) 41 | # endif 42 | # if defined __cplusplus && __GNUC_PREREQ (2,8) 43 | # define __THROW throw () 44 | # else 45 | # define __THROW 46 | # endif 47 | #endif 48 | 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | 53 | /* For communication from `getopt' to the caller. 54 | When `getopt' finds an option that takes an argument, 55 | the argument value is returned here. 56 | Also, when `ordering' is RETURN_IN_ORDER, 57 | each non-option ARGV-element is returned here. */ 58 | 59 | extern char *optarg; 60 | 61 | /* Index in ARGV of the next element to be scanned. 62 | This is used for communication to and from the caller 63 | and for communication between successive calls to `getopt'. 64 | 65 | On entry to `getopt', zero means this is the first call; initialize. 66 | 67 | When `getopt' returns -1, this is the index of the first of the 68 | non-option elements that the caller should itself scan. 69 | 70 | Otherwise, `optind' communicates from one call to the next 71 | how much of ARGV has been scanned so far. */ 72 | 73 | extern int optind; 74 | 75 | /* Callers store zero here to inhibit the error message `getopt' prints 76 | for unrecognized options. */ 77 | 78 | extern int opterr; 79 | 80 | /* Set to an option character which was unrecognized. */ 81 | 82 | extern int optopt; 83 | 84 | #ifndef __need_getopt 85 | /* Describe the long-named options requested by the application. 86 | The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector 87 | of `struct option' terminated by an element containing a name which is 88 | zero. 89 | 90 | The field `has_arg' is: 91 | no_argument (or 0) if the option does not take an argument, 92 | required_argument (or 1) if the option requires an argument, 93 | optional_argument (or 2) if the option takes an optional argument. 94 | 95 | If the field `flag' is not NULL, it points to a variable that is set 96 | to the value given in the field `val' when the option is found, but 97 | left unchanged if the option is not found. 98 | 99 | To have a long-named option do something other than set an `int' to 100 | a compiled-in constant, such as set a value from `optarg', set the 101 | option's `flag' field to zero and its `val' field to a nonzero 102 | value (the equivalent single-letter option character, if there is 103 | one). For long options that have a zero `flag' field, `getopt' 104 | returns the contents of the `val' field. */ 105 | 106 | struct option 107 | { 108 | const char *name; 109 | /* has_arg can't be an enum because some compilers complain about 110 | type mismatches in all the code that assumes it is an int. */ 111 | int has_arg; 112 | int *flag; 113 | int val; 114 | }; 115 | 116 | /* Names for the values of the `has_arg' field of `struct option'. */ 117 | 118 | # define no_argument 0 119 | # define required_argument 1 120 | # define optional_argument 2 121 | #endif /* need getopt */ 122 | 123 | 124 | /* Get definitions and prototypes for functions to process the 125 | arguments in ARGV (ARGC of them, minus the program name) for 126 | options given in OPTS. 127 | 128 | Return the option character from OPTS just read. Return -1 when 129 | there are no more options. For unrecognized options, or options 130 | missing arguments, `optopt' is set to the option letter, and '?' is 131 | returned. 132 | 133 | The OPTS string is a list of characters which are recognized option 134 | letters, optionally followed by colons, specifying that that letter 135 | takes an argument, to be placed in `optarg'. 136 | 137 | If a letter in OPTS is followed by two colons, its argument is 138 | optional. This behavior is specific to the GNU `getopt'. 139 | 140 | The argument `--' causes premature termination of argument 141 | scanning, explicitly telling `getopt' that there are no more 142 | options. 143 | 144 | If OPTS begins with `--', then non-option arguments are treated as 145 | arguments to the option '\0'. This behavior is specific to the GNU 146 | `getopt'. */ 147 | 148 | #ifdef __GNU_LIBRARY__ 149 | /* Many other libraries have conflicting prototypes for getopt, with 150 | differences in the consts, in stdlib.h. To avoid compilation 151 | errors, only prototype getopt for the GNU C library. */ 152 | extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) 153 | __THROW; 154 | 155 | # if defined __need_getopt && defined __USE_POSIX2 \ 156 | && !defined __USE_POSIX_IMPLICITLY && !defined __USE_GNU 157 | /* The GNU getopt has more functionality than the standard version. The 158 | additional functionality can be disable at runtime. This redirection 159 | helps to also do this at runtime. */ 160 | # ifdef __REDIRECT 161 | extern int __REDIRECT_NTH (getopt, (int ___argc, char *const *___argv, 162 | const char *__shortopts), 163 | __posix_getopt); 164 | # else 165 | extern int __posix_getopt (int ___argc, char *const *___argv, 166 | const char *__shortopts) __THROW; 167 | # define getopt __posix_getopt 168 | # endif 169 | # endif 170 | #else /* not __GNU_LIBRARY__ */ 171 | extern int getopt (); 172 | #endif /* __GNU_LIBRARY__ */ 173 | 174 | #ifndef __need_getopt 175 | extern int getopt_long (int ___argc, char *const *___argv, 176 | const char *__shortopts, 177 | const struct option *__longopts, int *__longind) 178 | __THROW; 179 | extern int getopt_long_only (int ___argc, char *const *___argv, 180 | const char *__shortopts, 181 | const struct option *__longopts, int *__longind) 182 | __THROW; 183 | 184 | #endif 185 | 186 | #ifdef __cplusplus 187 | } 188 | #endif 189 | 190 | /* Make sure we later can get all the definitions and declarations. */ 191 | #undef __need_getopt 192 | 193 | #endif /* getopt.h */ 194 | --------------------------------------------------------------------------------