├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── build-osx.yaml │ └── c-cpp.yml ├── .gitignore ├── .travis.yml ├── AUTHORS ├── COPYING ├── ChangeLog ├── LICENSE ├── Makefile.am ├── NEWS ├── README ├── README.md ├── bitwise.1 ├── bootstrap.sh ├── configure.ac ├── debian ├── changelog ├── compat ├── control ├── copyright ├── rules ├── source │ └── format └── watch ├── inc ├── bitwise.h ├── shunting-yard.h └── stack.h ├── m4 ├── ax_lib_readline.m4 ├── ax_require_defined.m4 ├── ax_with_curses.m4 └── ax_with_curses_extra.m4 ├── resources ├── bitwise.gif ├── bitwise.png ├── bitwise.svg ├── cmdline.png ├── conversion.png └── snip.txt ├── snapcraft.yaml ├── src ├── cmd.c ├── help.c ├── interactive.c ├── main.c ├── misc.c ├── shunting-yard.c └── stack.c ├── tests └── test-shunting-yard.c └── ubuntu_release.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [**] 4 | insert_final_newline = true 5 | charset = utf-8 6 | 7 | [**.{c,h}] 8 | indent_style = tab 9 | indent_size = tab 10 | trim_trailing_whitespace = true 11 | 12 | [**.{yml,yaml}] 13 | indent_style = space 14 | indent_size = 2 15 | trim_trailing_whitespace = true 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: mellowcandle 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Version:** 27 | - [e.g. v0.32, master] 28 | 29 | **Desktop (please complete the following information):** 30 | - OS: [e.g. Linux Fedora / Ubuntu 18.04] 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/workflows/build-osx.yaml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | env: 12 | LDFLAGS: "-L/usr/local/opt/readline/lib" 13 | CPPFLAGS: "-I/usr/local/opt/readline/include" 14 | 15 | runs-on: macos-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Install lib-cunit 20 | run: brew install readline cunit autoconf automake 21 | - name: Bootstrap 22 | run: ./bootstrap.sh 23 | - name: configure 24 | run: ./configure 25 | - name: make check 26 | run: make check 27 | 28 | -------------------------------------------------------------------------------- /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Install xmllint 17 | run: sudo apt-get install libcunit1-dev 18 | - name: Bootstrap 19 | run: ./bootstrap.sh 20 | - name: configure 21 | run: ./configure --enable-gcov 22 | - name: make check 23 | run: make check 24 | 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | bitwise 33 | *.exe 34 | *.out 35 | *.app 36 | *.i*86 37 | *.x86_64 38 | *.hex 39 | 40 | # Build output 41 | config.log 42 | inc/config.h 43 | inc/stamp-h1 44 | src/.deps/ 45 | src/.dirstamp 46 | tests/.deps/ 47 | 48 | # Debug files 49 | *.dSYM/ 50 | *.su 51 | *.idb 52 | *.pdb 53 | 54 | # Kernel Module Compile Results 55 | *.mod* 56 | *.cmd 57 | .tmp_versions/ 58 | modules.order 59 | Module.symvers 60 | Mkfile.old 61 | dkms.conf 62 | 63 | # Autotools stuff 64 | Makefile 65 | *.in 66 | aclocal.m4 67 | autom4te.cache/ 68 | build-aux/ 69 | config.status 70 | configure 71 | pre-inst-env 72 | install-sh 73 | missing 74 | test-driver 75 | compile 76 | depcomp 77 | 78 | # tracing stuff 79 | log.txt 80 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | compiler: gcc 4 | 5 | os: 6 | - linux 7 | - osx 8 | 9 | arch: 10 | - AMD64 11 | - ppc64le 12 | 13 | before_install: 14 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq update ; fi 15 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get install libcunit1-dev ; fi 16 | - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install readline; fi 17 | - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install cunit; fi 18 | - if [ "$TRAVIS_OS_NAME" == "osx" ]; then export LDFLAGS="-L/usr/local/opt/readline/lib"; fi 19 | - if [ "$TRAVIS_OS_NAME" == "osx" ]; then export CPPFLAGS="-I/usr/local/opt/readline/include"; fi 20 | 21 | script: 22 | - "./bootstrap.sh" 23 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ./configure --enable-gcov; fi 24 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then make check; fi 25 | 26 | - if [ "$TRAVIS_OS_NAME" = "osx" ]; then ./configure; fi 27 | - if [ "$TRAVIS_OS_NAME" = "osx" ]; then make check; fi 28 | 29 | after_success: 30 | - bash <(curl -s https://codecov.io/bash) 31 | 32 | after_failure: 33 | - if [ -f ./test-suite.log ]; then cat ./test-suite.log; fi 34 | 35 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mellowcandle/bitwise/0a4e7d93b3e922e2293251fdbfd0e4fb1cc7910b/AUTHORS -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | Bitwise v0.20 2 | ========================================== 3 | * Added calculator mode 4 | * Added support for commandline interface 5 | in interactive mode. 6 | 7 | Bitwise v0.14 8 | ========================================== 9 | * Added NOT (~) command to interactive mode 10 | * Support binary input in command line mode 11 | * Updated documentation 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS=bitwise 2 | bitwise_SOURCES= src/main.c src/misc.c \ 3 | src/interactive.c src/cmd.c \ 4 | src/stack.c src/shunting-yard.c \ 5 | src/help.c inc/bitwise.h inc/stack.h \ 6 | inc/shunting-yard.h 7 | 8 | dist_man_MANS=bitwise.1 9 | 10 | if COND_GCOV 11 | MAYBE_COVERAGE=--coverage --no-inline 12 | endif 13 | 14 | if COND_TRACE 15 | MAYBE_TRACE=-DTRACE 16 | endif 17 | 18 | if COND_DEBUG 19 | MAYBE_DEBUG=-g -O0 20 | endif 21 | 22 | AM_CFLAGS = $(MAYBE_COVERAGE) $(MAYBE_DEBUG) $(MAYBE_TRACE) 23 | 24 | check_PROGRAMS = tests/test-shunting-yard 25 | tests_test_shunting_yard_SOURCES = src/shunting-yard.c inc/shunting-yard.h \ 26 | src/stack.c inc/stack.h inc/bitwise.h \ 27 | src/misc.c \ 28 | tests/test-shunting-yard.c 29 | tests_test_shunting_yard_LDADD = -lcunit 30 | 31 | TESTS = $(check_PROGRAMS) 32 | 33 | clean-local: 34 | rm -f *.gcno 35 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mellowcandle/bitwise/0a4e7d93b3e922e2293251fdbfd0e4fb1cc7910b/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bitwise 2 | ## Terminal based bitwise calculator in curses 3 | [![Snap Status](https://build.snapcraft.io/badge/mellowcandle/bitwise.svg)](https://build.snapcraft.io/user/mellowcandle/bitwise) 4 | Coverity Scan Build Status 6 | 7 | Packaging status 8 | 9 | 10 | _Bitwise_ is multi base interactive calculator supporting dynamic base conversion and bit manipulation. 11 | It's a handy tool for low level hackers, kernel developers and device drivers developers. 12 | 13 | Some of the features include: 14 | * Interactive ncurses interface 15 | * Command line calculator supporting all bitwise operations. 16 | * Individual bit manipulator. 17 | * Bitwise operations such as NOT, OR, AND, XOR, and shifts. 18 | 19 | ## 20 | 21 | ![Demo](https://github.com/mellowcandle/bitwise/raw/master/resources/bitwise.gif "Bitwise demo2") 22 | 23 | ## Usage 24 | _bitwise_ can be used both interactively and in command line mode. 25 | 26 | ### Command line calculator mode 27 | In command line mode, bitwise will calculate the given expression and will output the result in all bases including binary representation. 28 | 29 | _bitwise_ detects the base by the prefix of the input (_0x/0X_ for hexadecimal, leading _0_ for octal, _b_ for binary, and the rest is decimal). 30 | 31 | **NEW** Bitwise now support parsing IPv4 addresses, it will also output the possible IPv4 address in both Network and reversed byte order. 32 | 33 | ### Examples: 34 | 35 | #### Simple base conversion 36 | 37 | ![conversion](https://github.com/mellowcandle/bitwise/raw/master/resources/cmdline.png "Bitwise conversion") 38 | 39 | 40 | #### C style syntax Calculator 41 | 42 | ![calculator](https://github.com/mellowcandle/bitwise/raw/master/resources/conversion.png "Bitwise calculator") 43 | 44 | ### Interactive mode 45 | _bitwise_ starts in interactive mode if no command line parameters are passed or if the _-i | --interactive_ flag is passed. 46 | In this mode, you can input a number and manipulate it and see the other bases change dynamically. 47 | It also allows changing individual bits in the binary. 48 | You can show the help screen by pressing F1 . 49 | 50 | #### Navigation in interactive mode 51 | To move around use the arrow keys, or use _vi_ key bindings : h j k l . 52 | Leave the program by pressing q . 53 | 54 | ##### Binary specific movement 55 | You can toggle a bit using the space key. 56 | You can jump a byte forward using w and backwards one byte using b . 57 | 58 | #### Bitwise operation in interactive mode 59 | 60 | ##### Setting the bit width: 61 | 62 | Reducing or extending the bit width interactively is also very easy, just use: 63 | ! for 8bit, @ for 16Bit, $ for 32Bit and * for 64Bit. 64 | When changing the bit width, the number is *masked* with the new width, so you might lose precision, use with care. 65 | 66 | ##### NOT: 67 | 68 | Press ~ to perform the NOT operator. 69 | 70 | ##### Reversing Endianness: 71 | 72 | Press r to reverse the endianness. 73 | 74 | ##### Shifts 75 | 76 | Press < and > to perform the left or right shift. 77 | 78 | #### expression calculator in interactive mode 79 | 80 | You can enter expression calculator mode by typing : (Just like in vim). 81 | 82 | To exit the mode, just press ESC . 83 | 84 | In this mode, you can type any expression you like to be evaluated. 85 | The result will be printed in the history window and also printed in the binary and various bases on top. 86 | 87 | ###### operators and functions 88 | * All C operators are supported, additionally, you can use the "$" symbol to refer to the last result. 89 | * Refer to a specific bit by using the function _BIT(x)_. 90 | 91 | ###### commands 92 | * _h(elp)_ - Show the help screen. 93 | * _c(lear)_ - Clear the history window. 94 | * _w(idth)_ [8 | 16 | 32 | 64] - Set the required width mask 95 | * _o(utput)_ [dec(imal) | hex(adecimal) | oct(al) | bin(ary) | all] - Set the default output for results. 96 | * _q(uit)_ - Exit 97 | 98 | ## Integration with other software 99 | ### Vim 100 | * [vim-bitwise](https://github.com/mellowcandle/vim-bitwise "vim bitwise") 101 | 102 | ## Installation 103 | 104 | ### Linux 105 | #### Ubuntu 106 | From 20.04 you can just type 107 | ``` 108 | sudo apt-get install bitwise 109 | ``` 110 | For earlier versions: 111 | ``` 112 | sudo add-apt-repository ppa:ramon-fried/bitwise 113 | sudo apt-get update 114 | sudo apt-get install bitwise 115 | ``` 116 | #### Snap 117 | If your distribution supports Snap just type: 118 | ` 119 | sudo snap install bitwise 120 | ` 121 | #### OpenSuse 122 | ` 123 | zypper install bitwise 124 | ` 125 | 126 | #### Arch 127 | You can use the AUR repository: https://aur.archlinux.org/packages/bitwise/ 128 | 129 | #### Void 130 | _bitwise_ is in the default repository, so just type: 131 | ` 132 | sudo xbps-install -S bitwise 133 | ` 134 | 135 | #### Fedora Linux 136 | 137 | bitwise is available in the [official repository](https://src.fedoraproject.org/rpms/bitwise) 138 | 139 | ``` 140 | sudo dnf install bitwise 141 | ``` 142 | 143 | #### Buildroot / Yocto 144 | Bitwise is available both in Buildroot and in Yocto, please refer to the documentation on how to add those to your target image. 145 | 146 | ### macOS 147 | 148 | #### MacPorts 149 | ``` 150 | sudo port install bitwise 151 | ``` 152 | 153 | #### Homebrew 154 | ``` 155 | brew install bitwise 156 | ``` 157 | 158 | ### Windows 159 | NCurses doesn't support Windows. You can use the Windows Subsystem for Linux as a workaround. 160 | 161 | ### Nix 162 | ``` 163 | nix-env -i bitwise 164 | ``` 165 | 166 | ### Building from source 167 | 168 | #### Prerequisites 169 | * libreadline 170 | * libncurses (with forms) 171 | * libcunit (only needed for testing) 172 | 173 | On Ubuntu/Debian system you can just paste: 174 | ``` 175 | sudo apt-get install build-essential 176 | sudo apt-get install libncurses5-dev 177 | sudo apt-get install libreadline-dev 178 | sudo apt-get install libcunit1-dev 179 | ``` 180 | On Mac systems: 181 | ``` 182 | brew install automake 183 | brew install autoconf 184 | brew install readline 185 | export LDFLAGS="-L/usr/local/opt/readline/lib" 186 | export CPPFLAGS="-I/usr/local/opt/readline/include" 187 | ``` 188 | - Download [the latest release](https://github.com/mellowcandle/bitwise/releases/latest) 189 | 190 | ```sh 191 | tar xfz RELEASE-FILE.TAR.GZ 192 | cd RELEASE-DIR 193 | ./configure 194 | make 195 | sudo make install 196 | ``` 197 | 198 | Running unit tests by typing 199 | ``` make check ``` 200 | 201 | ### Contribution 202 | * Install prerequisites 203 | * Fork the repo 204 | * Run ```./bootstrap.sh``` 205 | * Follow the building from source section. 206 | * commit and send pull request 207 | -------------------------------------------------------------------------------- /bitwise.1: -------------------------------------------------------------------------------- 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10. 2 | .TH BITWISE "1" "July 2023" "bitwise v0.50" "User Commands" 3 | .SH NAME 4 | bitwise \- Terminal based bit manipulator in ncurses 5 | .SH SYNOPSIS 6 | .B bitwise 7 | [\fI\,OPTION\/\fR...] [\fI\,expression\/\fR] 8 | .SH DESCRIPTION 9 | [expression] mathematical expression 10 | .TP 11 | \fB\-i\fR, \fB\-\-interactive\fR 12 | Load interactive mode (default if no input) 13 | .TP 14 | \fB\-w\fR, \fB\-\-width[b\fR|w|l|d] 15 | Set bit width (default: l) 16 | .TP 17 | \fB\-h\fR, \fB\-\-help\fR 18 | Display this help and exit 19 | .TP 20 | \fB\-v\fR, \fB\-\-version\fR 21 | Output version information and exit 22 | .TP 23 | \fB\-s\fR, \fB\-\-si\fR 24 | Output sizes according to SI standard. (default: IEC standard) 25 | .TP 26 | \fB\-\-no\-color\fR 27 | Start without color support 28 | .SH AUTHOR 29 | Written by Ramon Fried 30 | .SH "SEE ALSO" 31 | The full documentation for 32 | .B bitwise 33 | can be found at https://github.com/mellowcandle/bitwise 34 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf --verbose --install --force 4 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.69]) 5 | AC_INIT([bitwise], [v0.50], [rfried.dev@gmail.com]) 6 | AC_CONFIG_SRCDIR([src/misc.c]) 7 | AC_CONFIG_HEADERS([inc/config.h]) 8 | 9 | dnl Document where we keep our .m4 file. 10 | AC_CONFIG_MACRO_DIR([m4]) 11 | dnl Make sure aclocal actually found it! 12 | m4_pattern_forbid([^AX_]) 13 | 14 | AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) 15 | 16 | # Checks for programs. 17 | AC_PROG_CC 18 | AC_PROG_CC_STDC 19 | AC_PROG_INSTALL 20 | AC_PROG_CC_C99 21 | 22 | AX_LIB_READLINE 23 | if test "$ac_cv_have_readline" = no; then 24 | AC_MSG_ERROR([requires readline library]) 25 | fi 26 | 27 | # Checks for libraries. 28 | AC_CHECK_LIB([form], [form_driver]) 29 | AC_CHECK_LIB([ncurses], [newwin]) 30 | AC_SEARCH_LIBS([sqrt], [m]) 31 | 32 | # Checks for header files. 33 | AC_CHECK_HEADERS([fcntl.h inttypes.h stdint.h stdlib.h string.h curses.h form.h]) 34 | 35 | AC_CHECK_DECLS([bswap_32], [], [], [[#include ]]) 36 | AM_CONDITIONAL(HAVE_BYTESWAP_H, [test "x$ac_cv_have_decl_bswap_32" = "xyes"]) 37 | 38 | # Checks for typedefs, structures, and compiler characteristics. 39 | AC_CHECK_HEADER_STDBOOL 40 | AC_TYPE_UINT64_T 41 | 42 | # Checks for library functions. 43 | AC_FUNC_STRCOLL 44 | AC_CHECK_FUNCS([memchr memmove memset stpcpy strchr strcspn strdup strerror strpbrk strrchr strspn strstr]) 45 | 46 | AC_CONFIG_FILES([Makefile]) 47 | 48 | AC_ARG_ENABLE([gcov], 49 | [AS_HELP_STRING([--enable-gcov], 50 | [Build with coverage support])], 51 | [], 52 | [enable_gcov=no]) 53 | AM_CONDITIONAL([COND_GCOV],[test '!' "$enable_gcov" = no]) 54 | 55 | AC_ARG_ENABLE([trace], 56 | [AS_HELP_STRING([--enable-trace], 57 | [Build with trace support])], 58 | [], 59 | [enable_trace=no]) 60 | AM_CONDITIONAL([COND_TRACE],[test '!' "$enable_trace" = no]) 61 | 62 | AC_ARG_ENABLE([debug], 63 | [AS_HELP_STRING([--enable-debug], 64 | [Build with debug symbols])], 65 | [], 66 | [enable_debug=no]) 67 | AM_CONDITIONAL([COND_DEBUG],[test '!' "$enable_debug" = no]) 68 | 69 | AC_OUTPUT 70 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | bitwise (0.40-1) unstable; urgency=medium 2 | 3 | * Initial release Closes: Bug#933990 4 | 5 | -- Ramon Fried Sat, 10 Aug 2019 21:00:03 -0400 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 12 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: bitwise 2 | Section: science 3 | Priority: optional 4 | Maintainer: Ramon Fried 5 | Build-Depends: debhelper (>= 12~), libncurses-dev, libreadline-dev, libcunit1-dev 6 | Standards-Version: 4.4.0 7 | Homepage: https://github.com/mellowcandle/bitwise 8 | 9 | Package: bitwise 10 | Architecture: any 11 | Depends: ${shlibs:Depends}, ${misc:Depends} 12 | Description: Interactive bitwise operation in ncurses 13 | Bitwise is multi base interactive calculator supporting dynamic base 14 | conversion and bit manipulation. It's a handy tool for low level hackers, 15 | kernel developers and device drivers developers. 16 | . 17 | Some of the features include: 18 | . 19 | Interactive ncurses interface 20 | Command line calculator. 21 | Individual bit manipulator. 22 | Bitwise operations such as NOT, OR, AND, XOR, and shifts. 23 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: bitwise 3 | Upstream-Contact: Ramon Fried 4 | Source: https://github.com/mellowcandle/bitwise 5 | 6 | Files: inc/shunting-yard.h src/stack.c src/shunting-yard.c 7 | Copyright: 2011 - 2012, 2014 Brian Marshall 8 | 2019 Ramon Fried 9 | License: BSD-2-clause 10 | 11 | Files: m4/ax_require_defined.m4 12 | Copyright: 2014 Mike Frysinger vapier@gentoo.org 13 | License: GFDL 14 | 15 | Files: m4/ax_lib_readline.m4 16 | Copyright: 2008 Ville Laurikari 17 | License: GFDL 18 | 19 | Files: debian/* 20 | Copyright: 2019 Ramon Fried 21 | License: GPL-3.0+ 22 | 23 | Files: * 24 | Copyright: 2019 25 | License: GPL-3.0+ 26 | 27 | License: GPL-3.0+ 28 | This program is free software: you can redistribute it and/or modify 29 | it under the terms of the GNU General Public License as published by 30 | the Free Software Foundation, either version 3 of the License, or 31 | (at your option) any later version. 32 | . 33 | This package is distributed in the hope that it will be useful, 34 | but WITHOUT ANY WARRANTY; without even the implied warranty of 35 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 36 | GNU General Public License for more details. 37 | . 38 | You should have received a copy of the GNU General Public License 39 | along with this program. If not, see . 40 | . 41 | On Debian systems, the complete text of the GNU General 42 | Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". 43 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # See debhelper(7) (uncomment to enable) 3 | # output every command that modifies files on the build system. 4 | #export DH_VERBOSE = 1 5 | 6 | # see FEATURE AREAS in dpkg-buildflags(1) 7 | export DEB_BUILD_MAINT_OPTIONS = hardening=+all 8 | # package maintainers to append CFLAGS 9 | export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic 10 | # package maintainers to append LDFLAGS 11 | export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed 12 | 13 | 14 | %: 15 | dh $@ 16 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=4 2 | 3 | opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%bitwise-$1.tar.gz%" \ 4 | https://github.com/mellowcandle/bitwise/releases \ 5 | (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate 6 | -------------------------------------------------------------------------------- /inc/bitwise.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 2 | * Ramon Fried 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "config.h" 15 | /* Readine checks */ 16 | 17 | #ifdef HAVE_LIBREADLINE 18 | # if defined(HAVE_READLINE_READLINE_H) 19 | # include 20 | # elif defined(HAVE_READLINE_H) 21 | # include 22 | # else /* !defined(HAVE_READLINE_H) */ 23 | extern char *readline(); 24 | # endif /* !defined(HAVE_READLINE_H) */ 25 | #else /* !defined(HAVE_READLINE_READLINE_H) */ 26 | /* no readline */ 27 | #endif /* HAVE_LIBREADLINE */ 28 | 29 | #ifdef HAVE_READLINE_HISTORY 30 | # if defined(HAVE_READLINE_HISTORY_H) 31 | # include 32 | # elif defined(HAVE_HISTORY_H) 33 | # include 34 | # else /* !defined(HAVE_HISTORY_H) */ 35 | extern void add_history(); 36 | extern int write_history(); 37 | extern int read_history(); 38 | # endif /* defined(HAVE_READLINE_HISTORY_H) */ 39 | /* no history */ 40 | #endif /* HAVE_READLINE_HISTORY */ 41 | 42 | #define MAX_HISTORY_LEN 100 43 | 44 | #define FIELDS_WIN 0 45 | #define BINARY_WIN 1 46 | #define COMMAND_WIN 2 47 | 48 | #define BIT(nr) (1ULL << (nr)) 49 | #define MASK(s) (~0ULL >> (64 - s)) 50 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 51 | 52 | typedef enum output_type { 53 | CMD_OUTPUT_DECIMAL, 54 | CMD_OUTPUT_HEXADECIMAL, 55 | CMD_OUTPUT_OCTAL, 56 | CMD_OUTPUT_BINARY, 57 | CMD_OUTPUT_ALL, 58 | } output_type; 59 | 60 | /* Misc */ 61 | int lltostr(uint64_t val, char *buf, int base); 62 | int set_width(char width); 63 | void set_width_by_val(uint64_t val); 64 | void die(const char *fmt, ...); 65 | int parse_input(const char *input, uint64_t *val); 66 | int validate_input(int ch, int base); 67 | int sprintf_type(uint64_t val, char *buf, output_type type); 68 | 69 | void init_terminal(void); 70 | void deinit_terminal(void); 71 | 72 | /* Interactive */ 73 | extern FORM *form; 74 | 75 | int sprintf_size(uint64_t val, char *buf, bool si); 76 | int start_interactive(uint64_t start); 77 | void set_active_field(bool none); 78 | void set_fields_width(int width); 79 | void position_binary_curser(int previous_pos, int next_pos); 80 | void paint_screen(void); 81 | void unpaint_screen(void); 82 | void update_binary(); 83 | int update_fields(int index); 84 | 85 | /* Command */ 86 | void process_cmd(int ch); 87 | void init_readline(void); 88 | void deinit_readline(void); 89 | void readline_redisplay(void); 90 | 91 | /* calc */ 92 | int calc(int argc, char *argv[]); 93 | 94 | /* Help */ 95 | void show_help(void); 96 | 97 | #ifdef TRACE 98 | #define LOG(...) do { \ 99 | fprintf(fd, __VA_ARGS__); \ 100 | fflush(fd);\ 101 | } while (0) 102 | extern FILE *fd; 103 | #else 104 | #define LOG(...) do { } while (0) 105 | #endif 106 | 107 | /* Colors */ 108 | void init_colors(void); 109 | 110 | extern char *color_green; 111 | extern char *color_red; 112 | extern char *color_blue; 113 | extern char *color_magenta; 114 | extern char *color_cyan; 115 | extern char *color_white; 116 | extern char *color_reset; 117 | 118 | extern WINDOW *fields_win; 119 | extern WINDOW *binary_win; 120 | extern WINDOW *cmd_win; 121 | extern int active_win; 122 | extern int last_win; 123 | 124 | extern int bit_pos; 125 | extern int g_has_color; 126 | extern int g_width; 127 | extern int g_output; 128 | extern bool g_input_avail; 129 | extern int g_input; 130 | extern bool g_leave_req; 131 | extern uint64_t g_val; 132 | 133 | /* History */ 134 | typedef enum history_type { 135 | TYPE_INPUT_COMMAND = 0, 136 | TYPE_INPUT_EXPRESSION, 137 | TYPE_OUTPUT_RESULT, 138 | TYPE_OUTPUT_ERROR, 139 | } history_type; 140 | 141 | struct history_entry { 142 | history_type type; 143 | char *line; 144 | }; 145 | 146 | extern struct history_entry history[]; 147 | extern unsigned int history_pos; 148 | 149 | void flush_history(void); 150 | void update_history_win(void); 151 | 152 | static inline void append_to_history(const char *str, history_type type) { 153 | char *new_line; 154 | 155 | new_line = strdup(str); 156 | if (!new_line) { 157 | LOG("No memory to allocate string\n"); 158 | return; 159 | } 160 | 161 | history[history_pos % MAX_HISTORY_LEN].line = new_line; 162 | history[history_pos % MAX_HISTORY_LEN].type = type; 163 | history_pos++; 164 | 165 | update_history_win(); 166 | } 167 | 168 | static inline WINDOW *get_win(int win) 169 | { 170 | if (win == FIELDS_WIN) 171 | return fields_win; 172 | else if (win == BINARY_WIN) 173 | return binary_win; 174 | else if (win == COMMAND_WIN) 175 | return cmd_win; 176 | else 177 | return NULL; 178 | } 179 | 180 | #endif /* end of include guard: BITWISE_H */ 181 | -------------------------------------------------------------------------------- /inc/shunting-yard.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 - 2012, 2014 Brian Marshall. All rights reserved. 2 | // 3 | // Use of this source code is governed by the BSD 2-Clause License that can be 4 | // found in the LICENSE file. 5 | 6 | #include 7 | 8 | #ifndef SHUNTING_YARD_H 9 | #define SHUNTING_YARD_H 10 | 11 | typedef enum { 12 | STATUS_OK, 13 | ERROR_SYNTAX, 14 | ERROR_OPEN_PARENTHESIS, 15 | ERROR_CLOSE_PARENTHESIS, 16 | ERROR_UNRECOGNIZED, 17 | ERROR_NO_INPUT, 18 | ERROR_UNDEFINED_FUNCTION, 19 | ERROR_FUNCTION_ARGUMENTS, 20 | ERROR_UNDEFINED_CONSTANT, 21 | ERROR_WRONG_ARGUMENTS, 22 | ERROR_DIVIDE_BY_ZERO, 23 | } Status; 24 | 25 | // Calculates the result of a mathematical expression. 26 | Status shunting_yard(const char *expression, uint64_t *result); 27 | 28 | #endif // SHUNTING_YARD_H 29 | -------------------------------------------------------------------------------- /inc/stack.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 - 2014 Brian Marshall. All rights reserved. 2 | // 3 | // Use of this source code is governed by the BSD 2-Clause License that can be 4 | // found in the LICENSE file. 5 | 6 | #ifndef SHUNTING_YARD_STACK_H 7 | #define SHUNTING_YARD_STACK_H 8 | 9 | typedef struct Stack Stack; 10 | 11 | // Inserts an item at the top of the stack. 12 | void stack_push(Stack **stack, const void *value); 13 | 14 | // Removes an item from the top of the stack. 15 | const void *stack_pop(Stack **stack); 16 | 17 | // Returns the item at the top of the stack without removing it. 18 | const void *stack_top(const Stack *stack); 19 | 20 | #endif // SHUNTING_YARD_STACK_H 21 | -------------------------------------------------------------------------------- /m4/ax_lib_readline.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_lib_readline.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_LIB_READLINE 8 | # 9 | # DESCRIPTION 10 | # 11 | # Searches for a readline compatible library. If found, defines 12 | # `HAVE_LIBREADLINE'. If the found library has the `add_history' function, 13 | # sets also `HAVE_READLINE_HISTORY'. Also checks for the locations of the 14 | # necessary include files and sets `HAVE_READLINE_H' or 15 | # `HAVE_READLINE_READLINE_H' and `HAVE_READLINE_HISTORY_H' or 16 | # 'HAVE_HISTORY_H' if the corresponding include files exists. 17 | # 18 | # The libraries that may be readline compatible are `libedit', 19 | # `libeditline' and `libreadline'. Sometimes we need to link a termcap 20 | # library for readline to work, this macro tests these cases too by trying 21 | # to link with `libtermcap', `libcurses' or `libncurses' before giving up. 22 | # 23 | # Here is an example of how to use the information provided by this macro 24 | # to perform the necessary includes or declarations in a C file: 25 | # 26 | # #ifdef HAVE_LIBREADLINE 27 | # # if defined(HAVE_READLINE_READLINE_H) 28 | # # include 29 | # # elif defined(HAVE_READLINE_H) 30 | # # include 31 | # # else /* !defined(HAVE_READLINE_H) */ 32 | # extern char *readline (); 33 | # # endif /* !defined(HAVE_READLINE_H) */ 34 | # char *cmdline = NULL; 35 | # #else /* !defined(HAVE_READLINE_READLINE_H) */ 36 | # /* no readline */ 37 | # #endif /* HAVE_LIBREADLINE */ 38 | # 39 | # #ifdef HAVE_READLINE_HISTORY 40 | # # if defined(HAVE_READLINE_HISTORY_H) 41 | # # include 42 | # # elif defined(HAVE_HISTORY_H) 43 | # # include 44 | # # else /* !defined(HAVE_HISTORY_H) */ 45 | # extern void add_history (); 46 | # extern int write_history (); 47 | # extern int read_history (); 48 | # # endif /* defined(HAVE_READLINE_HISTORY_H) */ 49 | # /* no history */ 50 | # #endif /* HAVE_READLINE_HISTORY */ 51 | # 52 | # LICENSE 53 | # 54 | # Copyright (c) 2008 Ville Laurikari 55 | # 56 | # Copying and distribution of this file, with or without modification, are 57 | # permitted in any medium without royalty provided the copyright notice 58 | # and this notice are preserved. This file is offered as-is, without any 59 | # warranty. 60 | 61 | #serial 8 62 | 63 | AU_ALIAS([VL_LIB_READLINE], [AX_LIB_READLINE]) 64 | AC_DEFUN([AX_LIB_READLINE], [ 65 | AC_CACHE_CHECK([for a readline compatible library], 66 | ax_cv_lib_readline, [ 67 | ORIG_LIBS="$LIBS" 68 | for readline_lib in readline edit editline; do 69 | for termcap_lib in "" termcap curses ncurses; do 70 | if test -z "$termcap_lib"; then 71 | TRY_LIB="-l$readline_lib" 72 | else 73 | TRY_LIB="-l$readline_lib -l$termcap_lib" 74 | fi 75 | LIBS="$ORIG_LIBS $TRY_LIB" 76 | AC_LINK_IFELSE([AC_LANG_CALL([], [readline])], [ax_cv_lib_readline="$TRY_LIB"]) 77 | if test -n "$ax_cv_lib_readline"; then 78 | break 79 | fi 80 | done 81 | if test -n "$ax_cv_lib_readline"; then 82 | break 83 | fi 84 | done 85 | if test -z "$ax_cv_lib_readline"; then 86 | ax_cv_lib_readline="no" 87 | fi 88 | LIBS="$ORIG_LIBS" 89 | ]) 90 | 91 | if test "$ax_cv_lib_readline" != "no"; then 92 | LIBS="$LIBS $ax_cv_lib_readline" 93 | AC_DEFINE(HAVE_LIBREADLINE, 1, 94 | [Define if you have a readline compatible library]) 95 | AC_CHECK_HEADERS(readline.h readline/readline.h) 96 | AC_CACHE_CHECK([whether readline supports history], 97 | ax_cv_lib_readline_history, [ 98 | ax_cv_lib_readline_history="no" 99 | AC_LINK_IFELSE([AC_LANG_CALL([], [add_history])], [ax_cv_lib_readline_history="yes"]) 100 | ]) 101 | if test "$ax_cv_lib_readline_history" = "yes"; then 102 | AC_DEFINE(HAVE_READLINE_HISTORY, 1, 103 | [Define if your readline library has \`add_history']) 104 | AC_CHECK_HEADERS(history.h readline/history.h) 105 | fi 106 | fi 107 | ])dnl 108 | -------------------------------------------------------------------------------- /m4/ax_require_defined.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_require_defined.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_REQUIRE_DEFINED(MACRO) 8 | # 9 | # DESCRIPTION 10 | # 11 | # AX_REQUIRE_DEFINED is a simple helper for making sure other macros have 12 | # been defined and thus are available for use. This avoids random issues 13 | # where a macro isn't expanded. Instead the configure script emits a 14 | # non-fatal: 15 | # 16 | # ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found 17 | # 18 | # It's like AC_REQUIRE except it doesn't expand the required macro. 19 | # 20 | # Here's an example: 21 | # 22 | # AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) 23 | # 24 | # LICENSE 25 | # 26 | # Copyright (c) 2014 Mike Frysinger 27 | # 28 | # Copying and distribution of this file, with or without modification, are 29 | # permitted in any medium without royalty provided the copyright notice 30 | # and this notice are preserved. This file is offered as-is, without any 31 | # warranty. 32 | 33 | #serial 2 34 | 35 | AC_DEFUN([AX_REQUIRE_DEFINED], [dnl 36 | m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) 37 | ])dnl AX_REQUIRE_DEFINED 38 | -------------------------------------------------------------------------------- /m4/ax_with_curses.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_with_curses.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_WITH_CURSES 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro checks whether a SysV or X/Open-compatible Curses library is 12 | # present, along with the associated header file. The NcursesW 13 | # (wide-character) library is searched for first, followed by Ncurses, 14 | # then the system-default plain Curses. The first library found is the 15 | # one returned. Finding libraries will first be attempted by using 16 | # pkg-config, and should the pkg-config files not be available, will 17 | # fallback to combinations of known flags itself. 18 | # 19 | # The following options are understood: --with-ncursesw, --with-ncurses, 20 | # --without-ncursesw, --without-ncurses. The "--with" options force the 21 | # macro to use that particular library, terminating with an error if not 22 | # found. The "--without" options simply skip the check for that library. 23 | # The effect on the search pattern is: 24 | # 25 | # (no options) - NcursesW, Ncurses, Curses 26 | # --with-ncurses --with-ncursesw - NcursesW only [*] 27 | # --without-ncurses --with-ncursesw - NcursesW only [*] 28 | # --with-ncursesw - NcursesW only [*] 29 | # --with-ncurses --without-ncursesw - Ncurses only [*] 30 | # --with-ncurses - NcursesW, Ncurses [**] 31 | # --without-ncurses --without-ncursesw - Curses only 32 | # --without-ncursesw - Ncurses, Curses 33 | # --without-ncurses - NcursesW, Curses 34 | # 35 | # [*] If the library is not found, abort the configure script. 36 | # 37 | # [**] If the second library (Ncurses) is not found, abort configure. 38 | # 39 | # The following preprocessor symbols may be defined by this macro if the 40 | # appropriate conditions are met: 41 | # 42 | # HAVE_CURSES - if any SysV or X/Open Curses library found 43 | # HAVE_CURSES_ENHANCED - if library supports X/Open Enhanced functions 44 | # HAVE_CURSES_COLOR - if library supports color (enhanced functions) 45 | # HAVE_CURSES_OBSOLETE - if library supports certain obsolete features 46 | # HAVE_NCURSESW - if NcursesW (wide char) library is to be used 47 | # HAVE_NCURSES - if the Ncurses library is to be used 48 | # 49 | # HAVE_CURSES_H - if is present and should be used 50 | # HAVE_NCURSESW_H - if should be used 51 | # HAVE_NCURSES_H - if should be used 52 | # HAVE_NCURSESW_CURSES_H - if should be used 53 | # HAVE_NCURSES_CURSES_H - if should be used 54 | # 55 | # (These preprocessor symbols are discussed later in this document.) 56 | # 57 | # The following output variables are defined by this macro; they are 58 | # precious and may be overridden on the ./configure command line: 59 | # 60 | # CURSES_LIBS - library to add to xxx_LDADD 61 | # CURSES_CFLAGS - include paths to add to xxx_CPPFLAGS 62 | # 63 | # In previous versions of this macro, the flags CURSES_LIB and 64 | # CURSES_CPPFLAGS were defined. These have been renamed, in keeping with 65 | # AX_WITH_CURSES's close bigger brother, PKG_CHECK_MODULES, which should 66 | # eventually supersede the use of AX_WITH_CURSES. Neither the library 67 | # listed in CURSES_LIBS, nor the flags in CURSES_CFLAGS are added to LIBS, 68 | # respectively CPPFLAGS, by default. You need to add both to the 69 | # appropriate xxx_LDADD/xxx_CPPFLAGS line in your Makefile.am. For 70 | # example: 71 | # 72 | # prog_LDADD = @CURSES_LIBS@ 73 | # prog_CPPFLAGS = @CURSES_CFLAGS@ 74 | # 75 | # If CURSES_LIBS is set on the configure command line (such as by running 76 | # "./configure CURSES_LIBS=-lmycurses"), then the only header searched for 77 | # is . If the user needs to specify an alternative path for a 78 | # library (such as for a non-standard NcurseW), the user should use the 79 | # LDFLAGS variable. 80 | # 81 | # The following shell variables may be defined by this macro: 82 | # 83 | # ax_cv_curses - set to "yes" if any Curses library found 84 | # ax_cv_curses_enhanced - set to "yes" if Enhanced functions present 85 | # ax_cv_curses_color - set to "yes" if color functions present 86 | # ax_cv_curses_obsolete - set to "yes" if obsolete features present 87 | # 88 | # ax_cv_ncursesw - set to "yes" if NcursesW library found 89 | # ax_cv_ncurses - set to "yes" if Ncurses library found 90 | # ax_cv_plaincurses - set to "yes" if plain Curses library found 91 | # ax_cv_curses_which - set to "ncursesw", "ncurses", "plaincurses" or "no" 92 | # 93 | # These variables can be used in your configure.ac to determine the level 94 | # of support you need from the Curses library. For example, if you must 95 | # have either Ncurses or NcursesW, you could include: 96 | # 97 | # AX_WITH_CURSES 98 | # if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then 99 | # AC_MSG_ERROR([requires either NcursesW or Ncurses library]) 100 | # fi 101 | # 102 | # If any Curses library will do (but one must be present and must support 103 | # color), you could use: 104 | # 105 | # AX_WITH_CURSES 106 | # if test "x$ax_cv_curses" != xyes || test "x$ax_cv_curses_color" != xyes; then 107 | # AC_MSG_ERROR([requires an X/Open-compatible Curses library with color]) 108 | # fi 109 | # 110 | # Certain preprocessor symbols and shell variables defined by this macro 111 | # can be used to determine various features of the Curses library. In 112 | # particular, HAVE_CURSES and ax_cv_curses are defined if the Curses 113 | # library found conforms to the traditional SysV and/or X/Open Base Curses 114 | # definition. Any working Curses library conforms to this level. 115 | # 116 | # HAVE_CURSES_ENHANCED and ax_cv_curses_enhanced are defined if the 117 | # library supports the X/Open Enhanced Curses definition. In particular, 118 | # the wide-character types attr_t, cchar_t and wint_t, the functions 119 | # wattr_set() and wget_wch() and the macros WA_NORMAL and _XOPEN_CURSES 120 | # are checked. The Ncurses library does NOT conform to this definition, 121 | # although NcursesW does. 122 | # 123 | # HAVE_CURSES_COLOR and ax_cv_curses_color are defined if the library 124 | # supports color functions and macros such as COLOR_PAIR, A_COLOR, 125 | # COLOR_WHITE, COLOR_RED and init_pair(). These are NOT part of the 126 | # X/Open Base Curses definition, but are part of the Enhanced set of 127 | # functions. The Ncurses library DOES support these functions, as does 128 | # NcursesW. 129 | # 130 | # HAVE_CURSES_OBSOLETE and ax_cv_curses_obsolete are defined if the 131 | # library supports certain features present in SysV and BSD Curses but not 132 | # defined in the X/Open definition. In particular, the functions 133 | # getattrs(), getcurx() and getmaxx() are checked. 134 | # 135 | # To use the HAVE_xxx_H preprocessor symbols, insert the following into 136 | # your system.h (or equivalent) header file: 137 | # 138 | # #if defined HAVE_NCURSESW_CURSES_H 139 | # # include 140 | # #elif defined HAVE_NCURSESW_H 141 | # # include 142 | # #elif defined HAVE_NCURSES_CURSES_H 143 | # # include 144 | # #elif defined HAVE_NCURSES_H 145 | # # include 146 | # #elif defined HAVE_CURSES_H 147 | # # include 148 | # #else 149 | # # error "SysV or X/Open-compatible Curses header file required" 150 | # #endif 151 | # 152 | # For previous users of this macro: you should not need to change anything 153 | # in your configure.ac or Makefile.am, as the previous (serial 10) 154 | # semantics are still valid. However, you should update your system.h (or 155 | # equivalent) header file to the fragment shown above. You are encouraged 156 | # also to make use of the extended functionality provided by this version 157 | # of AX_WITH_CURSES, as well as in the additional macros 158 | # AX_WITH_CURSES_PANEL, AX_WITH_CURSES_MENU and AX_WITH_CURSES_FORM. 159 | # 160 | # LICENSE 161 | # 162 | # Copyright (c) 2009 Mark Pulford 163 | # Copyright (c) 2009 Damian Pietras 164 | # Copyright (c) 2012 Reuben Thomas 165 | # Copyright (c) 2011 John Zaitseff 166 | # 167 | # This program is free software: you can redistribute it and/or modify it 168 | # under the terms of the GNU General Public License as published by the 169 | # Free Software Foundation, either version 3 of the License, or (at your 170 | # option) any later version. 171 | # 172 | # This program is distributed in the hope that it will be useful, but 173 | # WITHOUT ANY WARRANTY; without even the implied warranty of 174 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 175 | # Public License for more details. 176 | # 177 | # You should have received a copy of the GNU General Public License along 178 | # with this program. If not, see . 179 | # 180 | # As a special exception, the respective Autoconf Macro's copyright owner 181 | # gives unlimited permission to copy, distribute and modify the configure 182 | # scripts that are the output of Autoconf when processing the Macro. You 183 | # need not follow the terms of the GNU General Public License when using 184 | # or distributing such scripts, even though portions of the text of the 185 | # Macro appear in them. The GNU General Public License (GPL) does govern 186 | # all other use of the material that constitutes the Autoconf Macro. 187 | # 188 | # This special exception to the GPL applies to versions of the Autoconf 189 | # Macro released by the Autoconf Archive. When you make and distribute a 190 | # modified version of the Autoconf Macro, you may extend this special 191 | # exception to the GPL to apply to your modified version as well. 192 | 193 | #serial 18 194 | 195 | # internal function to factorize common code that is used by both ncurses 196 | # and ncursesw 197 | AC_DEFUN([_FIND_CURSES_FLAGS], [ 198 | AC_MSG_CHECKING([for $1 via pkg-config]) 199 | 200 | AX_REQUIRE_DEFINED([PKG_CHECK_EXISTS]) 201 | _PKG_CONFIG([_ax_cv_$1_libs], [libs], [$1]) 202 | _PKG_CONFIG([_ax_cv_$1_cppflags], [cflags], [$1]) 203 | 204 | AS_IF([test "x$pkg_failed" = "xyes" || test "x$pkg_failed" = "xuntried"],[ 205 | AC_MSG_RESULT([no]) 206 | # No suitable .pc file found, have to find flags via fallback 207 | AC_CACHE_CHECK([for $1 via fallback], [ax_cv_$1], [ 208 | AS_ECHO() 209 | pkg_cv__ax_cv_$1_libs="-l$1" 210 | pkg_cv__ax_cv_$1_cppflags="-D_GNU_SOURCE $CURSES_CFLAGS" 211 | LIBS="$ax_saved_LIBS $pkg_cv__ax_cv_$1_libs" 212 | CPPFLAGS="$ax_saved_CPPFLAGS $pkg_cv__ax_cv_$1_cppflags" 213 | 214 | AC_MSG_CHECKING([for initscr() with $pkg_cv__ax_cv_$1_libs]) 215 | AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])], 216 | [ 217 | AC_MSG_RESULT([yes]) 218 | AC_MSG_CHECKING([for nodelay() with $pkg_cv__ax_cv_$1_libs]) 219 | AC_LINK_IFELSE([AC_LANG_CALL([], [nodelay])],[ 220 | ax_cv_$1=yes 221 | ],[ 222 | AC_MSG_RESULT([no]) 223 | m4_if( 224 | [$1],[ncursesw],[pkg_cv__ax_cv_$1_libs="$pkg_cv__ax_cv_$1_libs -ltinfow"], 225 | [$1],[ncurses],[pkg_cv__ax_cv_$1_libs="$pkg_cv__ax_cv_$1_libs -ltinfo"] 226 | ) 227 | LIBS="$ax_saved_LIBS $pkg_cv__ax_cv_$1_libs" 228 | 229 | AC_MSG_CHECKING([for nodelay() with $pkg_cv__ax_cv_$1_libs]) 230 | AC_LINK_IFELSE([AC_LANG_CALL([], [nodelay])],[ 231 | ax_cv_$1=yes 232 | ],[ 233 | ax_cv_$1=no 234 | ]) 235 | ]) 236 | ],[ 237 | ax_cv_$1=no 238 | ]) 239 | ]) 240 | ],[ 241 | AC_MSG_RESULT([yes]) 242 | # Found .pc file, using its information 243 | LIBS="$ax_saved_LIBS $pkg_cv__ax_cv_$1_libs" 244 | CPPFLAGS="$ax_saved_CPPFLAGS $pkg_cv__ax_cv_$1_cppflags" 245 | ax_cv_$1=yes 246 | ]) 247 | ]) 248 | 249 | AU_ALIAS([MP_WITH_CURSES], [AX_WITH_CURSES]) 250 | AC_DEFUN([AX_WITH_CURSES], [ 251 | AC_ARG_VAR([CURSES_LIBS], [linker library for Curses, e.g. -lcurses]) 252 | AC_ARG_VAR([CURSES_CFLAGS], [preprocessor flags for Curses, e.g. -I/usr/include/ncursesw]) 253 | AC_ARG_WITH([ncurses], [AS_HELP_STRING([--with-ncurses], 254 | [force the use of Ncurses or NcursesW])], 255 | [], [with_ncurses=check]) 256 | AC_ARG_WITH([ncursesw], [AS_HELP_STRING([--without-ncursesw], 257 | [do not use NcursesW (wide character support)])], 258 | [], [with_ncursesw=check]) 259 | 260 | ax_saved_LIBS=$LIBS 261 | ax_saved_CPPFLAGS=$CPPFLAGS 262 | 263 | AS_IF([test "x$with_ncurses" = xyes || test "x$with_ncursesw" = xyes], 264 | [ax_with_plaincurses=no], [ax_with_plaincurses=check]) 265 | 266 | ax_cv_curses_which=no 267 | 268 | # Test for NcursesW 269 | AS_IF([test "x$CURSES_LIBS" = x && test "x$with_ncursesw" != xno], [ 270 | _FIND_CURSES_FLAGS([ncursesw]) 271 | 272 | AS_IF([test "x$ax_cv_ncursesw" = xno && test "x$with_ncursesw" = xyes], [ 273 | AC_MSG_ERROR([--with-ncursesw specified but could not find NcursesW library]) 274 | ]) 275 | 276 | AS_IF([test "x$ax_cv_ncursesw" = xyes], [ 277 | ax_cv_curses=yes 278 | ax_cv_curses_which=ncursesw 279 | CURSES_LIBS="$pkg_cv__ax_cv_ncursesw_libs" 280 | CURSES_CFLAGS="$pkg_cv__ax_cv_ncursesw_cppflags" 281 | AC_DEFINE([HAVE_NCURSESW], [1], [Define to 1 if the NcursesW library is present]) 282 | AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present]) 283 | 284 | AC_CACHE_CHECK([for working ncursesw/curses.h], [ax_cv_header_ncursesw_curses_h], [ 285 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 286 | @%:@define _XOPEN_SOURCE_EXTENDED 1 287 | @%:@include 288 | ]], [[ 289 | chtype a = A_BOLD; 290 | int b = KEY_LEFT; 291 | chtype c = COLOR_PAIR(1) & A_COLOR; 292 | attr_t d = WA_NORMAL; 293 | cchar_t e; 294 | wint_t f; 295 | int g = getattrs(stdscr); 296 | int h = getcurx(stdscr) + getmaxx(stdscr); 297 | initscr(); 298 | init_pair(1, COLOR_WHITE, COLOR_RED); 299 | wattr_set(stdscr, d, 0, NULL); 300 | wget_wch(stdscr, &f); 301 | ]])], 302 | [ax_cv_header_ncursesw_curses_h=yes], 303 | [ax_cv_header_ncursesw_curses_h=no]) 304 | ]) 305 | AS_IF([test "x$ax_cv_header_ncursesw_curses_h" = xyes], [ 306 | ax_cv_curses_enhanced=yes 307 | ax_cv_curses_color=yes 308 | ax_cv_curses_obsolete=yes 309 | AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions]) 310 | AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) 311 | AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) 312 | AC_DEFINE([HAVE_NCURSESW_CURSES_H], [1], [Define to 1 if is present]) 313 | ]) 314 | 315 | AC_CACHE_CHECK([for working ncursesw.h], [ax_cv_header_ncursesw_h], [ 316 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 317 | @%:@define _XOPEN_SOURCE_EXTENDED 1 318 | @%:@include 319 | ]], [[ 320 | chtype a = A_BOLD; 321 | int b = KEY_LEFT; 322 | chtype c = COLOR_PAIR(1) & A_COLOR; 323 | attr_t d = WA_NORMAL; 324 | cchar_t e; 325 | wint_t f; 326 | int g = getattrs(stdscr); 327 | int h = getcurx(stdscr) + getmaxx(stdscr); 328 | initscr(); 329 | init_pair(1, COLOR_WHITE, COLOR_RED); 330 | wattr_set(stdscr, d, 0, NULL); 331 | wget_wch(stdscr, &f); 332 | ]])], 333 | [ax_cv_header_ncursesw_h=yes], 334 | [ax_cv_header_ncursesw_h=no]) 335 | ]) 336 | AS_IF([test "x$ax_cv_header_ncursesw_h" = xyes], [ 337 | ax_cv_curses_enhanced=yes 338 | ax_cv_curses_color=yes 339 | ax_cv_curses_obsolete=yes 340 | AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions]) 341 | AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) 342 | AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) 343 | AC_DEFINE([HAVE_NCURSESW_H], [1], [Define to 1 if is present]) 344 | ]) 345 | 346 | AC_CACHE_CHECK([for working ncurses.h], [ax_cv_header_ncurses_h_with_ncursesw], [ 347 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 348 | @%:@define _XOPEN_SOURCE_EXTENDED 1 349 | @%:@include 350 | ]], [[ 351 | chtype a = A_BOLD; 352 | int b = KEY_LEFT; 353 | chtype c = COLOR_PAIR(1) & A_COLOR; 354 | attr_t d = WA_NORMAL; 355 | cchar_t e; 356 | wint_t f; 357 | int g = getattrs(stdscr); 358 | int h = getcurx(stdscr) + getmaxx(stdscr); 359 | initscr(); 360 | init_pair(1, COLOR_WHITE, COLOR_RED); 361 | wattr_set(stdscr, d, 0, NULL); 362 | wget_wch(stdscr, &f); 363 | ]])], 364 | [ax_cv_header_ncurses_h_with_ncursesw=yes], 365 | [ax_cv_header_ncurses_h_with_ncursesw=no]) 366 | ]) 367 | AS_IF([test "x$ax_cv_header_ncurses_h_with_ncursesw" = xyes], [ 368 | ax_cv_curses_enhanced=yes 369 | ax_cv_curses_color=yes 370 | ax_cv_curses_obsolete=yes 371 | AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions]) 372 | AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) 373 | AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) 374 | AC_DEFINE([HAVE_NCURSES_H], [1], [Define to 1 if is present]) 375 | ]) 376 | 377 | AS_IF([test "x$ax_cv_header_ncursesw_curses_h" = xno && test "x$ax_cv_header_ncursesw_h" = xno && test "x$ax_cv_header_ncurses_h_with_ncursesw" = xno], [ 378 | AC_MSG_WARN([could not find a working ncursesw/curses.h, ncursesw.h or ncurses.h]) 379 | ]) 380 | ]) 381 | ]) 382 | unset pkg_cv__ax_cv_ncursesw_libs 383 | unset pkg_cv__ax_cv_ncursesw_cppflags 384 | 385 | # Test for Ncurses 386 | AS_IF([test "x$CURSES_LIBS" = x && test "x$with_ncurses" != xno && test "x$ax_cv_curses_which" = xno], [ 387 | _FIND_CURSES_FLAGS([ncurses]) 388 | 389 | AS_IF([test "x$ax_cv_ncurses" = xno && test "x$with_ncurses" = xyes], [ 390 | AC_MSG_ERROR([--with-ncurses specified but could not find Ncurses library]) 391 | ]) 392 | 393 | AS_IF([test "x$ax_cv_ncurses" = xyes], [ 394 | ax_cv_curses=yes 395 | ax_cv_curses_which=ncurses 396 | CURSES_LIBS="$pkg_cv__ax_cv_ncurses_libs" 397 | CURSES_CFLAGS="$pkg_cv__ax_cv_ncurses_cppflags" 398 | AC_DEFINE([HAVE_NCURSES], [1], [Define to 1 if the Ncurses library is present]) 399 | AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present]) 400 | 401 | AC_CACHE_CHECK([for working ncurses/curses.h], [ax_cv_header_ncurses_curses_h], [ 402 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 403 | @%:@include 404 | ]], [[ 405 | chtype a = A_BOLD; 406 | int b = KEY_LEFT; 407 | chtype c = COLOR_PAIR(1) & A_COLOR; 408 | int g = getattrs(stdscr); 409 | int h = getcurx(stdscr) + getmaxx(stdscr); 410 | initscr(); 411 | init_pair(1, COLOR_WHITE, COLOR_RED); 412 | ]])], 413 | [ax_cv_header_ncurses_curses_h=yes], 414 | [ax_cv_header_ncurses_curses_h=no]) 415 | ]) 416 | AS_IF([test "x$ax_cv_header_ncurses_curses_h" = xyes], [ 417 | ax_cv_curses_color=yes 418 | ax_cv_curses_obsolete=yes 419 | AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) 420 | AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) 421 | AC_DEFINE([HAVE_NCURSES_CURSES_H], [1], [Define to 1 if is present]) 422 | ]) 423 | 424 | AC_CACHE_CHECK([for working ncurses.h], [ax_cv_header_ncurses_h], [ 425 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 426 | @%:@include 427 | ]], [[ 428 | chtype a = A_BOLD; 429 | int b = KEY_LEFT; 430 | chtype c = COLOR_PAIR(1) & A_COLOR; 431 | int g = getattrs(stdscr); 432 | int h = getcurx(stdscr) + getmaxx(stdscr); 433 | initscr(); 434 | init_pair(1, COLOR_WHITE, COLOR_RED); 435 | ]])], 436 | [ax_cv_header_ncurses_h=yes], 437 | [ax_cv_header_ncurses_h=no]) 438 | ]) 439 | AS_IF([test "x$ax_cv_header_ncurses_h" = xyes], [ 440 | ax_cv_curses_color=yes 441 | ax_cv_curses_obsolete=yes 442 | AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) 443 | AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) 444 | AC_DEFINE([HAVE_NCURSES_H], [1], [Define to 1 if is present]) 445 | ]) 446 | 447 | AS_IF([test "x$ax_cv_header_ncurses_curses_h" = xno && test "x$ax_cv_header_ncurses_h" = xno], [ 448 | AC_MSG_WARN([could not find a working ncurses/curses.h or ncurses.h]) 449 | ]) 450 | ]) 451 | ]) 452 | unset pkg_cv__ax_cv_ncurses_libs 453 | unset pkg_cv__ax_cv_ncurses_cppflags 454 | 455 | # Test for plain Curses (or if CURSES_LIBS was set by user) 456 | AS_IF([test "x$with_plaincurses" != xno && test "x$ax_cv_curses_which" = xno], [ 457 | AS_IF([test "x$CURSES_LIBS" != x], [ 458 | LIBS="$ax_saved_LIBS $CURSES_LIBS" 459 | ], [ 460 | LIBS="$ax_saved_LIBS -lcurses" 461 | ]) 462 | 463 | AC_CACHE_CHECK([for Curses library], [ax_cv_plaincurses], [ 464 | AC_LINK_IFELSE([AC_LANG_CALL([], [initscr])], 465 | [ax_cv_plaincurses=yes], [ax_cv_plaincurses=no]) 466 | ]) 467 | 468 | AS_IF([test "x$ax_cv_plaincurses" = xyes], [ 469 | ax_cv_curses=yes 470 | ax_cv_curses_which=plaincurses 471 | AS_IF([test "x$CURSES_LIBS" = x], [ 472 | CURSES_LIBS="-lcurses" 473 | ]) 474 | AC_DEFINE([HAVE_CURSES], [1], [Define to 1 if a SysV or X/Open compatible Curses library is present]) 475 | 476 | # Check for base conformance (and header file) 477 | 478 | AC_CACHE_CHECK([for working curses.h], [ax_cv_header_curses_h], [ 479 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 480 | @%:@include 481 | ]], [[ 482 | chtype a = A_BOLD; 483 | int b = KEY_LEFT; 484 | initscr(); 485 | ]])], 486 | [ax_cv_header_curses_h=yes], 487 | [ax_cv_header_curses_h=no]) 488 | ]) 489 | AS_IF([test "x$ax_cv_header_curses_h" = xyes], [ 490 | AC_DEFINE([HAVE_CURSES_H], [1], [Define to 1 if is present]) 491 | 492 | # Check for X/Open Enhanced conformance 493 | 494 | AC_CACHE_CHECK([for X/Open Enhanced Curses conformance], [ax_cv_plaincurses_enhanced], [ 495 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 496 | @%:@define _XOPEN_SOURCE_EXTENDED 1 497 | @%:@include 498 | @%:@ifndef _XOPEN_CURSES 499 | @%:@error "this Curses library is not enhanced" 500 | "this Curses library is not enhanced" 501 | @%:@endif 502 | ]], [[ 503 | chtype a = A_BOLD; 504 | int b = KEY_LEFT; 505 | chtype c = COLOR_PAIR(1) & A_COLOR; 506 | attr_t d = WA_NORMAL; 507 | cchar_t e; 508 | wint_t f; 509 | initscr(); 510 | init_pair(1, COLOR_WHITE, COLOR_RED); 511 | wattr_set(stdscr, d, 0, NULL); 512 | wget_wch(stdscr, &f); 513 | ]])], 514 | [ax_cv_plaincurses_enhanced=yes], 515 | [ax_cv_plaincurses_enhanced=no]) 516 | ]) 517 | AS_IF([test "x$ax_cv_plaincurses_enhanced" = xyes], [ 518 | ax_cv_curses_enhanced=yes 519 | ax_cv_curses_color=yes 520 | AC_DEFINE([HAVE_CURSES_ENHANCED], [1], [Define to 1 if library supports X/Open Enhanced functions]) 521 | AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) 522 | ]) 523 | 524 | # Check for color functions 525 | 526 | AC_CACHE_CHECK([for Curses color functions], [ax_cv_plaincurses_color], [ 527 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 528 | @%:@define _XOPEN_SOURCE_EXTENDED 1 529 | @%:@include 530 | ]], [[ 531 | chtype a = A_BOLD; 532 | int b = KEY_LEFT; 533 | chtype c = COLOR_PAIR(1) & A_COLOR; 534 | initscr(); 535 | init_pair(1, COLOR_WHITE, COLOR_RED); 536 | ]])], 537 | [ax_cv_plaincurses_color=yes], 538 | [ax_cv_plaincurses_color=no]) 539 | ]) 540 | AS_IF([test "x$ax_cv_plaincurses_color" = xyes], [ 541 | ax_cv_curses_color=yes 542 | AC_DEFINE([HAVE_CURSES_COLOR], [1], [Define to 1 if library supports color (enhanced functions)]) 543 | ]) 544 | 545 | # Check for obsolete functions 546 | 547 | AC_CACHE_CHECK([for obsolete Curses functions], [ax_cv_plaincurses_obsolete], [ 548 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 549 | @%:@include 550 | ]], [[ 551 | chtype a = A_BOLD; 552 | int b = KEY_LEFT; 553 | int g = getattrs(stdscr); 554 | int h = getcurx(stdscr) + getmaxx(stdscr); 555 | initscr(); 556 | ]])], 557 | [ax_cv_plaincurses_obsolete=yes], 558 | [ax_cv_plaincurses_obsolete=no]) 559 | ]) 560 | AS_IF([test "x$ax_cv_plaincurses_obsolete" = xyes], [ 561 | ax_cv_curses_obsolete=yes 562 | AC_DEFINE([HAVE_CURSES_OBSOLETE], [1], [Define to 1 if library supports certain obsolete features]) 563 | ]) 564 | ]) 565 | 566 | AS_IF([test "x$ax_cv_header_curses_h" = xno], [ 567 | AC_MSG_WARN([could not find a working curses.h]) 568 | ]) 569 | ]) 570 | ]) 571 | 572 | AS_IF([test "x$ax_cv_curses" != xyes], [ax_cv_curses=no]) 573 | AS_IF([test "x$ax_cv_curses_enhanced" != xyes], [ax_cv_curses_enhanced=no]) 574 | AS_IF([test "x$ax_cv_curses_color" != xyes], [ax_cv_curses_color=no]) 575 | AS_IF([test "x$ax_cv_curses_obsolete" != xyes], [ax_cv_curses_obsolete=no]) 576 | 577 | LIBS=$ax_saved_LIBS 578 | CPPFLAGS=$ax_saved_CPPFLAGS 579 | 580 | unset ax_saved_LIBS 581 | unset ax_saved_CPPFLAGS 582 | ])dnl 583 | -------------------------------------------------------------------------------- /m4/ax_with_curses_extra.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_with_curses_extra.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_WITH_CURSES_PANEL 8 | # AX_WITH_CURSES_MENU 9 | # AX_WITH_CURSES_FORM 10 | # 11 | # DESCRIPTION 12 | # 13 | # These macros try to find additional libraries that often come with 14 | # SysV-compatible Curses. In particular, the Panel, Menu and Form 15 | # libraries are searched, along with their header files. These macros 16 | # depend on AX_WITH_CURSES. 17 | # 18 | # The following preprocessor symbols may be defined by these macros: 19 | # 20 | # By AX_WITH_CURSES_PANEL: 21 | # 22 | # HAVE_PANEL - if the Panel library is present 23 | # HAVE_PANEL_H - if is present and should be used 24 | # HAVE_NCURSES_PANEL_H - if should be used 25 | # HAVE_NCURSESW_PANEL_H - if should be used 26 | # 27 | # By AX_WITH_CURSES_MENU: 28 | # 29 | # HAVE_MENU - if the Menu library is present 30 | # HAVE_MENU_H - if is present and should be used 31 | # HAVE_NCURSES_MENU_H - if should be used 32 | # HAVE_NCURSESW_MENU_H - if should be used 33 | # 34 | # By AX_WITH_CURSES_FORM: 35 | # 36 | # HAVE_FORM - if the Form library is present 37 | # HAVE_FORM_H - if is present and should be used 38 | # HAVE_NCURSES_FORM_H - if should be used 39 | # HAVE_NCURSESW_FORM_H - if should be used 40 | # 41 | # The following output variables may be defined by these macros; these are 42 | # precious and may be overridden on the ./configure command line: 43 | # 44 | # PANEL_LIBS - library to add to xxx_LDADD before CURSES_LIBS 45 | # MENU_LIBS - library to add to xxx_LDADD before CURSES_LIBS 46 | # FORM_LIBS - library to add to xxx_LDADD before CURSES_LIBS 47 | # 48 | # In previous versions of this macro, the flags PANEL_LIB, MENU_LIB and 49 | # FORM_LIB were defined. These have been renamed, in keeping with the 50 | # variable scheme of PKG_CHECK_MODULES, which should eventually supersede 51 | # the use of AX_WITH_CURSES and AX_WITH_CURSES_* macros. These libraries 52 | # are NOT added to LIBS by default. You need to add them to the 53 | # appropriate xxx_LDADD line in your Makefile.am in front of the 54 | # equivalent CURSES_LIBS incantation. For example: 55 | # 56 | # prog_LDADD = @PANEL_LIBS@ @CURSES_LIBS@ 57 | # 58 | # If one of the xxx_LIBS variables is set on the configure command line 59 | # (such as by running "./configure PANEL_LIBS=-lmypanel"), then the header 60 | # file searched must NOT contain a subpath. In this case, in other words, 61 | # only would be searched for. The user may use the CPPFLAGS 62 | # precious variable to override the standard #include search path. 63 | # 64 | # The following shell variables may be defined by these macros: 65 | # 66 | # ax_cv_panel - set to "yes" if Panels library is present 67 | # ax_cv_menu - set to "yes" if Menu library is present 68 | # ax_cv_form - set to "yes" if Form library is present 69 | # 70 | # These variables can be used in your configure.ac to determine whether a 71 | # library you require is actually present. For example: 72 | # 73 | # AX_WITH_CURSES 74 | # if test "x$ax_cv_curses" != xyes; then 75 | # AC_MSG_ERROR([requires a SysV or X/Open-compatible Curses library]) 76 | # fi 77 | # AX_WITH_CURSES_PANEL 78 | # if test "x$ax_cv_panel" != xyes; then 79 | # AC_MSG_ERROR([requires the Curses Panel library]) 80 | # fi 81 | # 82 | # To use the HAVE_xxx_H preprocessor symbols, insert the following into 83 | # your system.h (or equivalent) header file: 84 | # 85 | # For AX_WITH_CURSES_PANEL: 86 | # 87 | # #if defined HAVE_NCURSESW_PANEL_H 88 | # # include 89 | # #elif defined HAVE_NCURSES_PANEL_H 90 | # # include 91 | # #elif defined HAVE_PANEL_H 92 | # # include 93 | # #else 94 | # # error "SysV-compatible Curses Panel header file required" 95 | # #endif 96 | # 97 | # For AX_WITH_CURSES_MENU: 98 | # 99 | # #if defined HAVE_NCURSESW_MENU_H 100 | # # include 101 | # #elif defined HAVE_NCURSES_MENU_H 102 | # # include 103 | # #elif defined HAVE_MENU_H 104 | # # include 105 | # #else 106 | # # error "SysV-compatible Curses Menu header file required" 107 | # #endif 108 | # 109 | # For AX_WITH_CURSES_FORM: 110 | # 111 | # #if defined HAVE_NCURSESW_FORM_H 112 | # # include 113 | # #elif defined HAVE_NCURSES_FORM_H 114 | # # include 115 | # #elif defined HAVE_FORM_H 116 | # # include 117 | # #else 118 | # # error "SysV-compatible Curses Form header file required" 119 | # #endif 120 | # 121 | # LICENSE 122 | # 123 | # Copyright (c) 2011 John Zaitseff 124 | # 125 | # This program is free software: you can redistribute it and/or modify it 126 | # under the terms of the GNU General Public License as published by the 127 | # Free Software Foundation, either version 3 of the License, or (at your 128 | # option) any later version. 129 | # 130 | # This program is distributed in the hope that it will be useful, but 131 | # WITHOUT ANY WARRANTY; without even the implied warranty of 132 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 133 | # Public License for more details. 134 | # 135 | # You should have received a copy of the GNU General Public License along 136 | # with this program. If not, see . 137 | # 138 | # As a special exception, the respective Autoconf Macro's copyright owner 139 | # gives unlimited permission to copy, distribute and modify the configure 140 | # scripts that are the output of Autoconf when processing the Macro. You 141 | # need not follow the terms of the GNU General Public License when using 142 | # or distributing such scripts, even though portions of the text of the 143 | # Macro appear in them. The GNU General Public License (GPL) does govern 144 | # all other use of the material that constitutes the Autoconf Macro. 145 | # 146 | # This special exception to the GPL applies to versions of the Autoconf 147 | # Macro released by the Autoconf Archive. When you make and distribute a 148 | # modified version of the Autoconf Macro, you may extend this special 149 | # exception to the GPL to apply to your modified version as well. 150 | 151 | #serial 5 152 | 153 | AC_DEFUN([_AX_WITH_CURSES_CHECKEXTRA], [ 154 | dnl Parameter 1 is the variable name component, using uppercase letters only 155 | dnl Parameter 2 is the printable library name 156 | dnl Parameter 3 is the C code to try compiling and linking 157 | dnl Parameter 4 is the header filename 158 | dnl Parameter 5 is the library command line 159 | 160 | AS_VAR_PUSHDEF([_AX_WITH_CURSES_CHECKEXTRA_have_var], [HAVE_$1])dnl 161 | AS_VAR_PUSHDEF([_AX_WITH_CURSES_CHECKEXTRA_cv_var], [ax_cv_[]m4_tolower($1)])dnl 162 | AS_VAR_PUSHDEF([_AX_WITH_CURSES_CHECKEXTRA_header_var], [ax_cv_header_$4])dnl 163 | AS_VAR_PUSHDEF([_AX_WITH_CURSES_CHECKEXTRA_have_header_var], [HAVE_[]m4_toupper($4)])dnl 164 | 165 | ax_saved_LIBS=$LIBS 166 | ax_saved_CPPFLAGS=$CPPFLAGS 167 | 168 | AC_CACHE_CHECK([for Curses $2 library with $4], [_AX_WITH_CURSES_CHECKEXTRA_header_var], [ 169 | LIBS="$ax_saved_LIBS $5 $CURSES_LIBS" 170 | CPPFLAGS="$ax_saved_CPPFLAGS $CURSES_CFLAGS" 171 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[ 172 | @%:@include <$4> 173 | ]], [$3])], 174 | [_AX_WITH_CURSES_CHECKEXTRA_header_var=yes], 175 | [_AX_WITH_CURSES_CHECKEXTRA_header_var=no]) 176 | ]) 177 | AS_IF([test "x$[]_AX_WITH_CURSES_CHECKEXTRA_header_var" = xyes], [ 178 | _AX_WITH_CURSES_CHECKEXTRA_cv_var=yes 179 | AS_LITERAL_IF([$5], [$1_LIBS="$5"]) 180 | AC_DEFINE([_AX_WITH_CURSES_CHECKEXTRA_have_var], [1], [Define to 1 if the Curses $2 library is present]) 181 | AC_DEFINE([_AX_WITH_CURSES_CHECKEXTRA_have_header_var], [1], [Define to 1 if <$4> is present]) 182 | ], [ 183 | AS_IF([test "x$[]_AX_WITH_CURSES_CHECKEXTRA_cv_var" = xyes], [], 184 | [_AX_WITH_CURSES_CHECKEXTRA_cv_var=no]) 185 | ]) 186 | 187 | LIBS=$ax_saved_LIBS 188 | CPPFLAGS=$ax_saved_CPPFLAGS 189 | unset ax_saved_LIBS 190 | unset ax_saved_CPPFLAGS 191 | 192 | AS_VAR_POPDEF([_AX_WITH_CURSES_CHECKEXTRA_have_header_var])dnl 193 | AS_VAR_POPDEF([_AX_WITH_CURSES_CHECKEXTRA_header_var])dnl 194 | AS_VAR_POPDEF([_AX_WITH_CURSES_CHECKEXTRA_cv_var])dnl 195 | AS_VAR_POPDEF([_AX_WITH_CURSES_CHECKEXTRA_have_var])dnl 196 | ])dnl 197 | 198 | AC_DEFUN([_AX_WITH_CURSES_EXTRA], [ 199 | dnl Parameter 1 is the variable name component, using uppercase letters only 200 | dnl Parameter 2 is the printable library name 201 | dnl Parameter 3 is the C code to try compiling and linking 202 | dnl Parameter 4 is the header filename component 203 | dnl Parameter 5 is the NCursesW library command line 204 | dnl Parameter 6 is the NCurses library command line 205 | dnl Parameter 7 is the plain Curses library command line 206 | 207 | AC_REQUIRE([AX_WITH_CURSES]) 208 | AC_ARG_VAR([$1_LIBS], [linker library for Curses $2, e.g. $7]) 209 | 210 | AS_IF([test "x$[]$1_LIBS" != x], [ 211 | _AX_WITH_CURSES_CHECKEXTRA([$1], [$2], [$3], [$4], [$[]$1_LIBS]) 212 | ], [ 213 | AS_IF([test "x$ax_cv_curses_which" = xncursesw], [ 214 | _AX_WITH_CURSES_CHECKEXTRA([$1], [$2], [$3], [ncursesw/$4], [$5]) 215 | ], [test "x$ax_cv_curses_which" = xncurses], [ 216 | _AX_WITH_CURSES_CHECKEXTRA([$1], [$2], [$3], [$4], [$6]) 217 | AS_IF([test x$[]ax_cv_[]m4_tolower($1) != "xyes"], [ 218 | _AX_WITH_CURSES_CHECKEXTRA([$1], [$2], [$3], [ncurses/$4], [$6]) 219 | ]) 220 | ], [test "x$ax_cv_curses_which" = xplaincurses], [ 221 | _AX_WITH_CURSES_CHECKEXTRA([$1], [$2], [$3], [$4], [$7]) 222 | ]) 223 | ]) 224 | ])dnl 225 | 226 | AC_DEFUN([AX_WITH_CURSES_PANEL], [ 227 | _AX_WITH_CURSES_EXTRA([PANEL], [Panel], [[ 228 | WINDOW *win = newwin(0, 0, 0, 0); 229 | PANEL *pan = new_panel(win); 230 | ]], [panel.h], [-lpanelw], [-lpanel], [-lpanel]) 231 | ])dnl 232 | 233 | AC_DEFUN([AX_WITH_CURSES_MENU], [ 234 | _AX_WITH_CURSES_EXTRA([MENU], [Menu], [[ 235 | ITEM **mi; 236 | MENU *m = new_menu(mi); 237 | ]], [menu.h], [-lmenuw], [-lmenu], [-lmenu]) 238 | ])dnl 239 | 240 | AC_DEFUN([AX_WITH_CURSES_FORM], [ 241 | _AX_WITH_CURSES_EXTRA([FORM], [Form], [[ 242 | FIELD **ff; 243 | FORM *f = new_form(ff); 244 | ]], [form.h], [-lformw], [-lform], [-lform]) 245 | ])dnl 246 | -------------------------------------------------------------------------------- /resources/bitwise.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mellowcandle/bitwise/0a4e7d93b3e922e2293251fdbfd0e4fb1cc7910b/resources/bitwise.gif -------------------------------------------------------------------------------- /resources/bitwise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mellowcandle/bitwise/0a4e7d93b3e922e2293251fdbfd0e4fb1cc7910b/resources/bitwise.png -------------------------------------------------------------------------------- /resources/bitwise.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | 13 | 16 | 19 | 23 | 27 | 31 | 35 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /resources/cmdline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mellowcandle/bitwise/0a4e7d93b3e922e2293251fdbfd0e4fb1cc7910b/resources/cmdline.png -------------------------------------------------------------------------------- /resources/conversion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mellowcandle/bitwise/0a4e7d93b3e922e2293251fdbfd0e4fb1cc7910b/resources/conversion.png -------------------------------------------------------------------------------- /resources/snip.txt: -------------------------------------------------------------------------------- 1 | scrot -a 1,50,1000,160 2 | -------------------------------------------------------------------------------- /snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: bitwise 2 | version: "v0.41" 3 | summary: Terminal based bitwise calculator in curses 4 | description: | 5 | Interactively manipulate bits. 6 | 7 | confinement: strict 8 | 9 | apps: 10 | bitwise: 11 | command: bitwise 12 | 13 | parts: 14 | bitwise: 15 | plugin: autotools 16 | source: https://github.com/mellowcandle/bitwise/releases/download/v0.40/bitwise-v0.40.tar.gz 17 | build-packages: 18 | - libncurses5-dev 19 | - libreadline-dev 20 | -------------------------------------------------------------------------------- /src/cmd.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 2 | * Ramon Fried 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include "bitwise.h" 8 | #include "shunting-yard.h" 9 | 10 | #define MAX_TOKENS 4 11 | 12 | static int cmd_clear(char **argv, int argc); 13 | static int cmd_quit(char **argv, int argc); 14 | static int cmd_help(char **argv, int argc); 15 | static int cmd_set_width(char **argv, int argc); 16 | static int cmd_set_output(char **argv, int argc); 17 | 18 | struct cmd { 19 | const char *name; 20 | int min_args; 21 | int max_args; 22 | int (*func)(char **argv, int argc); 23 | }; 24 | 25 | static struct cmd cmds[] = { 26 | {"clear", 0, 0, cmd_clear}, 27 | {"c", 0, 0, cmd_clear}, 28 | {"help", 0, 0, cmd_help}, 29 | {"h", 0, 0, cmd_help}, 30 | {"quit", 0, 0, cmd_quit}, 31 | {"q", 0, 0, cmd_quit}, 32 | {"width ", 1, 1, cmd_set_width}, 33 | {"w ", 1, 1, cmd_set_width}, 34 | {"output ", 1, 1, cmd_set_output}, 35 | {"o ", 1, 1, cmd_set_output}, 36 | }; 37 | 38 | static int get_cmd(const char *cmd_name) 39 | { 40 | size_t i = 0; 41 | 42 | for (i = 0; i < ARRAY_SIZE(cmds); i++) { 43 | LOG("comparing %s to command %s\n", cmd_name, cmds[i].name); 44 | if (cmds[i].max_args == 0) { 45 | /* These commands do not have arguments, compare exact */ 46 | if (!strcmp(cmds[i].name, cmd_name)) 47 | return i; 48 | } else { 49 | /* 50 | * Commands with arguments end with a trailing space, 51 | * compare just the beginning of the command including 52 | * the space 53 | */ 54 | if (!strncmp(cmds[i].name, cmd_name, strlen(cmds[i].name))) 55 | return i; 56 | } 57 | } 58 | 59 | return -1; 60 | } 61 | 62 | void show_error(Status status) 63 | { 64 | char *message = NULL; 65 | 66 | switch (status) { 67 | case ERROR_SYNTAX: 68 | message = "Syntax error"; 69 | break; 70 | case ERROR_OPEN_PARENTHESIS: 71 | message = "Missing parenthesis"; 72 | break; 73 | case ERROR_CLOSE_PARENTHESIS: 74 | message = "Extra parenthesis"; 75 | break; 76 | case ERROR_UNRECOGNIZED: 77 | message = "Unknown character"; 78 | break; 79 | case ERROR_NO_INPUT: 80 | message = "Empty expression"; 81 | break; 82 | case ERROR_UNDEFINED_FUNCTION: 83 | message = "Unknown function"; 84 | break; 85 | case ERROR_FUNCTION_ARGUMENTS: 86 | message = "Missing function arguments"; 87 | break; 88 | case ERROR_UNDEFINED_CONSTANT: 89 | message = "Unknown constant"; 90 | break; 91 | case ERROR_WRONG_ARGUMENTS: 92 | message = "Wrong arguments"; 93 | break; 94 | case ERROR_DIVIDE_BY_ZERO: 95 | message = "Divide by zero"; 96 | break; 97 | default: 98 | message = "Unknown error"; 99 | } 100 | 101 | werase(cmd_win); 102 | mvwprintw(cmd_win, 0, 0, "%s", message); 103 | append_to_history(message, TYPE_OUTPUT_ERROR); 104 | wrefresh(cmd_win); 105 | } 106 | 107 | /* Remove trailing and leading white spaces, and NULL if all-white */ 108 | static char *trim_whitespace(char *str) 109 | { 110 | char *str_end = &str[strlen(str) - 1]; 111 | size_t i; 112 | 113 | /* Remove leding white characters */ 114 | while (isspace(str[0])) 115 | str++; 116 | 117 | /* There are only white characters */ 118 | if (str[0] == '\0') 119 | return NULL; 120 | 121 | /* There is at least one non-white character, find the last one */ 122 | while (isspace(str_end[0])) 123 | str_end--; 124 | 125 | str_end[1] = '\0'; 126 | 127 | return str; 128 | } 129 | 130 | static int parse_cmd(char *cmdline) 131 | { 132 | static char *tokens[MAX_TOKENS]; 133 | int cmd_entry; 134 | int i = 0; 135 | int rc = 0; 136 | uint64_t result; 137 | 138 | cmdline = trim_whitespace(cmdline); 139 | if (!cmdline) 140 | return 0; 141 | 142 | LOG("got command: %s\n", cmdline); 143 | 144 | /* First let's see if this is a command */ 145 | cmd_entry = get_cmd(cmdline); 146 | if (cmd_entry >= 0) { 147 | /* It looks like a command, let's tokenize this */ 148 | append_to_history(cmdline, TYPE_INPUT_COMMAND); 149 | 150 | tokens[i] = strtok(cmdline, " "); 151 | LOG("%s\n", tokens[i]); 152 | do { 153 | i++; 154 | tokens[i] = strtok(NULL, " "); 155 | LOG("%s\n", tokens[i]); 156 | } while (tokens[i] != NULL && (i) < MAX_TOKENS); 157 | 158 | LOG("Finished tokenizing %d tokens\n", i); 159 | 160 | if ((i - 1 >= cmds[cmd_entry].min_args) && 161 | (i - 1 <= cmds[cmd_entry].max_args)) 162 | rc = cmds[cmd_entry].func(&tokens[1], i - 1); 163 | else { 164 | werase(cmd_win); 165 | mvwprintw(cmd_win, 0, 0, "%s: Invalid parameter(s)", tokens[0]); 166 | wrefresh(cmd_win); 167 | LOG("Invalid parameters\n"); 168 | return -1; 169 | } 170 | if (rc) { 171 | show_error(rc); 172 | return -1; 173 | } 174 | 175 | } else { 176 | append_to_history(cmdline, TYPE_INPUT_EXPRESSION); 177 | Status status = shunting_yard(cmdline, &result); 178 | if (status != OK) { 179 | show_error(status); 180 | return -1; 181 | } else { 182 | char result_string[256]; 183 | if (result > MASK(g_width)) { 184 | result &= MASK(g_width); 185 | append_to_history("Overflow!", TYPE_OUTPUT_ERROR); 186 | } 187 | g_val = result; 188 | 189 | if (g_output == CMD_OUTPUT_ALL) { 190 | sprintf_type(result, result_string, 191 | CMD_OUTPUT_DECIMAL); 192 | append_to_history(result_string, 193 | TYPE_OUTPUT_RESULT); 194 | sprintf_type(result, result_string, 195 | CMD_OUTPUT_HEXADECIMAL); 196 | append_to_history(result_string, 197 | TYPE_OUTPUT_RESULT); 198 | sprintf_type(result, result_string, 199 | CMD_OUTPUT_OCTAL); 200 | append_to_history(result_string, 201 | TYPE_OUTPUT_RESULT); 202 | sprintf_type(result, result_string, 203 | CMD_OUTPUT_BINARY); 204 | append_to_history(result_string, 205 | TYPE_OUTPUT_RESULT); 206 | update_binary(); 207 | update_fields(-1); 208 | } else { 209 | sprintf_type(result, result_string, g_output); 210 | update_binary(); 211 | update_fields(-1); 212 | append_to_history(result_string, 213 | TYPE_OUTPUT_RESULT); 214 | } 215 | } 216 | } 217 | 218 | return 0; 219 | } 220 | 221 | static int readline_input_avail(void) 222 | { 223 | return g_input_avail; 224 | } 225 | 226 | static int readline_getc(FILE *dummy) 227 | { 228 | g_input_avail = false; 229 | return g_input; 230 | } 231 | 232 | static void got_command(char *line) 233 | { 234 | int rc; 235 | /* Handle exit commands immediately */ 236 | if (!line) { 237 | /* Handle CTL-D */ 238 | g_leave_req = true; 239 | return; 240 | } 241 | 242 | if (*line) 243 | add_history(line); 244 | 245 | rc = parse_cmd(line); 246 | free(line); 247 | 248 | if (!rc) { 249 | keypad(stdscr, FALSE); 250 | werase(cmd_win); 251 | wrefresh(cmd_win); 252 | } 253 | 254 | return; 255 | } 256 | 257 | void readline_redisplay(void) 258 | { 259 | if (active_win != COMMAND_WIN) 260 | return; 261 | 262 | werase(cmd_win); 263 | mvwprintw(cmd_win, 0, 0, "%s%s", rl_display_prompt, rl_line_buffer); 264 | wmove(cmd_win, 0, rl_point + 1); 265 | wrefresh(cmd_win); 266 | } 267 | 268 | 269 | void init_readline(void) 270 | { 271 | rl_catch_signals = 0; 272 | rl_catch_sigwinch = 0; 273 | rl_deprep_term_function = NULL; 274 | rl_prep_term_function = NULL; 275 | rl_change_environment = 0; 276 | rl_getc_function = readline_getc; 277 | rl_input_available_hook = readline_input_avail; 278 | rl_redisplay_function = readline_redisplay; 279 | //rl_bind_key('\t', rl_insert); 280 | rl_callback_handler_install(":", got_command); 281 | 282 | } 283 | 284 | void deinit_readline(void) 285 | { 286 | rl_callback_handler_remove(); 287 | } 288 | 289 | void process_cmd(int ch) 290 | { 291 | int new_char; 292 | 293 | LOG("Process cmd %u\n", ch); 294 | 295 | if (ch == 27) { 296 | nodelay(get_win(active_win), true); 297 | new_char = wgetch(get_win(active_win)); 298 | nodelay(get_win(active_win), false); 299 | 300 | if (new_char == ERR) { 301 | LOG("IT's a real escape\n"); 302 | active_win = last_win; 303 | 304 | // Re-enable mouse events 305 | mousemask(BUTTON1_CLICKED, NULL); 306 | 307 | if (active_win == FIELDS_WIN) { 308 | set_active_field(false); 309 | form_driver(form, REQ_END_LINE); 310 | form_driver(form, REQ_VALIDATION); 311 | curs_set(1); 312 | wrefresh(fields_win); 313 | } else if (active_win == BINARY_WIN) { 314 | curs_set(0); 315 | position_binary_curser(0, bit_pos); 316 | wrefresh(binary_win); 317 | } 318 | keypad(stdscr, FALSE); 319 | werase(cmd_win); 320 | wrefresh(cmd_win); 321 | return; 322 | } else 323 | ungetch(new_char); 324 | } 325 | 326 | /* If TAB || BACKSPACE (to -1) */ 327 | if (ch == 127 && !rl_point) { 328 | LOG("Detected exit cmd\n"); 329 | active_win = last_win; 330 | if (active_win == FIELDS_WIN) { 331 | set_active_field(false); 332 | form_driver(form, REQ_END_LINE); 333 | form_driver(form, REQ_VALIDATION); 334 | curs_set(1); 335 | wrefresh(fields_win); 336 | } else if (active_win == BINARY_WIN) { 337 | curs_set(0); 338 | position_binary_curser(0, bit_pos); 339 | wrefresh(binary_win); 340 | } 341 | keypad(stdscr, FALSE); 342 | werase(cmd_win); 343 | wrefresh(cmd_win); 344 | return; 345 | } 346 | 347 | g_input = ch; 348 | g_input_avail = true; 349 | rl_callback_read_char(); 350 | } 351 | 352 | static int cmd_clear(char **argv, int argc) 353 | { 354 | LOG("%s: argc %d\n", __func__, argc); 355 | flush_history(); 356 | update_history_win(); 357 | return 0; 358 | } 359 | 360 | static int cmd_quit(char **argv, int argc) 361 | { 362 | LOG("%s: argc %d\n", __func__, argc); 363 | g_leave_req = true; 364 | return 0; 365 | } 366 | 367 | static int cmd_set_width(char **argv, int argc) 368 | { 369 | LOG("%s: argc %d\n", __func__, argc); 370 | if (!strcmp("64", argv[0])) 371 | set_fields_width(64); 372 | else if (!strcmp("32", argv[0])) 373 | set_fields_width(32); 374 | else if (!strcmp("16", argv[0])) 375 | set_fields_width(16); 376 | else if (!strcmp("8", argv[0])) 377 | set_fields_width(8); 378 | else 379 | return ERROR_WRONG_ARGUMENTS; 380 | 381 | unpaint_screen(); 382 | paint_screen(); 383 | 384 | return 0; 385 | } 386 | 387 | static int cmd_set_output(char **argv, int argc) 388 | { 389 | LOG("%s: argc %d\n", __func__, argc); 390 | if (!strcmp("hexadecimal", argv[0]) || !strcmp("hex", argv[0])) 391 | g_output = CMD_OUTPUT_HEXADECIMAL; 392 | else if (!strcmp("decimal", argv[0]) || !strcmp("dec", argv[0])) 393 | g_output = CMD_OUTPUT_DECIMAL; 394 | else if (!strcmp("octal", argv[0]) || !strcmp("oct", argv[0])) 395 | g_output = CMD_OUTPUT_OCTAL; 396 | else if (!strcmp("binary", argv[0]) || !strcmp("bin", argv[0])) 397 | g_output = CMD_OUTPUT_BINARY; 398 | else if (!strcmp("all", argv[0])) 399 | g_output = CMD_OUTPUT_ALL; 400 | else 401 | return ERROR_WRONG_ARGUMENTS; 402 | 403 | return 0; 404 | } 405 | 406 | static int cmd_help(char **argv, int argc) 407 | { 408 | unpaint_screen(); 409 | curs_set(0); 410 | show_help(); 411 | curs_set(2); 412 | paint_screen(); 413 | 414 | return 0; 415 | } 416 | -------------------------------------------------------------------------------- /src/help.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 2 | * Ramon Fried 3 | */ 4 | 5 | #include "bitwise.h" 6 | 7 | static const char *help_header = PACKAGE " " VERSION; 8 | static const char *interactive_mode = "Type numbers in different bases and directly manipulate bits.\n" \ 9 | "To move around use the arrow keys, or use vi key bindings ('h|j|k|l').\n" \ 10 | "In the binary field, toggle a bit using 'SPACE'.\n" \ 11 | "You can jump a byte forward using 'w' and backwards one byte using 'b'.\n\n" \ 12 | "Additional key mapping:\n" \ 13 | "'F1' Show this help screen.\n" \ 14 | "'~' Perform logical NOT.\n" \ 15 | "'<' Perform left shift.\n" \ 16 | "'>' Perform right shift.\n\n" \ 17 | "'!' Set bit width to 8bit.\n" \ 18 | "'@' Set bit width to 16bit.\n" \ 19 | "'$' Set bit width to 32bit.\n" \ 20 | "'*' Set bit width to 64bit.\n" \ 21 | "'r' Reverse the endianness\n" \ 22 | "':' Switch to command mode.\n" \ 23 | "'q' Exit back to shell.\n"; 24 | 25 | static const char *command_mode = "Type expressions or commands, result will be appended to history window.\n" \ 26 | "Supported operators: (,),+, -, *, /, !, ~, <<_, >>_, BIT(_).\n" \ 27 | "Precedence of operators is defined as C language precedence.\n\n" \ 28 | "You can referr to the last result with '$' inside an expression.\n" \ 29 | "To return to interactive mode type 'ESC'.\n\n" \ 30 | "Supported commands:\n" \ 31 | "'help' Show this help screen.\n" \ 32 | "'clear' Clear the history window.\n" \ 33 | "'width []' Set the bit width to [8 | 16 | 32 | 64]\n" \ 34 | "'output []' Set the default output for results [decimal | hex | octal | binary | all]\n" \ 35 | "'q' Exit back to shell.\n"; 36 | 37 | void show_help(void) 38 | { 39 | WINDOW *help_win; 40 | int ch; 41 | 42 | /* Create full screen window */ 43 | help_win = newwin(0, 0, 0, 0); 44 | 45 | if (g_has_color) 46 | wattron(help_win, COLOR_PAIR(2)); 47 | mvwprintw(help_win, 0, COLS / 2 - strlen(help_header), "%s", 48 | help_header); 49 | if (g_has_color) 50 | wattroff(help_win, COLOR_PAIR(2)); 51 | 52 | wmove(help_win, 1, 0); 53 | if (g_has_color) 54 | wattron(help_win, A_UNDERLINE | COLOR_PAIR(3)); 55 | wprintw(help_win, "Interactive Mode:\n\n"); 56 | if (g_has_color) 57 | wattroff(help_win, A_UNDERLINE | COLOR_PAIR(3)); 58 | 59 | wprintw(help_win, "%s\n", interactive_mode); 60 | if (g_has_color) 61 | wattroff(help_win, A_UNDERLINE | COLOR_PAIR(1)); 62 | 63 | if (g_has_color) 64 | wattron(help_win, A_UNDERLINE | COLOR_PAIR(3)); 65 | wprintw(help_win, "Command Mode:\n\n"); 66 | if (g_has_color) 67 | wattroff(help_win, A_UNDERLINE | COLOR_PAIR(3)); 68 | wprintw(help_win, "%s", command_mode); 69 | 70 | wrefresh(help_win); 71 | refresh(); 72 | ch = wgetch(help_win); 73 | 74 | werase(help_win); 75 | wrefresh(help_win); 76 | delwin(help_win); 77 | 78 | if (ch == 'q' || ch == 'Q') 79 | g_leave_req = true; 80 | 81 | if (ch == KEY_RESIZE) { 82 | rl_resize_terminal(); 83 | show_help(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/interactive.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 2 | * Ramon Fried 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "bitwise.h" 17 | 18 | #define MAX_DEC_DIGITS_64 20 19 | #define MAX_HEX_DIGITS_64 16 20 | #define MAX_OCT_DIGITS_64 32 21 | 22 | #define MAX_DEC_DIGITS_32 10 23 | #define MAX_HEX_DIGITS_32 8 24 | #define MAX_OCT_DIGITS_32 16 25 | 26 | #define MAX_DEC_DIGITS_16 5 27 | #define MAX_HEX_DIGITS_16 4 28 | #define MAX_OCT_DIGITS_16 8 29 | 30 | #define MAX_DEC_DIGITS_8 3 31 | #define MAX_HEX_DIGITS_8 2 32 | #define MAX_OCT_DIGITS_8 4 33 | 34 | #define CLEAR_BIT 0 35 | #define SET_BIT 1 36 | #define TOGGLE_BIT 2 37 | 38 | #ifdef TRACE 39 | FILE *fd; 40 | #endif 41 | 42 | int max_dec_digits, max_hex_digits, max_oct_digits; 43 | int min_frame_size; 44 | static char title[] = "Bitwise"; 45 | static char *width_str; 46 | WINDOW *fields_win; 47 | WINDOW *binary_win; 48 | WINDOW *cmd_win; 49 | WINDOW *history_win; 50 | 51 | int active_win, last_win; 52 | int g_output = CMD_OUTPUT_HEXADECIMAL; 53 | 54 | static FIELD *field[5]; 55 | FORM *form; 56 | uint64_t g_val; 57 | int bit_pos; 58 | static int binary_field_size; 59 | 60 | static int base[3] = { 61 | 10, 62 | 16, 63 | 8, 64 | }; 65 | 66 | struct history_entry history[MAX_HISTORY_LEN] = { { 0, NULL } }; 67 | unsigned int history_pos = 0; 68 | int max_display_history; 69 | 70 | #define BINARY_WIN_LEN 17 71 | #define BYTE_BINARY_WIN_LEN (BINARY_WIN_LEN + 2) 72 | #define WORD_BINARY_WIN_LEN (BINARY_WIN_LEN * 2) + 3 73 | #define LONG_BINARY_WIN_LEN (BINARY_WIN_LEN * 4) + 5 74 | #define DBL_BINARY_WIN_LEN (BINARY_WIN_LEN * 8) + 9 75 | 76 | void flush_history(void) 77 | { 78 | int i; 79 | 80 | history_pos = 0; 81 | 82 | for (i = 0; i < MAX_HISTORY_LEN; i++) 83 | if (history[i].line) { 84 | free(history[i].line); 85 | history[i].line = NULL; 86 | } 87 | } 88 | 89 | void update_history_win(void) 90 | { 91 | unsigned int max_display = LINES - 17; 92 | int i, j; 93 | 94 | if (history_pos < max_display) 95 | max_display = history_pos; 96 | 97 | werase(history_win); 98 | box(history_win, 0, 0); 99 | 100 | for (i = max_display, j = 1; i > 0; i--, j++) { 101 | if (g_has_color) 102 | switch (history[history_pos -i].type) { 103 | case TYPE_INPUT_COMMAND: 104 | wattron(history_win, COLOR_PAIR(2)); 105 | break; 106 | case TYPE_INPUT_EXPRESSION: 107 | wattron(history_win, COLOR_PAIR(1)); 108 | break; 109 | case TYPE_OUTPUT_RESULT: 110 | wattron(history_win, COLOR_PAIR(3)); 111 | break; 112 | case TYPE_OUTPUT_ERROR: 113 | wattron(history_win, COLOR_PAIR(5)); 114 | break; 115 | } 116 | 117 | mvwprintw(history_win, j, 2, "%s", history[history_pos - i].line); 118 | } 119 | 120 | if (g_has_color) 121 | wattroff(history_win, COLOR_PAIR(1)); 122 | wrefresh(history_win); 123 | } 124 | 125 | char binary_field[DBL_BINARY_WIN_LEN]; 126 | int dec_pos, hex_pos, oct_pos; 127 | bool g_leave_req; 128 | void set_fields_width(int width) 129 | { 130 | int min_field_distance; 131 | g_width = width; 132 | switch (width) { 133 | case 64: 134 | binary_field_size = DBL_BINARY_WIN_LEN; 135 | max_dec_digits = MAX_DEC_DIGITS_64; 136 | max_hex_digits = MAX_HEX_DIGITS_64; 137 | max_oct_digits = MAX_OCT_DIGITS_64; 138 | min_field_distance = 4; 139 | width_str = " 64Bit "; 140 | break; 141 | case 32: 142 | g_val &= 0xFFFFFFFF; 143 | binary_field_size = LONG_BINARY_WIN_LEN; 144 | max_dec_digits = MAX_DEC_DIGITS_32; 145 | max_hex_digits = MAX_HEX_DIGITS_32; 146 | max_oct_digits = MAX_OCT_DIGITS_32; 147 | min_field_distance = 6; 148 | width_str = " 32Bit "; 149 | break; 150 | case 16: 151 | g_val &= 0xFFFF; 152 | binary_field_size = WORD_BINARY_WIN_LEN; 153 | max_dec_digits = MAX_DEC_DIGITS_16; 154 | max_hex_digits = MAX_HEX_DIGITS_16; 155 | max_oct_digits = MAX_OCT_DIGITS_16; 156 | min_field_distance = 8; 157 | width_str = " 16Bit "; 158 | break; 159 | case 8: 160 | g_val &= 0xFF; 161 | binary_field_size = BYTE_BINARY_WIN_LEN; 162 | max_dec_digits = MAX_DEC_DIGITS_8; 163 | max_hex_digits = MAX_HEX_DIGITS_8; 164 | max_oct_digits = MAX_OCT_DIGITS_8; 165 | min_field_distance = 10; 166 | width_str = " 8Bit "; 167 | break; 168 | } 169 | 170 | /* Reserve space for the cursor at the end */ 171 | max_dec_digits += 1; 172 | max_hex_digits += 1; 173 | max_oct_digits += 1; 174 | 175 | dec_pos = 0; 176 | hex_pos = dec_pos + max_dec_digits + min_field_distance - 2; 177 | oct_pos = hex_pos + max_hex_digits + min_field_distance + 1; 178 | } 179 | 180 | static void update_bit(int pos, int op) 181 | { 182 | if (op == SET_BIT) 183 | g_val |= BIT(g_width - 1 - pos); 184 | else if (op == CLEAR_BIT) 185 | g_val &= ~(BIT(g_width - 1 - pos)); 186 | else 187 | g_val ^= BIT(g_width - 1 - pos); 188 | LOG("g_width: %d\ng_val: %llu\n", g_width, g_val); 189 | 190 | 191 | update_binary(); 192 | } 193 | 194 | void update_binary() 195 | { 196 | int i; 197 | int pos = 0; 198 | 199 | for (i = g_width; i > 0; i--) { 200 | if ((i % 8 == 0) && (i != g_width)) { 201 | binary_field[pos] = '|'; 202 | binary_field[pos + 1] = ' '; 203 | pos += 2; 204 | } 205 | if (g_val & BIT(i - 1)) 206 | binary_field[pos] = '1'; 207 | else 208 | binary_field[pos] = '0'; 209 | binary_field[pos + 1] = ' '; 210 | pos += 2; 211 | } 212 | 213 | binary_field[pos] = '\0'; 214 | mvwprintw(binary_win, 1, 2, "%s", binary_field); 215 | 216 | pos = 6; 217 | if (g_has_color) 218 | wattron(binary_win, COLOR_PAIR(3)); 219 | for (i = 0; i < g_width / 8; i++, pos += 18) 220 | mvwprintw(binary_win, 2, pos, "%2d - %2d", 221 | (g_width - 1) - (i * 8), 222 | (g_width - 8) - (i * 8)); 223 | if (g_has_color) 224 | wattroff(binary_win, COLOR_PAIR(3)); 225 | wrefresh(binary_win); 226 | } 227 | 228 | 229 | void mouse_to_bit(int xPos){ 230 | int binaryDigitWinSize = 18; 231 | //Indicates that user is clicking a separating bar 232 | if(xPos % binaryDigitWinSize == 0){ 233 | return; 234 | } 235 | int field = floor(xPos / binaryDigitWinSize); 236 | // How many bits from the previous separating line was the click 237 | int bitFromLine = floor((xPos%binaryDigitWinSize)/2) - 1; 238 | // If they are on the first bit 239 | if (bitFromLine < 0) { 240 | bitFromLine = 0; 241 | } 242 | int relativeBit = (8 * (field)) + bitFromLine; 243 | update_bit(relativeBit, TOGGLE_BIT); 244 | update_fields(-1); 245 | } 246 | 247 | WINDOW * process_mouse(MEVENT *event) 248 | { 249 | WINDOW *mouse_window = NULL; 250 | if (wmouse_trafo(binary_win, &event->y, &event->x, FALSE) == TRUE) { 251 | mouse_window = binary_win; 252 | mouse_to_bit(event->x); 253 | } else if (wmouse_trafo(fields_win, &event->y, &event->x, FALSE) == TRUE) { 254 | mouse_window = fields_win; 255 | } 256 | 257 | return mouse_window; 258 | } 259 | 260 | 261 | int update_fields(int index) 262 | { 263 | FIELD *tmp_field = current_field(form); 264 | int *cur_base = field_userptr(tmp_field); 265 | char *buffer; 266 | char number[64]; 267 | int *base; 268 | uint64_t tmp_val; 269 | if (index != -1) { 270 | buffer = field_buffer(tmp_field, 0); 271 | assert(buffer); 272 | 273 | tmp_val = strtoull(buffer, NULL, *cur_base); 274 | if (tmp_val == LLONG_MAX) { 275 | /* 276 | * Make sure we don't get a number which is 277 | * too big to represent in 64bit */ 278 | beep(); 279 | return 1; 280 | } 281 | if (tmp_val > MASK(g_width)) { 282 | FIELD *tmp_field = current_field(form); 283 | unpaint_screen(); 284 | set_fields_width(g_width * 2); 285 | paint_screen(); 286 | set_current_field(form, tmp_field); 287 | set_active_field(false); 288 | LOG("Overflow: tmp_val = %" PRIu64 "\n", tmp_val); 289 | index = -1; 290 | } 291 | g_val = tmp_val; 292 | } 293 | LOG("Val = %" PRIu64 "\n", g_val); 294 | for (int i = 0; i < 3; i++) { 295 | base = field_userptr(field[i]); 296 | if (g_val) 297 | lltostr(g_val, number, *base); 298 | else 299 | number[0] = '\0'; 300 | LOG("updating field %d\n", i); 301 | set_field_buffer(field[i], 0, number); 302 | } 303 | form_driver(form, REQ_VALIDATION); 304 | form_driver(form, REQ_END_FIELD); 305 | wrefresh(fields_win); 306 | 307 | return 0; 308 | } 309 | 310 | void set_active_field(bool none) 311 | { 312 | if (!g_has_color) 313 | return; 314 | 315 | if (!none) { 316 | set_field_fore(current_field(form), COLOR_PAIR(1)); 317 | set_field_back(current_field(form), 318 | A_UNDERLINE | COLOR_PAIR(1)); 319 | } 320 | 321 | for (int i = 0; i < 3; i++) { 322 | if ((field[i] == current_field(form)) && (!none)) 323 | continue; 324 | set_field_fore(field[i], COLOR_PAIR(0)); 325 | set_field_back(field[i], COLOR_PAIR(0)); 326 | } 327 | } 328 | 329 | void position_binary_curser(int previous_pos, int next_pos) 330 | { 331 | 332 | int pos; 333 | 334 | pos = 2 + (2 * previous_pos) + (2 * (previous_pos / 8)); 335 | mvwchgat(binary_win, 1, pos, 1, A_NORMAL, COLOR_PAIR(0), NULL); 336 | 337 | if (next_pos != -1) { 338 | pos = 2 + (2 * next_pos) + (2 * (next_pos / 8)); 339 | mvwchgat(binary_win, 1, pos, 1, A_UNDERLINE, 340 | COLOR_PAIR(0), NULL); 341 | mvwprintw(binary_win, 3, 1, "bit %.2u\t\t", 342 | g_width - 1 - next_pos); 343 | } 344 | wrefresh(binary_win); 345 | } 346 | 347 | void process_binary(int ch) 348 | { 349 | int tmp; 350 | 351 | switch (ch) { 352 | case 'w': 353 | case 'W': 354 | LOG("word right\n"); 355 | tmp = (bit_pos + 8) & ~(8 - 1); 356 | if (tmp >= g_width - 1) { 357 | beep(); 358 | break; 359 | } 360 | position_binary_curser(bit_pos, tmp); 361 | bit_pos = tmp; 362 | break; 363 | 364 | case 'b': 365 | case 'B': 366 | LOG("word left\n"); 367 | tmp = (bit_pos - 8) & ~(8 - 1); 368 | if (tmp < 0) { 369 | beep(); 370 | break; 371 | } 372 | position_binary_curser(bit_pos, tmp); 373 | bit_pos = tmp; 374 | break; 375 | case KEY_RIGHT: 376 | case 'l': 377 | LOG("Key right\n"); 378 | if (bit_pos == g_width - 1) { 379 | beep(); 380 | break; 381 | } 382 | position_binary_curser(bit_pos, bit_pos + 1); 383 | bit_pos++; 384 | break; 385 | case KEY_LEFT: 386 | case 'h': 387 | LOG("Key left\n"); 388 | if (bit_pos == 0) { 389 | beep(); 390 | break; 391 | } 392 | position_binary_curser(bit_pos, bit_pos - 1); 393 | bit_pos--; 394 | break; 395 | case KEY_UP: 396 | case 'k': 397 | case '\t': 398 | LOG("Key up\n"); 399 | active_win = FIELDS_WIN; 400 | set_active_field(false); 401 | position_binary_curser(bit_pos, -1); 402 | form_driver(form, REQ_END_LINE); 403 | form_driver(form, REQ_VALIDATION); 404 | curs_set(1); 405 | wrefresh(fields_win); 406 | break; 407 | case KEY_BACKSPACE: 408 | case 127: 409 | LOG("Backspace\n"); 410 | if (bit_pos != 0) { 411 | bit_pos--; 412 | update_bit(bit_pos, CLEAR_BIT); 413 | update_fields(-1); 414 | } else 415 | beep(); 416 | break; 417 | default: 418 | if (ch == '1') { 419 | update_bit(bit_pos, SET_BIT); 420 | position_binary_curser(bit_pos, 421 | (bit_pos + 1) == (g_width) ? 422 | (bit_pos) : (bit_pos + 1)); 423 | update_fields(-1); 424 | if (bit_pos != g_width - 1) 425 | bit_pos++; 426 | break; 427 | } else if (ch == '0') { 428 | update_bit(bit_pos, CLEAR_BIT); 429 | position_binary_curser(bit_pos, 430 | (bit_pos + 1) == (g_width) ? 431 | (bit_pos) : (bit_pos + 1)); 432 | update_fields(-1); 433 | if (bit_pos != g_width - 1) 434 | bit_pos++; 435 | break; 436 | } else if (ch == ' ') { 437 | update_bit(bit_pos, TOGGLE_BIT); 438 | position_binary_curser(bit_pos, bit_pos); 439 | update_fields(-1); 440 | } 441 | break; 442 | } 443 | } 444 | 445 | void process_fields(int ch) 446 | { 447 | FIELD *tmp_field; 448 | int *cur_base; 449 | 450 | switch (ch) { 451 | case KEY_RIGHT: 452 | case 'l': 453 | LOG("Key right\n"); 454 | /* Go to next field */ 455 | form_driver(form, REQ_NEXT_FIELD); 456 | /* Go to the end of the present buffer */ 457 | /* Leaves nicely at the last character */ 458 | form_driver(form, REQ_END_FIELD); 459 | set_active_field(false); 460 | wrefresh(fields_win); 461 | break; 462 | case KEY_LEFT: 463 | case 'h': 464 | LOG("Key left\n"); 465 | /* Go to previous field */ 466 | form_driver(form, REQ_PREV_FIELD); 467 | form_driver(form, REQ_END_FIELD); 468 | set_active_field(false); 469 | wrefresh(fields_win); 470 | break; 471 | case KEY_DOWN: 472 | case 'j': 473 | case '\t': 474 | LOG("Key down\n"); 475 | active_win = BINARY_WIN; 476 | curs_set(0); 477 | set_active_field(true); 478 | form_driver(form, REQ_VALIDATION); 479 | position_binary_curser(0, bit_pos); 480 | wrefresh(fields_win); 481 | break; 482 | case KEY_BACKSPACE: 483 | case KEY_DC: 484 | case 127: 485 | case 8: 486 | LOG("Backspace\n"); 487 | form_driver(form, REQ_DEL_CHAR); 488 | form_driver(form, REQ_DEL_PREV); 489 | form_driver(form, REQ_VALIDATION); 490 | update_fields(field_index(current_field(form))); 491 | set_active_field(false); 492 | update_binary(); 493 | wrefresh(fields_win); 494 | break; 495 | default: 496 | LOG("default char: %d\n", ch); 497 | 498 | tmp_field = current_field(form); 499 | cur_base = field_userptr(tmp_field); 500 | 501 | if (validate_input(ch, *cur_base)) 502 | break; 503 | form_driver(form, ch); 504 | form_driver(form, REQ_VALIDATION); 505 | if (update_fields(field_index(tmp_field))) { 506 | form_driver(form, REQ_DEL_CHAR); 507 | form_driver(form, REQ_PREV_CHAR); 508 | form_driver(form, REQ_VALIDATION); 509 | } 510 | update_binary(); 511 | wrefresh(fields_win); 512 | break; 513 | } 514 | } 515 | 516 | void paint_screen(void) 517 | { 518 | int rows, cols; 519 | int rc; 520 | 521 | /* Initialize the fields */ 522 | field[0] = new_field(1, max_dec_digits, 1, 523 | dec_pos, 0, 0); 524 | 525 | field[1] = new_field(1, max_hex_digits, 1, 526 | hex_pos, 0, 0); 527 | field[2] = new_field(1, max_oct_digits, 1, 528 | oct_pos, 0, 0); 529 | field[3] = NULL; 530 | 531 | for (int i = 0; i < 3; i++) { 532 | set_field_back(field[i], A_UNDERLINE); 533 | field_opts_off(field[i], O_AUTOSKIP); 534 | set_field_userptr(field[i], &base[i]); 535 | } 536 | 537 | if (g_has_color) { 538 | init_pair(1, COLOR_BLUE, COLOR_BLACK); 539 | init_pair(2, COLOR_GREEN, COLOR_BLACK); 540 | init_pair(3, COLOR_CYAN, COLOR_BLACK); 541 | init_pair(4, COLOR_MAGENTA, COLOR_BLACK); 542 | init_pair(5, COLOR_RED, COLOR_BLACK); 543 | } 544 | 545 | form = new_form(field); 546 | if (!form) 547 | die("new form failed\n"); 548 | 549 | scale_form(form, &rows, &cols); 550 | 551 | fields_win = newwin(rows + 3, cols + 6, 2, 0); 552 | keypad(fields_win, TRUE); 553 | 554 | binary_win = newwin(5, binary_field_size, 8, 0); 555 | keypad(binary_win, TRUE); 556 | box(binary_win, 0, 0); 557 | 558 | history_win = newwin(LINES - 15, COLS, 13, 0); 559 | box(history_win, 0, 0); 560 | 561 | rc = set_form_win(form, fields_win); 562 | if (rc != E_OK) 563 | die("set_form_win failed\n"); 564 | 565 | rc = set_form_sub(form, derwin(fields_win, rows, cols, 2, 2)); 566 | if (rc != E_OK) 567 | die("set_form_sub failed\n"); 568 | 569 | set_current_field(form, field[0]); 570 | set_active_field(false); 571 | 572 | mvprintw(0, (COLS - strlen(title)) / 2, "%s", title); 573 | box(fields_win, 0, 0); 574 | mvwprintw(fields_win, 0, (cols + 6 - strlen(width_str)) / 2, "%s", 575 | width_str); 576 | if (g_has_color) 577 | wattron(fields_win, COLOR_PAIR(2)); 578 | mvwprintw(fields_win, 1, dec_pos + 2, "Decimal:"); 579 | mvwprintw(fields_win, 1, hex_pos + 2, "Hexdecimal:"); 580 | mvwprintw(fields_win, 1, oct_pos + 2, "Octal:"); 581 | if (g_has_color) 582 | wattroff(binary_win, COLOR_PAIR(2)); 583 | 584 | cmd_win = newwin(1, COLS, LINES - 1, 0); 585 | 586 | wrefresh(fields_win); 587 | update_binary(); 588 | update_history_win(); 589 | 590 | wrefresh(cmd_win); 591 | refresh(); 592 | 593 | rc = post_form(form); 594 | if (rc != E_OK) 595 | die("post_form failed: %d\n", rc); 596 | 597 | update_fields(-1); 598 | } 599 | 600 | void unpaint_screen(void) 601 | { 602 | int i; 603 | 604 | unpost_form(form); 605 | free_form(form); 606 | for (i = 0; i < 3; i++) 607 | free_field(field[i]); 608 | delwin(fields_win); 609 | delwin(binary_win); 610 | delwin(history_win); 611 | delwin(cmd_win); 612 | clear(); 613 | refresh(); 614 | } 615 | 616 | int start_interactive(uint64_t start) 617 | { 618 | int ch; 619 | uint64_t tmp_val; 620 | MEVENT event; 621 | 622 | g_val = start; 623 | 624 | init_terminal(); 625 | init_readline(); 626 | mousemask(BUTTON1_CLICKED, NULL); 627 | 628 | refresh(); 629 | 630 | set_fields_width(g_width); 631 | 632 | paint_screen(); 633 | last_win = active_win = FIELDS_WIN; 634 | 635 | while (true) { 636 | if (g_leave_req) 637 | break; 638 | 639 | ch = wgetch(get_win(active_win)); 640 | LOG("%d window ch= %d\n", active_win, ch); 641 | 642 | if (active_win == COMMAND_WIN) { 643 | process_cmd(ch); 644 | continue; 645 | } 646 | 647 | switch (ch) { 648 | case KEY_MOUSE: 649 | if(getmouse(&event) == OK){ 650 | process_mouse(&event); 651 | } 652 | break; 653 | 654 | case KEY_F(1): 655 | unpaint_screen(); 656 | show_help(); 657 | paint_screen(); 658 | break; 659 | case 'q': 660 | case 'Q': 661 | g_leave_req = true; 662 | continue; 663 | case KEY_RESIZE: 664 | LOG("Terminal resize\n"); 665 | unpaint_screen(); 666 | paint_screen(); 667 | rl_resize_terminal(); 668 | break; 669 | case '!': 670 | unpaint_screen(); 671 | set_fields_width(8); 672 | if (bit_pos > 7) 673 | bit_pos = 7; 674 | paint_screen(); 675 | break; 676 | case '@': 677 | unpaint_screen(); 678 | set_fields_width(16); 679 | if (bit_pos > 15) 680 | bit_pos = 15; 681 | paint_screen(); 682 | break; 683 | case '$': 684 | unpaint_screen(); 685 | set_fields_width(32); 686 | if (bit_pos > 31) 687 | bit_pos = 31; 688 | paint_screen(); 689 | break; 690 | case '*': 691 | unpaint_screen(); 692 | set_fields_width(64); 693 | paint_screen(); 694 | break; 695 | case '~': 696 | unpaint_screen(); 697 | g_val = ~g_val & MASK(g_width); 698 | paint_screen(); 699 | break; 700 | case 'r': 701 | unpaint_screen(); 702 | switch (g_width) { 703 | case 16: 704 | g_val = __builtin_bswap16(g_val); 705 | break; 706 | case 32: 707 | g_val = __builtin_bswap32(g_val); 708 | break; 709 | case 64: 710 | g_val = __builtin_bswap64(g_val); 711 | break; 712 | } 713 | paint_screen(); 714 | break; 715 | case '>': 716 | unpaint_screen(); 717 | g_val = g_val >> 1; 718 | paint_screen(); 719 | break; 720 | case '<': 721 | tmp_val = (g_val << 1); 722 | 723 | if (tmp_val < MASK(g_width)) { 724 | unpaint_screen(); 725 | g_val = tmp_val; 726 | paint_screen(); 727 | } 728 | break; 729 | case ':': 730 | last_win = active_win; 731 | active_win = COMMAND_WIN; 732 | if (last_win == FIELDS_WIN) { 733 | set_active_field(true); 734 | form_driver(form, REQ_VALIDATION); 735 | wrefresh(fields_win); 736 | } else if (last_win == BINARY_WIN) 737 | position_binary_curser(bit_pos, -1); 738 | 739 | // Stop handling of mouse events 740 | mousemask(0, NULL); 741 | 742 | curs_set(1); 743 | keypad(stdscr, FALSE); 744 | intrflush(NULL, FALSE); 745 | readline_redisplay(); 746 | break; 747 | default: 748 | if (active_win == BINARY_WIN) 749 | process_binary(ch); 750 | else if (active_win == FIELDS_WIN) 751 | process_fields(ch); 752 | } 753 | 754 | if (active_win == BINARY_WIN) { 755 | LOG("Bit pos = %u\n", bit_pos); 756 | position_binary_curser(0, bit_pos); 757 | } 758 | 759 | } 760 | 761 | unpaint_screen(); 762 | /* OK. this is really weird, it seems that by calling 763 | * deinit_readline() before exiting is breaking bash 764 | * afterwards and must be fixed by typing reset in the 765 | * terminal. 766 | * I couldn't figure this one out, let's just leave it like 767 | * this, hopefully it won't affect other env */ 768 | 769 | /* deinit_readline(); */ 770 | 771 | flush_history(); 772 | deinit_terminal(); 773 | 774 | return 0; 775 | } 776 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 2 | * Ramon Fried 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef HAVE_DECL_BSWAP_32 15 | #include 16 | #else 17 | #define bswap_32(x) \ 18 | ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ 19 | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) 20 | 21 | #endif 22 | 23 | #include "bitwise.h" 24 | #include "shunting-yard.h" 25 | 26 | 27 | int print_conversions(uint64_t val, bool si) 28 | { 29 | char buf_size[16]; 30 | char binary[512]; 31 | int pos = 0; 32 | int i, j; 33 | struct in_addr ip_addr; 34 | 35 | buf_size[0] = '\0'; 36 | sprintf_size(val, buf_size, si); 37 | 38 | printf("%sUnsigned decimal: %s%" PRIu64 "\n", color_green, color_blue, val); 39 | 40 | switch (g_width) { 41 | case 64: 42 | printf("%sSigned decimal: %s%" PRId64 "\n", color_green, 43 | color_blue, (int64_t)val); 44 | break; 45 | case 32: 46 | printf("%sSigned decimal: %s%" PRId32 "\n", color_green, 47 | color_blue, (int32_t)val); 48 | break; 49 | case 16: 50 | printf("%sSigned decimal: %s%" PRId16 "\n", color_green, 51 | color_blue, (int16_t)val); 52 | break; 53 | case 8: 54 | printf("%sSigned decimal: %s%" PRId8 "\n", color_green, 55 | color_blue, (int8_t)val); 56 | break; 57 | default: 58 | break; 59 | } 60 | 61 | printf("%sHexadecimal: %s0x%" PRIx64 "\n", color_green, color_blue, val); 62 | printf("%sOctal: %s0%" PRIo64 "\n", color_green, color_blue, val); 63 | if (buf_size[0]) 64 | printf("%sHuman: %s%s\n", color_green, color_blue, buf_size); 65 | 66 | if (g_width < 64) 67 | printf("%sRadix64: %s%s\n", color_green, color_blue, l64a(val)); 68 | 69 | if (val > UINT_MAX) { 70 | printf("%sIPv4: %s%s\n", color_green, color_blue, "Value too big to be a valid IPv4 address"); 71 | } else { 72 | ip_addr.s_addr = val; 73 | printf("%sIPv4 (Network byte order - Big): %s %s\n", color_green, color_blue, inet_ntoa(ip_addr)); 74 | ip_addr.s_addr = bswap_32(val); 75 | printf("%sIPv4 (Reversed byte order - Little): %s %s\n", color_green, color_blue, inet_ntoa(ip_addr)); 76 | } 77 | 78 | printf("%sASCII: %s", color_green, color_blue); 79 | for (i = sizeof(uint64_t) - 1; i >= 0; i--) { 80 | char c = ((char *)&val)[i]; 81 | if (isgraph(c)) 82 | printf("%s%c", color_blue, c); 83 | else 84 | printf("%s.", color_white); 85 | } 86 | 87 | printf("\n%sBinary:\n%s", color_green, color_reset); 88 | for (i = g_width; i > 0; i--) { 89 | if ((i % 8 == 0) && (i != g_width)) { 90 | pos += sprintf(&binary[pos], "%s", color_white); 91 | binary[pos] = '|'; 92 | binary[pos + 1] = ' '; 93 | pos += 2; 94 | } 95 | if (val & BIT(i - 1)) { 96 | pos += sprintf(&binary[pos], "%s", color_blue); 97 | binary[pos] = '1'; 98 | } 99 | else { 100 | pos += sprintf(&binary[pos], "%s", color_magenta); 101 | binary[pos] = '0'; 102 | } 103 | binary[pos + 1] = ' '; 104 | pos += 2; 105 | } 106 | 107 | binary[pos-1] = '\0'; 108 | printf("%s\n ", binary); 109 | fputs(color_cyan, stdout); 110 | for (i = 0; i < g_width / 8; i++) { 111 | printf("%2d - %2d", g_width - 1 - (i * 8), (g_width - 8) - (i * 8)); 112 | if (i != (g_width / 8) - 1) 113 | for (j = 0; j < 11; j++) 114 | putchar(' '); 115 | } 116 | printf("\n"); 117 | puts(color_reset); 118 | return 0; 119 | } 120 | 121 | static void print_version(void) 122 | { 123 | printf(PACKAGE " " VERSION "\n"); 124 | } 125 | 126 | static void print_help(FILE *out) 127 | { 128 | fprintf(out, "Usage: bitwise [OPTION...] [expression]\n\n"); 129 | fprintf(out, 130 | "[expression] mathematical expression\n\n"); 131 | fprintf(out, 132 | " -i, --interactive\t Load interactive mode (default if no input)\n"); 133 | fprintf(out, " -w, --width[b|w|l|d]\t Set bit width (default: l)\n"); 134 | fprintf(out, " -h, --help\t\t Display this help and exit\n"); 135 | fprintf(out, " -v, --version\t\t Output version information and exit\n"); 136 | fprintf(out, " -s, --si\t\t Print size according to SI standard. (default: IEC standard)\n"); 137 | fprintf(out, " --no-color\t Start without color support\n\n"); 138 | } 139 | 140 | int main(int argc, char *argv[]) 141 | { 142 | int c; 143 | char width; 144 | int interactive = 0; 145 | uint64_t val = 0; 146 | int rc; 147 | bool si = false; 148 | 149 | #ifdef TRACE 150 | fd = fopen("log.txt", "w"); 151 | #endif 152 | 153 | setlocale(LC_ALL, ""); 154 | 155 | while (1) { 156 | static struct option long_options[] = { 157 | {"no-color", no_argument, &g_has_color, 0}, 158 | {"version", no_argument, 0, 'v'}, 159 | {"help", no_argument, 0, 'h'}, 160 | {"interactive", no_argument, 0, 'i'}, 161 | {"si", no_argument, 0, 's'}, 162 | {"width", required_argument, 0, 'w'}, 163 | {0, 0, 0, 0} 164 | }; 165 | 166 | int option_index = 0; 167 | 168 | c = getopt_long(argc, argv, "vhisw:", long_options, &option_index); 169 | if (c == -1) 170 | break; 171 | switch (c) { 172 | case 0: 173 | break; 174 | case 'v': 175 | print_version(); 176 | exit(EXIT_SUCCESS); 177 | case 'h': 178 | print_help(stdout); 179 | exit(EXIT_SUCCESS); 180 | case 'i': 181 | interactive = 1; 182 | break; 183 | case 's': 184 | si = true; 185 | break; 186 | case 'w': 187 | width = *optarg; 188 | if (!set_width(width)) 189 | break; 190 | fprintf(stderr, "Unsupported width size: accepted values are: [b|w|l|d]\n"); 191 | // fall through 192 | case '?': 193 | default: 194 | print_help(stderr); 195 | exit(EXIT_FAILURE); 196 | } 197 | } 198 | 199 | init_colors(); 200 | 201 | if (optind < argc) { // non-interactive mode 202 | uint32_t expr_len = argc - optind; // account for ' ' between args 203 | for (int i = optind; i < argc; i++) 204 | expr_len += strlen(argv[i]); 205 | 206 | char *expression = malloc(sizeof(char) * expr_len); 207 | if (expression == NULL) { 208 | fprintf(stderr, "Error parsing arguments"); 209 | exit(EXIT_FAILURE); 210 | } 211 | 212 | uint32_t expr_pos = 0; 213 | for (int i = optind; i < argc; i++) { 214 | strncpy(&expression[expr_pos], argv[i], expr_len - expr_pos); 215 | expr_pos += strlen(argv[i]); 216 | expression[expr_pos++] = ' '; 217 | } 218 | expression[expr_pos - 1] = '\0'; 219 | 220 | rc = shunting_yard(expression, &val); 221 | if (rc) { 222 | fprintf(stderr, "Couldn't parse expression: %s\n", expression); 223 | print_help(stderr); 224 | exit(EXIT_FAILURE); 225 | } 226 | free(expression); 227 | if (!g_width) 228 | set_width_by_val(val); 229 | if (val > MASK(g_width)) 230 | fprintf(stderr, "%sExpression overflowed!\n", color_red); 231 | val &= MASK(g_width); 232 | if (!interactive) 233 | return print_conversions(val, si); 234 | } 235 | 236 | if (!g_width) 237 | g_width = 32; 238 | start_interactive(val); 239 | 240 | #ifdef TRACE 241 | fclose(fd); 242 | #endif 243 | return 0; 244 | } 245 | -------------------------------------------------------------------------------- /src/misc.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 2 | * Ramon Fried 3 | */ 4 | 5 | #include 6 | #include 7 | #include "bitwise.h" 8 | 9 | /* IEC Standard */ 10 | #define KiB (1ULL << 10) 11 | #define MiB (1ULL << 20) 12 | #define GiB (1ULL << 30) 13 | #define TiB (1ULL << 40) 14 | #define PiB (1ULL << 50) 15 | 16 | /* SI Standard */ 17 | #define kB (1000ULL) 18 | #define MB (1000 * kB) 19 | #define GB (1000 * MB) 20 | #define TB (1000 * GB) 21 | #define PB (1000 * TB) 22 | 23 | int g_has_color = 1; 24 | int g_width = 0; 25 | bool g_input_avail; 26 | int g_input; 27 | 28 | #define RED "\x1B[31m" 29 | #define GREEN "\x1B[32m" 30 | #define YEL "\x1B[33m" 31 | #define BLUE "\x1B[34m" 32 | #define MAGENTA "\x1B[35m" 33 | #define CYAN "\x1B[36m" 34 | #define WHITE "\x1B[37m" 35 | #define RESET "\x1B[0m" 36 | #define NOTHING "" 37 | 38 | char *color_green = NOTHING; 39 | char *color_red = NOTHING; 40 | char *color_blue = NOTHING; 41 | char *color_magenta = NOTHING; 42 | char *color_cyan = NOTHING; 43 | char *color_white = NOTHING; 44 | char *color_reset = NOTHING; 45 | 46 | void init_colors(void) 47 | { 48 | if (g_has_color) { 49 | color_green = GREEN; 50 | color_red = RED; 51 | color_blue = BLUE; 52 | color_magenta = MAGENTA; 53 | color_cyan = CYAN; 54 | color_white = WHITE; 55 | color_reset = RESET; 56 | } else { 57 | color_green = NOTHING; 58 | color_red = NOTHING; 59 | color_blue = NOTHING; 60 | color_magenta = NOTHING; 61 | color_cyan = NOTHING; 62 | color_white = NOTHING; 63 | color_reset = NOTHING; 64 | } 65 | } 66 | 67 | void init_terminal(void) 68 | { 69 | initscr(); 70 | if (has_colors() == FALSE) 71 | g_has_color = 0; 72 | else { 73 | start_color(); 74 | init_colors(); 75 | } 76 | cbreak(); 77 | noecho(); 78 | nonl(); 79 | intrflush(NULL, FALSE); 80 | keypad(stdscr, TRUE); 81 | curs_set(2); 82 | } 83 | 84 | void deinit_terminal(void) 85 | { 86 | endwin(); 87 | } 88 | 89 | void die(const char *fmt, ...) 90 | { 91 | va_list args; 92 | va_start(args, fmt); 93 | 94 | deinit_terminal(); 95 | /* See interactive.c for reasoning */ 96 | /* deinit_readline(); */ 97 | vfprintf(stderr, fmt, args); 98 | va_end(args); 99 | exit(EXIT_FAILURE); 100 | } 101 | 102 | int validate_input(int ch, int base) 103 | { 104 | switch (base) { 105 | case 2: 106 | if (ch == '0' || ch == '1') 107 | return 0; 108 | break; 109 | case 8: 110 | if (ch >= '0' && ch <= '7') 111 | return 0; 112 | break; 113 | case 16: 114 | if ((ch >= '0' && ch <= '9') || 115 | (ch >= 'A' && ch <= 'F') || 116 | (ch >= 'a' && ch <= 'f')) 117 | return 0; 118 | break; 119 | case 10: 120 | if (isdigit(ch)) 121 | return 0; 122 | break; 123 | default: 124 | break; 125 | } 126 | 127 | return 1; 128 | } 129 | 130 | int binary_scanf(const char *buf, uint64_t *val) 131 | { 132 | uint64_t value = 0; 133 | 134 | /* Skip the leading 0 */ 135 | if (buf[0] == '0') { 136 | buf++; 137 | } 138 | 139 | /* Skip the leading b */ 140 | buf++; 141 | 142 | while (*buf) { 143 | switch (*buf) { 144 | 145 | case '0': 146 | value <<= 1; 147 | break; 148 | case '1': 149 | value <<= 1; 150 | value++; 151 | break; 152 | default: 153 | return 0; 154 | } 155 | buf++; 156 | } 157 | 158 | *val = value; 159 | 160 | return 1; 161 | } 162 | 163 | int base_scanf(const char *buf, int base, uint64_t *value) 164 | { 165 | int ret = 0; 166 | 167 | switch (base) { 168 | case 10: 169 | ret = sscanf(buf, "%" PRIu64, value); 170 | break; 171 | case 16: 172 | ret = sscanf(buf, "%" PRIX64, value); 173 | break; 174 | case 8: 175 | ret = sscanf(buf, "%" PRIo64, value); 176 | break; 177 | case 2: 178 | ret = binary_scanf(buf, value); 179 | break; 180 | default: 181 | fprintf(stderr, "Unknown base\n"); 182 | break; 183 | } 184 | 185 | if (ret == EOF || !ret) { 186 | LOG("Couldn't parse number: %s\n", buf); 187 | return 1; 188 | } 189 | 190 | return 0; 191 | } 192 | 193 | int ip_scanf(const char *input, uint64_t *val) 194 | { 195 | union { 196 | uint8_t ip[4]; 197 | uint32_t ip32; 198 | } ip; 199 | if (sscanf(input, "%hhu.%hhu.%hhu.%hhu", 200 | &ip.ip[0], &ip.ip[1], &ip.ip[2], &ip.ip[3]) != 4) { 201 | fprintf(stderr, "Failed parsing IPv4 address\n"); 202 | return 1; 203 | } 204 | 205 | *val = ip.ip32; 206 | return 0; 207 | } 208 | 209 | int parse_input(const char *input, uint64_t *val) 210 | { 211 | int base; 212 | 213 | if (strchr(input, '.')) 214 | return ip_scanf(input, val); 215 | if (tolower(input[0]) == 'b') 216 | base = 2; 217 | else if (input[0] == '0') 218 | if (tolower(input[1]) == 'b') 219 | base = 2; 220 | else if (input[1] == 'x' || input[1] == 'X') 221 | base = 16; 222 | else 223 | base = 8; 224 | else 225 | base = 10; 226 | 227 | return base_scanf(input, base, val); 228 | } 229 | 230 | int lltostr(uint64_t val, char *buf, int base) 231 | { 232 | int rc; 233 | 234 | switch (base) { 235 | case 10: 236 | rc = sprintf(buf, "%" PRIu64, val); 237 | break; 238 | case 16: 239 | rc = sprintf(buf, "%" PRIx64, val); 240 | break; 241 | case 8: 242 | rc = sprintf(buf, "%" PRIo64, val); 243 | break; 244 | case 2: 245 | default: 246 | sprintf(buf, "Not implemeted"); 247 | return -1; 248 | } 249 | 250 | if (rc < 0) 251 | LOG("sprintf failed with error: %d\n", rc); 252 | 253 | return rc; 254 | } 255 | 256 | int sprintf_type(uint64_t val, char *buf, output_type type) 257 | { 258 | int i; 259 | int pos = 0; 260 | 261 | switch (type) { 262 | case CMD_OUTPUT_DECIMAL: 263 | sprintf(buf, "Decimal: %" PRIu64, val); 264 | break; 265 | case CMD_OUTPUT_HEXADECIMAL: 266 | sprintf(buf, "Hexadecimal: 0x%" PRIx64, val); 267 | break; 268 | case CMD_OUTPUT_OCTAL: 269 | sprintf(buf, "Octal: 0%" PRIo64, val); 270 | break; 271 | case CMD_OUTPUT_BINARY: 272 | pos = sprintf(buf, "Binary: "); 273 | for (i = g_width; i > 0; i--) { 274 | if ((i % 8 == 0) && (i != g_width)) { 275 | buf[pos] = '|'; 276 | buf[pos + 1] = ' '; 277 | pos += 2; 278 | } 279 | if (val & BIT(i - 1)) { 280 | buf[pos] = '1'; 281 | } 282 | else { 283 | buf[pos] = '0'; 284 | } 285 | buf[pos + 1] = ' '; 286 | pos += 2; 287 | } 288 | buf[pos-1] = '\0'; 289 | break; 290 | 291 | default: 292 | break; 293 | } 294 | 295 | return 0; 296 | } 297 | 298 | int sprintf_size(uint64_t val, char *buf, bool si) 299 | { 300 | int ret; 301 | double f_val = val; 302 | 303 | if (si) { 304 | if (val >= PB) 305 | ret = sprintf(buf, "%.2lf PB", f_val / PB); 306 | else if (val >= TB) 307 | ret = sprintf(buf, "%.2lf TB", f_val / TB); 308 | else if (val >= GB) 309 | ret = sprintf(buf, "%.2lf GB", f_val / GB); 310 | else if (val >= MB) 311 | ret = sprintf(buf, "%.2lf MB", f_val / MB); 312 | else if (val >= kB) 313 | ret = sprintf(buf, "%.2lf Kb", f_val / kB); 314 | else 315 | ret = sprintf(buf, "%" PRIu64, val); 316 | } else { 317 | if (val >= PiB) 318 | ret = sprintf(buf, "%.2lf PiB", f_val / PiB); 319 | else if (val >= TiB) 320 | ret = sprintf(buf, "%.2lf TiB", f_val / TiB); 321 | else if (val >= GiB) 322 | ret = sprintf(buf, "%.2lf GiB", f_val / GiB); 323 | else if (val >= MiB) 324 | ret = sprintf(buf, "%.2lf MiB", f_val / MiB); 325 | else if (val >= KiB) 326 | ret = sprintf(buf, "%.2lf KiB", f_val / KiB); 327 | else 328 | ret = sprintf(buf, "%" PRIu64, val); 329 | } 330 | 331 | return ret; 332 | } 333 | 334 | void set_width_by_val(uint64_t val) 335 | { 336 | if (val & 0xFFFFFFFF00000000) 337 | g_width = 64; 338 | else if (val & 0xFFFF0000) 339 | g_width = 32; 340 | else if (val & 0xFF00) 341 | g_width = 16; 342 | else if (val & 0xFF) 343 | g_width = 8; 344 | else 345 | g_width = 32; 346 | } 347 | 348 | int set_width(char width) 349 | { 350 | if (tolower(width) == 'b') 351 | g_width = 8; 352 | else if (tolower(width) == 'w') 353 | g_width = 16; 354 | else if (tolower(width) == 'l') 355 | g_width = 32; 356 | else if (tolower(width) == 'd') 357 | g_width = 64; 358 | else 359 | return 1; 360 | 361 | return 0; 362 | } 363 | -------------------------------------------------------------------------------- /src/shunting-yard.c: -------------------------------------------------------------------------------- 1 | // Copyright 2011 - 2014 Brian Marshall. All rights reserved. 2 | // 3 | // Use of this source code is governed by the BSD 2-Clause License that can be 4 | // found in the LICENSE file. 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "bitwise.h" 13 | #include "shunting-yard.h" 14 | #include "stack.h" 15 | 16 | typedef enum { 17 | TOKEN_NONE, 18 | TOKEN_UNKNOWN, 19 | TOKEN_OPEN_PARENTHESIS, 20 | TOKEN_CLOSE_PARENTHESIS, 21 | TOKEN_OPERATOR, 22 | TOKEN_NUMBER, 23 | TOKEN_IDENTIFIER 24 | } TokenType; 25 | 26 | typedef struct { 27 | TokenType type; 28 | char *value; 29 | } Token; 30 | 31 | typedef enum { 32 | OPERATOR_OTHER, 33 | OPERATOR_UNARY, 34 | OPERATOR_BINARY 35 | } OperatorArity; 36 | 37 | typedef enum { 38 | OPERATOR_NONE, 39 | OPERATOR_LEFT, 40 | OPERATOR_RIGHT 41 | } OperatorAssociativity; 42 | 43 | typedef struct { 44 | char *symbol; 45 | int op_len; 46 | int precedence; 47 | OperatorArity arity; 48 | OperatorAssociativity associativity; 49 | } Operator; 50 | 51 | static const Token NO_TOKEN = {TOKEN_NONE, NULL}; 52 | 53 | static const Operator OPERATORS[] = { 54 | {"!", 1, 1, OPERATOR_UNARY, OPERATOR_RIGHT}, 55 | {"~", 1, 1, OPERATOR_UNARY, OPERATOR_RIGHT}, 56 | {"*", 1, 2, OPERATOR_BINARY, OPERATOR_LEFT}, 57 | {"/", 1, 2, OPERATOR_BINARY, OPERATOR_LEFT}, 58 | {"%", 1, 2, OPERATOR_BINARY, OPERATOR_LEFT}, 59 | {"+", 1, 3, OPERATOR_BINARY, OPERATOR_LEFT}, 60 | {"-", 1, 3, OPERATOR_BINARY, OPERATOR_LEFT}, 61 | {">>", 2, 4, OPERATOR_BINARY, OPERATOR_LEFT}, 62 | {"<<", 2, 4, OPERATOR_BINARY, OPERATOR_LEFT}, 63 | {"&", 1, 5, OPERATOR_BINARY, OPERATOR_LEFT}, 64 | {"^", 1, 5, OPERATOR_BINARY, OPERATOR_LEFT}, 65 | {"|", 1, 6, OPERATOR_BINARY, OPERATOR_LEFT}, 66 | {"(", 1, 7, OPERATOR_OTHER, OPERATOR_NONE} 67 | }; 68 | 69 | // Returns an array of tokens extracted from the expression. The array is 70 | // terminated by a token with type `TOKEN_NONE`. 71 | static Token *tokenize(const char *expression); 72 | 73 | // Parses a tokenized expression. 74 | static Status parse(const Token *tokens, Stack **operands, Stack **operators, 75 | Stack **functions); 76 | 77 | // Pushes an operator to the stack after applying operators with a higher 78 | // precedence. 79 | static Status push_operator(const Operator *operator, Stack **operands, 80 | Stack **operators); 81 | 82 | // Pushes the multiplication operator to the stack. 83 | static Status push_multiplication(Stack **operands, Stack **operators); 84 | 85 | // Allocates memory for a double and pushes it to the stack. 86 | static void push_num(uint64_t x, Stack **operands); 87 | 88 | // Pops a double from the stack, frees its memory and returns its value. 89 | static uint64_t pop_num(Stack **operands); 90 | 91 | // Converts a string into a number and pushes it to the stack. 92 | static Status push_number(const char *value, Stack **operands); 93 | 94 | // Converts a constant identifier into its value and pushes it to the stack. 95 | static Status push_constant(const char *value, Stack **operands); 96 | 97 | // Applies an operator to the top one or two operands, depending on if the 98 | // operator is unary or binary. 99 | static Status apply_operator(const Operator *operator, Stack **operands); 100 | 101 | // Applies a unary operator to the top operand. 102 | static Status apply_unary_operator(const Operator *operator, Stack **operands); 103 | 104 | // Applies a function to the top operand. 105 | static Status apply_function(const char *function, Stack **operands); 106 | 107 | // Returns the arity of an operator, using the previous token for context. 108 | static OperatorArity get_arity(char *symbol, const Token *previous); 109 | 110 | // Returns a matching operator. 111 | static const Operator *get_operator(char *symbol, OperatorArity arity); 112 | 113 | Status shunting_yard(const char *expression, uint64_t *result) 114 | { 115 | Token *tokens = tokenize(expression); 116 | Stack *operands = NULL, *operators = NULL, *functions = NULL; 117 | Status status = parse(tokens, &operands, &operators, &functions); 118 | if (operands) 119 | *result = pop_num(&operands); 120 | else if (status == STATUS_OK) 121 | status = ERROR_NO_INPUT; 122 | 123 | for (Token *token = tokens; token->type != TOKEN_NONE; token++) 124 | free(token->value); 125 | free(tokens); 126 | while (operands) 127 | pop_num(&operands); 128 | while (operators) 129 | stack_pop(&operators); 130 | while (functions) 131 | stack_pop(&functions); 132 | return status; 133 | } 134 | 135 | #define MAX_TOKEN_SIZE 64 136 | 137 | Token *tokenize(const char *expression) 138 | { 139 | int length = 0; 140 | Token *tokens = malloc(sizeof * tokens); 141 | const char *c = expression; 142 | while (*c) { 143 | char cur_token[MAX_TOKEN_SIZE]; 144 | Token token = {TOKEN_UNKNOWN, NULL}; 145 | 146 | if (*c == '(') 147 | token.type = TOKEN_OPEN_PARENTHESIS; 148 | else if (*c == ')') 149 | token.type = TOKEN_CLOSE_PARENTHESIS; 150 | else if (!strncmp("<<", c, 2) || !strncmp(">>", c, 2)) { 151 | token.type = TOKEN_OPERATOR; 152 | token.value = strndup(c, 2); 153 | } else if (strchr("~!^*/%+-|&", *c)) { 154 | token.type = TOKEN_OPERATOR; 155 | token.value = strndup(c, 1); 156 | } else if (!strncmp("bit", c, 3) || !strncmp("BIT", c, 3)) { 157 | token.value = strndup(c, 3); 158 | token.type = TOKEN_IDENTIFIER; 159 | } else if (sscanf(c, "%[xX0-9a-fA-F.]", cur_token)) { 160 | token.type = TOKEN_NUMBER; 161 | token.value = strdup(cur_token); 162 | } else if (sscanf(c, "%[A-Za-z$]", cur_token)) { 163 | token.type = TOKEN_IDENTIFIER; 164 | token.value = strdup(cur_token); 165 | } 166 | 167 | if (!isspace(*c)) { 168 | tokens = realloc(tokens, sizeof * tokens * 169 | (++length + 1)); 170 | tokens[length - 1] = token; 171 | } 172 | c += token.value ? strlen(token.value) : 1; 173 | } 174 | tokens[length] = NO_TOKEN; 175 | 176 | return tokens; 177 | } 178 | 179 | Status parse(const Token *tokens, Stack **operands, Stack **operators, 180 | Stack **functions) 181 | { 182 | Status status = STATUS_OK; 183 | 184 | for (const Token *token = tokens, *previous = &NO_TOKEN, *next = token + 1; 185 | token->type != TOKEN_NONE; previous = token, token = next++) { 186 | switch (token->type) { 187 | case TOKEN_OPEN_PARENTHESIS: 188 | // Implicit multiplication: "(2)(2)". 189 | if (previous->type == TOKEN_CLOSE_PARENTHESIS) 190 | status = push_multiplication(operands, operators); 191 | 192 | stack_push(operators, get_operator("(", OPERATOR_OTHER)); 193 | break; 194 | 195 | case TOKEN_CLOSE_PARENTHESIS: { 196 | // Apply operators until the previous open parenthesis is found. 197 | bool found_parenthesis = false; 198 | while (*operators && status == STATUS_OK && !found_parenthesis) { 199 | const Operator *operator = stack_pop(operators); 200 | if (!strncmp(operator->symbol, "(", 1)) 201 | found_parenthesis = true; 202 | else 203 | status = apply_operator(operator, operands); 204 | } 205 | if (!found_parenthesis) 206 | status = ERROR_CLOSE_PARENTHESIS; 207 | else if (*functions) 208 | status = apply_function(stack_pop(functions), operands); 209 | break; 210 | } 211 | 212 | case TOKEN_OPERATOR: 213 | status = push_operator( 214 | get_operator(token->value, 215 | get_arity(token->value, previous)), 216 | operands, operators); 217 | break; 218 | 219 | case TOKEN_NUMBER: 220 | if (previous->type == TOKEN_CLOSE_PARENTHESIS || 221 | previous->type == TOKEN_NUMBER || 222 | previous->type == TOKEN_IDENTIFIER) 223 | status = ERROR_SYNTAX; 224 | else { 225 | status = push_number(token->value, operands); 226 | 227 | // Implicit multiplication: "2(2)" or "2a". 228 | if (next->type == TOKEN_OPEN_PARENTHESIS || 229 | next->type == TOKEN_IDENTIFIER) 230 | status = push_multiplication(operands, operators); 231 | } 232 | break; 233 | 234 | case TOKEN_IDENTIFIER: 235 | // The identifier could be either a constant or function. 236 | status = push_constant(token->value, operands); 237 | if ((status == ERROR_UNDEFINED_CONSTANT) && 238 | (next->type == TOKEN_OPEN_PARENTHESIS)) { 239 | stack_push(functions, token->value); 240 | status = STATUS_OK; 241 | } else if (next->type == TOKEN_OPEN_PARENTHESIS || 242 | next->type == TOKEN_IDENTIFIER) { 243 | // Implicit multiplication: "a(2)" or "a b". 244 | status = push_multiplication(operands, operators); 245 | } 246 | break; 247 | 248 | default: 249 | status = ERROR_UNRECOGNIZED; 250 | } 251 | if (status != STATUS_OK) 252 | return status; 253 | } 254 | 255 | // Apply all remaining operators. 256 | while (*operators && status == STATUS_OK) { 257 | const Operator *operator = stack_pop(operators); 258 | if (!strncmp(operator->symbol, "(", 1)) 259 | status = ERROR_OPEN_PARENTHESIS; 260 | else 261 | status = apply_operator(operator, operands); 262 | } 263 | return status; 264 | } 265 | 266 | Status push_operator(const Operator *operator, Stack **operands, 267 | Stack **operators) 268 | { 269 | if (!operator) 270 | return ERROR_SYNTAX; 271 | 272 | Status status = STATUS_OK; 273 | while (*operators && status == STATUS_OK) { 274 | const Operator *stack_operator = stack_top(*operators); 275 | if (operator->arity == OPERATOR_UNARY || 276 | operator->precedence < stack_operator->precedence || 277 | (operator->associativity == OPERATOR_RIGHT && 278 | operator->precedence == stack_operator->precedence)) 279 | break; 280 | 281 | status = apply_operator(stack_pop(operators), operands); 282 | } 283 | stack_push(operators, operator); 284 | return status; 285 | } 286 | 287 | Status push_multiplication(Stack **operands, Stack **operators) 288 | { 289 | return push_operator(get_operator("*", OPERATOR_BINARY), operands, 290 | operators); 291 | } 292 | 293 | void push_num(uint64_t x, Stack **operands) 294 | { 295 | uint64_t *pointer = malloc(sizeof * pointer); 296 | *pointer = x; 297 | stack_push(operands, pointer); 298 | } 299 | 300 | uint64_t pop_num(Stack **operands) 301 | { 302 | const uint64_t *pointer = stack_pop(operands); 303 | uint64_t x = *pointer; 304 | free((void *)pointer); 305 | return x; 306 | } 307 | 308 | Status push_number(const char *value, Stack **operands) 309 | { 310 | uint64_t x; 311 | 312 | if (parse_input(value, &x)) 313 | return ERROR_SYNTAX; 314 | 315 | push_num(x, operands); 316 | return STATUS_OK; 317 | } 318 | 319 | Status push_constant(const char *value, Stack **operands) 320 | { 321 | uint64_t x; 322 | 323 | if (strncmp(value, "$", 1) == 0) 324 | x = g_val; 325 | else 326 | return ERROR_UNDEFINED_CONSTANT; 327 | 328 | push_num(x, operands); 329 | return STATUS_OK; 330 | } 331 | 332 | Status apply_operator(const Operator *operator, Stack **operands) 333 | { 334 | if (!operator || !*operands) 335 | return ERROR_SYNTAX; 336 | if (operator->arity == OPERATOR_UNARY) 337 | return apply_unary_operator(operator, operands); 338 | 339 | uint64_t y = pop_num(operands); 340 | if (!*operands) 341 | return ERROR_SYNTAX; 342 | uint64_t x = pop_num(operands); 343 | Status status = STATUS_OK; 344 | switch (*operator->symbol) { 345 | case '*': 346 | x = x * y; 347 | break; 348 | case '/': 349 | if (y == 0) 350 | return ERROR_DIVIDE_BY_ZERO; 351 | x = x / y; 352 | break; 353 | case '%': 354 | x = x % y; 355 | break; 356 | case '+': 357 | x = x + y; 358 | break; 359 | case '-': 360 | x = x - y; 361 | break; 362 | case '>': 363 | x = x >> y; 364 | break; 365 | case '<': 366 | x = x << y; 367 | break; 368 | case '|': 369 | x = x | y; 370 | break; 371 | case '&': 372 | x = x & y; 373 | break; 374 | case '^': 375 | x = x ^ y; 376 | break; 377 | default: 378 | return ERROR_UNRECOGNIZED; 379 | } 380 | push_num(x, operands); 381 | return status; 382 | } 383 | 384 | Status apply_unary_operator(const Operator *operator, Stack **operands) 385 | { 386 | uint64_t x = pop_num(operands); 387 | switch (*operator->symbol) { 388 | case '+': 389 | break; 390 | case '-': 391 | x = -x; 392 | break; 393 | case '~': 394 | x = ~x; 395 | break; 396 | case '!': 397 | x = !x; 398 | break; 399 | default: 400 | return ERROR_UNRECOGNIZED; 401 | } 402 | push_num(x, operands); 403 | return STATUS_OK; 404 | } 405 | 406 | Status apply_function(const char *function, Stack **operands) 407 | { 408 | if (!*operands) 409 | return ERROR_FUNCTION_ARGUMENTS; 410 | 411 | uint64_t x = pop_num(operands); 412 | 413 | if (strcasecmp(function, "bit") == 0) 414 | x = BIT(x); 415 | else 416 | return ERROR_UNDEFINED_FUNCTION; 417 | 418 | push_num(x, operands); 419 | return STATUS_OK; 420 | } 421 | 422 | OperatorArity get_arity(char *symbol, const Token *previous) 423 | { 424 | if (*symbol == '!' || previous->type == TOKEN_NONE || 425 | previous->type == TOKEN_OPEN_PARENTHESIS || 426 | (previous->type == TOKEN_OPERATOR && *previous->value != '!')) 427 | return OPERATOR_UNARY; 428 | return OPERATOR_BINARY; 429 | } 430 | 431 | const Operator *get_operator(char *symbol, OperatorArity arity) 432 | { 433 | for (size_t i = 0; i < sizeof OPERATORS / sizeof OPERATORS[0]; i++) { 434 | if (!strncmp(OPERATORS[i].symbol, symbol, OPERATORS[i].op_len) && 435 | OPERATORS[i].arity == arity) 436 | return &OPERATORS[i]; 437 | } 438 | 439 | LOG("couldn't find %s operator\n", symbol); 440 | return NULL; 441 | } 442 | -------------------------------------------------------------------------------- /src/stack.c: -------------------------------------------------------------------------------- 1 | // Copyright 2011 - 2014 Brian Marshall. All rights reserved. 2 | // 3 | // Use of this source code is governed by the BSD 2-Clause License that can be 4 | // found in the LICENSE file. 5 | 6 | #include "stack.h" 7 | 8 | #include 9 | 10 | struct Stack { 11 | const void *value; 12 | Stack *next; 13 | }; 14 | 15 | void stack_push(Stack **stack, const void *value) 16 | { 17 | Stack *item = malloc(sizeof * item); 18 | item->value = value; 19 | item->next = *stack; 20 | *stack = item; 21 | } 22 | 23 | const void *stack_pop(Stack **stack) 24 | { 25 | Stack *item = *stack; 26 | const void *value = item->value; 27 | *stack = item->next; 28 | free(item); 29 | return value; 30 | } 31 | 32 | const void *stack_top(const Stack *stack) 33 | { 34 | return stack->value; 35 | } 36 | -------------------------------------------------------------------------------- /tests/test-shunting-yard.c: -------------------------------------------------------------------------------- 1 | // Copyright 2012 - 2014 Brian Marshall. All rights reserved. 2 | // 3 | // Use of this source code is governed by the BSD 2-Clause License that can be 4 | // found in the LICENSE file. 5 | // 6 | // Based on CUnit example code: . 7 | 8 | #include "../inc/shunting-yard.h" 9 | 10 | #include 11 | #include 12 | 13 | #define ASSERT_RESULT(expression, expected) \ 14 | ASSERT_STATUS(expression, STATUS_OK); \ 15 | CU_ASSERT_EQUAL(result, expected) 16 | 17 | #define ASSERT_STATUS(expression, expected) \ 18 | CU_ASSERT(shunting_yard(expression, &result) == expected) 19 | 20 | static uint64_t result = 0; 21 | uint64_t g_val = 0x512; 22 | 23 | static void test_addition() 24 | { 25 | ASSERT_RESULT("2+2", 4); 26 | ASSERT_RESULT("0x2+0x2", 0x4); 27 | ASSERT_RESULT("0x2 + 0x2", 0x4); 28 | ASSERT_RESULT("0x2 + b101", 7); 29 | ASSERT_RESULT("0x2 + 0b101", 7); 30 | ASSERT_RESULT("0b101 + 0x2", 7); 31 | ASSERT_RESULT("2 + 2", 4); 32 | ASSERT_RESULT("3 + (5 + 1 + (2 + 2))", 13); 33 | ASSERT_RESULT("1+2+4+8+16 + 11", 42); 34 | 35 | } 36 | 37 | static void test_shifts() 38 | { 39 | ASSERT_RESULT("1<<0", 1); 40 | ASSERT_RESULT("1 << 2", 4); 41 | ASSERT_RESULT("2 >> 1", 1); 42 | ASSERT_RESULT("0x2 >> 1", 1); 43 | } 44 | 45 | static void test_subtraction() 46 | { 47 | ASSERT_RESULT("8-4", 4); 48 | ASSERT_RESULT("15-10", 5); 49 | ASSERT_RESULT("27 - (10 - 11)", 28); 50 | } 51 | 52 | static void test_multiplication() 53 | { 54 | ASSERT_RESULT("13 * 2", 26); 55 | ASSERT_RESULT("2(3)", 6); 56 | ASSERT_RESULT("(2)(3)", 6); 57 | ASSERT_RESULT("0x2(0x3)", 6); 58 | } 59 | 60 | static void test_division() 61 | { 62 | ASSERT_RESULT("2987898/34743", 86); 63 | } 64 | 65 | static void test_modulus() 66 | { 67 | ASSERT_RESULT("10 % 6", 4); 68 | ASSERT_RESULT("2+3 % 3", 2); 69 | ASSERT_RESULT("6*5%21", 9); 70 | ASSERT_RESULT("10%11", 10); 71 | ASSERT_RESULT("5 %5", 0); 72 | } 73 | 74 | 75 | static void test_functions() 76 | { 77 | ASSERT_RESULT("BIT(3)", 8); 78 | 79 | } 80 | 81 | static void test_constants() 82 | { 83 | ASSERT_RESULT("$+0x30", 0x542); 84 | } 85 | 86 | static void test_precedence() 87 | { 88 | ASSERT_RESULT("6/3*5", 10); 89 | ASSERT_RESULT("6+3*2", 12); 90 | ASSERT_RESULT("2+6/2*5+10/3-2/6", 20); 91 | } 92 | 93 | static void test_errors() 94 | { 95 | ASSERT_STATUS("2+*2", ERROR_SYNTAX); 96 | ASSERT_STATUS("2**2", ERROR_SYNTAX); 97 | ASSERT_STATUS("*1", ERROR_SYNTAX); 98 | ASSERT_STATUS("2*.", ERROR_SYNTAX); 99 | ASSERT_STATUS("2*2 3", ERROR_SYNTAX); 100 | ASSERT_STATUS("(2+2", ERROR_OPEN_PARENTHESIS); 101 | ASSERT_STATUS("(2+2)+(2+2", ERROR_OPEN_PARENTHESIS); 102 | ASSERT_STATUS("(2+2))", ERROR_CLOSE_PARENTHESIS); 103 | ASSERT_STATUS("", ERROR_NO_INPUT); 104 | ASSERT_STATUS(" ", ERROR_NO_INPUT); 105 | ASSERT_STATUS("foo(2)", ERROR_UNDEFINED_FUNCTION); 106 | // ASSERT_STATUS("bit(foo)", ERROR_FUNCTION_ARGUMENTS); 107 | // ASSERT_STATUS("foo", ERROR_UNDEFINED_CONSTANT); 108 | 109 | } 110 | 111 | int main() 112 | { 113 | if (CU_initialize_registry() != CUE_SUCCESS) 114 | return CU_get_error(); 115 | 116 | unsigned int tests_failed = 0; 117 | CU_pSuite suite = CU_add_suite("Shunting Yard", NULL, NULL); 118 | if (!suite) 119 | goto exit; 120 | 121 | if (!CU_add_test(suite, "addition", test_addition) || 122 | !CU_add_test(suite, "shifts", test_shifts) || 123 | !CU_add_test(suite, "subtraction", test_subtraction) || 124 | !CU_add_test(suite, "multiplication", test_multiplication) || 125 | !CU_add_test(suite, "division", test_division) || 126 | !CU_add_test(suite, "modulus", test_modulus) || 127 | !CU_add_test(suite, "functions", test_functions) || 128 | !CU_add_test(suite, "constants", test_constants) || 129 | !CU_add_test(suite, "operator precedence", test_precedence) || 130 | !CU_add_test(suite, "error handling", test_errors)) 131 | goto exit; 132 | 133 | CU_basic_set_mode(CU_BRM_NORMAL); 134 | CU_basic_run_tests(); 135 | tests_failed = CU_get_number_of_tests_failed(); 136 | exit: 137 | CU_cleanup_registry(); 138 | return tests_failed ? EXIT_FAILURE : CU_get_error(); 139 | } 140 | -------------------------------------------------------------------------------- /ubuntu_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | releases="xenial disco cosmic bionic trusty" # List of releases to generate 6 | 7 | if [ ! -f "bitwise-v$1.tar.gz" ]; then 8 | wget https://github.com/mellowcandle/bitwise/releases/download/v$1/bitwise-v$1.tar.gz 9 | fi 10 | 11 | for release in $releases; do 12 | echo "Creating release for $release" 13 | mkdir -p $release 14 | cd $release 15 | rm -rf bitwise-v$1 16 | tar xf ../bitwise-v$1.tar.gz 17 | cd bitwise-v$1 18 | cp -r ../../debian . 19 | dch -D $release -v $1-1ubuntu+$release v$1 20 | dpkg-buildpackage -S 21 | cd .. 22 | dput ppa bitwise_$1-1ubuntu+${release}_source.changes 23 | cd ../ 24 | done 25 | 26 | 27 | --------------------------------------------------------------------------------