├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── NEWS ├── README.md ├── config.h ├── inotify-tools-v3.14.tar.gz ├── jni ├── Android.mk ├── Application.mk ├── common.c ├── common.h ├── inotifywait.c ├── inotifywatch.c ├── libinotifytools │ ├── Doxyfile │ ├── example.c │ ├── inotifytools.c │ ├── inotifytools │ │ ├── inotify-nosys.h │ │ ├── inotify.h │ │ └── inotifytools.h │ ├── inotifytools_p.h │ ├── redblack.c │ ├── redblack.h │ └── test.c ├── regex │ ├── LICENSES │ ├── re_comp.h │ ├── regcomp.c │ ├── regcomp_bak.c │ ├── regex.c │ ├── regex.h │ ├── regex_internal.c │ ├── regex_internal.h │ ├── regexbug1.c │ └── regexec.c ├── wrap_inotifywait.c └── wrap_inotifywatch.c └── libs └── armeabi ├── inotifywait └── inotifywatch /.gitignore: -------------------------------------------------------------------------------- 1 | obj/ 2 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Rohan McGovern 2 | 3 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dstmath/inotifywait-for-Android/08291e2aadbb6fee8408ca02054bd25dd5cf8fdb/ChangeLog -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | 2 | * 19 October 2005 3 | inotify-tools begun. 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # inotifywait-for-Android 2 | ## 0x01 编译 3 | ``` 4 | git clone https://github.com/dstmath/inotifywait-for-Android.git 5 | cd inotifywait-for-Android 6 | ndk-build 7 | 8 | [armeabi] Compile thumb : inotifywait <= wrap_inotifywait.c 9 | [armeabi] Compile thumb : inotifywait <= common.c 10 | [armeabi] Compile thumb : inotifywait <= inotifytools.c 11 | In file included from jni/libinotifytools/inotifytools.c:31:0: 12 | jni/libinotifytools/../regex/regex.h:367:40: warning: declaration does not declare anything 13 | unsigned long int __REPB_PREFIX(used); 14 | ^ 15 | [armeabi] Compile thumb : inotifywait <= redblack.c 16 | [armeabi] Executable : inotifywait 17 | [armeabi] Install : inotifywait => libs/armeabi/inotifywait 18 | [armeabi] Compile thumb : inotifywatch <= wrap_inotifywatch.c 19 | [armeabi] Compile thumb : inotifywatch <= common.c 20 | [armeabi] Compile thumb : inotifywatch <= inotifytools.c 21 | In file included from jni/libinotifytools/inotifytools.c:31:0: 22 | jni/libinotifytools/../regex/regex.h:367:40: warning: declaration does not declare anything 23 | unsigned long int __REPB_PREFIX(used); 24 | ^ 25 | [armeabi] Compile thumb : inotifywatch <= redblack.c 26 | [armeabi] Executable : inotifywatch 27 | [armeabi] Install : inotifywatch => libs/armeabi/inotifywatch 28 | ``` 29 | ## 0x02 push inotifywatch和inofitywait到手机 30 | ``` 31 | adb push inotifywatch /data/local/tmp/ 32 | adb push inotifywait /data/local/tmp/ 33 | adb shell 34 | su 35 | mount -o rw,remount /system 36 | cp /data/local/tmp/inotifywatch /system/xbin 37 | chmod 755 /system/xbin/inotivywatch 38 | cp /data/local/tmp/inotifywait /system/xbin 39 | chmod 755 /system/xbin/inotivywait 40 | ``` 41 | ## 0x03 用法 42 | inotifywait主要用来监控文件系统,对文件和目录访问进行记录。 43 | 44 | ``` 45 | adb shell 46 | #查看帮助 47 | inotifywait -h 48 | #监控/system目录 49 | inotifywait -r -m --timefmt %a-%b-%d-%T --format '%e:------%w%f %T' /system 50 | #输出如下 51 | Setting up watches. Beware: since -r was given, this may take a while! 52 | Watches established. 53 | ACCESS:------/system/priv-app/SystemUI/SystemUI.apk Mon-Aug-29-22:08:32 54 | ACCESS:------/system/framework/framework-res.apk Mon-Aug-29-22:08:34 55 | ACCESS:------/system/framework/framework-res.apk Mon-Aug-29-22:08:34 56 | ACCESS:------/system/framework/framework-res.apk Mon-Aug-29-22:08:34 57 | ACCESS:------/system/framework/framework-res.apk Mon-Aug-29-22:08:34 58 | ACCESS:------/system/framework/framework-res.apk Mon-Aug-29-22:08:34 59 | ACCESS:------/system/framework/framework-res.apk Mon-Aug-29-22:08:34 60 | ACCESS:------/system/framework/org.cyanogenmod.platform-res.apk Mon-Aug-29-22:08:34 61 | OPEN:------/system/lib/hw/gralloc.msm8974.so Mon-Aug-29-22:08:34 62 | CLOSE_NOWRITE,CLOSE:------/system/lib/hw/gralloc.msm8974.so Mon-Aug-29-22:08:34 63 | ACCESS:------/system/framework/framework-res.apk Mon-Aug-29-22:08:34 64 | ACCESS:------/system/framework/framework-res.apk Mon-Aug-29-22:08:34 65 | OPEN:------/system/lib/hw/gralloc.msm8974.so Mon-Aug-29-22:08:35 66 | CLOSE_NOWRITE,CLOSE:------/system/lib/hw/gralloc.msm8974.so Mon-Aug-29-22:08:35 67 | ``` 68 | 更多用法可以用 -h来查看更多的选项。 69 | 70 | ## 0x04 参考链接 71 | * [https://github.com/rvoicilas/inotify-tools/wiki](https://github.com/rvoicilas/inotify-tools/wiki) 72 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #define PACKAGE_BUGREPORT "radu.voicilas@gmail.com" 5 | #define PACKAGE_VERSION "3.14" 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /inotify-tools-v3.14.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dstmath/inotifywait-for-Android/08291e2aadbb6fee8408ca02054bd25dd5cf8fdb/inotify-tools-v3.14.tar.gz -------------------------------------------------------------------------------- /jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | ### inotify 4 | include $(CLEAR_VARS) 5 | 6 | # build PIE (for Android 4.1.2 - 4.4 / 5.0 or later) 7 | LOCAL_CFLAGS += -fPIE -std=c99 8 | LOCAL_LDFLAGS += -fPIE -pie 9 | 10 | # build non-PIE (for Android 4.0.3 or earlier) 11 | #LOCAL_CFLAGS = -std=c99 12 | 13 | LOCAL_C_INCLUDES := \ 14 | ./jni/regex \ 15 | ./jni/libinotifytools 16 | 17 | LOCAL_MODULE := inotifywait 18 | LOCAL_SRC_FILES := wrap_inotifywait.c common.c libinotifytools/inotifytools.c libinotifytools/redblack.c 19 | 20 | include $(BUILD_EXECUTABLE) 21 | 22 | #### inotifywatch 23 | include $(CLEAR_VARS) 24 | 25 | # build PIE (for Android 4.1.2 - 4.4 / 5.0 or later) 26 | LOCAL_CFLAGS += -fPIE -std=c99 27 | LOCAL_LDFLAGS += -fPIE -pie 28 | 29 | # build non-PIE (for Android 4.0.3 or earlier) 30 | #LOCAL_CFLAGS = -std=c99 31 | 32 | LOCAL_C_INCLUDES := \ 33 | ./jni/regex \ 34 | ./jni/libinotifytools 35 | 36 | LOCAL_MODULE := inotifywatch 37 | LOCAL_SRC_FILES := wrap_inotifywatch.c common.c libinotifytools/inotifytools.c libinotifytools/redblack.c 38 | 39 | include $(BUILD_EXECUTABLE) 40 | -------------------------------------------------------------------------------- /jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := armeabi 2 | -------------------------------------------------------------------------------- /jni/common.c: -------------------------------------------------------------------------------- 1 | #include "../config.h" 2 | #include "common.h" 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #define MAXLEN 4096 15 | #define LIST_CHUNK 1024 16 | 17 | #define resize_if_necessary(count,len,ptr) \ 18 | if ( count >= len - 1 ) { \ 19 | len += LIST_CHUNK; \ 20 | ptr =(char const **)realloc(ptr, sizeof(char *)*len); \ 21 | } 22 | 23 | void print_event_descriptions() { 24 | printf("\taccess\t\tfile or directory contents were read\n"); 25 | printf("\tmodify\t\tfile or directory contents were written\n"); 26 | printf("\tattrib\t\tfile or directory attributes changed\n"); 27 | printf("\tclose_write\tfile or directory closed, after being opened in\n" 28 | "\t \twriteable mode\n"); 29 | printf("\tclose_nowrite\tfile or directory closed, after being opened in\n" 30 | "\t \tread-only mode\n"); 31 | printf("\tclose\t\tfile or directory closed, regardless of read/write " 32 | "mode\n"); 33 | printf("\topen\t\tfile or directory opened\n"); 34 | printf("\tmoved_to\tfile or directory moved to watched directory\n"); 35 | printf("\tmoved_from\tfile or directory moved from watched directory\n"); 36 | printf("\tmove\t\tfile or directory moved to or from watched directory\n"); 37 | printf("\tcreate\t\tfile or directory created within watched directory\n"); 38 | printf("\tdelete\t\tfile or directory deleted within watched directory\n"); 39 | printf("\tdelete_self\tfile or directory was deleted\n"); 40 | printf("\tunmount\t\tfile system containing file or directory unmounted\n"); 41 | } 42 | /* 43 | int isdir( char const * path ) { 44 | static struct stat64 my_stat; 45 | 46 | if ( -1 == lstat64( path, &my_stat ) ) { 47 | if (errno == ENOENT) return 0; 48 | fprintf(stderr, "Stat failed on %s: %s\n", path, strerror(errno)); 49 | return 0; 50 | } 51 | 52 | return S_ISDIR( my_stat.st_mode ) && !S_ISLNK( my_stat.st_mode ); 53 | } 54 | */ 55 | FileList construct_path_list( int argc, char ** argv, char const * filename ) { 56 | FileList list; 57 | list.watch_files = 0; 58 | list.exclude_files = 0; 59 | FILE * file = 0; 60 | 61 | if (!filename) { 62 | } 63 | else if (!strcmp(filename,"-")) { 64 | file = stdin; 65 | } 66 | else { 67 | file = fopen( filename, "r" ); 68 | } 69 | 70 | int watch_len = LIST_CHUNK; 71 | int exclude_len = LIST_CHUNK; 72 | int watch_count = 0; 73 | int exclude_count = 0; 74 | list.watch_files = (char const **)malloc(sizeof(char *)*watch_len); 75 | list.exclude_files = (char const **)malloc(sizeof(char *)*exclude_len); 76 | 77 | char name[MAXLEN]; 78 | while ( file && fgets(name, MAXLEN, file) ) { 79 | if ( name[strlen(name)-1] == '\n') name[strlen(name)-1] = 0; 80 | if ( strlen(name) == 0 ) continue; 81 | if ( '@' == name[0] && strlen(name) == 1 ) continue; 82 | if ( '@' == name[0] ) { 83 | resize_if_necessary(exclude_count, exclude_len, list.exclude_files); 84 | list.exclude_files[exclude_count++] = strdup(&name[1]); 85 | } 86 | else { 87 | resize_if_necessary(watch_count, watch_len, list.watch_files); 88 | list.watch_files[watch_count++] = strdup(name); 89 | } 90 | } 91 | if ( file && file != stdin) fclose(file); 92 | 93 | for ( int i = 0; i < argc; ++i ) { 94 | if ( strlen(argv[i]) == 0 ) continue; 95 | if ( '@' == argv[i][0] && strlen(argv[i]) == 1 ) continue; 96 | if ( '@' == argv[i][0] ) { 97 | resize_if_necessary(exclude_count, exclude_len, list.exclude_files); 98 | list.exclude_files[exclude_count++] = &argv[i][1]; 99 | } 100 | else { 101 | resize_if_necessary(watch_count, watch_len, list.watch_files); 102 | list.watch_files[watch_count++] = argv[i]; 103 | } 104 | } 105 | list.exclude_files[exclude_count] = 0; 106 | list.watch_files[watch_count] = 0; 107 | return list; 108 | } 109 | /* 110 | void _niceassert( long cond, int line, char const * file, char const * condstr, 111 | char const * mesg ) { 112 | if ( cond ) return; 113 | 114 | if ( mesg ) { 115 | fprintf(stderr, "%s:%d assertion ( %s ) failed: %s\n", file, line, 116 | condstr, mesg ); 117 | } 118 | else { 119 | fprintf(stderr, "%s:%d assertion ( %s ) failed.\n", file, line, condstr); 120 | } 121 | } 122 | */ 123 | -------------------------------------------------------------------------------- /jni/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #ifndef EXIT_SUCCESS 5 | #define EXIT_SUCCESS 0 6 | #define EXIT_FAILURE 1 7 | #endif 8 | #define EXIT_TIMEOUT 2 9 | 10 | void print_event_descriptions(); 11 | int isdir( char const * path ); 12 | 13 | typedef struct { 14 | char const ** watch_files; 15 | char const ** exclude_files; 16 | } FileList; 17 | FileList construct_path_list( int argc, char ** argv, char const * filename ); 18 | 19 | #define niceassert(cond,mesg) _niceassert((long)cond, __LINE__, __FILE__, \ 20 | #cond, mesg) 21 | 22 | void _niceassert( long cond, int line, char const * file, char const * condstr, 23 | char const * mesg ); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /jni/inotifywait.c: -------------------------------------------------------------------------------- 1 | #include "../config.h" 2 | #include "common.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "regex/regex.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "libinotifytools/inotifytools/inotifytools.h" 24 | #include "libinotifytools/inotifytools/inotify.h" 25 | 26 | extern char *optarg; 27 | extern int optind, opterr, optopt; 28 | 29 | #define MAX_STRLEN 4096 30 | #define EXCLUDE_CHUNK 1024 31 | 32 | #define nasprintf(...) niceassert( -1 != asprintf(__VA_ARGS__), "out of memory") 33 | 34 | // METHODS 35 | bool parse_opts( 36 | int * argc, 37 | char *** argv, 38 | int * events, 39 | bool * monitor, 40 | int * quiet, 41 | unsigned long int * timeout, 42 | int * recursive, 43 | bool * csv, 44 | bool * daemon, 45 | bool * syslog, 46 | char ** format, 47 | char ** timefmt, 48 | char ** fromfile, 49 | char ** outfile, 50 | char ** regex, 51 | char ** iregex 52 | ); 53 | 54 | void print_help(); 55 | 56 | 57 | char * csv_escape( char * string ) { 58 | static char csv[MAX_STRLEN+1]; 59 | static unsigned int i, ind; 60 | 61 | if ( strlen(string) > MAX_STRLEN ) { 62 | return NULL; 63 | } 64 | 65 | if ( strlen(string) == 0 ) { 66 | return NULL; 67 | } 68 | 69 | // May not need escaping 70 | if ( !strchr(string, '"') && !strchr(string, ',') && !strchr(string, '\n') 71 | && string[0] != ' ' && string[strlen(string)-1] != ' ' ) { 72 | strcpy( csv, string ); 73 | return csv; 74 | } 75 | 76 | // OK, so now we _do_ need escaping. 77 | csv[0] = '"'; 78 | ind = 1; 79 | for ( i = 0; i < strlen(string); ++i ) { 80 | if ( string[i] == '"' ) { 81 | csv[ind++] = '"'; 82 | } 83 | csv[ind++] = string[i]; 84 | } 85 | csv[ind++] = '"'; 86 | csv[ind] = '\0'; 87 | 88 | return csv; 89 | } 90 | 91 | 92 | void validate_format( char * fmt ) { 93 | // Make a fake event 94 | struct inotify_event * event = 95 | (struct inotify_event *)malloc(sizeof(struct inotify_event) + 4); 96 | if ( !event ) { 97 | fprintf( stderr, "Seem to be out of memory... yikes!\n" ); 98 | exit(EXIT_FAILURE); 99 | } 100 | event->wd = 0; 101 | event->mask = IN_ALL_EVENTS; 102 | event->len = 3; 103 | strcpy( event->name, "foo" ); 104 | FILE * devnull = fopen( "/dev/null", "a" ); 105 | if ( !devnull ) { 106 | fprintf( stderr, "Couldn't open /dev/null: %s\n", strerror(errno) ); 107 | free( event ); 108 | return; 109 | } 110 | if ( -1 == inotifytools_fprintf( devnull, event, fmt ) ) { 111 | fprintf( stderr, "Something is wrong with your format string.\n" ); 112 | exit(EXIT_FAILURE); 113 | } 114 | free( event ); 115 | fclose(devnull); 116 | } 117 | 118 | 119 | void output_event_csv( struct inotify_event * event ) { 120 | char *filename = csv_escape(inotifytools_filename_from_wd(event->wd)); 121 | if (filename != NULL) 122 | printf("%s,", csv_escape(filename)); 123 | 124 | printf("%s,", csv_escape( inotifytools_event_to_str( event->mask ) ) ); 125 | if ( event->len > 0 ) 126 | printf("%s", csv_escape( event->name ) ); 127 | printf("\n"); 128 | } 129 | 130 | 131 | void output_error( bool syslog, char* fmt, ... ) { 132 | va_list va; 133 | va_start(va, fmt); 134 | if ( syslog ) { 135 | vsyslog(LOG_INFO, fmt, va); 136 | } else { 137 | vfprintf(stderr, fmt, va); 138 | } 139 | va_end(va); 140 | } 141 | 142 | 143 | int main(int argc, char ** argv) 144 | { 145 | int events = 0; 146 | int orig_events; 147 | bool monitor = false; 148 | int quiet = 0; 149 | unsigned long int timeout = 0; 150 | int recursive = 0; 151 | bool csv = false; 152 | bool daemon = false; 153 | bool syslog = false; 154 | char * format = NULL; 155 | char * timefmt = NULL; 156 | char * fromfile = NULL; 157 | char * outfile = NULL; 158 | char * regex = NULL; 159 | char * iregex = NULL; 160 | pid_t pid; 161 | int fd; 162 | 163 | // Parse commandline options, aborting if something goes wrong 164 | if ( !parse_opts(&argc, &argv, &events, &monitor, &quiet, &timeout, 165 | &recursive, &csv, &daemon, &syslog, &format, &timefmt, 166 | &fromfile, &outfile, ®ex, &iregex) ) { 167 | return EXIT_FAILURE; 168 | } 169 | 170 | if ( !inotifytools_initialize() ) { 171 | fprintf(stderr, "Couldn't initialize inotify. Are you running Linux " 172 | "2.6.13 or later, and was the\n" 173 | "CONFIG_INOTIFY option enabled when your kernel was " 174 | "compiled? If so, \n" 175 | "something mysterious has gone wrong. Please e-mail " 176 | PACKAGE_BUGREPORT "\n" 177 | " and mention that you saw this message.\n"); 178 | return EXIT_FAILURE; 179 | } 180 | 181 | if ( timefmt ) inotifytools_set_printf_timefmt( timefmt ); 182 | if ( 183 | (regex && !inotifytools_ignore_events_by_regex(regex, REG_EXTENDED) ) || 184 | (iregex && !inotifytools_ignore_events_by_regex(iregex, REG_EXTENDED| 185 | REG_ICASE)) 186 | ) { 187 | fprintf(stderr, "Error in `exclude' regular expression.\n"); 188 | return EXIT_FAILURE; 189 | } 190 | 191 | 192 | if ( format ) validate_format(format); 193 | 194 | // Attempt to watch file 195 | // If events is still 0, make it all events. 196 | if (events == 0) 197 | events = IN_ALL_EVENTS; 198 | orig_events = events; 199 | if ( monitor && recursive ) { 200 | events = events | IN_CREATE | IN_MOVED_TO | IN_MOVED_FROM; 201 | } 202 | 203 | FileList list = construct_path_list( argc, argv, fromfile ); 204 | 205 | if (0 == list.watch_files[0]) { 206 | fprintf(stderr, "No files specified to watch!\n"); 207 | return EXIT_FAILURE; 208 | } 209 | 210 | 211 | // Daemonize - BSD double-fork approach 212 | if ( daemon ) { 213 | 214 | pid = fork(); 215 | if (pid < 0) { 216 | fprintf(stderr, "Failed to fork1 whilst daemonizing!\n"); 217 | return EXIT_FAILURE; 218 | } 219 | if (pid > 0) { 220 | _exit(0); 221 | } 222 | if (setsid() < 0) { 223 | fprintf(stderr, "Failed to setsid whilst daemonizing!\n"); 224 | return EXIT_FAILURE; 225 | } 226 | signal(SIGHUP,SIG_IGN); 227 | pid = fork(); 228 | if (pid < 0) { 229 | fprintf(stderr, "Failed to fork2 whilst daemonizing!\n"); 230 | return EXIT_FAILURE; 231 | } 232 | if (pid > 0) { 233 | _exit(0); 234 | } 235 | if (chdir("/") < 0) { 236 | fprintf(stderr, "Failed to chdir whilst daemonizing!\n"); 237 | return EXIT_FAILURE; 238 | } 239 | 240 | // Redirect stdin from /dev/null 241 | fd = open("/dev/null", O_RDONLY); 242 | if (fd != fileno(stdin)) { 243 | dup2(fd, fileno(stdin)); 244 | close(fd); 245 | } 246 | 247 | // Redirect stdout to a file 248 | fd = open(outfile, O_WRONLY | O_CREAT | O_APPEND, 0600); 249 | if (fd < 0) { 250 | fprintf( stderr, "Failed to open output file %s\n", outfile ); 251 | return EXIT_FAILURE; 252 | } 253 | if (fd != fileno(stdout)) { 254 | dup2(fd, fileno(stdout)); 255 | close(fd); 256 | } 257 | 258 | // Redirect stderr to /dev/null 259 | fd = open("/dev/null", O_WRONLY); 260 | if (fd != fileno(stderr)) { 261 | dup2(fd, fileno(stderr)); 262 | close(fd); 263 | } 264 | 265 | } else if (outfile != NULL) { // Redirect stdout to a file if specified 266 | fd = open(outfile, O_WRONLY | O_CREAT | O_APPEND, 0600); 267 | if (fd < 0) { 268 | fprintf( stderr, "Failed to open output file %s\n", outfile ); 269 | return EXIT_FAILURE; 270 | } 271 | if (fd != fileno(stdout)) { 272 | dup2(fd, fileno(stdout)); 273 | close(fd); 274 | } 275 | } 276 | 277 | if ( syslog ) { 278 | openlog ("inotifywait", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON); 279 | } 280 | 281 | if ( !quiet ) { 282 | if ( recursive ) { 283 | output_error( syslog, "Setting up watches. Beware: since -r " 284 | "was given, this may take a while!\n" ); 285 | } else { 286 | output_error( syslog, "Setting up watches.\n" ); 287 | } 288 | } 289 | 290 | // now watch files 291 | for ( int i = 0; list.watch_files[i]; ++i ) { 292 | char const *this_file = list.watch_files[i]; 293 | if ( (recursive && !inotifytools_watch_recursively_with_exclude( 294 | this_file, 295 | events, 296 | list.exclude_files )) 297 | || (!recursive && !inotifytools_watch_file( this_file, events )) ){ 298 | if ( inotifytools_error() == ENOSPC ) { 299 | output_error( syslog, "Failed to watch %s; upper limit on inotify " 300 | "watches reached!\n", this_file ); 301 | output_error( syslog, "Please increase the amount of inotify watches " 302 | "allowed per user via `/proc/sys/fs/inotify/" 303 | "max_user_watches'.\n"); 304 | } 305 | else { 306 | output_error( syslog, "Couldn't watch %s: %s\n", this_file, 307 | strerror( inotifytools_error() ) ); 308 | } 309 | return EXIT_FAILURE; 310 | } 311 | } 312 | 313 | if ( !quiet ) { 314 | output_error( syslog, "Watches established.\n" ); 315 | } 316 | 317 | // Now wait till we get event 318 | struct inotify_event * event; 319 | char * moved_from = 0; 320 | 321 | do { 322 | event = inotifytools_next_event( timeout ); 323 | if ( !event ) { 324 | if ( !inotifytools_error() ) { 325 | return EXIT_TIMEOUT; 326 | } 327 | else { 328 | output_error( syslog, "%s\n", strerror( inotifytools_error() ) ); 329 | return EXIT_FAILURE; 330 | } 331 | } 332 | 333 | if ( quiet < 2 && (event->mask & orig_events) ) { 334 | if ( csv ) { 335 | output_event_csv( event ); 336 | } 337 | else if ( format ) { 338 | inotifytools_printf( event, format ); 339 | } 340 | else { 341 | inotifytools_printf( event, "%w %,e %f\n" ); 342 | } 343 | } 344 | 345 | // if we last had MOVED_FROM and don't currently have MOVED_TO, 346 | // moved_from file must have been moved outside of tree - so unwatch it. 347 | if ( moved_from && !(event->mask & IN_MOVED_TO) ) { 348 | if ( !inotifytools_remove_watch_by_filename( moved_from ) ) { 349 | output_error( syslog, "Error removing watch on %s: %s\n", 350 | moved_from, strerror(inotifytools_error()) ); 351 | } 352 | free( moved_from ); 353 | moved_from = 0; 354 | } 355 | 356 | if ( monitor && recursive ) { 357 | if ((event->mask & IN_CREATE) || 358 | (!moved_from && (event->mask & IN_MOVED_TO))) { 359 | // New file - if it is a directory, watch it 360 | static char * new_file; 361 | 362 | nasprintf( &new_file, "%s%s", 363 | inotifytools_filename_from_wd( event->wd ), 364 | event->name ); 365 | 366 | if ( isdir(new_file) && 367 | !inotifytools_watch_recursively( new_file, events ) ) { 368 | output_error( syslog, "Couldn't watch new directory %s: %s\n", 369 | new_file, strerror( inotifytools_error() ) ); 370 | } 371 | free( new_file ); 372 | } // IN_CREATE 373 | else if (event->mask & IN_MOVED_FROM) { 374 | nasprintf( &moved_from, "%s%s/", 375 | inotifytools_filename_from_wd( event->wd ), 376 | event->name ); 377 | // if not watched... 378 | if ( inotifytools_wd_from_filename(moved_from) == -1 ) { 379 | free( moved_from ); 380 | moved_from = 0; 381 | } 382 | } // IN_MOVED_FROM 383 | else if (event->mask & IN_MOVED_TO) { 384 | if ( moved_from ) { 385 | static char * new_name; 386 | nasprintf( &new_name, "%s%s/", 387 | inotifytools_filename_from_wd( event->wd ), 388 | event->name ); 389 | inotifytools_replace_filename( moved_from, new_name ); 390 | free( moved_from ); 391 | moved_from = 0; 392 | } // moved_from 393 | } 394 | } 395 | 396 | fflush( NULL ); 397 | 398 | } while ( monitor ); 399 | 400 | // If we weren't trying to listen for this event... 401 | if ( (events & event->mask) == 0 ) { 402 | // ...then most likely something bad happened, like IGNORE etc. 403 | return EXIT_FAILURE; 404 | } 405 | 406 | return EXIT_SUCCESS; 407 | } 408 | 409 | 410 | bool parse_opts( 411 | int * argc, 412 | char *** argv, 413 | int * events, 414 | bool * monitor, 415 | int * quiet, 416 | unsigned long int * timeout, 417 | int * recursive, 418 | bool * csv, 419 | bool * daemon, 420 | bool * syslog, 421 | char ** format, 422 | char ** timefmt, 423 | char ** fromfile, 424 | char ** outfile, 425 | char ** regex, 426 | char ** iregex 427 | ) { 428 | assert( argc ); assert( argv ); assert( events ); assert( monitor ); 429 | assert( quiet ); assert( timeout ); assert( csv ); assert( daemon ); 430 | assert( syslog ); assert( format ); assert( timefmt ); assert( fromfile ); 431 | assert( outfile ); assert( regex ); assert( iregex ); 432 | 433 | // Short options 434 | char * opt_string = "mrhcdsqt:fo:e:"; 435 | 436 | // Construct array 437 | struct option long_opts[17]; 438 | 439 | // --help 440 | long_opts[0].name = "help"; 441 | long_opts[0].has_arg = 0; 442 | long_opts[0].flag = NULL; 443 | long_opts[0].val = (int)'h'; 444 | // --event 445 | long_opts[1].name = "event"; 446 | long_opts[1].has_arg = 1; 447 | long_opts[1].flag = NULL; 448 | long_opts[1].val = (int)'e'; 449 | int new_event; 450 | // --monitor 451 | long_opts[2].name = "monitor"; 452 | long_opts[2].has_arg = 0; 453 | long_opts[2].flag = NULL; 454 | long_opts[2].val = (int)'m'; 455 | // --quiet 456 | long_opts[3].name = "quiet"; 457 | long_opts[3].has_arg = 0; 458 | long_opts[3].flag = NULL; 459 | long_opts[3].val = (int)'q'; 460 | // --timeout 461 | long_opts[4].name = "timeout"; 462 | long_opts[4].has_arg = 1; 463 | long_opts[4].flag = NULL; 464 | long_opts[4].val = (int)'t'; 465 | char * timeout_end = NULL; 466 | // --filename 467 | long_opts[5].name = "filename"; 468 | long_opts[5].has_arg = 0; 469 | long_opts[5].flag = NULL; 470 | long_opts[5].val = (int)'f'; 471 | // --recursive 472 | long_opts[6].name = "recursive"; 473 | long_opts[6].has_arg = 0; 474 | long_opts[6].flag = NULL; 475 | long_opts[6].val = (int)'r'; 476 | // --csv 477 | long_opts[7].name = "csv"; 478 | long_opts[7].has_arg = 0; 479 | long_opts[7].flag = NULL; 480 | long_opts[7].val = (int)'c'; 481 | // --daemon 482 | long_opts[8].name = "daemon"; 483 | long_opts[8].has_arg = 0; 484 | long_opts[8].flag = NULL; 485 | long_opts[8].val = (int)'d'; 486 | // --syslog 487 | long_opts[9].name = "syslog"; 488 | long_opts[9].has_arg = 0; 489 | long_opts[9].flag = NULL; 490 | long_opts[9].val = (int)'s'; 491 | // --format 492 | long_opts[10].name = "format"; 493 | long_opts[10].has_arg = 1; 494 | long_opts[10].flag = NULL; 495 | long_opts[10].val = (int)'n'; 496 | // format with trailing newline 497 | static char * newlineformat; 498 | // --timefmt 499 | long_opts[11].name = "timefmt"; 500 | long_opts[11].has_arg = 1; 501 | long_opts[11].flag = NULL; 502 | long_opts[11].val = (int)'i'; 503 | // --fromfile 504 | long_opts[12].name = "fromfile"; 505 | long_opts[12].has_arg = 1; 506 | long_opts[12].flag = NULL; 507 | long_opts[12].val = (int)'z'; 508 | // --outfile 509 | long_opts[13].name = "outfile"; 510 | long_opts[13].has_arg = 1; 511 | long_opts[13].flag = NULL; 512 | long_opts[13].val = (int)'o'; 513 | // --exclude 514 | long_opts[14].name = "exclude"; 515 | long_opts[14].has_arg = 1; 516 | long_opts[14].flag = NULL; 517 | long_opts[14].val = (int)'a'; 518 | // --excludei 519 | long_opts[15].name = "excludei"; 520 | long_opts[15].has_arg = 1; 521 | long_opts[15].flag = NULL; 522 | long_opts[15].val = (int)'b'; 523 | // Empty last element 524 | long_opts[16].name = 0; 525 | long_opts[16].has_arg = 0; 526 | long_opts[16].flag = 0; 527 | long_opts[16].val = 0; 528 | 529 | // Get first option 530 | char curr_opt = getopt_long(*argc, *argv, opt_string, long_opts, NULL); 531 | 532 | // While more options exist... 533 | while ( (curr_opt != '?') && (curr_opt != (char)-1) ) 534 | { 535 | switch ( curr_opt ) 536 | { 537 | // --help or -h 538 | case 'h': 539 | print_help(); 540 | // Shouldn't process any further... 541 | return false; 542 | break; 543 | 544 | // --monitor or -m 545 | case 'm': 546 | *monitor = true; 547 | break; 548 | 549 | // --quiet or -q 550 | case 'q': 551 | (*quiet)++; 552 | break; 553 | 554 | // --recursive or -r 555 | case 'r': 556 | (*recursive)++; 557 | break; 558 | 559 | // --csv or -c 560 | case 'c': 561 | (*csv) = true; 562 | break; 563 | 564 | // --daemon or -d 565 | case 'd': 566 | (*daemon) = true; 567 | (*monitor) = true; 568 | (*syslog) = true; 569 | break; 570 | 571 | // --syslog or -s 572 | case 's': 573 | (*syslog) = true; 574 | break; 575 | 576 | // --filename or -f 577 | case 'f': 578 | fprintf(stderr, "The '--filename' option no longer exists. " 579 | "The option it enabled in earlier\nversions of " 580 | "inotifywait is now turned on by default.\n"); 581 | return false; 582 | break; 583 | 584 | // --format 585 | case 'n': 586 | newlineformat = (char *)malloc(strlen(optarg)+2); 587 | strcpy( newlineformat, optarg ); 588 | strcat( newlineformat, "\n" ); 589 | (*format) = newlineformat; 590 | break; 591 | 592 | // --timefmt 593 | case 'i': 594 | (*timefmt) = optarg; 595 | break; 596 | 597 | // --exclude 598 | case 'a': 599 | (*regex) = optarg; 600 | break; 601 | 602 | // --excludei 603 | case 'b': 604 | (*iregex) = optarg; 605 | break; 606 | 607 | // --fromfile 608 | case 'z': 609 | if (*fromfile) { 610 | fprintf(stderr, "Multiple --fromfile options given.\n"); 611 | return false; 612 | } 613 | (*fromfile) = optarg; 614 | break; 615 | 616 | // --outfile 617 | case 'o': 618 | if (*outfile) { 619 | fprintf(stderr, "Multiple --outfile options given.\n"); 620 | return false; 621 | } 622 | (*outfile) = optarg; 623 | break; 624 | 625 | // --timeout or -t 626 | case 't': 627 | *timeout = strtoul(optarg, &timeout_end, 10); 628 | if ( *timeout_end != '\0' ) 629 | { 630 | fprintf(stderr, "'%s' is not a valid timeout value.\n" 631 | "Please specify an integer of value 0 or " 632 | "greater.\n", 633 | optarg); 634 | return false; 635 | } 636 | break; 637 | 638 | // --event or -e 639 | case 'e': 640 | // Get event mask from event string 641 | new_event = inotifytools_str_to_event(optarg); 642 | 643 | // If optarg was invalid, abort 644 | if ( new_event == -1 ) 645 | { 646 | fprintf(stderr, "'%s' is not a valid event! Run with the " 647 | "'--help' option to see a list of " 648 | "events.\n", optarg); 649 | return false; 650 | } 651 | 652 | // Add the new event to the event mask 653 | (*events) = ( (*events) | new_event ); 654 | 655 | break; 656 | 657 | 658 | } 659 | 660 | curr_opt = getopt_long(*argc, *argv, opt_string, long_opts, NULL); 661 | 662 | } 663 | 664 | if ( *monitor && *timeout != 0 ) { 665 | fprintf(stderr, "-m and -t cannot both be specified.\n"); 666 | return false; 667 | } 668 | 669 | if ( *regex && *iregex ) { 670 | fprintf(stderr, "--exclude and --excludei cannot both be specified.\n"); 671 | return false; 672 | } 673 | 674 | if ( *format && *csv ) { 675 | fprintf(stderr, "-c and --format cannot both be specified.\n"); 676 | return false; 677 | } 678 | 679 | if ( !*format && *timefmt ) { 680 | fprintf(stderr, "--timefmt cannot be specified without --format.\n"); 681 | return false; 682 | } 683 | 684 | if ( *format && strstr( *format, "%T" ) && !*timefmt ) { 685 | fprintf(stderr, "%%T is in --format string, but --timefmt was not " 686 | "specified.\n"); 687 | return false; 688 | } 689 | 690 | if ( *daemon && *outfile == NULL ) { 691 | fprintf(stderr, "-o must be specified with -d.\n"); 692 | return false; 693 | } 694 | 695 | (*argc) -= optind; 696 | *argv = &(*argv)[optind]; 697 | 698 | // If ? returned, invalid option 699 | return (curr_opt != '?'); 700 | } 701 | 702 | 703 | void print_help() 704 | { 705 | printf("inotifywait %s\n", PACKAGE_VERSION); 706 | printf("Wait for a particular event on a file or set of files.\n"); 707 | printf("Usage: inotifywait [ options ] file1 [ file2 ] [ file3 ] " 708 | "[ ... ]\n"); 709 | printf("Options:\n"); 710 | printf("\t-h|--help \tShow this help text.\n"); 711 | printf("\t@ \tExclude the specified file from being " 712 | "watched.\n"); 713 | printf("\t--exclude \n" 714 | "\t \tExclude all events on files matching the\n" 715 | "\t \textended regular expression .\n"); 716 | printf("\t--excludei \n" 717 | "\t \tLike --exclude but case insensitive.\n"); 718 | printf("\t-m|--monitor \tKeep listening for events forever. Without\n" 719 | "\t \tthis option, inotifywait will exit after one\n" 720 | "\t \tevent is received.\n"); 721 | printf("\t-d|--daemon \tSame as --monitor, except run in the background\n" 722 | "\t \tlogging events to a file specified by --outfile.\n" 723 | "\t \tImplies --syslog.\n"); 724 | printf("\t-r|--recursive\tWatch directories recursively.\n"); 725 | printf("\t--fromfile \n" 726 | "\t \tRead files to watch from or `-' for " 727 | "stdin.\n"); 728 | printf("\t-o|--outfile \n" 729 | "\t \tPrint events to rather than stdout.\n"); 730 | printf("\t-s|--syslog \tSend errors to syslog rather than stderr.\n"); 731 | printf("\t-q|--quiet \tPrint less (only print events).\n"); 732 | printf("\t-qq \tPrint nothing (not even events).\n"); 733 | printf("\t--format \tPrint using a specified printf-like format\n" 734 | "\t \tstring; read the man page for more details.\n"); 735 | printf("\t--timefmt \tstrftime-compatible format string for use with\n" 736 | "\t \t%%T in --format string.\n"); 737 | printf("\t-c|--csv \tPrint events in CSV format.\n"); 738 | printf("\t-t|--timeout \n" 739 | "\t \tWhen listening for a single event, time out " 740 | "after\n" 741 | "\t \twaiting for an event for seconds.\n" 742 | "\t \tIf is 0, inotifywait will never time " 743 | "out.\n"); 744 | printf("\t-e|--event [ -e|--event ... ]\n" 745 | "\t\tListen for specific event(s). If omitted, all events are \n" 746 | "\t\tlistened for.\n\n"); 747 | printf("Exit status:\n"); 748 | printf("\t%d - An event you asked to watch for was received.\n", 749 | EXIT_SUCCESS ); 750 | printf("\t%d - An event you did not ask to watch for was received\n", 751 | EXIT_FAILURE); 752 | printf("\t (usually delete_self or unmount), or some error " 753 | "occurred.\n"); 754 | printf("\t%d - The --timeout option was given and no events occurred\n", 755 | EXIT_TIMEOUT); 756 | printf("\t in the specified interval of time.\n\n"); 757 | printf("Events:\n"); 758 | print_event_descriptions(); 759 | } 760 | -------------------------------------------------------------------------------- /jni/inotifywatch.c: -------------------------------------------------------------------------------- 1 | // FIXME this is cheating! Make this use only the public API. 2 | #include "libinotifytools/inotifytools_p.h" 3 | #include "../config.h" 4 | #include "common.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "regex/regex.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "libinotifytools/inotifytools/inotifytools.h" 24 | #include "libinotifytools/inotifytools/inotify.h" 25 | 26 | 27 | extern char *optarg; 28 | extern int optind, opterr, optopt; 29 | 30 | #define EXCLUDE_CHUNK 1024 31 | 32 | #define nasprintf(...) niceassert( -1 != asprintf(__VA_ARGS__), "out of memory") 33 | 34 | // METHODS 35 | bool parse_opts( 36 | int * argc, 37 | char *** argv, 38 | int * events, 39 | int * timeout, 40 | int * verbose, 41 | int * zero, 42 | int * sort, 43 | int * recursive, 44 | char ** fromfile, 45 | char ** regex, 46 | char ** iregex 47 | ); 48 | 49 | void print_help(); 50 | 51 | static bool done; 52 | 53 | void handle_impatient_user( int signal __attribute__((unused)) ) { 54 | static int times_called = 0; 55 | if ( times_called ) { 56 | fprintf( stderr, "No statistics collected, asked to abort before all " 57 | "watches could be established.\n" ); 58 | exit(1); 59 | } 60 | fprintf( stderr, "No statistics have been collected because I haven't " 61 | "finished establishing\n" 62 | "inotify watches yet. If you are sure you want me to exit, " 63 | "interrupt me again.\n" ); 64 | ++times_called; 65 | } 66 | 67 | void handle_signal( int signal __attribute__((unused)) ) { 68 | done = true; 69 | } 70 | 71 | int print_info(); 72 | 73 | void print_info_now( int signal __attribute__((unused)) ) { 74 | print_info(); 75 | printf("\n"); 76 | } 77 | 78 | int events; 79 | int sort; 80 | int zero; 81 | 82 | int main(int argc, char ** argv) 83 | { 84 | events = 0; 85 | int timeout = 0; 86 | int verbose = 0; 87 | zero = 0; 88 | int recursive = 0; 89 | char * fromfile = 0; 90 | sort = -1; 91 | done = false; 92 | char * regex = NULL; 93 | char * iregex = NULL; 94 | 95 | signal( SIGINT, handle_impatient_user ); 96 | 97 | // Parse commandline options, aborting if something goes wrong 98 | if ( !parse_opts( &argc, &argv, &events, &timeout, &verbose, &zero, &sort, 99 | &recursive, &fromfile, ®ex, &iregex ) ) { 100 | return EXIT_FAILURE; 101 | } 102 | 103 | if ( 104 | (regex && !inotifytools_ignore_events_by_regex(regex, REG_EXTENDED) ) || 105 | (iregex && !inotifytools_ignore_events_by_regex(iregex, REG_EXTENDED| 106 | REG_ICASE)) 107 | ) { 108 | fprintf(stderr, "Error in `exclude' regular expression.\n"); 109 | return EXIT_FAILURE; 110 | } 111 | 112 | if ( !inotifytools_initialize() ) { 113 | fprintf(stderr, "Couldn't initialize inotify. Are you running Linux " 114 | "2.6.13 or later, and was the\n" 115 | "CONFIG_INOTIFY option enabled when your kernel was " 116 | "compiled? If so, \n" 117 | "something mysterious has gone wrong. Please e-mail " 118 | PACKAGE_BUGREPORT "\n" 119 | " and mention that you saw this message.\n"); 120 | return EXIT_FAILURE; 121 | } 122 | 123 | // Attempt to watch file 124 | // If events is still 0, make it all events. 125 | if ( !events ) 126 | events = IN_ALL_EVENTS; 127 | 128 | FileList list = construct_path_list( argc, argv, fromfile ); 129 | 130 | if (0 == list.watch_files[0]) { 131 | fprintf(stderr, "No files specified to watch!\n"); 132 | return EXIT_FAILURE; 133 | } 134 | 135 | unsigned int num_watches = 0; 136 | unsigned int status; 137 | fprintf( stderr, "Establishing watches...\n" ); 138 | for ( int i = 0; list.watch_files[i]; ++i ) { 139 | char const *this_file = list.watch_files[i]; 140 | if ( recursive && verbose ) { 141 | fprintf( stderr, "Setting up watch(es) on %s\n", this_file ); 142 | } 143 | 144 | if ( recursive ) { 145 | status = inotifytools_watch_recursively_with_exclude( 146 | this_file, 147 | events, 148 | list.exclude_files ); 149 | } 150 | else { 151 | status = inotifytools_watch_file( this_file, events ); 152 | } 153 | if ( !status ) { 154 | if ( inotifytools_error() == ENOSPC ) { 155 | fprintf(stderr, "Failed to watch %s; upper limit on inotify " 156 | "watches reached!\n", this_file ); 157 | fprintf(stderr, "Please increase the amount of inotify watches " 158 | "allowed per user via `/proc/sys/fs/inotify/" 159 | "max_user_watches'.\n"); 160 | } 161 | else { 162 | fprintf(stderr, "Failed to watch %s: %s\n", this_file, 163 | strerror( inotifytools_error() ) ); 164 | } 165 | return EXIT_FAILURE; 166 | } 167 | if ( recursive && verbose ) { 168 | fprintf( stderr, "OK, %s is now being watched.\n", this_file ); 169 | } 170 | } 171 | num_watches = inotifytools_get_num_watches(); 172 | 173 | if ( verbose ) { 174 | fprintf( stderr, "Total of %d watches.\n", 175 | num_watches ); 176 | } 177 | fprintf( stderr, "Finished establishing watches, now collecting statistics.\n" ); 178 | 179 | if ( timeout && verbose ) { 180 | fprintf( stderr, "Will listen for events for %d seconds.\n", timeout ); 181 | } 182 | 183 | signal( SIGINT, handle_signal ); 184 | signal( SIGHUP, handle_signal ); 185 | signal( SIGTERM, handle_signal ); 186 | if ( timeout ) { 187 | signal( SIGALRM, handle_signal ); 188 | alarm( timeout ); 189 | } 190 | signal( SIGUSR1, print_info_now ); 191 | 192 | inotifytools_initialize_stats(); 193 | // Now wait till we get event 194 | struct inotify_event * event; 195 | char * moved_from = 0; 196 | 197 | do { 198 | event = inotifytools_next_event( 0 ); 199 | if ( !event ) { 200 | if ( !inotifytools_error() ) { 201 | return EXIT_TIMEOUT; 202 | } 203 | else if ( inotifytools_error() != EINTR ) { 204 | fprintf(stderr, "%s\n", strerror( inotifytools_error() ) ); 205 | return EXIT_FAILURE; 206 | } 207 | else { 208 | continue; 209 | } 210 | } 211 | 212 | // if we last had MOVED_FROM and don't currently have MOVED_TO, 213 | // moved_from file must have been moved outside of tree - so unwatch it. 214 | if ( moved_from && !(event->mask & IN_MOVED_TO) ) { 215 | if ( !inotifytools_remove_watch_by_filename( moved_from ) ) { 216 | fprintf( stderr, "Error removing watch on %s: %s\n", 217 | moved_from, strerror(inotifytools_error()) ); 218 | } 219 | free( moved_from ); 220 | moved_from = 0; 221 | } 222 | 223 | if ( recursive ) { 224 | if ((event->mask & IN_CREATE) || 225 | (!moved_from && (event->mask & IN_MOVED_TO))) { 226 | // New file - if it is a directory, watch it 227 | static char * new_file; 228 | 229 | nasprintf( &new_file, "%s%s", 230 | inotifytools_filename_from_wd( event->wd ), 231 | event->name ); 232 | 233 | if ( isdir(new_file) && 234 | !inotifytools_watch_recursively( new_file, events ) ) { 235 | fprintf( stderr, "Couldn't watch new directory %s: %s\n", 236 | new_file, strerror( inotifytools_error() ) ); 237 | } 238 | free( new_file ); 239 | } // IN_CREATE 240 | else if (event->mask & IN_MOVED_FROM) { 241 | nasprintf( &moved_from, "%s%s/", 242 | inotifytools_filename_from_wd( event->wd ), 243 | event->name ); 244 | // if not watched... 245 | if ( inotifytools_wd_from_filename(moved_from) == -1 ) { 246 | free( moved_from ); 247 | moved_from = 0; 248 | } 249 | } // IN_MOVED_FROM 250 | else if (event->mask & IN_MOVED_TO) { 251 | if ( moved_from ) { 252 | static char * new_name; 253 | nasprintf( &new_name, "%s%s/", 254 | inotifytools_filename_from_wd( event->wd ), 255 | event->name ); 256 | inotifytools_replace_filename( moved_from, new_name ); 257 | free( moved_from ); 258 | moved_from = 0; 259 | } // moved_from 260 | } 261 | } 262 | 263 | } while ( !done ); 264 | return print_info(); 265 | } 266 | 267 | int print_info() { 268 | unsigned int num_watches = 0; 269 | num_watches = inotifytools_get_num_watches(); 270 | 271 | if ( !inotifytools_get_stat_total( 0 ) ) { 272 | fprintf( stderr, "No events occurred.\n" ); 273 | return EXIT_SUCCESS; 274 | } 275 | 276 | // OK, go through the watches and print stats. 277 | printf("total "); 278 | if ( (IN_ACCESS & events) && 279 | ( zero || inotifytools_get_stat_total( IN_ACCESS ) ) ) 280 | printf("access "); 281 | if ( ( IN_MODIFY & events) && 282 | ( zero || inotifytools_get_stat_total( IN_MODIFY ) ) ) 283 | printf("modify "); 284 | if ( ( IN_ATTRIB & events) && 285 | ( zero || inotifytools_get_stat_total( IN_ATTRIB ) ) ) 286 | printf("attrib "); 287 | if ( ( IN_CLOSE_WRITE & events) && 288 | ( zero || inotifytools_get_stat_total( IN_CLOSE_WRITE ) ) ) 289 | printf("close_write "); 290 | if ( ( IN_CLOSE_NOWRITE & events) && 291 | ( zero || inotifytools_get_stat_total( IN_CLOSE_NOWRITE ) ) ) 292 | printf("close_nowrite "); 293 | if ( ( IN_OPEN & events) && 294 | ( zero || inotifytools_get_stat_total( IN_OPEN ) ) ) 295 | printf("open "); 296 | if ( ( IN_MOVED_FROM & events) && 297 | ( zero || inotifytools_get_stat_total( IN_MOVED_FROM ) ) ) 298 | printf("moved_from "); 299 | if ( ( IN_MOVED_TO & events) && 300 | ( zero || inotifytools_get_stat_total( IN_MOVED_TO ) ) ) 301 | printf("moved_to "); 302 | if ( ( IN_MOVE_SELF & events) && 303 | ( zero || inotifytools_get_stat_total( IN_MOVE_SELF ) ) ) 304 | printf("move_self "); 305 | if ( ( IN_CREATE & events) && 306 | ( zero || inotifytools_get_stat_total( IN_CREATE ) ) ) 307 | printf("create "); 308 | if ( ( IN_DELETE & events) && 309 | ( zero || inotifytools_get_stat_total( IN_DELETE ) ) ) 310 | printf("delete "); 311 | if ( ( IN_DELETE_SELF & events) && 312 | ( zero || inotifytools_get_stat_total( IN_DELETE_SELF ) ) ) 313 | printf("delete_self "); 314 | if ( ( IN_UNMOUNT & events) && 315 | ( zero || inotifytools_get_stat_total( IN_UNMOUNT ) ) ) 316 | printf("unmount "); 317 | 318 | printf("filename\n"); 319 | 320 | struct rbtree *tree = inotifytools_wd_sorted_by_event(sort); 321 | RBLIST *rblist = rbopenlist(tree); 322 | watch *w = (watch*)rbreadlist(rblist); 323 | 324 | while (w) { 325 | if ( !zero && !w->hit_total ) { 326 | w = (watch*)rbreadlist(rblist); 327 | continue; 328 | } 329 | printf("%-5u ", w->hit_total ); 330 | if ( ( IN_ACCESS & events) && 331 | ( zero || inotifytools_get_stat_total( IN_ACCESS ) ) ) 332 | printf("%-6u ", w->hit_access ); 333 | if ( ( IN_MODIFY & events) && 334 | ( zero || inotifytools_get_stat_total( IN_MODIFY ) ) ) 335 | printf("%-6u ", w->hit_modify ); 336 | if ( ( IN_ATTRIB & events) && 337 | ( zero || inotifytools_get_stat_total( IN_ATTRIB ) ) ) 338 | printf("%-6u ", w->hit_attrib ); 339 | if ( ( IN_CLOSE_WRITE & events) && 340 | ( zero || inotifytools_get_stat_total( IN_CLOSE_WRITE ) ) ) 341 | printf("%-11u ",w->hit_close_write ); 342 | if ( ( IN_CLOSE_NOWRITE & events) && 343 | ( zero || inotifytools_get_stat_total( IN_CLOSE_NOWRITE ) ) ) 344 | printf("%-13u ",w->hit_close_nowrite ); 345 | if ( ( IN_OPEN & events) && 346 | ( zero || inotifytools_get_stat_total( IN_OPEN ) ) ) 347 | printf("%-4u ", w->hit_open ); 348 | if ( ( IN_MOVED_FROM & events) && 349 | ( zero || inotifytools_get_stat_total( IN_MOVED_FROM ) ) ) 350 | printf("%-10u ", w->hit_moved_from ); 351 | if ( ( IN_MOVED_TO & events) && 352 | ( zero || inotifytools_get_stat_total( IN_MOVED_TO ) ) ) 353 | printf("%-8u ", w->hit_moved_to ); 354 | if ( ( IN_MOVE_SELF & events) && 355 | ( zero || inotifytools_get_stat_total( IN_MOVE_SELF ) ) ) 356 | printf("%-9u ", w->hit_move_self ); 357 | if ( ( IN_CREATE & events) && 358 | ( zero || inotifytools_get_stat_total( IN_CREATE ) ) ) 359 | printf("%-6u ", w->hit_create ); 360 | if ( ( IN_DELETE & events) && 361 | ( zero || inotifytools_get_stat_total( IN_DELETE ) ) ) 362 | printf("%-6u ", w->hit_delete ); 363 | if ( ( IN_DELETE_SELF & events) && 364 | ( zero || inotifytools_get_stat_total( IN_DELETE_SELF ) ) ) 365 | printf("%-11u ",w->hit_delete_self ); 366 | if ( ( IN_UNMOUNT & events) && 367 | ( zero || inotifytools_get_stat_total( IN_UNMOUNT ) ) ) 368 | printf("%-7u ", w->hit_unmount ); 369 | 370 | printf("%s\n", w->filename ); 371 | w = (watch*)rbreadlist(rblist); 372 | } 373 | rbcloselist(rblist); 374 | rbdestroy(tree); 375 | 376 | return EXIT_SUCCESS; 377 | } 378 | 379 | 380 | 381 | 382 | bool parse_opts( 383 | int * argc, 384 | char *** argv, 385 | int * events, 386 | int * timeout, 387 | int * verbose, 388 | int * zero, 389 | int * sort, 390 | int * recursive, 391 | char ** fromfile, 392 | char ** regex, 393 | char ** iregex 394 | ) { 395 | assert( argc ); assert( argv ); assert( events ); assert( timeout ); 396 | assert( verbose ); assert( zero ); assert( sort ); assert( recursive ); 397 | assert( fromfile ); assert( regex ); assert( iregex ); 398 | 399 | // Short options 400 | char * opt_string = "hra:d:zve:t:"; 401 | 402 | // Construct array 403 | struct option long_opts[12]; 404 | 405 | // --help 406 | long_opts[0].name = "help"; 407 | long_opts[0].has_arg = 0; 408 | long_opts[0].flag = NULL; 409 | long_opts[0].val = (int)'h'; 410 | // --event 411 | long_opts[1].name = "event"; 412 | long_opts[1].has_arg = 1; 413 | long_opts[1].flag = NULL; 414 | long_opts[1].val = (int)'e'; 415 | int new_event; 416 | // --timeout 417 | long_opts[2].name = "timeout"; 418 | long_opts[2].has_arg = 1; 419 | long_opts[2].flag = NULL; 420 | long_opts[2].val = (int)'t'; 421 | char * timeout_end = NULL; 422 | // --verbose 423 | long_opts[3].name = "verbose"; 424 | long_opts[3].has_arg = 0; 425 | long_opts[3].flag = NULL; 426 | long_opts[3].val = (int)'v'; 427 | // --nonzero 428 | long_opts[4].name = "zero"; 429 | long_opts[4].has_arg = 0; 430 | long_opts[4].flag = NULL; 431 | long_opts[4].val = (int)'z'; 432 | // --ascending 433 | long_opts[5].name = "ascending"; 434 | long_opts[5].has_arg = 1; 435 | long_opts[5].flag = NULL; 436 | long_opts[5].val = (int)'a'; 437 | bool sort_set = false; 438 | // --descending 439 | long_opts[6].name = "descending"; 440 | long_opts[6].has_arg = 1; 441 | long_opts[6].flag = NULL; 442 | long_opts[6].val = (int)'d'; 443 | // --recursive 444 | long_opts[7].name = "recursive"; 445 | long_opts[7].has_arg = 0; 446 | long_opts[7].flag = NULL; 447 | long_opts[7].val = (int)'r'; 448 | // --fromfile 449 | long_opts[8].name = "fromfile"; 450 | long_opts[8].has_arg = 1; 451 | long_opts[8].flag = NULL; 452 | long_opts[8].val = (int)'o'; 453 | // --exclude 454 | long_opts[9].name = "exclude"; 455 | long_opts[9].has_arg = 1; 456 | long_opts[9].flag = NULL; 457 | long_opts[9].val = (int)'c'; 458 | // --excludei 459 | long_opts[10].name = "excludei"; 460 | long_opts[10].has_arg = 1; 461 | long_opts[10].flag = NULL; 462 | long_opts[10].val = (int)'b'; 463 | // Empty last element 464 | long_opts[11].name = 0; 465 | long_opts[11].has_arg = 0; 466 | long_opts[11].flag = 0; 467 | long_opts[11].val = 0; 468 | 469 | // Get first option 470 | char curr_opt = getopt_long(*argc, *argv, opt_string, long_opts, NULL); 471 | 472 | // While more options exist... 473 | while ( (curr_opt != '?') && (curr_opt != (char)-1) ) 474 | { 475 | switch ( curr_opt ) 476 | { 477 | // --help or -h 478 | case 'h': 479 | print_help(); 480 | // Shouldn't process any further... 481 | return false; 482 | break; 483 | 484 | // --verbose or -v 485 | case 'v': 486 | ++(*verbose); 487 | break; 488 | 489 | // --recursive or -r 490 | case 'r': 491 | ++(*recursive); 492 | break; 493 | 494 | // --zero or -z 495 | case 'z': 496 | ++(*zero); 497 | break; 498 | 499 | // --exclude 500 | case 'c': 501 | (*regex) = optarg; 502 | break; 503 | 504 | // --excludei 505 | case 'b': 506 | (*iregex) = optarg; 507 | break; 508 | 509 | // --fromfile 510 | case 'o': 511 | if (*fromfile) { 512 | fprintf(stderr, "Multiple --fromfile options given.\n"); 513 | return false; 514 | } 515 | (*fromfile) = optarg; 516 | break; 517 | 518 | // --timeout or -t 519 | case 't': 520 | *timeout = strtoul(optarg, &timeout_end, 10); 521 | if ( *timeout_end != '\0' || *timeout < 0) 522 | { 523 | fprintf(stderr, "'%s' is not a valid timeout value.\n" 524 | "Please specify an integer of value 0 or " 525 | "greater.\n", 526 | optarg); 527 | return false; 528 | } 529 | break; 530 | 531 | // --event or -e 532 | case 'e': 533 | // Get event mask from event string 534 | new_event = inotifytools_str_to_event(optarg); 535 | 536 | // If optarg was invalid, abort 537 | if ( new_event == -1 ) { 538 | fprintf(stderr, "'%s' is not a valid event! Run with the " 539 | "'--help' option to see a list of " 540 | "events.\n", optarg); 541 | return false; 542 | } 543 | 544 | // Add the new event to the event mask 545 | (*events) = ( (*events) | new_event ); 546 | 547 | break; 548 | 549 | // --ascending or -a 550 | case 'a': 551 | if ( sort_set ) { 552 | fprintf( stderr, "Please specify -a or -d once only!\n" ); 553 | return false; 554 | } 555 | if ( 0 == strcasecmp( optarg, "total" ) ) { 556 | (*sort) = 0; 557 | } 558 | else if ( 0 == strcasecmp( optarg, "move" ) ) { 559 | fprintf( stderr, "Cannot sort by `move' event; please use " 560 | "`moved_from' or `moved_to'.\n" ); 561 | return false; 562 | } 563 | else if ( 0 == strcasecmp( optarg, "close" ) ) { 564 | fprintf( stderr, "Cannot sort by `close' event; please use " 565 | "`close_write' or `close_nowrite'.\n" ); 566 | return false; 567 | } 568 | else { 569 | int event = inotifytools_str_to_event(optarg); 570 | 571 | // If optarg was invalid, abort 572 | if ( event == -1 ) { 573 | fprintf(stderr, "'%s' is not a valid key for " 574 | "sorting!\n", optarg); 575 | return false; 576 | } 577 | 578 | (*sort) = event; 579 | } 580 | sort_set = true; 581 | break; 582 | 583 | 584 | // --descending or -d 585 | case 'd': 586 | if ( sort_set ) { 587 | fprintf( stderr, "Please specify -a or -d once only!\n" ); 588 | return false; 589 | } 590 | if ( 0 == strcasecmp( optarg, "total" ) ) { 591 | (*sort) = -1; 592 | } 593 | else { 594 | int event = inotifytools_str_to_event(optarg); 595 | 596 | // If optarg was invalid, abort 597 | if ( event == -1 ) { 598 | fprintf(stderr, "'%s' is not a valid key for " 599 | "sorting!\n", optarg); 600 | return false; 601 | } 602 | 603 | (*sort) = -event; 604 | } 605 | break; 606 | 607 | } 608 | 609 | curr_opt = getopt_long(*argc, *argv, opt_string, long_opts, NULL); 610 | 611 | } 612 | 613 | (*argc) -= optind; 614 | *argv = &(*argv)[optind]; 615 | 616 | if ( (*sort) != 0 && (*sort) != -1 && 617 | !(abs(*sort) & ((*events) ? (*events) : IN_ALL_EVENTS) )) { 618 | fprintf( stderr, "Can't sort by an event which isn't being watched " 619 | "for!\n" ); 620 | return false; 621 | } 622 | 623 | if ( *regex && *iregex ) { 624 | fprintf(stderr, "--exclude and --excludei cannot both be specified.\n"); 625 | return false; 626 | } 627 | 628 | // If ? returned, invalid option 629 | return (curr_opt != '?'); 630 | } 631 | 632 | 633 | void print_help() 634 | { 635 | printf("inotifywatch %s\n", PACKAGE_VERSION); 636 | printf("Gather filesystem usage statistics using inotify.\n"); 637 | printf("Usage: inotifywatch [ options ] file1 [ file2 ] [ ... ]\n"); 638 | printf("Options:\n"); 639 | printf("\t-h|--help \tShow this help text.\n"); 640 | printf("\t-v|--verbose \tBe verbose.\n"); 641 | printf("\t@ \tExclude the specified file from being " 642 | "watched.\n"); 643 | printf("\t--fromfile \n" 644 | "\t\tRead files to watch from or `-' for stdin.\n"); 645 | printf("\t--exclude \n" 646 | "\t\tExclude all events on files matching the extended regular\n" 647 | "\t\texpression .\n"); 648 | printf("\t--excludei \n" 649 | "\t\tLike --exclude but case insensitive.\n"); 650 | printf("\t-z|--zero\n" 651 | "\t\tIn the final table of results, output rows and columns even\n" 652 | "\t\tif they consist only of zeros (the default is to not output\n" 653 | "\t\tthese rows and columns).\n"); 654 | printf("\t-r|--recursive\tWatch directories recursively.\n"); 655 | printf("\t-t|--timeout \n" 656 | "\t\tListen only for specified amount of time in seconds; if\n" 657 | "\t\tomitted or 0, inotifywatch will execute until receiving an\n" 658 | "\t\tinterrupt signal.\n"); 659 | printf("\t-e|--event [ -e|--event ... ]\n" 660 | "\t\tListen for specific event(s). If omitted, all events are \n" 661 | "\t\tlistened for.\n"); 662 | printf("\t-a|--ascending \n" 663 | "\t\tSort ascending by a particular event, or `total'.\n"); 664 | printf("\t-d|--descending \n" 665 | "\t\tSort descending by a particular event, or `total'.\n\n"); 666 | printf("Exit status:\n"); 667 | printf("\t%d - Exited normally.\n", EXIT_SUCCESS); 668 | printf("\t%d - Some error occurred.\n\n", EXIT_FAILURE); 669 | printf("Events:\n"); 670 | print_event_descriptions(); 671 | } 672 | -------------------------------------------------------------------------------- /jni/libinotifytools/example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* 7 | * libinotifytools example program. 8 | * Compile with gcc -linotifytools example.c 9 | */ 10 | int main() { 11 | // initialize and watch the entire directory tree from the current working 12 | // directory downwards for all events 13 | if ( !inotifytools_initialize() 14 | || !inotifytools_watch_recursively( ".", IN_ALL_EVENTS ) ) { 15 | fprintf(stderr, "%s\n", strerror( inotifytools_error() ) ); 16 | return -1; 17 | } 18 | 19 | // set time format to 24 hour time, HH:MM:SS 20 | inotifytools_set_printf_timefmt( "%T" ); 21 | 22 | // Output all events as " " 23 | struct inotify_event * event = inotifytools_next_event( -1 ); 24 | while ( event ) { 25 | inotifytools_printf( event, "%T %w%f %e\n" ); 26 | event = inotifytools_next_event( -1 ); 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /jni/libinotifytools/inotifytools/inotify-nosys.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This header is used if cannot be found. 3 | * 4 | * Inode based directory notification for Linux 5 | * 6 | * Copyright (C) 2005 John McCutchan 7 | */ 8 | 9 | #ifndef _LINUX_INOTIFY_H 10 | #define _LINUX_INOTIFY_H 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | /* 17 | * struct inotify_event - structure read from the inotify device for each event 18 | * 19 | * When you are watching a directory, you will receive the filename for events 20 | * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd. 21 | */ 22 | struct inotify_event { 23 | int wd; /* watch descriptor */ 24 | uint32_t mask; /* watch mask */ 25 | uint32_t cookie; /* cookie to synchronize two events */ 26 | uint32_t len; /* length (including nulls) of name */ 27 | char name __flexarr; /* stub for possible name */ 28 | }; 29 | 30 | /* the following are legal, implemented events that user-space can watch for */ 31 | #define IN_ACCESS 0x00000001 /* File was accessed */ 32 | #define IN_MODIFY 0x00000002 /* File was modified */ 33 | #define IN_ATTRIB 0x00000004 /* Metadata changed */ 34 | #define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */ 35 | #define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */ 36 | #define IN_OPEN 0x00000020 /* File was opened */ 37 | #define IN_MOVED_FROM 0x00000040 /* File was moved from X */ 38 | #define IN_MOVED_TO 0x00000080 /* File was moved to Y */ 39 | #define IN_CREATE 0x00000100 /* Subfile was created */ 40 | #define IN_DELETE 0x00000200 /* Subfile was deleted */ 41 | #define IN_DELETE_SELF 0x00000400 /* Self was deleted */ 42 | #define IN_MOVE_SELF 0x00000800 /* Self was moved */ 43 | 44 | /* the following are legal events. they are sent as needed to any watch */ 45 | #define IN_UNMOUNT 0x00002000 /* Backing fs was unmounted */ 46 | #define IN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ 47 | #define IN_IGNORED 0x00008000 /* File was ignored */ 48 | 49 | /* helper events */ 50 | #define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* close */ 51 | #define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */ 52 | 53 | /* special flags */ 54 | #define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */ 55 | #define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */ 56 | #define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */ 57 | #define IN_ISDIR 0x40000000 /* event occurred against dir */ 58 | #define IN_ONESHOT 0x80000000 /* only send event once */ 59 | 60 | /* 61 | * All of the events - we build the list by hand so that we can add flags in 62 | * the future and not break backward compatibility. Apps will get only the 63 | * events that they originally wanted. Be sure to add new events here! 64 | */ 65 | #define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \ 66 | IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \ 67 | IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | \ 68 | IN_MOVE_SELF) 69 | 70 | #if defined (__alpha__) 71 | # define __NR_inotify_init 444 72 | # define __NR_inotify_add_watch 445 73 | # define __NR_inotify_rm_watch 446 74 | 75 | #elif defined (__arm__) 76 | # define __NR_inotify_init (__NR_SYSCALL_BASE+316) 77 | # define __NR_inotify_add_watch (__NR_SYSCALL_BASE+317) 78 | # define __NR_inotify_rm_watch (__NR_SYSCALL_BASE+318) 79 | 80 | #elif defined (__frv__) 81 | # define __NR_inotify_init 291 82 | # define __NR_inotify_add_watch 292 83 | # define __NR_inotify_rm_watch 293 84 | 85 | #elif defined(__i386__) 86 | # define __NR_inotify_init 291 87 | # define __NR_inotify_add_watch 292 88 | # define __NR_inotify_rm_watch 293 89 | 90 | #elif defined (__ia64__) 91 | # define __NR_inotify_init 1277 92 | # define __NR_inotify_add_watch 1278 93 | # define __NR_inotify_rm_watch 1279 94 | 95 | #elif defined (__mips__) 96 | # if _MIPS_SIM == _MIPS_SIM_ABI32 97 | # define __NR_inotify_init (__NR_Linux + 284) 98 | # define __NR_inotify_add_watch (__NR_Linux + 285) 99 | # define __NR_inotify_rm_watch (__NR_Linux + 286) 100 | # endif 101 | # if _MIPS_SIM == _MIPS_SIM_ABI64 102 | # define __NR_inotify_init (__NR_Linux + 243) 103 | # define __NR_inotify_add_watch (__NR_Linux + 243) 104 | # define __NR_inotify_rm_watch (__NR_Linux + 243) 105 | # endif 106 | # if _MIPS_SIM == _MIPS_SIM_NABI32 107 | # define __NR_inotify_init (__NR_Linux + 247) 108 | # define __NR_inotify_add_watch (__NR_Linux + 248) 109 | # define __NR_inotify_rm_watch (__NR_Linux + 249) 110 | # endif 111 | 112 | #elif defined(__parisc__) 113 | # define __NR_inotify_init (__NR_Linux + 269) 114 | # define __NR_inotify_add_watch (__NR_Linux + 270) 115 | # define __NR_inotify_rm_watch (__NR_Linux + 271) 116 | 117 | #elif defined(__powerpc__) || defined(__powerpc64__) 118 | # define __NR_inotify_init 275 119 | # define __NR_inotify_add_watch 276 120 | # define __NR_inotify_rm_watch 277 121 | 122 | #elif defined (__s390__) 123 | # define __NR_inotify_init 284 124 | # define __NR_inotify_add_watch 285 125 | # define __NR_inotify_rm_watch 286 126 | 127 | #elif defined (__sh__) 128 | # define __NR_inotify_init 290 129 | # define __NR_inotify_add_watch 291 130 | # define __NR_inotify_rm_watch 292 131 | 132 | #elif defined (__sh64__) 133 | # define __NR_inotify_init 318 134 | # define __NR_inotify_add_watch 319 135 | # define __NR_inotify_rm_watch 320 136 | 137 | #elif defined (__sparc__) || defined (__sparc64__) 138 | # define __NR_inotify_init 151 139 | # define __NR_inotify_add_watch 152 140 | # define __NR_inotify_rm_watch 156 141 | 142 | #elif defined(__x86_64__) 143 | # define __NR_inotify_init 253 144 | # define __NR_inotify_add_watch 254 145 | # define __NR_inotify_rm_watch 255 146 | 147 | #else 148 | # error "Unsupported architecture!" 149 | #endif 150 | 151 | static inline int inotify_init (void) 152 | { 153 | return syscall (__NR_inotify_init); 154 | } 155 | 156 | static inline int inotify_add_watch (int fd, const char *name, uint32_t mask) 157 | { 158 | return syscall (__NR_inotify_add_watch, fd, name, mask); 159 | } 160 | 161 | static inline int inotify_rm_watch (int fd, uint32_t wd) 162 | { 163 | return syscall (__NR_inotify_rm_watch, fd, wd); 164 | } 165 | 166 | 167 | #endif /* _LINUX_INOTIFY_H */ 168 | -------------------------------------------------------------------------------- /jni/libinotifytools/inotifytools/inotify.h: -------------------------------------------------------------------------------- 1 | #ifndef _INOTIFYTOOLS_INOTIFY_H 2 | #define _INOTIFYTOOLS_INOTIFY_H 1 3 | 4 | #define SYS_INOTIFY_H_EXISTS_AND_WORKS 1 5 | 6 | 7 | #ifdef SYS_INOTIFY_H_EXISTS_AND_WORKS 8 | #include 9 | #else 10 | #include "inotify-nosys.h" 11 | #endif // SYS_INOTIFY_H_EXISTS_AND_WORKS 12 | 13 | 14 | #endif 15 | 16 | -------------------------------------------------------------------------------- /jni/libinotifytools/inotifytools/inotifytools.h: -------------------------------------------------------------------------------- 1 | #ifndef _inotifytools_H 2 | #define _inotifytools_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | #include 10 | 11 | int inotifytools_str_to_event(char const * event); 12 | int inotifytools_str_to_event_sep(char const * event, char sep); 13 | char * inotifytools_event_to_str(int events); 14 | char * inotifytools_event_to_str_sep(int events, char sep); 15 | void inotifytools_set_filename_by_wd( int wd, char const * filename ); 16 | void inotifytools_set_filename_by_filename( char const * oldname, 17 | char const * newname ); 18 | void inotifytools_replace_filename( char const * oldname, 19 | char const * newname ); 20 | char * inotifytools_filename_from_wd( int wd ); 21 | int inotifytools_wd_from_filename( char const * filename ); 22 | int inotifytools_remove_watch_by_filename( char const * filename ); 23 | int inotifytools_remove_watch_by_wd( int wd ); 24 | int inotifytools_watch_file( char const * filename, int events ); 25 | int inotifytools_watch_files( char const * filenames[], int events ); 26 | int inotifytools_watch_recursively( char const * path, int events ); 27 | int inotifytools_watch_recursively_with_exclude( char const * path, 28 | int events, 29 | char const ** exclude_list ); 30 | // [UH] 31 | int inotifytools_ignore_events_by_regex( char const *pattern, int flags ); 32 | struct inotify_event * inotifytools_next_event( int timeout ); 33 | struct inotify_event * inotifytools_next_events( int timeout, int num_events ); 34 | int inotifytools_error(); 35 | int inotifytools_get_stat_by_wd( int wd, int event ); 36 | int inotifytools_get_stat_total( int event ); 37 | int inotifytools_get_stat_by_filename( char const * filename, 38 | int event ); 39 | void inotifytools_initialize_stats(); 40 | int inotifytools_initialize(); 41 | void inotifytools_cleanup(); 42 | int inotifytools_get_num_watches(); 43 | 44 | int inotifytools_printf( struct inotify_event* event, char* fmt ); 45 | int inotifytools_fprintf( FILE* file, struct inotify_event* event, char* fmt ); 46 | int inotifytools_sprintf( char * out, struct inotify_event* event, char* fmt ); 47 | int inotifytools_snprintf( char * out, int size, struct inotify_event* event, 48 | char* fmt ); 49 | void inotifytools_set_printf_timefmt( char * fmt ); 50 | 51 | int inotifytools_get_max_user_watches(); 52 | int inotifytools_get_max_user_instances(); 53 | int inotifytools_get_max_queued_events(); 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif // _inotifytools_H 60 | -------------------------------------------------------------------------------- /jni/libinotifytools/inotifytools_p.h: -------------------------------------------------------------------------------- 1 | #ifndef INOTIFYTOOLS_P_H 2 | #define INOTIFYTOOLS_P_H 3 | 4 | #include "redblack.h" 5 | 6 | struct rbtree *inotifytools_wd_sorted_by_event(int sort_event); 7 | 8 | typedef struct watch { 9 | char *filename; 10 | int wd; 11 | unsigned hit_access; 12 | unsigned hit_modify; 13 | unsigned hit_attrib; 14 | unsigned hit_close_write; 15 | unsigned hit_close_nowrite; 16 | unsigned hit_open; 17 | unsigned hit_moved_from; 18 | unsigned hit_moved_to; 19 | unsigned hit_create; 20 | unsigned hit_delete; 21 | unsigned hit_delete_self; 22 | unsigned hit_unmount; 23 | unsigned hit_move_self; 24 | unsigned hit_total; 25 | } watch; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /jni/libinotifytools/redblack.c: -------------------------------------------------------------------------------- 1 | static char rcsid[]="$Id: redblack.c,v 1.9 2003/10/24 01:31:21 damo Exp $"; 2 | 3 | /* 4 | Redblack balanced tree algorithm 5 | Copyright (C) Damian Ivereigh 2000 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU Lesser General Public License as published by 9 | the Free Software Foundation; either version 2.1 of the License, or 10 | (at your option) any later version. See the file COPYING for details. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | */ 21 | 22 | /* Implement the red/black tree structure. It is designed to emulate 23 | ** the standard tsearch() stuff. i.e. the calling conventions are 24 | ** exactly the same 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include "redblack.h" 31 | 32 | #define assert(expr) 33 | 34 | /* Uncomment this if you would rather use a raw sbrk to get memory 35 | ** (however the memory is never released again (only re-used). Can't 36 | ** see any point in using this these days. 37 | */ 38 | /* #define USE_SBRK */ 39 | 40 | enum nodecolour { BLACK, RED }; 41 | 42 | struct RB_ENTRY(node) 43 | { 44 | struct RB_ENTRY(node) *left; /* Left down */ 45 | struct RB_ENTRY(node) *right; /* Right down */ 46 | struct RB_ENTRY(node) *up; /* Up */ 47 | enum nodecolour colour; /* Node colour */ 48 | #ifdef RB_INLINE 49 | RB_ENTRY(data_t) key; /* User's key (and data) */ 50 | #define RB_GET(x,y) &x->y 51 | #define RB_SET(x,y,v) x->y = *(v) 52 | #else 53 | const RB_ENTRY(data_t) *key; /* Pointer to user's key (and data) */ 54 | #define RB_GET(x,y) x->y 55 | #define RB_SET(x,y,v) x->y = v 56 | #endif /* RB_INLINE */ 57 | }; 58 | 59 | /* Dummy (sentinel) node, so that we can make X->left->up = X 60 | ** We then use this instead of NULL to mean the top or bottom 61 | ** end of the rb tree. It is a black node. 62 | ** 63 | ** Initialization of the last field in this initializer is left implicit 64 | ** because it could be of any type. We count on the compiler to zero it. 65 | */ 66 | struct RB_ENTRY(node) RB_ENTRY(_null)={&RB_ENTRY(_null), &RB_ENTRY(_null), &RB_ENTRY(_null), BLACK}; 67 | #define RBNULL (&RB_ENTRY(_null)) 68 | 69 | #if defined(USE_SBRK) 70 | 71 | static struct RB_ENTRY(node) *RB_ENTRY(_alloc)(); 72 | static void RB_ENTRY(_free)(struct RB_ENTRY(node) *); 73 | 74 | #else 75 | 76 | static struct RB_ENTRY(node) *RB_ENTRY(_alloc)() {return (struct RB_ENTRY(node) *) malloc(sizeof(struct RB_ENTRY(node)));} 77 | static void RB_ENTRY(_free)(struct RB_ENTRY(node) *x) {free(x);} 78 | 79 | #endif 80 | 81 | /* These functions are always needed */ 82 | static void RB_ENTRY(_left_rotate)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *); 83 | static void RB_ENTRY(_right_rotate)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *); 84 | static struct RB_ENTRY(node) *RB_ENTRY(_successor)(const struct RB_ENTRY(node) *); 85 | static struct RB_ENTRY(node) *RB_ENTRY(_predecessor)(const struct RB_ENTRY(node) *); 86 | static struct RB_ENTRY(node) *RB_ENTRY(_traverse)(int, const RB_ENTRY(data_t) * , struct RB_ENTRY(tree) *); 87 | 88 | /* These functions may not be needed */ 89 | #ifndef no_lookup 90 | static struct RB_ENTRY(node) *RB_ENTRY(_lookup)(int, const RB_ENTRY(data_t) * , struct RB_ENTRY(tree) *); 91 | #endif 92 | 93 | #ifndef no_destroy 94 | static void RB_ENTRY(_destroy)(struct RB_ENTRY(node) *); 95 | #endif 96 | 97 | #ifndef no_delete 98 | static void RB_ENTRY(_delete)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *); 99 | static void RB_ENTRY(_delete_fix)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *); 100 | #endif 101 | 102 | #ifndef no_walk 103 | static void RB_ENTRY(_walk)(const struct RB_ENTRY(node) *, void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *, int); 104 | #endif 105 | 106 | #ifndef no_readlist 107 | static RBLIST *RB_ENTRY(_openlist)(const struct RB_ENTRY(node) *); 108 | static const RB_ENTRY(data_t) * RB_ENTRY(_readlist)(RBLIST *); 109 | static void RB_ENTRY(_closelist)(RBLIST *); 110 | #endif 111 | 112 | /* 113 | ** OK here we go, the balanced tree stuff. The algorithm is the 114 | ** fairly standard red/black taken from "Introduction to Algorithms" 115 | ** by Cormen, Leiserson & Rivest. Maybe one of these days I will 116 | ** fully understand all this stuff. 117 | ** 118 | ** Basically a red/black balanced tree has the following properties:- 119 | ** 1) Every node is either red or black (colour is RED or BLACK) 120 | ** 2) A leaf (RBNULL pointer) is considered black 121 | ** 3) If a node is red then its children are black 122 | ** 4) Every path from a node to a leaf contains the same no 123 | ** of black nodes 124 | ** 125 | ** 3) & 4) above guarantee that the longest path (alternating 126 | ** red and black nodes) is only twice as long as the shortest 127 | ** path (all black nodes). Thus the tree remains fairly balanced. 128 | */ 129 | 130 | /* 131 | * Initialise a tree. Identifies the comparison routine and any config 132 | * data that must be sent to it when called. 133 | * Returns a pointer to the top of the tree. 134 | */ 135 | #ifndef RB_CUSTOMIZE 136 | RB_STATIC struct RB_ENTRY(tree) * 137 | rbinit(int (*cmp)(const void *, const void *, const void *), const void *config) 138 | #else 139 | RB_STATIC struct RB_ENTRY(tree) *RB_ENTRY(init)(void) 140 | #endif /* RB_CUSTOMIZE */ 141 | { 142 | struct RB_ENTRY(tree) *retval; 143 | char c; 144 | 145 | c=rcsid[0]; /* This does nothing but shutup the -Wall */ 146 | 147 | if ((retval=(struct RB_ENTRY(tree) *) malloc(sizeof(struct RB_ENTRY(tree))))==NULL) 148 | return(NULL); 149 | 150 | #ifndef RB_CUSTOMIZE 151 | retval->rb_cmp=cmp; 152 | retval->rb_config=config; 153 | #endif /* RB_CUSTOMIZE */ 154 | retval->rb_root=RBNULL; 155 | 156 | return(retval); 157 | } 158 | 159 | #ifndef no_destroy 160 | RB_STATIC void 161 | RB_ENTRY(destroy)(struct RB_ENTRY(tree) *rbinfo) 162 | { 163 | if (rbinfo==NULL) 164 | return; 165 | 166 | if (rbinfo->rb_root!=RBNULL) 167 | RB_ENTRY(_destroy)(rbinfo->rb_root); 168 | 169 | free(rbinfo); 170 | } 171 | #endif /* no_destroy */ 172 | 173 | #ifndef no_search 174 | RB_STATIC const RB_ENTRY(data_t) * 175 | RB_ENTRY(search)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) 176 | { 177 | struct RB_ENTRY(node) *x; 178 | 179 | if (rbinfo==NULL) 180 | return(NULL); 181 | 182 | x=RB_ENTRY(_traverse)(1, key, rbinfo); 183 | 184 | return((x==RBNULL) ? NULL : RB_GET(x, key)); 185 | } 186 | #endif /* no_search */ 187 | 188 | #ifndef no_find 189 | RB_STATIC const RB_ENTRY(data_t) * 190 | RB_ENTRY(find)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) 191 | { 192 | struct RB_ENTRY(node) *x; 193 | 194 | if (rbinfo==NULL) 195 | return(NULL); 196 | 197 | /* If we have a NULL root (empty tree) then just return */ 198 | if (rbinfo->rb_root==RBNULL) 199 | return(NULL); 200 | 201 | x=RB_ENTRY(_traverse)(0, key, rbinfo); 202 | 203 | return((x==RBNULL) ? NULL : RB_GET(x, key)); 204 | } 205 | #endif /* no_find */ 206 | 207 | #ifndef no_delete 208 | RB_STATIC const RB_ENTRY(data_t) * 209 | RB_ENTRY(delete)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) 210 | { 211 | struct RB_ENTRY(node) *x; 212 | const RB_ENTRY(data_t) * y; 213 | 214 | if (rbinfo==NULL) 215 | return(NULL); 216 | 217 | x=RB_ENTRY(_traverse)(0, key, rbinfo); 218 | 219 | if (x==RBNULL) 220 | { 221 | return(NULL); 222 | } 223 | else 224 | { 225 | y=RB_GET(x, key); 226 | RB_ENTRY(_delete)(&rbinfo->rb_root, x); 227 | 228 | return(y); 229 | } 230 | } 231 | #endif /* no_delete */ 232 | 233 | #ifndef no_walk 234 | RB_STATIC void 235 | RB_ENTRY(walk)(const struct RB_ENTRY(tree) *rbinfo, void (*action)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *arg) 236 | { 237 | if (rbinfo==NULL) 238 | return; 239 | 240 | RB_ENTRY(_walk)(rbinfo->rb_root, action, arg, 0); 241 | } 242 | #endif /* no_walk */ 243 | 244 | #ifndef no_readlist 245 | RB_STATIC RBLIST * 246 | RB_ENTRY(openlist)(const struct RB_ENTRY(tree) *rbinfo) 247 | { 248 | if (rbinfo==NULL) 249 | return(NULL); 250 | 251 | return(RB_ENTRY(_openlist)(rbinfo->rb_root)); 252 | } 253 | 254 | RB_STATIC const RB_ENTRY(data_t) * 255 | RB_ENTRY(readlist)(RBLIST *rblistp) 256 | { 257 | if (rblistp==NULL) 258 | return(NULL); 259 | 260 | return(RB_ENTRY(_readlist)(rblistp)); 261 | } 262 | 263 | RB_STATIC void 264 | RB_ENTRY(closelist)(RBLIST *rblistp) 265 | { 266 | if (rblistp==NULL) 267 | return; 268 | 269 | RB_ENTRY(_closelist)(rblistp); 270 | } 271 | #endif /* no_readlist */ 272 | 273 | #ifndef no_lookup 274 | RB_STATIC const RB_ENTRY(data_t) * 275 | RB_ENTRY(lookup)(int mode, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) 276 | { 277 | struct RB_ENTRY(node) *x; 278 | 279 | /* If we have a NULL root (empty tree) then just return NULL */ 280 | if (rbinfo==NULL || rbinfo->rb_root==NULL) 281 | return(NULL); 282 | 283 | x=RB_ENTRY(_lookup)(mode, key, rbinfo); 284 | 285 | return((x==RBNULL) ? NULL : RB_GET(x, key)); 286 | } 287 | #endif /* no_lookup */ 288 | 289 | /* --------------------------------------------------------------------- */ 290 | 291 | /* Search for and if not found and insert is true, will add a new 292 | ** node in. Returns a pointer to the new node, or the node found 293 | */ 294 | static struct RB_ENTRY(node) * 295 | RB_ENTRY(_traverse)(int insert, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) 296 | { 297 | struct RB_ENTRY(node) *x,*y,*z; 298 | int cmp; 299 | int found=0; 300 | int cmpmods(); 301 | 302 | y=RBNULL; /* points to the parent of x */ 303 | x=rbinfo->rb_root; 304 | 305 | /* walk x down the tree */ 306 | while(x!=RBNULL && found==0) 307 | { 308 | y=x; 309 | /* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */ 310 | #ifndef RB_CUSTOMIZE 311 | cmp=RB_CMP(key, RB_GET(x, key), rbinfo->rb_config); 312 | #else 313 | cmp=RB_CMP(key, RB_GET(x, key)); 314 | #endif /* RB_CUSTOMIZE */ 315 | 316 | if (cmp<0) 317 | x=x->left; 318 | else if (cmp>0) 319 | x=x->right; 320 | else 321 | found=1; 322 | } 323 | 324 | if (found || !insert) 325 | return(x); 326 | 327 | if ((z=RB_ENTRY(_alloc)())==NULL) 328 | { 329 | /* Whoops, no memory */ 330 | return(RBNULL); 331 | } 332 | 333 | RB_SET(z, key, key); 334 | z->up=y; 335 | if (y==RBNULL) 336 | { 337 | rbinfo->rb_root=z; 338 | } 339 | else 340 | { 341 | #ifndef RB_CUSTOMIZE 342 | cmp=RB_CMP(RB_GET(z, key), RB_GET(y, key), rbinfo->rb_config); 343 | #else 344 | cmp=RB_CMP(RB_GET(z, key), RB_GET(y, key)); 345 | #endif /* RB_CUSTOMIZE */ 346 | if (cmp<0) 347 | y->left=z; 348 | else 349 | y->right=z; 350 | } 351 | 352 | z->left=RBNULL; 353 | z->right=RBNULL; 354 | 355 | /* colour this new node red */ 356 | z->colour=RED; 357 | 358 | /* Having added a red node, we must now walk back up the tree balancing 359 | ** it, by a series of rotations and changing of colours 360 | */ 361 | x=z; 362 | 363 | /* While we are not at the top and our parent node is red 364 | ** N.B. Since the root node is garanteed black, then we 365 | ** are also going to stop if we are the child of the root 366 | */ 367 | 368 | while(x != rbinfo->rb_root && (x->up->colour == RED)) 369 | { 370 | /* if our parent is on the left side of our grandparent */ 371 | if (x->up == x->up->up->left) 372 | { 373 | /* get the right side of our grandparent (uncle?) */ 374 | y=x->up->up->right; 375 | if (y->colour == RED) 376 | { 377 | /* make our parent black */ 378 | x->up->colour = BLACK; 379 | /* make our uncle black */ 380 | y->colour = BLACK; 381 | /* make our grandparent red */ 382 | x->up->up->colour = RED; 383 | 384 | /* now consider our grandparent */ 385 | x=x->up->up; 386 | } 387 | else 388 | { 389 | /* if we are on the right side of our parent */ 390 | if (x == x->up->right) 391 | { 392 | /* Move up to our parent */ 393 | x=x->up; 394 | RB_ENTRY(_left_rotate)(&rbinfo->rb_root, x); 395 | } 396 | 397 | /* make our parent black */ 398 | x->up->colour = BLACK; 399 | /* make our grandparent red */ 400 | x->up->up->colour = RED; 401 | /* right rotate our grandparent */ 402 | RB_ENTRY(_right_rotate)(&rbinfo->rb_root, x->up->up); 403 | } 404 | } 405 | else 406 | { 407 | /* everything here is the same as above, but 408 | ** exchanging left for right 409 | */ 410 | 411 | y=x->up->up->left; 412 | if (y->colour == RED) 413 | { 414 | x->up->colour = BLACK; 415 | y->colour = BLACK; 416 | x->up->up->colour = RED; 417 | 418 | x=x->up->up; 419 | } 420 | else 421 | { 422 | if (x == x->up->left) 423 | { 424 | x=x->up; 425 | RB_ENTRY(_right_rotate)(&rbinfo->rb_root, x); 426 | } 427 | 428 | x->up->colour = BLACK; 429 | x->up->up->colour = RED; 430 | RB_ENTRY(_left_rotate)(&rbinfo->rb_root, x->up->up); 431 | } 432 | } 433 | } 434 | 435 | /* Set the root node black */ 436 | (rbinfo->rb_root)->colour = BLACK; 437 | 438 | return(z); 439 | } 440 | 441 | #ifndef no_lookup 442 | /* Search for a key according to mode (see redblack.h) 443 | */ 444 | static struct RB_ENTRY(node) * 445 | RB_ENTRY(_lookup)(int mode, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) 446 | { 447 | struct RB_ENTRY(node) *x,*y; 448 | int cmp; 449 | int found=0; 450 | 451 | y=RBNULL; /* points to the parent of x */ 452 | x=rbinfo->rb_root; 453 | 454 | if (mode==RB_LUFIRST) 455 | { 456 | /* Keep going left until we hit a NULL */ 457 | while(x!=RBNULL) 458 | { 459 | y=x; 460 | x=x->left; 461 | } 462 | 463 | return(y); 464 | } 465 | else if (mode==RB_LULAST) 466 | { 467 | /* Keep going right until we hit a NULL */ 468 | while(x!=RBNULL) 469 | { 470 | y=x; 471 | x=x->right; 472 | } 473 | 474 | return(y); 475 | } 476 | 477 | /* walk x down the tree */ 478 | while(x!=RBNULL && found==0) 479 | { 480 | y=x; 481 | /* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */ 482 | #ifndef RB_CUSTOMIZE 483 | cmp=RB_CMP(key, RB_GET(x, key), rbinfo->rb_config); 484 | #else 485 | cmp=RB_CMP(key, RB_GET(x, key)); 486 | #endif /* RB_CUSTOMIZE */ 487 | 488 | 489 | if (cmp<0) 490 | x=x->left; 491 | else if (cmp>0) 492 | x=x->right; 493 | else 494 | found=1; 495 | } 496 | 497 | if (found && (mode==RB_LUEQUAL || mode==RB_LUGTEQ || mode==RB_LULTEQ)) 498 | return(x); 499 | 500 | if (!found && (mode==RB_LUEQUAL || mode==RB_LUNEXT || mode==RB_LUPREV)) 501 | return(RBNULL); 502 | 503 | if (mode==RB_LUGTEQ || (!found && mode==RB_LUGREAT)) 504 | { 505 | if (cmp>0) 506 | return(RB_ENTRY(_successor)(y)); 507 | else 508 | return(y); 509 | } 510 | 511 | if (mode==RB_LULTEQ || (!found && mode==RB_LULESS)) 512 | { 513 | if (cmp<0) 514 | return(RB_ENTRY(_predecessor)(y)); 515 | else 516 | return(y); 517 | } 518 | 519 | if (mode==RB_LUNEXT || (found && mode==RB_LUGREAT)) 520 | return(RB_ENTRY(_successor)(x)); 521 | 522 | if (mode==RB_LUPREV || (found && mode==RB_LULESS)) 523 | return(RB_ENTRY(_predecessor)(x)); 524 | 525 | /* Shouldn't get here */ 526 | return(RBNULL); 527 | } 528 | #endif /* no_lookup */ 529 | 530 | #ifndef no_destroy 531 | /* 532 | * Destroy all the elements blow us in the tree 533 | * only useful as part of a complete tree destroy. 534 | */ 535 | static void 536 | RB_ENTRY(_destroy)(struct RB_ENTRY(node) *x) 537 | { 538 | if (x!=RBNULL) 539 | { 540 | if (x->left!=RBNULL) 541 | RB_ENTRY(_destroy)(x->left); 542 | if (x->right!=RBNULL) 543 | RB_ENTRY(_destroy)(x->right); 544 | RB_ENTRY(_free)(x); 545 | } 546 | } 547 | #endif /* no_destroy */ 548 | 549 | /* 550 | ** Rotate our tree thus:- 551 | ** 552 | ** X rb_left_rotate(X)---> Y 553 | ** / \ / \ 554 | ** A Y <---rb_right_rotate(Y) X C 555 | ** / \ / \ 556 | ** B C A B 557 | ** 558 | ** N.B. This does not change the ordering. 559 | ** 560 | ** We assume that neither X or Y is NULL 561 | */ 562 | 563 | static void 564 | RB_ENTRY(_left_rotate)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *x) 565 | { 566 | struct RB_ENTRY(node) *y; 567 | 568 | assert(x!=RBNULL); 569 | assert(x->right!=RBNULL); 570 | 571 | y=x->right; /* set Y */ 572 | 573 | /* Turn Y's left subtree into X's right subtree (move B)*/ 574 | x->right = y->left; 575 | 576 | /* If B is not null, set it's parent to be X */ 577 | if (y->left != RBNULL) 578 | y->left->up = x; 579 | 580 | /* Set Y's parent to be what X's parent was */ 581 | y->up = x->up; 582 | 583 | /* if X was the root */ 584 | if (x->up == RBNULL) 585 | { 586 | *rootp=y; 587 | } 588 | else 589 | { 590 | /* Set X's parent's left or right pointer to be Y */ 591 | if (x == x->up->left) 592 | { 593 | x->up->left=y; 594 | } 595 | else 596 | { 597 | x->up->right=y; 598 | } 599 | } 600 | 601 | /* Put X on Y's left */ 602 | y->left=x; 603 | 604 | /* Set X's parent to be Y */ 605 | x->up = y; 606 | } 607 | 608 | static void 609 | RB_ENTRY(_right_rotate)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *y) 610 | { 611 | struct RB_ENTRY(node) *x; 612 | 613 | assert(y!=RBNULL); 614 | assert(y->left!=RBNULL); 615 | 616 | x=y->left; /* set X */ 617 | 618 | /* Turn X's right subtree into Y's left subtree (move B) */ 619 | y->left = x->right; 620 | 621 | /* If B is not null, set it's parent to be Y */ 622 | if (x->right != RBNULL) 623 | x->right->up = y; 624 | 625 | /* Set X's parent to be what Y's parent was */ 626 | x->up = y->up; 627 | 628 | /* if Y was the root */ 629 | if (y->up == RBNULL) 630 | { 631 | *rootp=x; 632 | } 633 | else 634 | { 635 | /* Set Y's parent's left or right pointer to be X */ 636 | if (y == y->up->left) 637 | { 638 | y->up->left=x; 639 | } 640 | else 641 | { 642 | y->up->right=x; 643 | } 644 | } 645 | 646 | /* Put Y on X's right */ 647 | x->right=y; 648 | 649 | /* Set Y's parent to be X */ 650 | y->up = x; 651 | } 652 | 653 | /* Return a pointer to the smallest key greater than x 654 | */ 655 | static struct RB_ENTRY(node) * 656 | RB_ENTRY(_successor)(const struct RB_ENTRY(node) *x) 657 | { 658 | struct RB_ENTRY(node) *y; 659 | 660 | if (x->right!=RBNULL) 661 | { 662 | /* If right is not NULL then go right one and 663 | ** then keep going left until we find a node with 664 | ** no left pointer. 665 | */ 666 | for (y=x->right; y->left!=RBNULL; y=y->left); 667 | } 668 | else 669 | { 670 | /* Go up the tree until we get to a node that is on the 671 | ** left of its parent (or the root) and then return the 672 | ** parent. 673 | */ 674 | y=x->up; 675 | while(y!=RBNULL && x==y->right) 676 | { 677 | x=y; 678 | y=y->up; 679 | } 680 | } 681 | return(y); 682 | } 683 | 684 | /* Return a pointer to the largest key smaller than x 685 | */ 686 | static struct RB_ENTRY(node) * 687 | RB_ENTRY(_predecessor)(const struct RB_ENTRY(node) *x) 688 | { 689 | struct RB_ENTRY(node) *y; 690 | 691 | if (x->left!=RBNULL) 692 | { 693 | /* If left is not NULL then go left one and 694 | ** then keep going right until we find a node with 695 | ** no right pointer. 696 | */ 697 | for (y=x->left; y->right!=RBNULL; y=y->right); 698 | } 699 | else 700 | { 701 | /* Go up the tree until we get to a node that is on the 702 | ** right of its parent (or the root) and then return the 703 | ** parent. 704 | */ 705 | y=x->up; 706 | while(y!=RBNULL && x==y->left) 707 | { 708 | x=y; 709 | y=y->up; 710 | } 711 | } 712 | return(y); 713 | } 714 | 715 | #ifndef no_delete 716 | /* Delete the node z, and free up the space 717 | */ 718 | static void 719 | RB_ENTRY(_delete)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *z) 720 | { 721 | struct RB_ENTRY(node) *x, *y; 722 | 723 | if (z->left == RBNULL || z->right == RBNULL) 724 | y=z; 725 | else 726 | y=RB_ENTRY(_successor)(z); 727 | 728 | if (y->left != RBNULL) 729 | x=y->left; 730 | else 731 | x=y->right; 732 | 733 | x->up = y->up; 734 | 735 | if (y->up == RBNULL) 736 | { 737 | *rootp=x; 738 | } 739 | else 740 | { 741 | if (y==y->up->left) 742 | y->up->left = x; 743 | else 744 | y->up->right = x; 745 | } 746 | 747 | if (y!=z) 748 | { 749 | RB_SET(z, key, RB_GET(y, key)); 750 | } 751 | 752 | if (y->colour == BLACK) 753 | RB_ENTRY(_delete_fix)(rootp, x); 754 | 755 | RB_ENTRY(_free)(y); 756 | } 757 | 758 | /* Restore the reb-black properties after a delete */ 759 | static void 760 | RB_ENTRY(_delete_fix)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *x) 761 | { 762 | struct RB_ENTRY(node) *w; 763 | 764 | while (x!=*rootp && x->colour==BLACK) 765 | { 766 | if (x==x->up->left) 767 | { 768 | w=x->up->right; 769 | if (w->colour==RED) 770 | { 771 | w->colour=BLACK; 772 | x->up->colour=RED; 773 | rb_left_rotate(rootp, x->up); 774 | w=x->up->right; 775 | } 776 | 777 | if (w->left->colour==BLACK && w->right->colour==BLACK) 778 | { 779 | w->colour=RED; 780 | x=x->up; 781 | } 782 | else 783 | { 784 | if (w->right->colour == BLACK) 785 | { 786 | w->left->colour=BLACK; 787 | w->colour=RED; 788 | RB_ENTRY(_right_rotate)(rootp, w); 789 | w=x->up->right; 790 | } 791 | 792 | 793 | w->colour=x->up->colour; 794 | x->up->colour = BLACK; 795 | w->right->colour = BLACK; 796 | RB_ENTRY(_left_rotate)(rootp, x->up); 797 | x=*rootp; 798 | } 799 | } 800 | else 801 | { 802 | w=x->up->left; 803 | if (w->colour==RED) 804 | { 805 | w->colour=BLACK; 806 | x->up->colour=RED; 807 | RB_ENTRY(_right_rotate)(rootp, x->up); 808 | w=x->up->left; 809 | } 810 | 811 | if (w->right->colour==BLACK && w->left->colour==BLACK) 812 | { 813 | w->colour=RED; 814 | x=x->up; 815 | } 816 | else 817 | { 818 | if (w->left->colour == BLACK) 819 | { 820 | w->right->colour=BLACK; 821 | w->colour=RED; 822 | RB_ENTRY(_left_rotate)(rootp, w); 823 | w=x->up->left; 824 | } 825 | 826 | w->colour=x->up->colour; 827 | x->up->colour = BLACK; 828 | w->left->colour = BLACK; 829 | RB_ENTRY(_right_rotate)(rootp, x->up); 830 | x=*rootp; 831 | } 832 | } 833 | } 834 | 835 | x->colour=BLACK; 836 | } 837 | #endif /* no_delete */ 838 | 839 | #ifndef no_walk 840 | static void 841 | RB_ENTRY(_walk)(const struct RB_ENTRY(node) *x, void (*action)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *arg, int level) 842 | { 843 | if (x==RBNULL) 844 | return; 845 | 846 | if (x->left==RBNULL && x->right==RBNULL) 847 | { 848 | /* leaf */ 849 | (*action)(RB_GET(x, key), leaf, level, arg); 850 | } 851 | else 852 | { 853 | (*action)(RB_GET(x, key), preorder, level, arg); 854 | 855 | RB_ENTRY(_walk)(x->left, action, arg, level+1); 856 | 857 | (*action)(RB_GET(x, key), postorder, level, arg); 858 | 859 | RB_ENTRY(_walk)(x->right, action, arg, level+1); 860 | 861 | (*action)(RB_GET(x, key), endorder, level, arg); 862 | } 863 | } 864 | #endif /* no_walk */ 865 | 866 | #ifndef no_readlist 867 | static RBLIST * 868 | RB_ENTRY(_openlist)(const struct RB_ENTRY(node) *rootp) 869 | { 870 | RBLIST *rblistp; 871 | 872 | rblistp=(RBLIST *) malloc(sizeof(RBLIST)); 873 | if (!rblistp) 874 | return(NULL); 875 | 876 | rblistp->rootp=rootp; 877 | rblistp->nextp=rootp; 878 | 879 | if (rootp!=RBNULL) 880 | { 881 | while(rblistp->nextp->left!=RBNULL) 882 | { 883 | rblistp->nextp=rblistp->nextp->left; 884 | } 885 | } 886 | 887 | return(rblistp); 888 | } 889 | 890 | static const RB_ENTRY(data_t) * 891 | RB_ENTRY(_readlist)(RBLIST *rblistp) 892 | { 893 | const RB_ENTRY(data_t) *key=NULL; 894 | 895 | if (rblistp!=NULL && rblistp->nextp!=RBNULL) 896 | { 897 | key=RB_GET(rblistp->nextp, key); 898 | rblistp->nextp=RB_ENTRY(_successor)(rblistp->nextp); 899 | } 900 | 901 | return(key); 902 | } 903 | 904 | static void 905 | rb_closelist(RBLIST *rblistp) 906 | { 907 | if (rblistp) 908 | free(rblistp); 909 | } 910 | #endif /* no_readlist */ 911 | 912 | #if defined(RB_USE_SBRK) 913 | /* Allocate space for our nodes, allowing us to get space from 914 | ** sbrk in larger chucks. 915 | */ 916 | static struct RB_ENTRY(node) *rbfreep=NULL; 917 | 918 | #define RB_ENTRY(NODE)ALLOC_CHUNK_SIZE 1000 919 | static struct RB_ENTRY(node) * 920 | RB_ENTRY(_alloc)() 921 | { 922 | struct RB_ENTRY(node) *x; 923 | int i; 924 | 925 | if (rbfreep==NULL) 926 | { 927 | /* must grab some more space */ 928 | rbfreep=(struct RB_ENTRY(node) *) sbrk(sizeof(struct RB_ENTRY(node)) * RB_ENTRY(NODE)ALLOC_CHUNK_SIZE); 929 | 930 | if (rbfreep==(struct RB_ENTRY(node) *) -1) 931 | { 932 | return(NULL); 933 | } 934 | 935 | /* tie them together in a linked list (use the up pointer) */ 936 | for (i=0, x=rbfreep; iup = (x+1); 939 | } 940 | x->up=NULL; 941 | } 942 | 943 | x=rbfreep; 944 | rbfreep = rbfreep->up; 945 | #ifdef RB_ALLOC 946 | RB_ALLOC(ACCESS(x, key)); 947 | #endif /* RB_ALLOC */ 948 | return(x); 949 | } 950 | 951 | /* free (dealloc) an RB_ENTRY(node) structure - add it onto the front of the list 952 | ** N.B. RB_ENTRY(node) need not have been allocated through rb_alloc() 953 | */ 954 | static void 955 | RB_ENTRY(_free)(struct RB_ENTRY(node) *x) 956 | { 957 | #ifdef RB_FREE 958 | RB_FREE(ACCESS(x, key)); 959 | #endif /* RB_FREE */ 960 | x->up=rbfreep; 961 | rbfreep=x; 962 | } 963 | 964 | #endif 965 | 966 | #if 0 967 | int 968 | RB_ENTRY(_check)(struct RB_ENTRY(node) *rootp) 969 | { 970 | if (rootp==NULL || rootp==RBNULL) 971 | return(0); 972 | 973 | if (rootp->up!=RBNULL) 974 | { 975 | fprintf(stderr, "Root up pointer not RBNULL"); 976 | dumptree(rootp, 0); 977 | return(1); 978 | } 979 | 980 | if (RB_ENTRY(_check)1(rootp)) 981 | { 982 | RB_ENTRY(dumptree)(rootp, 0); 983 | return(1); 984 | } 985 | 986 | if (RB_ENTRY(count_black)(rootp)==-1) 987 | { 988 | RB_ENTRY(dumptree)(rootp, 0); 989 | return(-1); 990 | } 991 | 992 | return(0); 993 | } 994 | 995 | int 996 | RB_ENTRY(_check1)(struct RB_ENTRY(node) *x) 997 | { 998 | if (x->left==NULL || x->right==NULL) 999 | { 1000 | fprintf(stderr, "Left or right is NULL"); 1001 | return(1); 1002 | } 1003 | 1004 | if (x->colour==RED) 1005 | { 1006 | if (x->left->colour!=BLACK && x->right->colour!=BLACK) 1007 | { 1008 | fprintf(stderr, "Children of red node not both black, x=%ld", x); 1009 | return(1); 1010 | } 1011 | } 1012 | 1013 | if (x->left != RBNULL) 1014 | { 1015 | if (x->left->up != x) 1016 | { 1017 | fprintf(stderr, "x->left->up != x, x=%ld", x); 1018 | return(1); 1019 | } 1020 | 1021 | if (rb_check1(x->left)) 1022 | return(1); 1023 | } 1024 | 1025 | if (x->right != RBNULL) 1026 | { 1027 | if (x->right->up != x) 1028 | { 1029 | fprintf(stderr, "x->right->up != x, x=%ld", x); 1030 | return(1); 1031 | } 1032 | 1033 | if (rb_check1(x->right)) 1034 | return(1); 1035 | } 1036 | return(0); 1037 | } 1038 | 1039 | RB_ENTRY(count_black)(struct RB_ENTRY(node) *x) 1040 | { 1041 | int nleft, nright; 1042 | 1043 | if (x==RBNULL) 1044 | return(1); 1045 | 1046 | nleft=RB_ENTRY(count_black)(x->left); 1047 | nright=RB_ENTRY(count_black)(x->right); 1048 | 1049 | if (nleft==-1 || nright==-1) 1050 | return(-1); 1051 | 1052 | if (nleft != nright) 1053 | { 1054 | fprintf(stderr, "Black count not equal on left & right, x=%ld", x); 1055 | return(-1); 1056 | } 1057 | 1058 | if (x->colour == BLACK) 1059 | { 1060 | nleft++; 1061 | } 1062 | 1063 | return(nleft); 1064 | } 1065 | 1066 | RB_ENTRY(dumptree)(struct RB_ENTRY(node) *x, int n) 1067 | { 1068 | char *prkey(); 1069 | 1070 | if (x!=NULL && x!=RBNULL) 1071 | { 1072 | n++; 1073 | fprintf(stderr, "Tree: %*s %ld: left=%ld, right=%ld, colour=%s, key=%s", 1074 | n, 1075 | "", 1076 | x, 1077 | x->left, 1078 | x->right, 1079 | (x->colour==BLACK) ? "BLACK" : "RED", 1080 | prkey(RB_GET(x, key))); 1081 | 1082 | RB_ENTRY(dumptree)(x->left, n); 1083 | RB_ENTRY(dumptree)(x->right, n); 1084 | } 1085 | } 1086 | #endif 1087 | 1088 | /* 1089 | * $Log: redblack.c,v $ 1090 | * Revision 1.9 2003/10/24 01:31:21 damo 1091 | * Patches from Eric Raymond: %prefix is implemented.  Various other small 1092 | * changes avoid stepping on global namespaces and improve the documentation. 1093 | * 1094 | * Revision 1.8 2002/08/26 05:33:47 damo 1095 | * Some minor fixes:- 1096 | * Stopped ./configure warning about stuff being in the wrong order 1097 | * Fixed compiler warning about const (not sure about this) 1098 | * Changed directory of redblack.c in documentation 1099 | * 1100 | * Revision 1.7 2002/08/26 03:11:40 damo 1101 | * Fixed up a bunch of compiler warnings when compiling example4 1102 | * 1103 | * Tidies up the Makefile.am & Specfile. 1104 | * 1105 | * Renamed redblack to rbgen 1106 | * 1107 | * Revision 1.6 2002/08/26 01:03:35 damo 1108 | * Patch from Eric Raymond to change the way the library is used:- 1109 | * 1110 | * Eric's idea is to convert libredblack into a piece of in-line code 1111 | * generated by another program. This should be faster, smaller and easier 1112 | * to use. 1113 | * 1114 | * This is the first check-in of his code before I start futzing with it! 1115 | * 1116 | * Revision 1.5 2002/01/30 07:54:53 damo 1117 | * Fixed up the libtool versioning stuff (finally) 1118 | * Fixed bug 500600 (not detecting a NULL return from malloc) 1119 | * Fixed bug 509485 (no longer needs search.h) 1120 | * Cleaned up debugging section 1121 | * Allow multiple inclusions of redblack.h 1122 | * Thanks to Matthias Andree for reporting (and fixing) these 1123 | * 1124 | * Revision 1.4 2000/06/06 14:43:43 damo 1125 | * Added all the rbwalk & rbopenlist stuff. Fixed up malloc instead of sbrk. 1126 | * Added two new examples 1127 | * 1128 | * Revision 1.3 2000/05/24 06:45:27 damo 1129 | * Converted everything over to using const 1130 | * Added a new example1.c file to demonstrate the worst case scenario 1131 | * Minor fixups of the spec file 1132 | * 1133 | * Revision 1.2 2000/05/24 06:17:10 damo 1134 | * Fixed up the License (now the LGPL) 1135 | * 1136 | * Revision 1.1 2000/05/24 04:15:53 damo 1137 | * Initial import of files. Versions are now all over the place. Oh well 1138 | * 1139 | */ 1140 | 1141 | -------------------------------------------------------------------------------- /jni/libinotifytools/redblack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * RCS $Id: redblack.h,v 1.9 2003/10/24 01:31:21 damo Exp $ 3 | */ 4 | 5 | /* 6 | Redblack balanced tree algorithm 7 | Copyright (C) Damian Ivereigh 2000 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU Lesser General Public License as published by 11 | the Free Software Foundation; either version 2.1 of the License, or 12 | (at your option) any later version. See the file COPYING for details. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU Lesser General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 | */ 23 | 24 | /* Header file for redblack.c, should be included by any code that 25 | ** uses redblack.c since it defines the functions 26 | */ 27 | 28 | /* Stop multiple includes */ 29 | #ifndef _REDBLACK_H 30 | 31 | #ifndef RB_CUSTOMIZE 32 | /* 33 | * Without customization, the data member in the tree nodes is a void 34 | * pointer, and you need to pass in a comparison function to be 35 | * applied at runtime. With customization, you specify the data type 36 | * as the macro RB_ENTRY(data_t) (has to be a macro because compilers 37 | * gag on typdef void) and the name of the compare function as the 38 | * value of the macro RB_CMP. Because the comparison function is 39 | * compiled in, RB_CMP only needs to take two arguments. If your 40 | * content type is not a pointer, define INLINE to get direct access. 41 | */ 42 | #define rbdata_t void 43 | #define RB_CMP(s, t, e) (*rbinfo->rb_cmp)(s, t, e) 44 | #undef RB_INLINE 45 | #define RB_ENTRY(name) rb##name 46 | #endif /* RB_CUSTOMIZE */ 47 | 48 | #ifndef RB_STATIC 49 | #define RB_STATIC 50 | #endif 51 | 52 | /* Modes for rblookup */ 53 | #define RB_NONE -1 /* None of those below */ 54 | #define RB_LUEQUAL 0 /* Only exact match */ 55 | #define RB_LUGTEQ 1 /* Exact match or greater */ 56 | #define RB_LULTEQ 2 /* Exact match or less */ 57 | #define RB_LULESS 3 /* Less than key (not equal to) */ 58 | #define RB_LUGREAT 4 /* Greater than key (not equal to) */ 59 | #define RB_LUNEXT 5 /* Next key after current */ 60 | #define RB_LUPREV 6 /* Prev key before current */ 61 | #define RB_LUFIRST 7 /* First key in index */ 62 | #define RB_LULAST 8 /* Last key in index */ 63 | 64 | /* For rbwalk - pinched from search.h */ 65 | typedef enum 66 | { 67 | preorder, 68 | postorder, 69 | endorder, 70 | leaf 71 | } 72 | VISIT; 73 | 74 | struct RB_ENTRY(lists) { 75 | const struct RB_ENTRY(node) *rootp; 76 | const struct RB_ENTRY(node) *nextp; 77 | }; 78 | 79 | #define RBLIST struct RB_ENTRY(lists) 80 | 81 | struct RB_ENTRY(tree) { 82 | #ifndef RB_CUSTOMIZE 83 | /* comparison routine */ 84 | int (*rb_cmp)(const void *, const void *, const void *); 85 | /* config data to be passed to rb_cmp */ 86 | const void *rb_config; 87 | /* root of tree */ 88 | #endif /* RB_CUSTOMIZE */ 89 | struct RB_ENTRY(node) *rb_root; 90 | }; 91 | 92 | #ifndef RB_CUSTOMIZE 93 | RB_STATIC struct RB_ENTRY(tree) *rbinit(int (*)(const void *, const void *, const void *), 94 | const void *); 95 | #else 96 | RB_STATIC struct RB_ENTRY(tree) *RB_ENTRY(init)(void); 97 | #endif /* RB_CUSTOMIZE */ 98 | 99 | #ifndef no_delete 100 | RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(delete)(const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *); 101 | #endif 102 | 103 | #ifndef no_find 104 | RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(find)(const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *); 105 | #endif 106 | 107 | #ifndef no_lookup 108 | RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(lookup)(int, const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *); 109 | #endif 110 | 111 | #ifndef no_search 112 | RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(search)(const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *); 113 | #endif 114 | 115 | #ifndef no_destroy 116 | RB_STATIC void RB_ENTRY(destroy)(struct RB_ENTRY(tree) *); 117 | #endif 118 | 119 | #ifndef no_walk 120 | RB_STATIC void RB_ENTRY(walk)(const struct RB_ENTRY(tree) *, 121 | void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), 122 | void *); 123 | #endif 124 | 125 | #ifndef no_readlist 126 | RB_STATIC RBLIST *RB_ENTRY(openlist)(const struct RB_ENTRY(tree) *); 127 | RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(readlist)(RBLIST *); 128 | RB_STATIC void RB_ENTRY(closelist)(RBLIST *); 129 | #endif 130 | 131 | /* Some useful macros */ 132 | #define rbmin(rbinfo) RB_ENTRY(lookup)(RB_LUFIRST, NULL, (rbinfo)) 133 | #define rbmax(rbinfo) RB_ENTRY(lookup)(RB_LULAST, NULL, (rbinfo)) 134 | 135 | #define _REDBLACK_H 136 | #endif /* _REDBLACK_H */ 137 | 138 | /* 139 | * 140 | * $Log: redblack.h,v $ 141 | * Revision 1.9 2003/10/24 01:31:21 damo 142 | * Patches from Eric Raymond: %prefix is implemented.  Various other small 143 | * changes avoid stepping on global namespaces and improve the documentation. 144 | * 145 | * Revision 1.8 2003/10/23 04:18:47 damo 146 | * Fixed up the rbgen stuff ready for the 1.3 release 147 | * 148 | * Revision 1.7 2002/08/26 03:11:40 damo 149 | * Fixed up a bunch of compiler warnings when compiling example4 150 | * 151 | * Tidies up the Makefile.am & Specfile. 152 | * 153 | * Renamed redblack to rbgen 154 | * 155 | * Revision 1.6 2002/08/26 01:03:35 damo 156 | * Patch from Eric Raymond to change the way the library is used:- 157 | * 158 | * Eric's idea is to convert libredblack into a piece of in-line code 159 | * generated by another program. This should be faster, smaller and easier 160 | * to use. 161 | * 162 | * This is the first check-in of his code before I start futzing with it! 163 | * 164 | * Revision 1.5 2002/01/30 07:54:53 damo 165 | * Fixed up the libtool versioning stuff (finally) 166 | * Fixed bug 500600 (not detecting a NULL return from malloc) 167 | * Fixed bug 509485 (no longer needs search.h) 168 | * Cleaned up debugging section 169 | * Allow multiple inclusions of redblack.h 170 | * Thanks to Matthias Andree for reporting (and fixing) these 171 | * 172 | * Revision 1.4 2000/06/06 14:43:43 damo 173 | * Added all the rbwalk & rbopenlist stuff. Fixed up malloc instead of sbrk. 174 | * Added two new examples 175 | * 176 | * Revision 1.3 2000/05/24 06:45:27 damo 177 | * Converted everything over to using const 178 | * Added a new example1.c file to demonstrate the worst case scenario 179 | * Minor fixups of the spec file 180 | * 181 | * Revision 1.2 2000/05/24 06:17:10 damo 182 | * Fixed up the License (now the LGPL) 183 | * 184 | * Revision 1.1 2000/05/24 04:15:53 damo 185 | * Initial import of files. Versions are now all over the place. Oh well 186 | * 187 | */ 188 | 189 | -------------------------------------------------------------------------------- /jni/libinotifytools/test.c: -------------------------------------------------------------------------------- 1 | // kate: replace-tabs off; space-indent off; 2 | 3 | #include "inotifytools/inotifytools.h" 4 | #include "inotifytools/inotify.h" 5 | 6 | #include "../../config.h" 7 | 8 | #define __USE_MISC 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifdef HAVE_MCHECK_H 21 | #include 22 | #endif 23 | 24 | #define verify(A) if (!_verify((int)(A), #A, __FILE__, __LINE__, __PRETTY_FUNCTION__)) return; 25 | #define verify2(A,B) if (!_verify((int)(A), B, __FILE__, __LINE__, __PRETTY_FUNCTION__)) return; 26 | #define compare(A,B) if (!_compare((int)(A), (int)(B), #A, #B, __FILE__, __LINE__, __PRETTY_FUNCTION__))return; 27 | 28 | #define succeed() do {\ 29 | ++tests_succeeded;\ 30 | /*fprintf(stderr, "%s:%d Test '%s' passed", file, line, func);*/\ 31 | /*fprintf(stderr, "\n");*/\ 32 | } while(0) 33 | 34 | #define fail(...) do {\ 35 | ++tests_failed;\ 36 | fprintf(stderr, "%s:%d Test '%s' failed: ", file, line, func);\ 37 | fprintf(stderr, __VA_ARGS__);\ 38 | fprintf(stderr, "\n");\ 39 | if (inotifytools_error() != 0) {\ 40 | fprintf(stderr, "inotifytools_error() returns %d (%s)\n",\ 41 | inotifytools_error(), strerror( inotifytools_error() ) );\ 42 | }\ 43 | } while(0) 44 | 45 | #define TEST_DIR "/tmp/inotifytools_test" 46 | 47 | #define INFO(...) do { \ 48 | printf("%s: ", __PRETTY_FUNCTION__); \ 49 | printf(__VA_ARGS__); \ 50 | } while(0) 51 | 52 | #define ENTER INFO("test begin\n"); 53 | #define EXIT INFO("test end\n"); 54 | 55 | 56 | static int tests_failed; 57 | static int tests_succeeded; 58 | 59 | int _verify( int cond, char const * teststr, char const * file, int line, char const *func ) { 60 | if ( cond ) { 61 | succeed(); 62 | return cond; 63 | } 64 | 65 | fail("Verification failed (%s)", teststr); 66 | return cond; 67 | } 68 | 69 | int _compare( int value, int expval, char const* act_str, char const* exp_str, char const* file, 70 | int line, char const *func ) { 71 | if ( value == expval ) { 72 | succeed(); 73 | return 1; 74 | } 75 | 76 | fail("Actual (%s): %d, Expected (%s): %d", act_str, value, exp_str, expval); 77 | return 0; 78 | } 79 | 80 | void event_to_str() { 81 | ENTER 82 | verify2( 83 | !strcmp( inotifytools_event_to_str( IN_OPEN | IN_MODIFY | IN_ACCESS ), 84 | "OPEN,MODIFY,ACCESS" ) || 85 | !strcmp( inotifytools_event_to_str( IN_OPEN | IN_MODIFY | IN_ACCESS ), 86 | "OPEN,ACCESS,MODIFY" ) || 87 | !strcmp( inotifytools_event_to_str( IN_OPEN | IN_MODIFY | IN_ACCESS ), 88 | "ACCESS,OPEN,MODIFY" ) || 89 | !strcmp( inotifytools_event_to_str( IN_OPEN | IN_MODIFY | IN_ACCESS ), 90 | "MODIFY,OPEN,ACCESS" ) || 91 | !strcmp( inotifytools_event_to_str( IN_OPEN | IN_MODIFY | IN_ACCESS ), 92 | "ACCESS,MODIFY,OPEN" ) || 93 | !strcmp( inotifytools_event_to_str( IN_OPEN | IN_MODIFY | IN_ACCESS ), 94 | "MODIFY,ACCESS,OPEN" ) 95 | , inotifytools_event_to_str( IN_OPEN | IN_MODIFY | IN_ACCESS )); 96 | EXIT 97 | } 98 | 99 | void event_to_str_sep() { 100 | ENTER 101 | verify2( 102 | !strcmp( inotifytools_event_to_str_sep(IN_OPEN|IN_MODIFY|IN_ACCESS,':'), 103 | "OPEN:MODIFY:ACCESS" ) || 104 | !strcmp( inotifytools_event_to_str_sep(IN_OPEN|IN_MODIFY|IN_ACCESS,':'), 105 | "OPEN:ACCESS:MODIFY" ) || 106 | !strcmp( inotifytools_event_to_str_sep(IN_OPEN|IN_MODIFY|IN_ACCESS,':'), 107 | "ACCESS:OPEN:MODIFY" ) || 108 | !strcmp( inotifytools_event_to_str_sep(IN_OPEN|IN_MODIFY|IN_ACCESS,':'), 109 | "MODIFY:OPEN:ACCESS" ) || 110 | !strcmp( inotifytools_event_to_str_sep(IN_OPEN|IN_MODIFY|IN_ACCESS,':'), 111 | "ACCESS:MODIFY:OPEN" ) || 112 | !strcmp( inotifytools_event_to_str_sep(IN_OPEN|IN_MODIFY|IN_ACCESS,':'), 113 | "MODIFY:ACCESS:OPEN" ) 114 | ,inotifytools_event_to_str_sep(IN_OPEN|IN_MODIFY|IN_ACCESS,':')); 115 | EXIT 116 | } 117 | 118 | void str_to_event() { 119 | ENTER 120 | compare( inotifytools_str_to_event("open,modify,access"), 121 | IN_OPEN | IN_MODIFY | IN_ACCESS ); 122 | compare( inotifytools_str_to_event(",open,modify,access"), 0 ); 123 | compare( inotifytools_str_to_event("open,modify,access,"), 0 ); 124 | compare( inotifytools_str_to_event("open,modify,,access,close"), 0 ); 125 | compare( inotifytools_str_to_event("open,mod,access,close"), -1 ); 126 | compare( inotifytools_str_to_event("mod"), -1 ); 127 | compare( inotifytools_str_to_event(","), 0 ); 128 | compare( inotifytools_str_to_event(",,"), 0 ); 129 | compare( inotifytools_str_to_event("open"), IN_OPEN ); 130 | compare( inotifytools_str_to_event("close"), IN_CLOSE ); 131 | compare( inotifytools_str_to_event(",close"), 0 ); 132 | compare( inotifytools_str_to_event(",,close"), 0 ); 133 | compare( inotifytools_str_to_event("close,"), 0 ); 134 | compare( inotifytools_str_to_event("close,,"), 0 ); 135 | EXIT 136 | } 137 | 138 | void str_to_event_sep() { 139 | ENTER 140 | compare( inotifytools_str_to_event_sep("open:modify:access", ':'), 141 | IN_OPEN | IN_MODIFY | IN_ACCESS ); 142 | compare( inotifytools_str_to_event_sep("open,modify,access", ','), 143 | IN_OPEN | IN_MODIFY | IN_ACCESS ); 144 | compare( inotifytools_str_to_event_sep(":open:modify:access", ':'), 0 ); 145 | compare( inotifytools_str_to_event_sep("open:modify:access:", ':'), 0 ); 146 | compare( inotifytools_str_to_event_sep("open:modify::access:close", ':'),0); 147 | compare( inotifytools_str_to_event_sep("open:mod:access:close", ':'), -1 ); 148 | compare( inotifytools_str_to_event_sep("mod", ':'), -1 ); 149 | compare( inotifytools_str_to_event_sep(":", ':'), 0 ); 150 | compare( inotifytools_str_to_event_sep("::", ':'), 0 ); 151 | compare( inotifytools_str_to_event_sep("open", ':'), IN_OPEN ); 152 | compare( inotifytools_str_to_event_sep("close", ':'), IN_CLOSE ); 153 | compare( inotifytools_str_to_event_sep(":close", ':'), 0 ); 154 | compare( inotifytools_str_to_event_sep("::close", ':'), 0 ); 155 | compare( inotifytools_str_to_event_sep("close:", ':'), 0 ); 156 | compare( inotifytools_str_to_event_sep("close::", ':'), 0 ); 157 | compare( inotifytools_str_to_event_sep("open:modify:access", ','), -1 ); 158 | compare( inotifytools_str_to_event_sep("open:modify:access", 'o'), -1 ); 159 | EXIT 160 | } 161 | 162 | void basic_watch_info() { 163 | ENTER 164 | verify( inotifytools_initialize() ); 165 | verify( inotifytools_watch_file( "/", IN_CLOSE ) ); 166 | compare( inotifytools_wd_from_filename( "/" ), 1 ); 167 | compare( inotifytools_wd_from_filename( "foobar" ), -1 ); 168 | verify( !strcmp( inotifytools_filename_from_wd(1), "/" ) ); 169 | verify( inotifytools_remove_watch_by_filename( "/" ) ); 170 | compare( inotifytools_wd_from_filename( "/" ), -1 ); 171 | compare( inotifytools_filename_from_wd( 1 ), 0 ); 172 | verify( inotifytools_watch_file( "/", IN_CLOSE ) ); 173 | compare( inotifytools_wd_from_filename( "/" ), 2 ); 174 | compare( inotifytools_wd_from_filename( "foobar" ), -1 ); 175 | verify( !strcmp( inotifytools_filename_from_wd(2), "/" ) ); 176 | verify( inotifytools_remove_watch_by_wd( 2 ) ); 177 | compare( inotifytools_wd_from_filename( "/" ), -1 ); 178 | compare( inotifytools_filename_from_wd( 2 ), 0 ); 179 | EXIT 180 | } 181 | 182 | void tst_inotifytools_snprintf() { 183 | ENTER 184 | verify( (0 == mkdir(TEST_DIR, 0700)) || (EEXIST == errno) ); 185 | verify( inotifytools_initialize() ); 186 | verify( inotifytools_watch_file( TEST_DIR, IN_CLOSE ) ); 187 | 188 | #define BUFSZ 2048 189 | #define RESET do { \ 190 | memset(buf, 0, BUFSZ); \ 191 | memset(test_event, 0, sizeof(struct inotify_event)); \ 192 | test_event->wd = inotifytools_wd_from_filename( TEST_DIR "/"); \ 193 | verify( test_event->wd >= 0 ); \ 194 | inotifytools_set_printf_timefmt(0); \ 195 | } while(0) 196 | 197 | char buf[BUFSZ]; 198 | char event_buf[4096]; 199 | struct inotify_event *test_event = (struct inotify_event*)event_buf; 200 | 201 | RESET; 202 | test_event->mask = IN_ACCESS; 203 | inotifytools_snprintf(buf, 1024, test_event, "Event %e %.e on %w %f %T"); 204 | verify2( !strcmp(buf, "Event ACCESS ACCESS on " TEST_DIR "/ "), buf ); 205 | 206 | RESET; 207 | test_event->mask = IN_ACCESS | IN_DELETE; 208 | inotifytools_snprintf(buf, 1024, test_event, "Event %e %.e on %w %f %T"); 209 | verify2( !strcmp(buf, "Event ACCESS,DELETE ACCESS.DELETE on " TEST_DIR "/ ") 210 | || !strcmp(buf, "Event DELETE,ACCESS DELETE.ACCESS on " TEST_DIR "/ "), buf ); 211 | 212 | RESET; 213 | test_event->mask = IN_MODIFY; 214 | inotifytools_snprintf(buf, 10, test_event, "Event %e %.e on %w %f %T"); 215 | verify2( !strcmp(buf, "Event MODI"), buf ); 216 | 217 | RESET; 218 | test_event->mask = IN_ACCESS; 219 | strcpy( test_event->name, "my_great_file" ); 220 | test_event->len = strlen( test_event->name )+1; 221 | inotifytools_snprintf(buf, 1024, test_event, "Event %e %.e on %w %f %T"); 222 | verify2( !strcmp(buf, "Event ACCESS ACCESS on " TEST_DIR "/ my_great_file "), buf ); 223 | 224 | RESET; 225 | test_event->mask = IN_ACCESS; 226 | inotifytools_set_printf_timefmt("%D%% %H:%M"); 227 | { 228 | char expected[1024]; 229 | char timestr[1024]; 230 | time_t now = time(0); 231 | strftime(timestr, 1024, "%D%% %H:%M", localtime(&now)); 232 | snprintf(expected, 1024, "Event ACCESS ACCESS on %s/ %s", TEST_DIR, timestr); 233 | inotifytools_snprintf(buf, 1024, test_event, "Event %e %.e on %w %f %T"); 234 | verify2( !strcmp(buf, expected), buf ); 235 | } 236 | 237 | #undef BUFSZ 238 | EXIT 239 | } 240 | 241 | void watch_limit() { 242 | ENTER 243 | verify( (0 == mkdir(TEST_DIR, 0700)) || (EEXIST == errno) ); 244 | 245 | INFO("Warning, this test may take a while\n"); 246 | #define INNER_LIMIT 16000 247 | #define OUTER_LIMIT 5 248 | 249 | verify( inotifytools_initialize() ); 250 | inotifytools_initialize_stats(); 251 | 252 | for (int j = 0; j < OUTER_LIMIT; ++j) { 253 | char fn[1024]; 254 | int max = 0; 255 | for (int i = 0; i < INNER_LIMIT; ++i) { 256 | snprintf(fn, 1023, "%s/%d", TEST_DIR, i); 257 | int fd = creat(fn, 0700); 258 | verify( -1 != fd ); 259 | verify( 0 == close(fd) ); 260 | int ret = inotifytools_watch_file(fn, IN_ALL_EVENTS); 261 | verify( ret || inotifytools_error() == ENOSPC ); 262 | if (ret) { 263 | max = i + 1; 264 | int wd = inotifytools_wd_from_filename(fn); 265 | verify(wd > 0); 266 | verify( !strcmp(fn, inotifytools_filename_from_wd(wd) ) ); 267 | } 268 | } 269 | 270 | compare( inotifytools_get_num_watches(), max ); 271 | 272 | for (int i = 0; i < max; ++i) { 273 | snprintf(fn, 1023, "%s/%d", TEST_DIR, i); 274 | verify( inotifytools_remove_watch_by_filename(fn) ); 275 | } 276 | } 277 | EXIT 278 | } 279 | 280 | void cleanup() { 281 | compare( system("rm -rf " TEST_DIR), 0 ); 282 | inotifytools_cleanup(); 283 | } 284 | 285 | int main() { 286 | tests_failed = 0; 287 | tests_succeeded = 0; 288 | 289 | #ifdef HAVE_MCHECK_H 290 | char *mtrace_name = getenv("MALLOC_TRACE"); 291 | if (mtrace_name) { 292 | printf("malloc trace might be written to %s\n", mtrace_name); 293 | } else { 294 | printf("If you want to do a malloc trace, set MALLOC_TRACE to " 295 | "a path for logging.\n"); 296 | } 297 | mtrace(); 298 | #endif 299 | 300 | cleanup(); 301 | 302 | event_to_str(); 303 | cleanup(); 304 | event_to_str_sep(); 305 | cleanup(); 306 | 307 | str_to_event(); 308 | cleanup(); 309 | str_to_event_sep(); 310 | cleanup(); 311 | 312 | basic_watch_info(); 313 | cleanup(); 314 | 315 | watch_limit(); 316 | cleanup(); 317 | 318 | tst_inotifytools_snprintf(); 319 | cleanup(); 320 | 321 | printf("Out of %d tests, %d succeeded and %d failed.\n", 322 | tests_failed + tests_succeeded, tests_succeeded, tests_failed ); 323 | 324 | if ( tests_failed ) return -tests_failed; 325 | } 326 | -------------------------------------------------------------------------------- /jni/regex/LICENSES: -------------------------------------------------------------------------------- 1 | This file contains the copying permission notices for various files in the 2 | GNU C Library distribution that have copyright owners other than the Free 3 | Software Foundation. These notices all require that a copy of the notice 4 | be included in the accompanying documentation and be distributed with 5 | binary distributions of the code, so be sure to include this file along 6 | with any binary distributions derived from the GNU C Library. 7 | 8 | 9 | All code incorporated from 4.4 BSD is distributed under the following 10 | license: 11 | 12 | Copyright (C) 1991 Regents of the University of California. 13 | All rights reserved. 14 | 15 | Redistribution and use in source and binary forms, with or without 16 | modification, are permitted provided that the following conditions 17 | are met: 18 | 19 | 1. Redistributions of source code must retain the above copyright 20 | notice, this list of conditions and the following disclaimer. 21 | 2. Redistributions in binary form must reproduce the above copyright 22 | notice, this list of conditions and the following disclaimer in the 23 | documentation and/or other materials provided with the distribution. 24 | 3. [This condition was removed.] 25 | 4. Neither the name of the University nor the names of its contributors 26 | may be used to endorse or promote products derived from this software 27 | without specific prior written permission. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 | SUCH DAMAGE. 40 | 41 | The DNS resolver code, taken from BIND 4.9.5, is copyrighted both by 42 | UC Berkeley and by Digital Equipment Corporation. The DEC portions 43 | are under the following license: 44 | 45 | Portions Copyright (C) 1993 by Digital Equipment Corporation. 46 | 47 | Permission to use, copy, modify, and distribute this software for any 48 | purpose with or without fee is hereby granted, provided that the above 49 | copyright notice and this permission notice appear in all copies, and 50 | that the name of Digital Equipment Corporation not be used in 51 | advertising or publicity pertaining to distribution of the document or 52 | software without specific, written prior permission. 53 | 54 | THE SOFTWARE IS PROVIDED ``AS IS'' AND DIGITAL EQUIPMENT CORP. 55 | DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 56 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 57 | DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, 58 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 59 | FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 60 | NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 61 | WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 62 | 63 | The Sun RPC support (from rpcsrc-4.0) is covered by the following 64 | license: 65 | 66 | Copyright (C) 1984, Sun Microsystems, Inc. 67 | 68 | Sun RPC is a product of Sun Microsystems, Inc. and is provided for 69 | unrestricted use provided that this legend is included on all tape media 70 | and as a part of the software program in whole or part. Users may copy 71 | or modify Sun RPC without charge, but are not authorized to license or 72 | distribute it to anyone else except as part of a product or program 73 | developed by the user. 74 | 75 | SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 76 | WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 77 | PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 78 | 79 | Sun RPC is provided with no support and without any obligation on the 80 | part of Sun Microsystems, Inc. to assist in its use, correction, 81 | modification or enhancement. 82 | 83 | SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 84 | INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 85 | OR ANY PART THEREOF. 86 | 87 | In no event will Sun Microsystems, Inc. be liable for any lost revenue 88 | or profits or other special, indirect and consequential damages, even if 89 | Sun has been advised of the possibility of such damages. 90 | 91 | 92 | The following CMU license covers some of the support code for Mach, 93 | derived from Mach 3.0: 94 | 95 | Mach Operating System 96 | Copyright (C) 1991,1990,1989 Carnegie Mellon University 97 | All Rights Reserved. 98 | 99 | Permission to use, copy, modify and distribute this software and its 100 | documentation is hereby granted, provided that both the copyright 101 | notice and this permission notice appear in all copies of the 102 | software, derivative works or modified versions, and any portions 103 | thereof, and that both notices appear in supporting documentation. 104 | 105 | CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS ``AS IS'' 106 | CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 107 | ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 108 | 109 | Carnegie Mellon requests users of this software to return to 110 | 111 | Software Distribution Coordinator 112 | School of Computer Science 113 | Carnegie Mellon University 114 | Pittsburgh PA 15213-3890 115 | 116 | or Software.Distribution@CS.CMU.EDU any improvements or 117 | extensions that they make and grant Carnegie Mellon the rights to 118 | redistribute these changes. 119 | 120 | The file if_ppp.h is under the following CMU license: 121 | 122 | Redistribution and use in source and binary forms, with or without 123 | modification, are permitted provided that the following conditions 124 | are met: 125 | 1. Redistributions of source code must retain the above copyright 126 | notice, this list of conditions and the following disclaimer. 127 | 2. Redistributions in binary form must reproduce the above copyright 128 | notice, this list of conditions and the following disclaimer in the 129 | documentation and/or other materials provided with the distribution. 130 | 3. Neither the name of the University nor the names of its contributors 131 | may be used to endorse or promote products derived from this software 132 | without specific prior written permission. 133 | 134 | THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY AND 135 | CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 136 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 137 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 138 | IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY 139 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 140 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 141 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 142 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 143 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 144 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 145 | IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 146 | 147 | The following license covers the files from Intel's "Highly Optimized 148 | Mathematical Functions for Itanium" collection: 149 | 150 | Intel License Agreement 151 | 152 | Copyright (c) 2000, Intel Corporation 153 | 154 | All rights reserved. 155 | 156 | Redistribution and use in source and binary forms, with or without 157 | modification, are permitted provided that the following conditions are 158 | met: 159 | 160 | * Redistributions of source code must retain the above copyright 161 | notice, this list of conditions and the following disclaimer. 162 | 163 | * Redistributions in binary form must reproduce the above copyright 164 | notice, this list of conditions and the following disclaimer in the 165 | documentation and/or other materials provided with the distribution. 166 | 167 | * The name of Intel Corporation may not be used to endorse or promote 168 | products derived from this software without specific prior written 169 | permission. 170 | 171 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 173 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 174 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 175 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 176 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 177 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 178 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 179 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 180 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 181 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 182 | 183 | The files inet/getnameinfo.c and sysdeps/posix/getaddrinfo.c are copyright 184 | (C) by Craig Metz and are distributed under the following license: 185 | 186 | /* The Inner Net License, Version 2.00 187 | 188 | The author(s) grant permission for redistribution and use in source and 189 | binary forms, with or without modification, of the software and documentation 190 | provided that the following conditions are met: 191 | 192 | 0. If you receive a version of the software that is specifically labelled 193 | as not being for redistribution (check the version message and/or README), 194 | you are not permitted to redistribute that version of the software in any 195 | way or form. 196 | 1. All terms of the all other applicable copyrights and licenses must be 197 | followed. 198 | 2. Redistributions of source code must retain the authors' copyright 199 | notice(s), this list of conditions, and the following disclaimer. 200 | 3. Redistributions in binary form must reproduce the authors' copyright 201 | notice(s), this list of conditions, and the following disclaimer in the 202 | documentation and/or other materials provided with the distribution. 203 | 4. [The copyright holder has authorized the removal of this clause.] 204 | 5. Neither the name(s) of the author(s) nor the names of its contributors 205 | may be used to endorse or promote products derived from this software 206 | without specific prior written permission. 207 | 208 | THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY 209 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 210 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 211 | DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY 212 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 213 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 214 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 215 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 216 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 217 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 218 | 219 | If these license terms cause you a real problem, contact the author. */ 220 | -------------------------------------------------------------------------------- /jni/regex/re_comp.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 1996 Free Software Foundation, Inc. 2 | This file is part of the GNU C Library. 3 | 4 | The GNU C Library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public 6 | License as published by the Free Software Foundation; either 7 | version 2.1 of the License, or (at your option) any later version. 8 | 9 | The GNU C Library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with the GNU C Library; if not, write to the Free 16 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 17 | 02111-1307 USA. */ 18 | 19 | #ifndef _RE_COMP_H 20 | #define _RE_COMP_H 1 21 | 22 | /* This is only a wrapper around the file. XPG4.2 mentions 23 | this name. */ 24 | #include 25 | 26 | #endif /* re_comp.h */ 27 | -------------------------------------------------------------------------------- /jni/regex/regex.c: -------------------------------------------------------------------------------- 1 | /* Extended regular expression matching and search library. 2 | Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. 3 | This file is part of the GNU C Library. 4 | Contributed by Isamu Hasegawa . 5 | 6 | The GNU C Library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | The GNU C Library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with the GNU C Library; if not, write to the Free 18 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 19 | 02111-1307 USA. */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | /* Make sure noone compiles this code with a C++ compiler. */ 26 | #ifdef __cplusplus 27 | # error "This is C code, use a C compiler" 28 | #endif 29 | 30 | #ifdef _LIBC 31 | /* We have to keep the namespace clean. */ 32 | # define regfree(preg) __regfree (preg) 33 | # define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) 34 | # define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) 35 | # define regerror(errcode, preg, errbuf, errbuf_size) \ 36 | __regerror(errcode, preg, errbuf, errbuf_size) 37 | # define re_set_registers(bu, re, nu, st, en) \ 38 | __re_set_registers (bu, re, nu, st, en) 39 | # define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ 40 | __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) 41 | # define re_match(bufp, string, size, pos, regs) \ 42 | __re_match (bufp, string, size, pos, regs) 43 | # define re_search(bufp, string, size, startpos, range, regs) \ 44 | __re_search (bufp, string, size, startpos, range, regs) 45 | # define re_compile_pattern(pattern, length, bufp) \ 46 | __re_compile_pattern (pattern, length, bufp) 47 | # define re_set_syntax(syntax) __re_set_syntax (syntax) 48 | # define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ 49 | __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) 50 | # define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) 51 | 52 | # include "../locale/localeinfo.h" 53 | #endif 54 | 55 | /* On some systems, limits.h sets RE_DUP_MAX to a lower value than 56 | GNU regex allows. Include it before , which correctly 57 | #undefs RE_DUP_MAX and sets it to the right value. */ 58 | #include 59 | 60 | #include "regex.h" 61 | #include "regex_internal.h" 62 | 63 | #include "regex_internal.c" 64 | #include "regcomp.c" 65 | #include "regexec.c" 66 | 67 | /* Binary backward compatibility. */ 68 | #if _LIBC 69 | # include 70 | # if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3) 71 | link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.") 72 | int re_max_failures = 2000; 73 | # endif 74 | #endif 75 | -------------------------------------------------------------------------------- /jni/regex/regex.h: -------------------------------------------------------------------------------- 1 | /* Definitions for data structures and routines for the regular 2 | expression library. 3 | Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003,2005,2006,2008 4 | Free Software Foundation, Inc. 5 | This file is part of the GNU C Library. 6 | 7 | The GNU C Library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | The GNU C Library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with the GNU C Library; if not, write to the Free 19 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 20 | 02111-1307 USA. */ 21 | 22 | #ifndef _REGEX_H 23 | #define _REGEX_H 1 24 | 25 | #include 26 | 27 | /* Allow the use in C++ code. */ 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | /* The following two types have to be signed and unsigned integer type 33 | wide enough to hold a value of a pointer. For most ANSI compilers 34 | ptrdiff_t and size_t should be likely OK. Still size of these two 35 | types is 2 for Microsoft C. Ugh... */ 36 | typedef long int s_reg_t; 37 | typedef unsigned long int active_reg_t; 38 | 39 | /* The following bits are used to determine the regexp syntax we 40 | recognize. The set/not-set meanings are chosen so that Emacs syntax 41 | remains the value 0. The bits are given in alphabetical order, and 42 | the definitions shifted by one from the previous bit; thus, when we 43 | add or remove a bit, only one other definition need change. */ 44 | typedef unsigned long int reg_syntax_t; 45 | 46 | #ifdef __USE_GNU 47 | /* If this bit is not set, then \ inside a bracket expression is literal. 48 | If set, then such a \ quotes the following character. */ 49 | # define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) 50 | 51 | /* If this bit is not set, then + and ? are operators, and \+ and \? are 52 | literals. 53 | If set, then \+ and \? are operators and + and ? are literals. */ 54 | # define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) 55 | 56 | /* If this bit is set, then character classes are supported. They are: 57 | [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], 58 | [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. 59 | If not set, then character classes are not supported. */ 60 | # define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) 61 | 62 | /* If this bit is set, then ^ and $ are always anchors (outside bracket 63 | expressions, of course). 64 | If this bit is not set, then it depends: 65 | ^ is an anchor if it is at the beginning of a regular 66 | expression or after an open-group or an alternation operator; 67 | $ is an anchor if it is at the end of a regular expression, or 68 | before a close-group or an alternation operator. 69 | 70 | This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because 71 | POSIX draft 11.2 says that * etc. in leading positions is undefined. 72 | We already implemented a previous draft which made those constructs 73 | invalid, though, so we haven't changed the code back. */ 74 | # define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) 75 | 76 | /* If this bit is set, then special characters are always special 77 | regardless of where they are in the pattern. 78 | If this bit is not set, then special characters are special only in 79 | some contexts; otherwise they are ordinary. Specifically, 80 | * + ? and intervals are only special when not after the beginning, 81 | open-group, or alternation operator. */ 82 | # define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) 83 | 84 | /* If this bit is set, then *, +, ?, and { cannot be first in an re or 85 | immediately after an alternation or begin-group operator. */ 86 | # define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) 87 | 88 | /* If this bit is set, then . matches newline. 89 | If not set, then it doesn't. */ 90 | # define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) 91 | 92 | /* If this bit is set, then . doesn't match NUL. 93 | If not set, then it does. */ 94 | # define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) 95 | 96 | /* If this bit is set, nonmatching lists [^...] do not match newline. 97 | If not set, they do. */ 98 | # define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) 99 | 100 | /* If this bit is set, either \{...\} or {...} defines an 101 | interval, depending on RE_NO_BK_BRACES. 102 | If not set, \{, \}, {, and } are literals. */ 103 | # define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) 104 | 105 | /* If this bit is set, +, ? and | aren't recognized as operators. 106 | If not set, they are. */ 107 | # define RE_LIMITED_OPS (RE_INTERVALS << 1) 108 | 109 | /* If this bit is set, newline is an alternation operator. 110 | If not set, newline is literal. */ 111 | # define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) 112 | 113 | /* If this bit is set, then `{...}' defines an interval, and \{ and \} 114 | are literals. 115 | If not set, then `\{...\}' defines an interval. */ 116 | # define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) 117 | 118 | /* If this bit is set, (...) defines a group, and \( and \) are literals. 119 | If not set, \(...\) defines a group, and ( and ) are literals. */ 120 | # define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) 121 | 122 | /* If this bit is set, then \ matches . 123 | If not set, then \ is a back-reference. */ 124 | # define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) 125 | 126 | /* If this bit is set, then | is an alternation operator, and \| is literal. 127 | If not set, then \| is an alternation operator, and | is literal. */ 128 | # define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) 129 | 130 | /* If this bit is set, then an ending range point collating higher 131 | than the starting range point, as in [z-a], is invalid. 132 | If not set, then when ending range point collates higher than the 133 | starting range point, the range is ignored. */ 134 | # define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) 135 | 136 | /* If this bit is set, then an unmatched ) is ordinary. 137 | If not set, then an unmatched ) is invalid. */ 138 | # define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) 139 | 140 | /* If this bit is set, succeed as soon as we match the whole pattern, 141 | without further backtracking. */ 142 | # define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) 143 | 144 | /* If this bit is set, do not process the GNU regex operators. 145 | If not set, then the GNU regex operators are recognized. */ 146 | # define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) 147 | 148 | /* If this bit is set, turn on internal regex debugging. 149 | If not set, and debugging was on, turn it off. 150 | This only works if regex.c is compiled -DDEBUG. 151 | We define this bit always, so that all that's needed to turn on 152 | debugging is to recompile regex.c; the calling code can always have 153 | this bit set, and it won't affect anything in the normal case. */ 154 | # define RE_DEBUG (RE_NO_GNU_OPS << 1) 155 | 156 | /* If this bit is set, a syntactically invalid interval is treated as 157 | a string of ordinary characters. For example, the ERE 'a{1' is 158 | treated as 'a\{1'. */ 159 | # define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1) 160 | 161 | /* If this bit is set, then ignore case when matching. 162 | If not set, then case is significant. */ 163 | # define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) 164 | 165 | /* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only 166 | for ^, because it is difficult to scan the regex backwards to find 167 | whether ^ should be special. */ 168 | # define RE_CARET_ANCHORS_HERE (RE_ICASE << 1) 169 | 170 | /* If this bit is set, then \{ cannot be first in an bre or 171 | immediately after an alternation or begin-group operator. */ 172 | # define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1) 173 | 174 | /* If this bit is set, then no_sub will be set to 1 during 175 | re_compile_pattern. */ 176 | # define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1) 177 | #endif 178 | 179 | /* This global variable defines the particular regexp syntax to use (for 180 | some interfaces). When a regexp is compiled, the syntax used is 181 | stored in the pattern buffer, so changing this does not affect 182 | already-compiled regexps. */ 183 | extern reg_syntax_t re_syntax_options; 184 | 185 | #ifdef __USE_GNU 186 | /* Define combinations of the above bits for the standard possibilities. 187 | (The [[[ comments delimit what gets put into the Texinfo file, so 188 | don't delete them!) */ 189 | /* [[[begin syntaxes]]] */ 190 | #define RE_SYNTAX_EMACS 0 191 | 192 | #define RE_SYNTAX_AWK \ 193 | (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ 194 | | RE_NO_BK_PARENS | RE_NO_BK_REFS \ 195 | | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ 196 | | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ 197 | | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) 198 | 199 | #define RE_SYNTAX_GNU_AWK \ 200 | ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \ 201 | & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS \ 202 | | RE_CONTEXT_INVALID_OPS )) 203 | 204 | #define RE_SYNTAX_POSIX_AWK \ 205 | (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ 206 | | RE_INTERVALS | RE_NO_GNU_OPS) 207 | 208 | #define RE_SYNTAX_GREP \ 209 | (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ 210 | | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ 211 | | RE_NEWLINE_ALT) 212 | 213 | #define RE_SYNTAX_EGREP \ 214 | (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ 215 | | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ 216 | | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ 217 | | RE_NO_BK_VBAR) 218 | 219 | #define RE_SYNTAX_POSIX_EGREP \ 220 | (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \ 221 | | RE_INVALID_INTERVAL_ORD) 222 | 223 | /* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ 224 | #define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC 225 | 226 | #define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC 227 | 228 | /* Syntax bits common to both basic and extended POSIX regex syntax. */ 229 | #define _RE_SYNTAX_POSIX_COMMON \ 230 | (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ 231 | | RE_INTERVALS | RE_NO_EMPTY_RANGES) 232 | 233 | #define RE_SYNTAX_POSIX_BASIC \ 234 | (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP) 235 | 236 | /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes 237 | RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this 238 | isn't minimal, since other operators, such as \`, aren't disabled. */ 239 | #define RE_SYNTAX_POSIX_MINIMAL_BASIC \ 240 | (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) 241 | 242 | #define RE_SYNTAX_POSIX_EXTENDED \ 243 | (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ 244 | | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ 245 | | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ 246 | | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) 247 | 248 | /* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is 249 | removed and RE_NO_BK_REFS is added. */ 250 | #define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ 251 | (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ 252 | | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ 253 | | RE_NO_BK_PARENS | RE_NO_BK_REFS \ 254 | | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) 255 | /* [[[end syntaxes]]] */ 256 | 257 | /* Maximum number of duplicates an interval can allow. Some systems 258 | (erroneously) define this in other header files, but we want our 259 | value, so remove any previous define. */ 260 | # ifdef RE_DUP_MAX 261 | # undef RE_DUP_MAX 262 | # endif 263 | /* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */ 264 | # define RE_DUP_MAX (0x7fff) 265 | #endif 266 | 267 | 268 | /* POSIX `cflags' bits (i.e., information for `regcomp'). */ 269 | 270 | /* If this bit is set, then use extended regular expression syntax. 271 | If not set, then use basic regular expression syntax. */ 272 | #define REG_EXTENDED 1 273 | 274 | /* If this bit is set, then ignore case when matching. 275 | If not set, then case is significant. */ 276 | #define REG_ICASE (REG_EXTENDED << 1) 277 | 278 | /* If this bit is set, then anchors do not match at newline 279 | characters in the string. 280 | If not set, then anchors do match at newlines. */ 281 | #define REG_NEWLINE (REG_ICASE << 1) 282 | 283 | /* If this bit is set, then report only success or fail in regexec. 284 | If not set, then returns differ between not matching and errors. */ 285 | #define REG_NOSUB (REG_NEWLINE << 1) 286 | 287 | 288 | /* POSIX `eflags' bits (i.e., information for regexec). */ 289 | 290 | /* If this bit is set, then the beginning-of-line operator doesn't match 291 | the beginning of the string (presumably because it's not the 292 | beginning of a line). 293 | If not set, then the beginning-of-line operator does match the 294 | beginning of the string. */ 295 | #define REG_NOTBOL 1 296 | 297 | /* Like REG_NOTBOL, except for the end-of-line. */ 298 | #define REG_NOTEOL (1 << 1) 299 | 300 | /* Use PMATCH[0] to delimit the start and end of the search in the 301 | buffer. */ 302 | #define REG_STARTEND (1 << 2) 303 | 304 | 305 | /* If any error codes are removed, changed, or added, update the 306 | `re_error_msg' table in regex.c. */ 307 | typedef enum 308 | { 309 | #if defined _XOPEN_SOURCE || defined __USE_XOPEN2K 310 | REG_ENOSYS = -1, /* This will never happen for this implementation. */ 311 | #endif 312 | 313 | REG_NOERROR = 0, /* Success. */ 314 | REG_NOMATCH, /* Didn't find a match (for regexec). */ 315 | 316 | /* POSIX regcomp return error codes. (In the order listed in the 317 | standard.) */ 318 | REG_BADPAT, /* Invalid pattern. */ 319 | REG_ECOLLATE, /* Inalid collating element. */ 320 | REG_ECTYPE, /* Invalid character class name. */ 321 | REG_EESCAPE, /* Trailing backslash. */ 322 | REG_ESUBREG, /* Invalid back reference. */ 323 | REG_EBRACK, /* Unmatched left bracket. */ 324 | REG_EPAREN, /* Parenthesis imbalance. */ 325 | REG_EBRACE, /* Unmatched \{. */ 326 | REG_BADBR, /* Invalid contents of \{\}. */ 327 | REG_ERANGE, /* Invalid range end. */ 328 | REG_ESPACE, /* Ran out of memory. */ 329 | REG_BADRPT, /* No preceding re for repetition op. */ 330 | 331 | /* Error codes we've added. */ 332 | REG_EEND, /* Premature end. */ 333 | REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ 334 | REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ 335 | } reg_errcode_t; 336 | 337 | /* This data structure represents a compiled pattern. Before calling 338 | the pattern compiler, the fields `buffer', `allocated', `fastmap', 339 | `translate', and `no_sub' can be set. After the pattern has been 340 | compiled, the `re_nsub' field is available. All other fields are 341 | private to the regex routines. */ 342 | 343 | #ifndef RE_TRANSLATE_TYPE 344 | # define __RE_TRANSLATE_TYPE unsigned char * 345 | # ifdef __USE_GNU 346 | # define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE 347 | # endif 348 | #endif 349 | 350 | #ifdef __USE_GNU 351 | # define __REPB_PREFIX(name) name 352 | #else 353 | # define __REPB_PREFIX(name) __##name 354 | #endif 355 | 356 | struct re_pattern_buffer 357 | { 358 | /* Space that holds the compiled pattern. It is declared as 359 | `unsigned char *' because its elements are sometimes used as 360 | array indexes. */ 361 | unsigned char *__REPB_PREFIX(buffer); 362 | 363 | /* Number of bytes to which `buffer' points. */ 364 | unsigned long int __REPB_PREFIX(allocated); 365 | 366 | /* Number of bytes actually used in `buffer'. */ 367 | unsigned long int __REPB_PREFIX(used); 368 | 369 | /* Syntax setting with which the pattern was compiled. */ 370 | reg_syntax_t __REPB_PREFIX(syntax); 371 | 372 | /* Pointer to a fastmap, if any, otherwise zero. re_search uses the 373 | fastmap, if there is one, to skip over impossible starting points 374 | for matches. */ 375 | char *__REPB_PREFIX(fastmap); 376 | 377 | /* Either a translate table to apply to all characters before 378 | comparing them, or zero for no translation. The translation is 379 | applied to a pattern when it is compiled and to a string when it 380 | is matched. */ 381 | __RE_TRANSLATE_TYPE __REPB_PREFIX(translate); 382 | 383 | /* Number of subexpressions found by the compiler. */ 384 | size_t re_nsub; 385 | 386 | /* Zero if this pattern cannot match the empty string, one else. 387 | Well, in truth it's used only in `re_search_2', to see whether or 388 | not we should use the fastmap, so we don't set this absolutely 389 | perfectly; see `re_compile_fastmap' (the `duplicate' case). */ 390 | unsigned __REPB_PREFIX(can_be_null) : 1; 391 | 392 | /* If REGS_UNALLOCATED, allocate space in the `regs' structure 393 | for `max (RE_NREGS, re_nsub + 1)' groups. 394 | If REGS_REALLOCATE, reallocate space if necessary. 395 | If REGS_FIXED, use what's there. */ 396 | #ifdef __USE_GNU 397 | # define REGS_UNALLOCATED 0 398 | # define REGS_REALLOCATE 1 399 | # define REGS_FIXED 2 400 | #endif 401 | unsigned __REPB_PREFIX(regs_allocated) : 2; 402 | 403 | /* Set to zero when `regex_compile' compiles a pattern; set to one 404 | by `re_compile_fastmap' if it updates the fastmap. */ 405 | unsigned __REPB_PREFIX(fastmap_accurate) : 1; 406 | 407 | /* If set, `re_match_2' does not return information about 408 | subexpressions. */ 409 | unsigned __REPB_PREFIX(no_sub) : 1; 410 | 411 | /* If set, a beginning-of-line anchor doesn't match at the beginning 412 | of the string. */ 413 | unsigned __REPB_PREFIX(not_bol) : 1; 414 | 415 | /* Similarly for an end-of-line anchor. */ 416 | unsigned __REPB_PREFIX(not_eol) : 1; 417 | 418 | /* If true, an anchor at a newline matches. */ 419 | unsigned __REPB_PREFIX(newline_anchor) : 1; 420 | }; 421 | 422 | typedef struct re_pattern_buffer regex_t; 423 | 424 | /* Type for byte offsets within the string. POSIX mandates this. */ 425 | typedef int regoff_t; 426 | 427 | 428 | #ifdef __USE_GNU 429 | /* This is the structure we store register match data in. See 430 | regex.texinfo for a full description of what registers match. */ 431 | struct re_registers 432 | { 433 | unsigned num_regs; 434 | regoff_t *start; 435 | regoff_t *end; 436 | }; 437 | 438 | 439 | /* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, 440 | `re_match_2' returns information about at least this many registers 441 | the first time a `regs' structure is passed. */ 442 | # ifndef RE_NREGS 443 | # define RE_NREGS 30 444 | # endif 445 | #endif 446 | 447 | 448 | /* POSIX specification for registers. Aside from the different names than 449 | `re_registers', POSIX uses an array of structures, instead of a 450 | structure of arrays. */ 451 | typedef struct 452 | { 453 | regoff_t rm_so; /* Byte offset from string's start to substring's start. */ 454 | regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ 455 | } regmatch_t; 456 | 457 | /* Declarations for routines. */ 458 | 459 | #ifdef __USE_GNU 460 | /* Sets the current default syntax to SYNTAX, and return the old syntax. 461 | You can also simply assign to the `re_syntax_options' variable. */ 462 | extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax); 463 | 464 | /* Compile the regular expression PATTERN, with length LENGTH 465 | and syntax given by the global `re_syntax_options', into the buffer 466 | BUFFER. Return NULL if successful, and an error string if not. */ 467 | extern const char *re_compile_pattern (const char *__pattern, size_t __length, 468 | struct re_pattern_buffer *__buffer); 469 | 470 | 471 | /* Compile a fastmap for the compiled pattern in BUFFER; used to 472 | accelerate searches. Return 0 if successful and -2 if was an 473 | internal error. */ 474 | extern int re_compile_fastmap (struct re_pattern_buffer *__buffer); 475 | 476 | 477 | /* Search in the string STRING (with length LENGTH) for the pattern 478 | compiled into BUFFER. Start searching at position START, for RANGE 479 | characters. Return the starting position of the match, -1 for no 480 | match, or -2 for an internal error. Also return register 481 | information in REGS (if REGS and BUFFER->no_sub are nonzero). */ 482 | extern int re_search (struct re_pattern_buffer *__buffer, const char *__string, 483 | int __length, int __start, int __range, 484 | struct re_registers *__regs); 485 | 486 | 487 | /* Like `re_search', but search in the concatenation of STRING1 and 488 | STRING2. Also, stop searching at index START + STOP. */ 489 | extern int re_search_2 (struct re_pattern_buffer *__buffer, 490 | const char *__string1, int __length1, 491 | const char *__string2, int __length2, int __start, 492 | int __range, struct re_registers *__regs, int __stop); 493 | 494 | 495 | /* Like `re_search', but return how many characters in STRING the regexp 496 | in BUFFER matched, starting at position START. */ 497 | extern int re_match (struct re_pattern_buffer *__buffer, const char *__string, 498 | int __length, int __start, struct re_registers *__regs); 499 | 500 | 501 | /* Relates to `re_match' as `re_search_2' relates to `re_search'. */ 502 | extern int re_match_2 (struct re_pattern_buffer *__buffer, 503 | const char *__string1, int __length1, 504 | const char *__string2, int __length2, int __start, 505 | struct re_registers *__regs, int __stop); 506 | 507 | 508 | /* Set REGS to hold NUM_REGS registers, storing them in STARTS and 509 | ENDS. Subsequent matches using BUFFER and REGS will use this memory 510 | for recording register information. STARTS and ENDS must be 511 | allocated with malloc, and must each be at least `NUM_REGS * sizeof 512 | (regoff_t)' bytes long. 513 | 514 | If NUM_REGS == 0, then subsequent matches should allocate their own 515 | register data. 516 | 517 | Unless this function is called, the first search or match using 518 | PATTERN_BUFFER will allocate its own register data, without 519 | freeing the old data. */ 520 | extern void re_set_registers (struct re_pattern_buffer *__buffer, 521 | struct re_registers *__regs, 522 | unsigned int __num_regs, 523 | regoff_t *__starts, regoff_t *__ends); 524 | #endif /* Use GNU */ 525 | 526 | #if defined _REGEX_RE_COMP || (defined _LIBC && defined __USE_BSD) 527 | # ifndef _CRAY 528 | /* 4.2 bsd compatibility. */ 529 | extern char *re_comp (const char *); 530 | extern int re_exec (const char *); 531 | # endif 532 | #endif 533 | 534 | /* GCC 2.95 and later have "__restrict"; C99 compilers have 535 | "restrict", and "configure" may have defined "restrict". */ 536 | #ifndef __restrict 537 | # if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) 538 | # if defined restrict || 199901L <= __STDC_VERSION__ 539 | # define __restrict restrict 540 | # else 541 | # define __restrict 542 | # endif 543 | # endif 544 | #endif 545 | /* gcc 3.1 and up support the [restrict] syntax. */ 546 | #ifndef __restrict_arr 547 | # if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) \ 548 | && !defined __GNUG__ 549 | # define __restrict_arr __restrict 550 | # else 551 | # define __restrict_arr 552 | # endif 553 | #endif 554 | 555 | /* POSIX compatibility. */ 556 | extern int regcomp (regex_t *__restrict __preg, 557 | const char *__restrict __pattern, 558 | int __cflags); 559 | 560 | extern int regexec (const regex_t *__restrict __preg, 561 | const char *__restrict __string, size_t __nmatch, 562 | regmatch_t __pmatch[__restrict_arr], 563 | int __eflags); 564 | 565 | extern size_t regerror (int __errcode, const regex_t *__restrict __preg, 566 | char *__restrict __errbuf, size_t __errbuf_size); 567 | 568 | extern void regfree (regex_t *__preg); 569 | 570 | 571 | #ifdef __cplusplus 572 | } 573 | #endif /* C++ */ 574 | 575 | #endif /* regex.h */ 576 | -------------------------------------------------------------------------------- /jni/regex/regex_internal.h: -------------------------------------------------------------------------------- 1 | /* Extended regular expression matching and search library. 2 | Copyright (C) 2002-2005, 2007, 2008 Free Software Foundation, Inc. 3 | This file is part of the GNU C Library. 4 | Contributed by Isamu Hasegawa . 5 | 6 | The GNU C Library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | The GNU C Library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with the GNU C Library; if not, write to the Free 18 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 19 | 02111-1307 USA. */ 20 | 21 | #ifndef _REGEX_INTERNAL_H 22 | #define _REGEX_INTERNAL_H 1 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC 31 | # include 32 | #endif 33 | #if defined HAVE_LOCALE_H || defined _LIBC 34 | # include 35 | #endif 36 | #if defined HAVE_WCHAR_H || defined _LIBC 37 | # include 38 | #endif /* HAVE_WCHAR_H || _LIBC */ 39 | #if defined HAVE_WCTYPE_H || defined _LIBC 40 | # include 41 | #endif /* HAVE_WCTYPE_H || _LIBC */ 42 | #if defined HAVE_STDBOOL_H || defined _LIBC 43 | # include 44 | #endif /* HAVE_STDBOOL_H || _LIBC */ 45 | #if defined HAVE_STDINT_H || defined _LIBC 46 | # include 47 | #endif /* HAVE_STDINT_H || _LIBC */ 48 | #if defined _LIBC 49 | # include 50 | #else 51 | # define __libc_lock_define(CLASS,NAME) 52 | # define __libc_lock_init(NAME) do { } while (0) 53 | # define __libc_lock_lock(NAME) do { } while (0) 54 | # define __libc_lock_unlock(NAME) do { } while (0) 55 | #endif 56 | 57 | /* In case that the system doesn't have isblank(). */ 58 | #if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank 59 | # define isblank(ch) ((ch) == ' ' || (ch) == '\t') 60 | #endif 61 | 62 | #ifdef _LIBC 63 | # ifndef _RE_DEFINE_LOCALE_FUNCTIONS 64 | # define _RE_DEFINE_LOCALE_FUNCTIONS 1 65 | # include 66 | # include 67 | # include 68 | # endif 69 | #endif 70 | 71 | /* This is for other GNU distributions with internationalized messages. */ 72 | #if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC 73 | # include 74 | # ifdef _LIBC 75 | # undef gettext 76 | # define gettext(msgid) \ 77 | INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES) 78 | # endif 79 | #else 80 | # define gettext(msgid) (msgid) 81 | #endif 82 | 83 | #ifndef gettext_noop 84 | /* This define is so xgettext can find the internationalizable 85 | strings. */ 86 | # define gettext_noop(String) String 87 | #endif 88 | 89 | /* For loser systems without the definition. */ 90 | #ifndef SIZE_MAX 91 | # define SIZE_MAX ((size_t) -1) 92 | #endif 93 | 94 | #if (defined MB_CUR_MAX && HAVE_LOCALE_H && HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_WCRTOMB && HAVE_MBRTOWC && HAVE_WCSCOLL) || _LIBC 95 | # define RE_ENABLE_I18N 96 | #endif 97 | 98 | #if __GNUC__ >= 3 99 | # define BE(expr, val) __builtin_expect (expr, val) 100 | #else 101 | # define BE(expr, val) (expr) 102 | # define inline 103 | #endif 104 | 105 | /* Number of single byte character. */ 106 | #define SBC_MAX 256 107 | 108 | #define COLL_ELEM_LEN_MAX 8 109 | 110 | /* The character which represents newline. */ 111 | #define NEWLINE_CHAR '\n' 112 | #define WIDE_NEWLINE_CHAR L'\n' 113 | 114 | /* Rename to standard API for using out of glibc. */ 115 | #ifndef _LIBC 116 | # define __wctype wctype 117 | # define __iswctype iswctype 118 | # define __btowc btowc 119 | # define __mbrtowc mbrtowc 120 | # define __mempcpy mempcpy 121 | # define __wcrtomb wcrtomb 122 | # define __regfree regfree 123 | # define attribute_hidden 124 | #endif /* not _LIBC */ 125 | 126 | #ifdef __GNUC__ 127 | # define __attribute(arg) __attribute__ (arg) 128 | #else 129 | # define __attribute(arg) 130 | #endif 131 | 132 | extern const char __re_error_msgid[] attribute_hidden; 133 | extern const size_t __re_error_msgid_idx[] attribute_hidden; 134 | 135 | /* An integer used to represent a set of bits. It must be unsigned, 136 | and must be at least as wide as unsigned int. */ 137 | typedef unsigned long int bitset_word_t; 138 | /* All bits set in a bitset_word_t. */ 139 | #define BITSET_WORD_MAX ULONG_MAX 140 | /* Number of bits in a bitset_word_t. */ 141 | #define BITSET_WORD_BITS (sizeof (bitset_word_t) * CHAR_BIT) 142 | /* Number of bitset_word_t in a bit_set. */ 143 | #define BITSET_WORDS (SBC_MAX / BITSET_WORD_BITS) 144 | typedef bitset_word_t bitset_t[BITSET_WORDS]; 145 | typedef bitset_word_t *re_bitset_ptr_t; 146 | typedef const bitset_word_t *re_const_bitset_ptr_t; 147 | 148 | #define bitset_set(set,i) \ 149 | (set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS) 150 | #define bitset_clear(set,i) \ 151 | (set[i / BITSET_WORD_BITS] &= ~((bitset_word_t) 1 << i % BITSET_WORD_BITS)) 152 | #define bitset_contain(set,i) \ 153 | (set[i / BITSET_WORD_BITS] & ((bitset_word_t) 1 << i % BITSET_WORD_BITS)) 154 | #define bitset_empty(set) memset (set, '\0', sizeof (bitset_t)) 155 | #define bitset_set_all(set) memset (set, '\xff', sizeof (bitset_t)) 156 | #define bitset_copy(dest,src) memcpy (dest, src, sizeof (bitset_t)) 157 | 158 | #define PREV_WORD_CONSTRAINT 0x0001 159 | #define PREV_NOTWORD_CONSTRAINT 0x0002 160 | #define NEXT_WORD_CONSTRAINT 0x0004 161 | #define NEXT_NOTWORD_CONSTRAINT 0x0008 162 | #define PREV_NEWLINE_CONSTRAINT 0x0010 163 | #define NEXT_NEWLINE_CONSTRAINT 0x0020 164 | #define PREV_BEGBUF_CONSTRAINT 0x0040 165 | #define NEXT_ENDBUF_CONSTRAINT 0x0080 166 | #define WORD_DELIM_CONSTRAINT 0x0100 167 | #define NOT_WORD_DELIM_CONSTRAINT 0x0200 168 | 169 | typedef enum 170 | { 171 | INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, 172 | WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, 173 | WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, 174 | INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, 175 | LINE_FIRST = PREV_NEWLINE_CONSTRAINT, 176 | LINE_LAST = NEXT_NEWLINE_CONSTRAINT, 177 | BUF_FIRST = PREV_BEGBUF_CONSTRAINT, 178 | BUF_LAST = NEXT_ENDBUF_CONSTRAINT, 179 | WORD_DELIM = WORD_DELIM_CONSTRAINT, 180 | NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT 181 | } re_context_type; 182 | 183 | typedef struct 184 | { 185 | int alloc; 186 | int nelem; 187 | int *elems; 188 | } re_node_set; 189 | 190 | typedef enum 191 | { 192 | NON_TYPE = 0, 193 | 194 | /* Node type, These are used by token, node, tree. */ 195 | CHARACTER = 1, 196 | END_OF_RE = 2, 197 | SIMPLE_BRACKET = 3, 198 | OP_BACK_REF = 4, 199 | OP_PERIOD = 5, 200 | #ifdef RE_ENABLE_I18N 201 | COMPLEX_BRACKET = 6, 202 | OP_UTF8_PERIOD = 7, 203 | #endif /* RE_ENABLE_I18N */ 204 | 205 | /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used 206 | when the debugger shows values of this enum type. */ 207 | #define EPSILON_BIT 8 208 | OP_OPEN_SUBEXP = EPSILON_BIT | 0, 209 | OP_CLOSE_SUBEXP = EPSILON_BIT | 1, 210 | OP_ALT = EPSILON_BIT | 2, 211 | OP_DUP_ASTERISK = EPSILON_BIT | 3, 212 | ANCHOR = EPSILON_BIT | 4, 213 | 214 | /* Tree type, these are used only by tree. */ 215 | CONCAT = 16, 216 | SUBEXP = 17, 217 | 218 | /* Token type, these are used only by token. */ 219 | OP_DUP_PLUS = 18, 220 | OP_DUP_QUESTION, 221 | OP_OPEN_BRACKET, 222 | OP_CLOSE_BRACKET, 223 | OP_CHARSET_RANGE, 224 | OP_OPEN_DUP_NUM, 225 | OP_CLOSE_DUP_NUM, 226 | OP_NON_MATCH_LIST, 227 | OP_OPEN_COLL_ELEM, 228 | OP_CLOSE_COLL_ELEM, 229 | OP_OPEN_EQUIV_CLASS, 230 | OP_CLOSE_EQUIV_CLASS, 231 | OP_OPEN_CHAR_CLASS, 232 | OP_CLOSE_CHAR_CLASS, 233 | OP_WORD, 234 | OP_NOTWORD, 235 | OP_SPACE, 236 | OP_NOTSPACE, 237 | BACK_SLASH 238 | 239 | } re_token_type_t; 240 | 241 | #ifdef RE_ENABLE_I18N 242 | typedef struct 243 | { 244 | /* Multibyte characters. */ 245 | wchar_t *mbchars; 246 | 247 | /* Collating symbols. */ 248 | # ifdef _LIBC 249 | int32_t *coll_syms; 250 | # endif 251 | 252 | /* Equivalence classes. */ 253 | # ifdef _LIBC 254 | int32_t *equiv_classes; 255 | # endif 256 | 257 | /* Range expressions. */ 258 | # ifdef _LIBC 259 | uint32_t *range_starts; 260 | uint32_t *range_ends; 261 | # else /* not _LIBC */ 262 | wchar_t *range_starts; 263 | wchar_t *range_ends; 264 | # endif /* not _LIBC */ 265 | 266 | /* Character classes. */ 267 | wctype_t *char_classes; 268 | 269 | /* If this character set is the non-matching list. */ 270 | unsigned int non_match : 1; 271 | 272 | /* # of multibyte characters. */ 273 | int nmbchars; 274 | 275 | /* # of collating symbols. */ 276 | int ncoll_syms; 277 | 278 | /* # of equivalence classes. */ 279 | int nequiv_classes; 280 | 281 | /* # of range expressions. */ 282 | int nranges; 283 | 284 | /* # of character classes. */ 285 | int nchar_classes; 286 | } re_charset_t; 287 | #endif /* RE_ENABLE_I18N */ 288 | 289 | typedef struct 290 | { 291 | union 292 | { 293 | unsigned char c; /* for CHARACTER */ 294 | re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */ 295 | #ifdef RE_ENABLE_I18N 296 | re_charset_t *mbcset; /* for COMPLEX_BRACKET */ 297 | #endif /* RE_ENABLE_I18N */ 298 | int idx; /* for BACK_REF */ 299 | re_context_type ctx_type; /* for ANCHOR */ 300 | } opr; 301 | #if __GNUC__ >= 2 302 | re_token_type_t type : 8; 303 | #else 304 | re_token_type_t type; 305 | #endif 306 | unsigned int constraint : 10; /* context constraint */ 307 | unsigned int duplicated : 1; 308 | unsigned int opt_subexp : 1; 309 | #ifdef RE_ENABLE_I18N 310 | unsigned int accept_mb : 1; 311 | /* These 2 bits can be moved into the union if needed (e.g. if running out 312 | of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */ 313 | unsigned int mb_partial : 1; 314 | #endif 315 | unsigned int word_char : 1; 316 | } re_token_t; 317 | 318 | #define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT) 319 | 320 | struct re_string_t 321 | { 322 | /* Indicate the raw buffer which is the original string passed as an 323 | argument of regexec(), re_search(), etc.. */ 324 | const unsigned char *raw_mbs; 325 | /* Store the multibyte string. In case of "case insensitive mode" like 326 | REG_ICASE, upper cases of the string are stored, otherwise MBS points 327 | the same address that RAW_MBS points. */ 328 | unsigned char *mbs; 329 | #ifdef RE_ENABLE_I18N 330 | /* Store the wide character string which is corresponding to MBS. */ 331 | wint_t *wcs; 332 | int *offsets; 333 | mbstate_t cur_state; 334 | #endif 335 | /* Index in RAW_MBS. Each character mbs[i] corresponds to 336 | raw_mbs[raw_mbs_idx + i]. */ 337 | int raw_mbs_idx; 338 | /* The length of the valid characters in the buffers. */ 339 | int valid_len; 340 | /* The corresponding number of bytes in raw_mbs array. */ 341 | int valid_raw_len; 342 | /* The length of the buffers MBS and WCS. */ 343 | int bufs_len; 344 | /* The index in MBS, which is updated by re_string_fetch_byte. */ 345 | int cur_idx; 346 | /* length of RAW_MBS array. */ 347 | int raw_len; 348 | /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */ 349 | int len; 350 | /* End of the buffer may be shorter than its length in the cases such 351 | as re_match_2, re_search_2. Then, we use STOP for end of the buffer 352 | instead of LEN. */ 353 | int raw_stop; 354 | /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */ 355 | int stop; 356 | 357 | /* The context of mbs[0]. We store the context independently, since 358 | the context of mbs[0] may be different from raw_mbs[0], which is 359 | the beginning of the input string. */ 360 | unsigned int tip_context; 361 | /* The translation passed as a part of an argument of re_compile_pattern. */ 362 | RE_TRANSLATE_TYPE trans; 363 | /* Copy of re_dfa_t's word_char. */ 364 | re_const_bitset_ptr_t word_char; 365 | /* 1 if REG_ICASE. */ 366 | unsigned char icase; 367 | unsigned char is_utf8; 368 | unsigned char map_notascii; 369 | unsigned char mbs_allocated; 370 | unsigned char offsets_needed; 371 | unsigned char newline_anchor; 372 | unsigned char word_ops_used; 373 | int mb_cur_max; 374 | }; 375 | typedef struct re_string_t re_string_t; 376 | 377 | 378 | struct re_dfa_t; 379 | typedef struct re_dfa_t re_dfa_t; 380 | 381 | #ifndef _LIBC 382 | # ifdef __i386__ 383 | # define internal_function __attribute ((regparm (3), stdcall)) 384 | # else 385 | # define internal_function 386 | # endif 387 | #endif 388 | 389 | #ifndef NOT_IN_libc 390 | static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr, 391 | int new_buf_len) 392 | internal_function; 393 | # ifdef RE_ENABLE_I18N 394 | static void build_wcs_buffer (re_string_t *pstr) internal_function; 395 | static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr) 396 | internal_function; 397 | # endif /* RE_ENABLE_I18N */ 398 | static void build_upper_buffer (re_string_t *pstr) internal_function; 399 | static void re_string_translate_buffer (re_string_t *pstr) internal_function; 400 | static unsigned int re_string_context_at (const re_string_t *input, int idx, 401 | int eflags) 402 | internal_function __attribute ((pure)); 403 | #endif 404 | #define re_string_peek_byte(pstr, offset) \ 405 | ((pstr)->mbs[(pstr)->cur_idx + offset]) 406 | #define re_string_fetch_byte(pstr) \ 407 | ((pstr)->mbs[(pstr)->cur_idx++]) 408 | #define re_string_first_byte(pstr, idx) \ 409 | ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF) 410 | #define re_string_is_single_byte_char(pstr, idx) \ 411 | ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \ 412 | || (pstr)->wcs[(idx) + 1] != WEOF)) 413 | #define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx) 414 | #define re_string_cur_idx(pstr) ((pstr)->cur_idx) 415 | #define re_string_get_buffer(pstr) ((pstr)->mbs) 416 | #define re_string_length(pstr) ((pstr)->len) 417 | #define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx]) 418 | #define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) 419 | #define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) 420 | 421 | #include 422 | 423 | #ifndef _LIBC 424 | # if HAVE_ALLOCA 425 | /* The OS usually guarantees only one guard page at the bottom of the stack, 426 | and a page size can be as small as 4096 bytes. So we cannot safely 427 | allocate anything larger than 4096 bytes. Also care for the possibility 428 | of a few compiler-allocated temporary stack slots. */ 429 | # define __libc_use_alloca(n) ((n) < 4032) 430 | # else 431 | /* alloca is implemented with malloc, so just use malloc. */ 432 | # define __libc_use_alloca(n) 0 433 | # endif 434 | #endif 435 | 436 | #define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) 437 | #define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t))) 438 | #define re_free(p) free (p) 439 | 440 | struct bin_tree_t 441 | { 442 | struct bin_tree_t *parent; 443 | struct bin_tree_t *left; 444 | struct bin_tree_t *right; 445 | struct bin_tree_t *first; 446 | struct bin_tree_t *next; 447 | 448 | re_token_t token; 449 | 450 | /* `node_idx' is the index in dfa->nodes, if `type' == 0. 451 | Otherwise `type' indicate the type of this node. */ 452 | int node_idx; 453 | }; 454 | typedef struct bin_tree_t bin_tree_t; 455 | 456 | #define BIN_TREE_STORAGE_SIZE \ 457 | ((1024 - sizeof (void *)) / sizeof (bin_tree_t)) 458 | 459 | struct bin_tree_storage_t 460 | { 461 | struct bin_tree_storage_t *next; 462 | bin_tree_t data[BIN_TREE_STORAGE_SIZE]; 463 | }; 464 | typedef struct bin_tree_storage_t bin_tree_storage_t; 465 | 466 | #define CONTEXT_WORD 1 467 | #define CONTEXT_NEWLINE (CONTEXT_WORD << 1) 468 | #define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1) 469 | #define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1) 470 | 471 | #define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD) 472 | #define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE) 473 | #define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF) 474 | #define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF) 475 | #define IS_ORDINARY_CONTEXT(c) ((c) == 0) 476 | 477 | #define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_') 478 | #define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR) 479 | #define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_') 480 | #define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR) 481 | 482 | #define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \ 483 | ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ 484 | || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ 485 | || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\ 486 | || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context))) 487 | 488 | #define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \ 489 | ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ 490 | || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ 491 | || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \ 492 | || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context))) 493 | 494 | struct re_dfastate_t 495 | { 496 | unsigned int hash; 497 | re_node_set nodes; 498 | re_node_set non_eps_nodes; 499 | re_node_set inveclosure; 500 | re_node_set *entrance_nodes; 501 | struct re_dfastate_t **trtable, **word_trtable; 502 | unsigned int context : 4; 503 | unsigned int halt : 1; 504 | /* If this state can accept `multi byte'. 505 | Note that we refer to multibyte characters, and multi character 506 | collating elements as `multi byte'. */ 507 | unsigned int accept_mb : 1; 508 | /* If this state has backreference node(s). */ 509 | unsigned int has_backref : 1; 510 | unsigned int has_constraint : 1; 511 | }; 512 | typedef struct re_dfastate_t re_dfastate_t; 513 | 514 | struct re_state_table_entry 515 | { 516 | int num; 517 | int alloc; 518 | re_dfastate_t **array; 519 | }; 520 | 521 | /* Array type used in re_sub_match_last_t and re_sub_match_top_t. */ 522 | 523 | typedef struct 524 | { 525 | int next_idx; 526 | int alloc; 527 | re_dfastate_t **array; 528 | } state_array_t; 529 | 530 | /* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */ 531 | 532 | typedef struct 533 | { 534 | int node; 535 | int str_idx; /* The position NODE match at. */ 536 | state_array_t path; 537 | } re_sub_match_last_t; 538 | 539 | /* Store information about the node NODE whose type is OP_OPEN_SUBEXP. 540 | And information about the node, whose type is OP_CLOSE_SUBEXP, 541 | corresponding to NODE is stored in LASTS. */ 542 | 543 | typedef struct 544 | { 545 | int str_idx; 546 | int node; 547 | state_array_t *path; 548 | int alasts; /* Allocation size of LASTS. */ 549 | int nlasts; /* The number of LASTS. */ 550 | re_sub_match_last_t **lasts; 551 | } re_sub_match_top_t; 552 | 553 | struct re_backref_cache_entry 554 | { 555 | int node; 556 | int str_idx; 557 | int subexp_from; 558 | int subexp_to; 559 | char more; 560 | char unused; 561 | unsigned short int eps_reachable_subexps_map; 562 | }; 563 | 564 | typedef struct 565 | { 566 | /* The string object corresponding to the input string. */ 567 | re_string_t input; 568 | #if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) 569 | const re_dfa_t *const dfa; 570 | #else 571 | const re_dfa_t *dfa; 572 | #endif 573 | /* EFLAGS of the argument of regexec. */ 574 | int eflags; 575 | /* Where the matching ends. */ 576 | int match_last; 577 | int last_node; 578 | /* The state log used by the matcher. */ 579 | re_dfastate_t **state_log; 580 | int state_log_top; 581 | /* Back reference cache. */ 582 | int nbkref_ents; 583 | int abkref_ents; 584 | struct re_backref_cache_entry *bkref_ents; 585 | int max_mb_elem_len; 586 | int nsub_tops; 587 | int asub_tops; 588 | re_sub_match_top_t **sub_tops; 589 | } re_match_context_t; 590 | 591 | typedef struct 592 | { 593 | re_dfastate_t **sifted_states; 594 | re_dfastate_t **limited_states; 595 | int last_node; 596 | int last_str_idx; 597 | re_node_set limits; 598 | } re_sift_context_t; 599 | 600 | struct re_fail_stack_ent_t 601 | { 602 | int idx; 603 | int node; 604 | regmatch_t *regs; 605 | re_node_set eps_via_nodes; 606 | }; 607 | 608 | struct re_fail_stack_t 609 | { 610 | int num; 611 | int alloc; 612 | struct re_fail_stack_ent_t *stack; 613 | }; 614 | 615 | struct re_dfa_t 616 | { 617 | re_token_t *nodes; 618 | size_t nodes_alloc; 619 | size_t nodes_len; 620 | int *nexts; 621 | int *org_indices; 622 | re_node_set *edests; 623 | re_node_set *eclosures; 624 | re_node_set *inveclosures; 625 | struct re_state_table_entry *state_table; 626 | re_dfastate_t *init_state; 627 | re_dfastate_t *init_state_word; 628 | re_dfastate_t *init_state_nl; 629 | re_dfastate_t *init_state_begbuf; 630 | bin_tree_t *str_tree; 631 | bin_tree_storage_t *str_tree_storage; 632 | re_bitset_ptr_t sb_char; 633 | int str_tree_storage_idx; 634 | 635 | /* number of subexpressions `re_nsub' is in regex_t. */ 636 | unsigned int state_hash_mask; 637 | int init_node; 638 | int nbackref; /* The number of backreference in this dfa. */ 639 | 640 | /* Bitmap expressing which backreference is used. */ 641 | bitset_word_t used_bkref_map; 642 | bitset_word_t completed_bkref_map; 643 | 644 | unsigned int has_plural_match : 1; 645 | /* If this dfa has "multibyte node", which is a backreference or 646 | a node which can accept multibyte character or multi character 647 | collating element. */ 648 | unsigned int has_mb_node : 1; 649 | unsigned int is_utf8 : 1; 650 | unsigned int map_notascii : 1; 651 | unsigned int word_ops_used : 1; 652 | int mb_cur_max; 653 | bitset_t word_char; 654 | reg_syntax_t syntax; 655 | int *subexp_map; 656 | #ifdef DEBUG 657 | char* re_str; 658 | #endif 659 | __libc_lock_define (, lock) 660 | }; 661 | 662 | #define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set)) 663 | #define re_node_set_remove(set,id) \ 664 | (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1)) 665 | #define re_node_set_empty(p) ((p)->nelem = 0) 666 | #define re_node_set_free(set) re_free ((set)->elems) 667 | 668 | 669 | typedef enum 670 | { 671 | SB_CHAR, 672 | MB_CHAR, 673 | EQUIV_CLASS, 674 | COLL_SYM, 675 | CHAR_CLASS 676 | } bracket_elem_type; 677 | 678 | typedef struct 679 | { 680 | bracket_elem_type type; 681 | union 682 | { 683 | unsigned char ch; 684 | unsigned char *name; 685 | wchar_t wch; 686 | } opr; 687 | } bracket_elem_t; 688 | 689 | 690 | /* Inline functions for bitset operation. */ 691 | static inline void 692 | bitset_not (bitset_t set) 693 | { 694 | int bitset_i; 695 | for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) 696 | set[bitset_i] = ~set[bitset_i]; 697 | } 698 | 699 | static inline void 700 | bitset_merge (bitset_t dest, const bitset_t src) 701 | { 702 | int bitset_i; 703 | for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) 704 | dest[bitset_i] |= src[bitset_i]; 705 | } 706 | 707 | static inline void 708 | bitset_mask (bitset_t dest, const bitset_t src) 709 | { 710 | int bitset_i; 711 | for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) 712 | dest[bitset_i] &= src[bitset_i]; 713 | } 714 | 715 | #ifdef RE_ENABLE_I18N 716 | /* Inline functions for re_string. */ 717 | static inline int 718 | internal_function __attribute ((pure)) 719 | re_string_char_size_at (const re_string_t *pstr, int idx) 720 | { 721 | int byte_idx; 722 | if (pstr->mb_cur_max == 1) 723 | return 1; 724 | for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx) 725 | if (pstr->wcs[idx + byte_idx] != WEOF) 726 | break; 727 | return byte_idx; 728 | } 729 | 730 | static inline wint_t 731 | internal_function __attribute ((pure)) 732 | re_string_wchar_at (const re_string_t *pstr, int idx) 733 | { 734 | if (pstr->mb_cur_max == 1) 735 | return (wint_t) pstr->mbs[idx]; 736 | return (wint_t) pstr->wcs[idx]; 737 | } 738 | 739 | # ifndef NOT_IN_libc 740 | static int 741 | internal_function __attribute ((pure)) 742 | re_string_elem_size_at (const re_string_t *pstr, int idx) 743 | { 744 | # ifdef _LIBC 745 | const unsigned char *p, *extra; 746 | const int32_t *table, *indirect; 747 | int32_t tmp; 748 | # include 749 | uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); 750 | 751 | if (nrules != 0) 752 | { 753 | table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); 754 | extra = (const unsigned char *) 755 | _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); 756 | indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, 757 | _NL_COLLATE_INDIRECTMB); 758 | p = pstr->mbs + idx; 759 | tmp = findidx (&p); 760 | return p - pstr->mbs - idx; 761 | } 762 | else 763 | # endif /* _LIBC */ 764 | return 1; 765 | } 766 | # endif 767 | #endif /* RE_ENABLE_I18N */ 768 | 769 | #endif /* _REGEX_INTERNAL_H */ 770 | -------------------------------------------------------------------------------- /jni/regex/regexbug1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int 8 | main (void) 9 | { 10 | regex_t re; 11 | regmatch_t ma[2]; 12 | int reerr; 13 | int res = 0; 14 | 15 | re_set_syntax (RE_DEBUG); 16 | reerr = regcomp (&re, "0*[0-9][0-9]", 0); 17 | if (reerr != 0) 18 | { 19 | char buf[100]; 20 | regerror (reerr, &re, buf, sizeof buf); 21 | error (EXIT_FAILURE, 0, buf); 22 | } 23 | 24 | if (regexec (&re, "002", 2, ma, 0) != 0) 25 | { 26 | error (0, 0, "\"0*[0-9][0-9]\" does not match \"002\""); 27 | res = 1; 28 | } 29 | puts ("Succesful match with \"0*[0-9][0-9]\""); 30 | 31 | regfree (&re); 32 | 33 | reerr = regcomp (&re, "[0a]*[0-9][0-9]", 0); 34 | if (reerr != 0) 35 | { 36 | char buf[100]; 37 | regerror (reerr, &re, buf, sizeof buf); 38 | error (EXIT_FAILURE, 0, buf); 39 | } 40 | 41 | if (regexec (&re, "002", 2, ma, 0) != 0) 42 | { 43 | error (0, 0, "\"[0a]*[0-9][0-9]\" does not match \"002\""); 44 | res = 1; 45 | } 46 | puts ("Succesful match with \"[0a]*[0-9][0-9]\""); 47 | 48 | regfree (&re); 49 | 50 | return res; 51 | } 52 | -------------------------------------------------------------------------------- /jni/wrap_inotifywait.c: -------------------------------------------------------------------------------- 1 | #define __USE_GNU 2 | typedef unsigned char bool; 3 | #define false 0 4 | #define true (!false) 5 | #define MAX(a, b) ((a < b) ? (b) : (a)) 6 | 7 | #include "regex/regex.c" 8 | 9 | #include "inotifywait.c" 10 | -------------------------------------------------------------------------------- /jni/wrap_inotifywatch.c: -------------------------------------------------------------------------------- 1 | #define __USE_GNU 2 | typedef unsigned char bool; 3 | #define false 0 4 | #define true (!false) 5 | #define MAX(a, b) ((a < b) ? (b) : (a)) 6 | 7 | #include "regex/regex.c" 8 | 9 | #include "inotifywatch.c" 10 | -------------------------------------------------------------------------------- /libs/armeabi/inotifywait: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dstmath/inotifywait-for-Android/08291e2aadbb6fee8408ca02054bd25dd5cf8fdb/libs/armeabi/inotifywait -------------------------------------------------------------------------------- /libs/armeabi/inotifywatch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dstmath/inotifywait-for-Android/08291e2aadbb6fee8408ca02054bd25dd5cf8fdb/libs/armeabi/inotifywatch --------------------------------------------------------------------------------