├── .dir-locals.el ├── .gitignore ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.in ├── README ├── bootstrap ├── borked.c ├── configure.ac ├── indent-all ├── install-sh ├── xcdef.h ├── xclib.c ├── xclib.h ├── xclip-copyfile ├── xclip-copyfile.1 ├── xclip-cutfile ├── xclip-pastefile ├── xclip.1 ├── xclip.c ├── xclip.spec ├── xcprint.c ├── xcprint.h └── xctest /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil . ((indent-tabs-mode . t) 2 | (fill-column . 80) 3 | (tab-width . 8) 4 | )) 5 | (c-mode . ((c-file-style . "stroustrup") 6 | (subdirs . nil)))) 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # autotools generated 2 | .deps/ 3 | Makefile 4 | Makefile.in 5 | aclocal.m4 6 | autom4te.cache/ 7 | compile 8 | config.h 9 | config.h.in 10 | config.log 11 | config.status 12 | configure 13 | depcomp 14 | install-sh 15 | missing 16 | stamp-h1 17 | configure.ac~ 18 | configure~ 19 | 20 | # compiling output 21 | *.o 22 | xclip 23 | borked 24 | 25 | # temporary files 26 | *.swp 27 | -------------------------------------------------------------------------------- /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 Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | commit 0a1bbcc10d1a17969587d5995e4d47ca543a129c 2 | Merge: 1175740 aae47c9 3 | Author: astrand 4 | Date: Mon Mar 14 10:42:31 2016 +0100 5 | 6 | Merge pull request #23 from hwangcc23/remove_last_newline 7 | 8 | Add the remove-last-newline option 9 | 10 | commit 1175740013bbc4f22c55b894a2367c07c8cf499a 11 | Merge: e2dd115 e0828ad 12 | Author: astrand 13 | Date: Mon Mar 14 10:40:14 2016 +0100 14 | 15 | Merge pull request #22 from hwangcc23/fix-warning 16 | 17 | Fix the compile warning & build steps, and add .gitignore 18 | 19 | commit aae47c927a969d48009a7e372331ed17ecc7c80c 20 | Author: hwangcc23 21 | Date: Thu Mar 10 09:57:54 2016 +0800 22 | 23 | Add the remove-last-newline option 24 | 25 | This is an option proposed by Philipp Spitzer. 26 | See https://github.com/astrand/xclip/issues/7 27 | 28 | Use his patch (but only keep code related to the rmlastnl option). 29 | A new option "-rmlastnl" is added to remove the last newline character if present. 30 | 31 | commit e0828ad502287394f1a9ea40f52b5deb013204ad 32 | Author: hwangcc23 33 | Date: Wed Mar 9 21:44:41 2016 +0800 34 | 35 | Fix building steps in INSTALL 36 | 37 | Before running ./configure, autoreconf is required to generate configuration files. 38 | 39 | commit cde9c46b29216b9aae014dc4ef5b57c8426831b3 40 | Author: hwangcc23 41 | Date: Wed Mar 9 21:41:33 2016 +0800 42 | 43 | Fix one compile warning 44 | 45 | Fix this compile warning: 46 | xclip.c: In function 'doIn': 47 | xclip.c:302:5: warning: ignoring return value of 'chdir', declared with attribute warn_unused_result [-Wunused-result] 48 | chdir("/"); 49 | ^ 50 | 51 | commit 650dc6278c7f5d1bb79ed284c6883ae2302fbbc5 52 | Author: hwangcc23 53 | Date: Wed Mar 9 21:41:13 2016 +0800 54 | 55 | Add .gitignore 56 | 57 | commit e2dd115d66ecf5c772fd5359362990c17ee0defd 58 | Author: Peter Åstrand (astrand) 59 | Date: Tue Feb 2 09:03:12 2016 +0100 60 | 61 | Changing Sourceforge URLs to GitHub. 62 | 63 | commit d1f416958743a2c121ea4fa7554b9b19646911fd 64 | Author: astrand 65 | Date: Sun Feb 9 14:36:26 2014 +0000 66 | 67 | Applied patch from Marcin Szewczyk : 68 | 69 | don't treat TARGETS request as contents request 70 | 71 | commit 23c15101a77a584b1ae6c996de8aac254135ae16 72 | Author: astrand 73 | Date: Sun Oct 17 16:53:38 2010 +0000 74 | 75 | Applied patch from Alexia: 76 | 77 | * Document the -noutf8 option. 78 | 79 | * Minor lang corrections. 80 | 81 | commit c31ad0ac9bef4e4861f2af5cce6079213c787815 82 | Author: astrand 83 | Date: Mon May 3 18:39:33 2010 +0000 84 | 85 | Avoid warnings about unused variable; only define html if HAVE_ICONV. 86 | 87 | commit b8adfb971b99ce8723059aaedd9ecd032561d151 88 | Author: astrand 89 | Date: Mon May 3 18:38:50 2010 +0000 90 | 91 | Indented 92 | 93 | commit d7e6f233c24346b8a1a8a8ccde72fa0bc1cf2a68 94 | Author: astrand 95 | Date: Fri Apr 30 20:12:25 2010 +0000 96 | 97 | Applied 2924602 - 0005-Added-a-target-command-line-option.patch 98 | 99 | commit 743b9d2181f08c9fbc5901e3c15c154ddd9d874e 100 | Author: astrand 101 | Date: Fri Apr 30 20:11:34 2010 +0000 102 | 103 | Applied 2924602 - 0004-Improved-xclip-s-error-handling.patch 104 | 105 | commit 92eac7137a04da6673c92504a7ce75b50522b3a2 106 | Author: astrand 107 | Date: Fri Apr 30 20:10:29 2010 +0000 108 | 109 | Applied 2924602 - 0003-Added-support-for-printing-more-data-types.patch 110 | 111 | commit 5eb998ddaf5f4454d6119466a0e41ded4011912e 112 | Author: astrand 113 | Date: Fri Apr 30 20:09:50 2010 +0000 114 | 115 | Applied 2924602 - 0002-Added-support-in-xcout-for-receiving-16-and-32-bit-d.patch 116 | 117 | commit be7e3580bfca59f7c78140a80098ec2002538a12 118 | Author: astrand 119 | Date: Fri Apr 30 20:09:08 2010 +0000 120 | 121 | Applied 2924602 - 0001-Added-a-parameter-to-xcout-which-receives-the-type-o.patch 122 | 123 | 124 | === Old ChangeLog === 125 | 126 | Version 0.12 (Peter Åstrand) 127 | Build fixes: Check for Xmu and Xt 128 | 129 | The version number has been corrected. 130 | 131 | Man pages are now available. Contributed by Maximilian Gass. 132 | 133 | Version 0.11 (Peter Åstrand) 134 | xclip-copyfile is now compatible with recent tar versions. 135 | 136 | The Fedora UTF-8 patch has been applied. 137 | 138 | Version 0.10 (Peter Åstrand) 139 | The performance has been greatly enhanced, especially over 140 | slow networks. Two helper scripts, xclip-copyfile and 141 | xclip-pastefile, has been added. Taken together, xclip can now 142 | be used as an alternative to sftp/scp, thus avoiding password 143 | prompt when X11 forwarding has already been setup. 144 | 145 | Autoconf is now used instead of Imake. 146 | 147 | The maintainer and web site address has been updated. 148 | 149 | All Debian patches have been applied. 150 | 151 | 152 | Version 0.09: (Baruch Even) 153 | Changed dir to / when staying running so that the current directory can 154 | be umounted if necessary. 155 | 156 | 157 | Version 0.08: 158 | Remove all event loops from xclib functions, to allow xclib to be 159 | integrated into general-purpose event loops of other software more 160 | easily. 161 | 162 | Started using debian.org for email and website. 163 | 164 | 165 | Version 0.07: 166 | Not a lot of changes in terms of features, but tonnes of bug and 167 | portability fixes, as well as general code cleanup. 168 | 169 | Fixed a segfault problem with errperror in v0.06. Can't believe I 170 | didn't notice it before I released it. 171 | 172 | Cleaned up the code, hopefully for complete compatibility with more C 173 | compilers and platforms. xclip compiles without warning on my Debian 174 | GNU/Linux development platform with gcc -Wall -W -pedantic -ansi 175 | -Wtraditional -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast 176 | -Wcast-qual -Wcast-align -Wwrite-strings -Wconversion -Wsign-compare 177 | -Waggregate-return -Wstrict-prototypes -Wmissing-prototypes 178 | -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline 179 | 180 | I figure if it compiles without warning with those options, it should 181 | compile OK on pretty much any suitable platform (see README for what 182 | counts as a suitable platform). I wish GCC just had a -Wanal-retentive 183 | option... 184 | 185 | I discovered the wonders of Electric Fence, so I was able to fix up 186 | some memory problems that didn't cause problems before, but probably 187 | wouldn't have helped things either. 188 | 189 | I rewrote the way a few things work. For example, xclip doesn't store 190 | the selection data in strings any more, but rather just in allocated 191 | memory of known length, so you can now copy and paste data with nulls 192 | in it. It's probably not recommended though, gtk doesn't seem to read 193 | beyond the first null byte. 194 | 195 | I have successfully used xclip to copy and paste a 500k PNG image, it 196 | came out identical (same md5sum), so it's fairly robust in terms of 197 | the size and nature of the data that it will handle. 198 | 199 | 200 | Version 0.06: 201 | Added support for INCR mechanism. This means that -o should be able to 202 | print out selections that were previously too big and would have 203 | resulted in a message "Error: Support for format not yet implemented." 204 | In in mode, using the INCR mechanism means that you can use xclip on 205 | really big data. It used to work OK on big data, but it is better 206 | behaved about it now. 207 | 208 | Created xclib.c file to look after the xlib selection and property code 209 | from xclip.c. This may (or may not) be handy for anyone who wants a 210 | simple way to use selections without using a widget set or getting 211 | too involved in doing it themselves with xlib. I know a lot of people 212 | are using xclip from inside scripts or other programs at the moment, 213 | perhaps it xclib.c would be allow people to integrate the code into 214 | their own projects easily. 215 | 216 | All in all, a general cleanup (as I am now semi-competent with C), and 217 | complete support for the INCR mechanism. 218 | 219 | 220 | Version 0.05: 221 | Added -selection option to allow access to XA_SECONDARY and 222 | XA_CLIPBOARD. Use "-selection secondary", or "-s s" 223 | 224 | Changed email address. 225 | 226 | Added -Wall to C compiler options in Imakefile, fixed up some warnings. 227 | 228 | Updated man page. 229 | 230 | 231 | Version 0.04: 232 | Changed use of getopt_long() to XrmParseCommand(), a function in xlib, 233 | for portability. Apparently System V Unix derived machines don't have 234 | getopt_long(). XrmParseCommand() is part of xlib, and hence should 235 | *always* be available. XrmParseCommand is pretty average. It ignores 236 | ambiguous options (-ver gets ignored, instead of going to -verbose or 237 | -version). It doesn't do multiple options with one hyphen (-if instead 238 | of (-i -f), etc. 239 | 240 | Added xclip -out (out mode) and -filter (print stdin back to stdout). 241 | 242 | 243 | Version 0.03: 244 | Changed use of getopt_long_only to getopt_long, which should work 245 | better with non-GNU platforms. 246 | 247 | Fixed segfault when given a non-existent file to read. 248 | 249 | Made Imakefile for use with xmkmf. This means that xclip should build 250 | and install fairly nicely on any system with an X Consortium derived 251 | X server (nearly all Unix style X servers I would imagine). 252 | 253 | Wrote a decent man page. 254 | 255 | 256 | Version 0.02: 257 | Patch to allow reading from files if specified as arguments applied. 258 | 259 | Cleaned up source file (indenting, comments, etc). 260 | 261 | Started wrapping documentation at 80 chars. 262 | 263 | Added this changelog. 264 | 265 | 266 | Version 0.01: 267 | Everything. First release, pretty basic, but it worked. 268 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | BUILDING 2 | ======== 3 | 4 | You should be able to build and install xclip by running the following commands 5 | in the xclip source directory: 6 | 7 | autoreconf # create configuration files 8 | ./configure # create the Makefile 9 | make # build the binary 10 | su # su to root to install 11 | make install # install xclip 12 | make install.man # install man page 13 | 14 | This should make and install xclip using the configuration (in terms of install 15 | directories, libraries, etc) used to build everything else in your X11 16 | distribution. 17 | 18 | REQUIREMENTS 19 | ============ 20 | 21 | xclip should compile on pretty much any unix-like system. The requirements to 22 | compile xclip are pretty minimal, if you can compile any X apps at all, you'll 23 | be able to compile xclip. 24 | 25 | This means you will need a C compiler, C development environment, xlib 26 | development environment, make, etc. All of these should be available as 27 | packages for most useful distributions. 28 | 29 | For example, in Ubuntu 16.04 LTS you will need to install the following 30 | packages before the installation will succeed. 31 | 32 | libx11-dev 33 | libxmu-headers 34 | libxt-dev 35 | libxmu-dev 36 | 37 | PLATFORMS 38 | ========= 39 | 40 | xclip should compile and work on any unix-like platform, I have taken great 41 | effort to avoid using anything that isn't absolutely standard. 42 | 43 | I have decided that it's not practical to compile a list of specific platforms 44 | that xclip works on, but it has been known to work on GNU/Linux, Solaris, 45 | Cygwin and Irix. If you are able to get xclip working on a different platform, 46 | or have any problems getting it to work on a platform you feel it should work 47 | on, please drop me an email - I'd be interested to know. 48 | 49 | TESTING 50 | ======= 51 | 52 | The xctest shell script tests xclip by creating a file, and transferring it 53 | with xclip -i and xclip -o to put it trough xclip, then making sure that 54 | xclip -o returns exactly what we put in with xclip -i with diff. It was written 55 | primarily for my own benefit so that I can quickly test that all xclip features 56 | are working correctly after I make a change. However, I have included it to 57 | help out anyone who may be modifying the xclip code themselves. 58 | 59 | Basically, when you run xctest, you shouldn't see any extra output from diff 60 | in between each test (because the input and output should be identical). 61 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | prefix = @prefix@ 2 | exec_prefix = @exec_prefix@ 3 | bindir = @bindir@ 4 | mandir = @mandir@ 5 | datarootdir = @datarootdir@ 6 | datadir = @datadir@ 7 | 8 | VERSION = @PACKAGE_VERSION@ 9 | 10 | CC = @CC@ 11 | INSTALL = @INSTALL@ 12 | CFLAGS = @CFLAGS@ @X_CFLAGS@ @DEFS@ 13 | LDFLAGS = @LDFLAGS@ @LIBS@ @X_LIBS@ @X_EXTRA_LIBS@ -lX11 -lXmu 14 | STRIP = @STRIP@ 15 | 16 | OBJS = xclib.o xcprint.o xclip.o 17 | 18 | .PHONY: all 19 | all: xclip 20 | 21 | xclip: $(X11OBJ) $(OBJS) 22 | $(CC) $(OBJS) $(CFLAGS) -o $@ $(X11OBJ) $(LDFLAGS) 23 | 24 | install: installbin install.man 25 | 26 | .PHONY: installbin 27 | installbin: xclip xclip-copyfile xclip-pastefile xclip-cutfile 28 | mkdir -p $(DESTDIR)$(bindir) 29 | $(INSTALL) $^ $(DESTDIR)$(bindir) 30 | 31 | 32 | .PHONY: install.man 33 | install.man: xclip.1 xclip-copyfile.1 34 | mkdir -p $(DESTDIR)$(mandir)/man1 35 | $(INSTALL) -m 644 $^ $(DESTDIR)$(mandir)/man1 36 | 37 | .PHONY: clean 38 | clean: 39 | rm -f *.o *~ xclip xclip-$(VERSION).tar.gz borked 40 | 41 | .PHONY: distclean 42 | distclean: clean 43 | rm -rf autom4te.cache config.log config.status Makefile 44 | 45 | .PHONY: dist 46 | dist: xclip-$(VERSION).tar.gz 47 | 48 | .PHONY: xclip-$(VERSION).tar.gz 49 | xclip-$(VERSION).tar.gz: 50 | mkdir -p /tmp/xclip-make-dist-dir 51 | ln -sf `pwd` /tmp/xclip-make-dist-dir/xclip-$(VERSION) 52 | (cd /tmp/xclip-make-dist-dir; \ 53 | tar zcvf xclip-$(VERSION)/xclip-$(VERSION).tar.gz \ 54 | xclip-$(VERSION)/COPYING \ 55 | xclip-$(VERSION)/README \ 56 | xclip-$(VERSION)/ChangeLog \ 57 | xclip-$(VERSION)/configure \ 58 | xclip-$(VERSION)/configure.ac \ 59 | xclip-$(VERSION)/bootstrap \ 60 | xclip-$(VERSION)/xclip-copyfile \ 61 | xclip-$(VERSION)/xclip-pastefile \ 62 | xclip-$(VERSION)/xclip-cutfile \ 63 | xclip-$(VERSION)/install-sh \ 64 | xclip-$(VERSION)/Makefile.in \ 65 | xclip-$(VERSION)/xclip.spec \ 66 | xclip-$(VERSION)/*.c \ 67 | xclip-$(VERSION)/*.h \ 68 | xclip-$(VERSION)/xclip-copyfile.1 \ 69 | xclip-$(VERSION)/xclip.1 ) 70 | rm -rf /tmp/xclip-make-dist-dir 71 | 72 | Makefile: Makefile.in configure 73 | ./config.status 74 | 75 | configure: configure.ac 76 | ./bootstrap 77 | 78 | borked: borked.c xclib.o xcprint.o 79 | $(CC) $^ $(CFLAGS) -o $@ $(X11OBJ) $(LDFLAGS) 80 | 81 | .SUFFIXES: 82 | .SUFFIXES: .c .o 83 | 84 | .c.o: 85 | $(CC) $(CFLAGS) -o $@ -c $< 86 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | WHAT IS XCLIP? 2 | ============== 3 | 4 | xclip is a command line utility that is designed to run on any system with an 5 | X11 implementation. It provides an interface to X selections ("the clipboard") 6 | from the command line. It can read data from standard in or a file and place it 7 | in an X selection for pasting into other X applications. xclip can also print 8 | an X selection to standard out, which can then be redirected to a file or 9 | another program. 10 | 11 | USING XCLIP 12 | =========== 13 | 14 | Here are some ideas for things you can do with xclip: 15 | 16 | Copy your uptime into the selection for pasting: 17 | uptime | xclip 18 | 19 | Copy your password file for pasting: 20 | xclip /etc/passwd 21 | 22 | Save some text you have Edit | Copied in a web browser: 23 | xclip -o -sel clip > webpage.txt 24 | 25 | Open a URL selected in an email client 26 | mozilla `xclip -o` 27 | 28 | Copy XA_PRIMARY to XA_CLIPBOARD 29 | xclip -o | xclip -sel clip 30 | 31 | In command mode in vim, select some lines of text, then press shift-: 32 | for an ex prompt, and use this command to copy the selected lines of 33 | text to the primary X selection: 34 | !xclip -f 35 | 36 | 37 | USING XCLIP FOR MOVING FILES 38 | ============================ 39 | 40 | The programs xclip-copyfile, xclip-pastefile, and xclip-cutfile can be 41 | used for copying and moving files between different directories and 42 | even machines, assuming that you have a working X11 connection. Here 43 | are some examples: 44 | 45 | # Copying a file to a remote host 46 | [maggie.lkpg.cendio.se ~]$ echo "A file created on ${HOSTNAME}" > file1 47 | [maggie.lkpg.cendio.se ~]$ xclip-copyfile file1 48 | [sofie.homeip.net ~/doc]$ xclip-pastefile 49 | file1 50 | [sofie.homeip.net ~/doc]$ cat file1 51 | A file created on maggie.lkpg.cendio.se 52 | 53 | 54 | # Copying an entire tree structure 55 | [sofie.homeip.net ~]$ xclip-copyfile doc 56 | [maggie.lkpg.cendio.se ~/tmp]$ xclip-pastefile 57 | doc/ 58 | doc/letter-mom-april.txt 59 | doc/file1 60 | doc/letter-dad-march.txt 61 | 62 | 63 | # Copying files with preserved path information 64 | [maggie.lkpg.cendio.se ~]$ xclip-copyfile -p /etc/sysconfig/grub 65 | tar: Removing leading `/' from member names 66 | [sofie.homeip.net ~/tmp]$ xclip-pastefile 67 | etc/sysconfig/grub 68 | [sofie.homeip.net ~/tmp]$ ls etc/sysconfig/grub 69 | etc/sysconfig/grub 70 | 71 | 72 | # Moving files 73 | [sofie.homeip.net ~]$ ls letter-brother-may.txt 74 | letter-brother-may.txt 75 | [sofie.homeip.net ~]$ xclip-cutfile letter-brother-may.txt 76 | [sofie.homeip.net ~]$ ls letter-brother-may.txt 77 | ls: cannot access letter-brother-may.txt: No such file or directory 78 | [sofie.homeip.net ~]$ cd doc 79 | [sofie.homeip.net ~/doc]$ xclip-pastefile 80 | letter-brother-may.txt 81 | 82 | 83 | FEATURES 84 | ======== 85 | 86 | * Reads data piped to standard in or files given as arguments 87 | * Prints contents of selection to standard out 88 | * Accesses the XA_PRIMARY, XA_SECONDARY or XA_CLIPBOARD selection 89 | * Accesses the cut-buffers 90 | * Supports the INCR mechanism for large transfers 91 | * Connects to the X display in $DISPLAY, or specified with -display host:0 92 | * Waits for selection requests in the background 93 | 94 | SELECTIONS 95 | ========== 96 | 97 | For a good overview of what selections are about, have a look at 98 | . Short version: 99 | 100 | * XA_PRIMARY contains the last text you highlighted 101 | * Middle click pastes XA_PRIMARY 102 | * XA_CLIPBOARD contains text explicitly copied with Edit | Copy, Ctrl-C etc. 103 | * Edit | Paste pastes XA_CLIPBOARD 104 | * xclip uses XA_PRIMARY unless you specify otherwise with -selection 105 | 106 | CAN I HELP? 107 | =========== 108 | 109 | Glad you asked! At this stage, I'm pretty happy with the features and 110 | implementation, so if you have anything at all that should be done, I want to 111 | hear about it. Doesn't matter how small, compiler warnings, segfaults, spelling 112 | mistakes, whatever, I want to get it sorted out. xclip is not a big project, 113 | I'd like to get all these things sorted out and then declare it "complete". 114 | 115 | LICENSE 116 | ======= 117 | 118 | GNU GPL, see the COPYING file for details. 119 | 120 | CONTACT 121 | ======= 122 | 123 | Web: 124 | https://github.com/astrand/xclip 125 | 126 | Email: 127 | astrand@lysator.liu.se 128 | 129 | Please email me about problems, experiences, patches, fixes, etc. 130 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -rf autom4te.cache 3 | autoreconf -i 4 | -------------------------------------------------------------------------------- /borked.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * borked.c - emulate ways X selections can break for testing. 5 | * Copyright (C) 2020 Hackerb9, Peter Åstrand 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 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 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | // gcc -g -O2 borked.c xclib.o xcprint.o -o borked -lXmu -lX11 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #ifdef HAVE_ICONV 29 | #include 30 | #include 31 | #endif 32 | #include 33 | #include 34 | #include 35 | #include "xcdef.h" 36 | #include "xcprint.h" 37 | #include "xclib.h" 38 | 39 | 40 | /* Globals */ 41 | Display *dpy; /* connection to X11 display */ 42 | Atom sseln = XA_PRIMARY; /* X selection to work with */ 43 | Atom target = XA_STRING; /* Gets changed to UTF8_STRING later. */ 44 | 45 | static int 46 | outReadAndDie(Window win) 47 | { 48 | /* Start reading (paste) but then suddenly quit in the middle. */ 49 | 50 | Atom sel_type = None; 51 | unsigned char *sel_buf; /* buffer for selection data */ 52 | unsigned long sel_len = 0; /* length of sel_buf */ 53 | XEvent evt; /* X Event Structures */ 54 | unsigned int context = XCLIB_XCOUT_NONE; 55 | 56 | while (1) { 57 | /* only get an event if xcout() is doing something */ 58 | if (context != XCLIB_XCOUT_NONE) 59 | XNextEvent(dpy, &evt); 60 | 61 | /* fetch the selection, or part of it */ 62 | xcout(dpy, win, evt, sseln, target, &sel_type, &sel_buf, &sel_len, &context); 63 | if (context == XCLIB_XCOUT_BAD_TARGET) { 64 | if (target == XA_UTF8_STRING(dpy)) { 65 | /* fallback is needed. set XA_STRING to target and restart the loop. */ 66 | context = XCLIB_XCOUT_NONE; 67 | target = XA_STRING; 68 | continue; 69 | } 70 | else { 71 | /* no fallback available, exit with failure */ 72 | XSetSelectionOwner(dpy, sseln, None, CurrentTime); 73 | xcmemzero(sel_buf,sel_len); 74 | errconvsel(dpy, target, sseln); 75 | // errconvsel does not return but exits with EXIT_FAILURE 76 | } 77 | } 78 | 79 | /* normally, we'd only continue if xcout() is doing something */ 80 | if (context == XCLIB_XCOUT_NONE) 81 | break; 82 | 83 | /* but since we're intentionally borken, we'll always exit! */ 84 | break; 85 | } 86 | 87 | printf("Read %ld bytes and quit in the middle\n", sel_len) ; 88 | 89 | return EXIT_SUCCESS; 90 | } 91 | 92 | 93 | static int 94 | outReadAndSteal(Window win) 95 | { 96 | /* Start reading (paste) but then suddenly set selection owner to None. */ 97 | 98 | Atom sel_type = None; 99 | unsigned char *sel_buf; /* buffer for selection data */ 100 | unsigned long sel_len = 0; /* length of sel_buf */ 101 | XEvent evt; /* X Event Structures */ 102 | unsigned int context = XCLIB_XCOUT_NONE; 103 | 104 | while (1) { 105 | /* only get an event if xcout() is doing something */ 106 | if (context != XCLIB_XCOUT_NONE) 107 | XNextEvent(dpy, &evt); 108 | 109 | /* fetch the selection, or part of it */ 110 | xcout(dpy, win, evt, sseln, target, &sel_type, &sel_buf, &sel_len, &context); 111 | 112 | printf("Read %ld bytes\n", sel_len); 113 | 114 | if (context == XCLIB_XCOUT_BAD_TARGET) { 115 | if (target == XA_UTF8_STRING(dpy)) { 116 | /* fallback is needed. set XA_STRING to target and restart the loop. */ 117 | context = XCLIB_XCOUT_NONE; 118 | target = XA_STRING; 119 | continue; 120 | } 121 | else { 122 | /* no fallback available, exit with failure */ 123 | XSetSelectionOwner(dpy, sseln, None, CurrentTime); 124 | xcmemzero(sel_buf,sel_len); 125 | errconvsel(dpy, target, sseln); 126 | // errconvsel does not return but exits with EXIT_FAILURE 127 | } 128 | } 129 | 130 | /* normally, we'd only continue if xcout() is doing something */ 131 | if (context == XCLIB_XCOUT_NONE) 132 | break; 133 | 134 | /* but since we're intentionally borken, we'll steal the selection! */ 135 | XSetSelectionOwner(dpy, sseln, None, CurrentTime); 136 | printf("Selection owner set to None.\n"); 137 | } 138 | 139 | return EXIT_SUCCESS; 140 | } 141 | 142 | 143 | static int 144 | outReadAndHang(Window win) 145 | { 146 | /* Start reading (paste) but then just hang forever. */ 147 | 148 | Atom sel_type = None; 149 | unsigned char *sel_buf; /* buffer for selection data */ 150 | unsigned long sel_len = 0; /* length of sel_buf */ 151 | XEvent evt; /* X Event Structures */ 152 | unsigned int context = XCLIB_XCOUT_NONE; 153 | 154 | while (1) { 155 | /* only get an event if xcout() is doing something */ 156 | if (context != XCLIB_XCOUT_NONE) 157 | XNextEvent(dpy, &evt); 158 | 159 | /* fetch the selection, or part of it */ 160 | xcout(dpy, win, evt, sseln, target, &sel_type, &sel_buf, &sel_len, &context); 161 | 162 | printf("Read %ld bytes\n", sel_len); 163 | 164 | if (context == XCLIB_XCOUT_BAD_TARGET) { 165 | if (target == XA_UTF8_STRING(dpy)) { 166 | /* fallback is needed. set XA_STRING to target and restart the loop. */ 167 | context = XCLIB_XCOUT_NONE; 168 | target = XA_STRING; 169 | continue; 170 | } 171 | else { 172 | /* no fallback available, exit with failure */ 173 | XSetSelectionOwner(dpy, sseln, None, CurrentTime); 174 | xcmemzero(sel_buf,sel_len); 175 | errconvsel(dpy, target, sseln); 176 | // errconvsel does not return but exits with EXIT_FAILURE 177 | } 178 | } 179 | 180 | /* normally, we'd only continue if xcout() is doing something */ 181 | if (context == XCLIB_XCOUT_NONE) 182 | break; 183 | 184 | /* but since we're intentionally borken, we'll hang forever! */ 185 | printf("Selection now hanging forever. Hit ^C to cancel.\n"); 186 | while (1) 187 | sleep(1); 188 | } 189 | 190 | return EXIT_SUCCESS; 191 | } 192 | 193 | int 194 | main(int argc, char *argv[]) 195 | { 196 | /* Declare variables */ 197 | Window win; /* Window */ 198 | 199 | int mode = 0; /* What sort of brokenness to emulate */ 200 | if (argc > 1) 201 | mode = atoi(argv[1]); 202 | 203 | /* Connect to the X server. */ 204 | if (! (dpy = XOpenDisplay(NULL)) ) { 205 | /* couldn't connect to X server. Print error and exit */ 206 | errxdisplay(NULL); 207 | } 208 | 209 | /* Use UTF8_STRING since that's xclip's default */ 210 | target = XA_UTF8_STRING(dpy); 211 | 212 | /* Create a window to trap events */ 213 | win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 214 | 0, 0, 1, 1, 0, 0, 0); 215 | 216 | /* get events about property changes */ 217 | XSelectInput(dpy, win, PropertyChangeMask); 218 | 219 | switch (mode) { 220 | case 0: 221 | printf("Mode 0: start reading X selection for paste but then exit suddenly.\n"); 222 | outReadAndDie(win); 223 | break; 224 | case 1: 225 | printf("Mode 1: start reading X selection (paste), but then steal selection (copy).\n"); 226 | outReadAndSteal(win); 227 | break; 228 | case 2: 229 | printf("Mode 2: start reading X selection (paste), but then just hang forever.\n"); 230 | outReadAndHang(win); 231 | break; 232 | default: 233 | errx(1, "Unknown mode number '%s'", argv[1]); 234 | } 235 | 236 | /* Disconnect from the X server */ 237 | printf("Closing the X Display\n"); 238 | XCloseDisplay(dpy); 239 | 240 | /* exit */ 241 | return 0; 242 | } 243 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([xclip],[0.13]) 2 | 3 | AC_CONFIG_SRCDIR([xclip.c]) 4 | 5 | AC_PROG_CC 6 | if test "$GCC" = yes; then 7 | CFLAGS="$CFLAGS -Wall" 8 | fi 9 | 10 | AC_PROG_INSTALL 11 | AC_LANG([C]) 12 | 13 | AC_PATH_XTRA 14 | AC_CHECK_TOOL(STRIP, strip, :) 15 | AC_CHECK_HEADER([X11/Xmu/Atoms.h], [], AC_MSG_ERROR([*** X11/Xmu/Atoms.h is missing ***])) 16 | AC_CHECK_HEADER([X11/Intrinsic.h], [], AC_MSG_ERROR([*** X11/Intrinsic.h is missing ***])) 17 | AC_CHECK_HEADER([iconv.h], 18 | AC_SEARCH_LIBS([iconv], [iconv], 19 | AC_DEFINE([HAVE_ICONV]), []), []) 20 | AC_CHECK_LIB(Xmu, XmuClientWindow, [], AC_MSG_ERROR([*** libXmu not found ***])) 21 | 22 | AC_CONFIG_FILES([Makefile]) 23 | AC_OUTPUT 24 | -------------------------------------------------------------------------------- /indent-all: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | indent -i4 -br -l100 -npcs *.c 3 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # install - install a program, script, or datafile 4 | # This comes from X11R5 (mit/util/scripts/install.sh). 5 | # 6 | # Copyright 1991 by the Massachusetts Institute of Technology 7 | # 8 | # Permission to use, copy, modify, distribute, and sell this software and its 9 | # documentation for any purpose is hereby granted without fee, provided that 10 | # the above copyright notice appear in all copies and that both that 11 | # copyright notice and this permission notice appear in supporting 12 | # documentation, and that the name of M.I.T. not be used in advertising or 13 | # publicity pertaining to distribution of the software without specific, 14 | # written prior permission. M.I.T. makes no representations about the 15 | # suitability of this software for any purpose. It is provided "as is" 16 | # without express or implied warranty. 17 | # 18 | # Calling this script install-sh is preferred over install.sh, to prevent 19 | # `make' implicit rules from creating a file called install from it 20 | # when there is no Makefile. 21 | # 22 | # This script is compatible with the BSD install script, but was written 23 | # from scratch. It can only install one file at a time, a restriction 24 | # shared with many OS's install programs. 25 | 26 | 27 | # set DOITPROG to echo to test this script 28 | 29 | # Don't use :- since 4.3BSD and earlier shells don't like it. 30 | doit="${DOITPROG-}" 31 | 32 | 33 | # put in absolute paths if you don't have them in your path; or use env. vars. 34 | 35 | mvprog="${MVPROG-mv}" 36 | cpprog="${CPPROG-cp}" 37 | chmodprog="${CHMODPROG-chmod}" 38 | chownprog="${CHOWNPROG-chown}" 39 | chgrpprog="${CHGRPPROG-chgrp}" 40 | stripprog="${STRIPPROG-strip}" 41 | rmprog="${RMPROG-rm}" 42 | mkdirprog="${MKDIRPROG-mkdir}" 43 | 44 | transformbasename="" 45 | transform_arg="" 46 | instcmd="$mvprog" 47 | chmodcmd="$chmodprog 0755" 48 | chowncmd="" 49 | chgrpcmd="" 50 | stripcmd="" 51 | rmcmd="$rmprog -f" 52 | mvcmd="$mvprog" 53 | src="" 54 | dst="" 55 | dir_arg="" 56 | 57 | while [ x"$1" != x ]; do 58 | case $1 in 59 | -c) instcmd="$cpprog" 60 | shift 61 | continue;; 62 | 63 | -d) dir_arg=true 64 | shift 65 | continue;; 66 | 67 | -m) chmodcmd="$chmodprog $2" 68 | shift 69 | shift 70 | continue;; 71 | 72 | -o) chowncmd="$chownprog $2" 73 | shift 74 | shift 75 | continue;; 76 | 77 | -g) chgrpcmd="$chgrpprog $2" 78 | shift 79 | shift 80 | continue;; 81 | 82 | -s) stripcmd="$stripprog" 83 | shift 84 | continue;; 85 | 86 | -t=*) transformarg=`echo $1 | sed 's/-t=//'` 87 | shift 88 | continue;; 89 | 90 | -b=*) transformbasename=`echo $1 | sed 's/-b=//'` 91 | shift 92 | continue;; 93 | 94 | *) if [ x"$src" = x ] 95 | then 96 | src=$1 97 | else 98 | # this colon is to work around a 386BSD /bin/sh bug 99 | : 100 | dst=$1 101 | fi 102 | shift 103 | continue;; 104 | esac 105 | done 106 | 107 | if [ x"$src" = x ] 108 | then 109 | echo "install: no input file specified" 110 | exit 1 111 | else 112 | : 113 | fi 114 | 115 | if [ x"$dir_arg" != x ]; then 116 | dst=$src 117 | src="" 118 | 119 | if [ -d $dst ]; then 120 | instcmd=: 121 | chmodcmd="" 122 | else 123 | instcmd=$mkdirprog 124 | fi 125 | else 126 | 127 | # Waiting for this to be detected by the "$instcmd $src $dsttmp" command 128 | # might cause directories to be created, which would be especially bad 129 | # if $src (and thus $dsttmp) contains '*'. 130 | 131 | if [ -f "$src" ] || [ -d "$src" ] 132 | then 133 | : 134 | else 135 | echo "install: $src does not exist" 136 | exit 1 137 | fi 138 | 139 | if [ x"$dst" = x ] 140 | then 141 | echo "install: no destination specified" 142 | exit 1 143 | else 144 | : 145 | fi 146 | 147 | # If destination is a directory, append the input filename; if your system 148 | # does not like double slashes in filenames, you may need to add some logic 149 | 150 | if [ -d $dst ] 151 | then 152 | dst="$dst"/`basename $src` 153 | else 154 | : 155 | fi 156 | fi 157 | 158 | ## this sed command emulates the dirname command 159 | dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` 160 | 161 | # Make sure that the destination directory exists. 162 | # this part is taken from Noah Friedman's mkinstalldirs script 163 | 164 | # Skip lots of stat calls in the usual case. 165 | if [ ! -d "$dstdir" ]; then 166 | defaultIFS=' 167 | ' 168 | IFS="${IFS-${defaultIFS}}" 169 | 170 | oIFS="${IFS}" 171 | # Some sh's can't handle IFS=/ for some reason. 172 | IFS='%' 173 | set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` 174 | IFS="${oIFS}" 175 | 176 | pathcomp='' 177 | 178 | while [ $# -ne 0 ] ; do 179 | pathcomp="${pathcomp}${1}" 180 | shift 181 | 182 | if [ ! -d "${pathcomp}" ] ; 183 | then 184 | $mkdirprog "${pathcomp}" 185 | else 186 | : 187 | fi 188 | 189 | pathcomp="${pathcomp}/" 190 | done 191 | fi 192 | 193 | if [ x"$dir_arg" != x ] 194 | then 195 | $doit $instcmd $dst && 196 | 197 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi && 198 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi && 199 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi && 200 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi 201 | else 202 | 203 | # If we're going to rename the final executable, determine the name now. 204 | 205 | if [ x"$transformarg" = x ] 206 | then 207 | dstfile=`basename $dst` 208 | else 209 | dstfile=`basename $dst $transformbasename | 210 | sed $transformarg`$transformbasename 211 | fi 212 | 213 | # don't allow the sed command to completely eliminate the filename 214 | 215 | if [ x"$dstfile" = x ] 216 | then 217 | dstfile=`basename $dst` 218 | else 219 | : 220 | fi 221 | 222 | # Make a temp file name in the proper directory. 223 | 224 | dsttmp=$dstdir/#inst.$$# 225 | 226 | # Move or copy the file name to the temp name 227 | 228 | $doit $instcmd $src $dsttmp && 229 | 230 | trap "rm -f ${dsttmp}" 0 && 231 | 232 | # and set any options; do chmod last to preserve setuid bits 233 | 234 | # If any of these fail, we abort the whole thing. If we want to 235 | # ignore errors from any of these, just make sure not to ignore 236 | # errors from the above "$doit $instcmd $src $dsttmp" command. 237 | 238 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi && 239 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi && 240 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi && 241 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi && 242 | 243 | # Now rename the file to the real destination. 244 | 245 | $doit $rmcmd -f $dstdir/$dstfile && 246 | $doit $mvcmd $dsttmp $dstdir/$dstfile 247 | 248 | fi && 249 | 250 | 251 | exit 0 252 | -------------------------------------------------------------------------------- /xcdef.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * xcdef.h - definitions for use throughout xclip 5 | * Copyright (C) 2001 Kim Saunders 6 | * Copyright (C) 2007-2008 Peter Åstrand 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | /* generic true/false constants for stuff */ 23 | #define F 0 /* false... */ 24 | #define T 1 /* true... */ 25 | 26 | /* true/false string constants */ 27 | #define SF "F" /* false */ 28 | #define ST "T" /* true */ 29 | -------------------------------------------------------------------------------- /xclib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * xclib.c - xclip library to look after xlib mechanics for xclip 5 | * Copyright (C) 2001 Kim Saunders 6 | * Copyright (C) 2007-2008 Peter Åstrand 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "xcdef.h" 28 | #include "xcprint.h" 29 | #include "xclib.h" 30 | 31 | /* global verbosity output level, defaults to OSILENT */ 32 | int xcverb = OSILENT; 33 | 34 | /* Table of event names from event numbers */ 35 | const char *evtstr[LASTEvent] = { 36 | "ProtocolError", "ProtocolReply", "KeyPress", "KeyRelease", 37 | "ButtonPress", "ButtonRelease", "MotionNotify", "EnterNotify", 38 | "LeaveNotify", "FocusIn", "FocusOut", "KeymapNotify", "Expose", 39 | "GraphicsExpose", "NoExpose", "VisibilityNotify", "CreateNotify", 40 | "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest", 41 | "ReparentNotify", "ConfigureNotify", "ConfigureRequest", 42 | "GravityNotify", "ResizeRequest", "CirculateNotify", 43 | "CirculateRequest", "PropertyNotify", "SelectionClear", 44 | "SelectionRequest", "SelectionNotify", "ColormapNotify", 45 | "ClientMessage", "MappingNotify", "GenericEvent", }; 46 | 47 | /* a memset function that won't be optimized away by compiler */ 48 | void 49 | xcmemzero(void *ptr, size_t len) 50 | { 51 | if (xcverb >= ODEBUG) { 52 | fprintf(stderr, "xclip: debug: Zeroing memory buffer\n"); 53 | } 54 | memset_func(ptr, 0, len); 55 | } 56 | 57 | /* check a pointer to allocated memory, print an error if it's null */ 58 | void 59 | xcmemcheck(void *ptr) 60 | { 61 | if (ptr == NULL) 62 | errmalloc(); 63 | } 64 | 65 | /* wrapper for malloc that checks for errors */ 66 | void * 67 | xcmalloc(size_t size) 68 | { 69 | void *mem; 70 | 71 | mem = malloc(size); 72 | xcmemcheck(mem); 73 | 74 | return (mem); 75 | } 76 | 77 | /* wrapper for realloc that checks for errors */ 78 | void * 79 | xcrealloc(void *ptr, size_t size) 80 | { 81 | void *mem; 82 | 83 | mem = realloc(ptr, size); 84 | xcmemcheck(mem); 85 | 86 | return (mem); 87 | } 88 | 89 | /* a strdup() implementation since ANSI C doesn't include strdup() */ 90 | void * 91 | xcstrdup(const char *string) 92 | { 93 | void *mem; 94 | 95 | /* allocate a buffer big enough to hold the characters and the 96 | * null terminator, then copy the string into the buffer 97 | */ 98 | mem = xcmalloc(strlen(string) + sizeof(char)); 99 | strcpy(mem, string); 100 | 101 | return (mem); 102 | } 103 | 104 | /* Returns the machine-specific number of bytes per data element 105 | * returned by XGetWindowProperty */ 106 | static size_t 107 | mach_itemsize(int format) 108 | { 109 | if (format == 8) 110 | return sizeof(char); 111 | if (format == 16) 112 | return sizeof(short); 113 | if (format == 32) 114 | return sizeof(long); 115 | return 0; 116 | } 117 | 118 | /* Retrieves the contents of a selections. Arguments are: 119 | * 120 | * A display that has been opened. 121 | * 122 | * A window 123 | * 124 | * An event to process 125 | * 126 | * The selection to return 127 | * 128 | * The target(UTF8_STRING or XA_STRING) to return 129 | * 130 | * A pointer to an atom that receives the type of the data 131 | * 132 | * A pointer to a char array to put the selection into. 133 | * 134 | * A pointer to a long to record the length of the char array 135 | * 136 | * A pointer to an int to record the context in which to process the event 137 | * 138 | * Return value is 1 if the retrieval of the selection data is complete, 139 | * otherwise it's 0. 140 | */ 141 | int 142 | xcout(Display * dpy, 143 | Window win, 144 | XEvent evt, Atom sel, Atom target, Atom * type, unsigned char **txt, unsigned long *len, 145 | unsigned int *context) 146 | { 147 | /* a property for other windows to put their selection into */ 148 | static Atom pty; 149 | static Atom inc; 150 | int pty_format; 151 | 152 | /* buffer for XGetWindowProperty to dump data into */ 153 | unsigned char *buffer; 154 | unsigned long pty_size, pty_items, pty_machsize; 155 | 156 | /* local buffer of text to return */ 157 | unsigned char *ltxt = *txt; 158 | 159 | if (!pty) { 160 | pty = XInternAtom(dpy, "XCLIP_OUT", False); 161 | } 162 | 163 | if (!inc) { 164 | inc = XInternAtom(dpy, "INCR", False); 165 | } 166 | 167 | switch (*context) { 168 | /* there is no context, do an XConvertSelection() */ 169 | case XCLIB_XCOUT_NONE: 170 | /* initialise return length to 0 */ 171 | if (*len > 0) { 172 | free(*txt); 173 | *len = 0; 174 | } 175 | 176 | /* send a selection request */ 177 | XConvertSelection(dpy, sel, target, pty, win, CurrentTime); 178 | *context = XCLIB_XCOUT_SENTCONVSEL; 179 | return (0); 180 | 181 | case XCLIB_XCOUT_SENTCONVSEL: 182 | if (evt.type != SelectionNotify) 183 | return (0); 184 | 185 | /* return failure when the current target failed */ 186 | if (evt.xselection.property == None) { 187 | *context = XCLIB_XCOUT_BAD_TARGET; 188 | return (0); 189 | } 190 | 191 | /* find the size and format of the data in property */ 192 | XGetWindowProperty(dpy, 193 | win, 194 | pty, 195 | 0, 196 | 0, 197 | False, 198 | AnyPropertyType, type, &pty_format, &pty_items, &pty_size, &buffer); 199 | XFree(buffer); 200 | 201 | if (*type == inc) { 202 | /* start INCR mechanism by deleting property */ 203 | if (xcverb >= OVERBOSE) { 204 | fprintf(stderr, 205 | "xclib: debug: Starting INCR by deleting property\n"); 206 | } 207 | XDeleteProperty(dpy, win, pty); 208 | XFlush(dpy); 209 | *context = XCLIB_XCOUT_INCR; 210 | return (0); 211 | } 212 | 213 | /* not using INCR mechanism, just read the property */ 214 | XGetWindowProperty(dpy, 215 | win, 216 | pty, 217 | 0, 218 | (long) pty_size, 219 | False, 220 | AnyPropertyType, type, &pty_format, &pty_items, &pty_size, &buffer); 221 | 222 | /* finished with property, delete it */ 223 | XDeleteProperty(dpy, win, pty); 224 | 225 | /* compute the size of the data buffer we received */ 226 | pty_machsize = pty_items * mach_itemsize(pty_format); 227 | 228 | /* copy the buffer to the pointer for returned data */ 229 | ltxt = (unsigned char *) xcmalloc(pty_machsize); 230 | memcpy(ltxt, buffer, pty_machsize); 231 | 232 | /* set the length of the returned data */ 233 | *len = pty_machsize; 234 | *txt = ltxt; 235 | 236 | /* free the buffer */ 237 | XFree(buffer); 238 | 239 | *context = XCLIB_XCOUT_NONE; 240 | 241 | /* complete contents of selection fetched, return 1 */ 242 | return (1); 243 | 244 | case XCLIB_XCOUT_INCR: 245 | /* To use the INCR method, we basically delete the 246 | * property with the selection in it, wait for an 247 | * event indicating that the property has been created, 248 | * then read it, delete it, etc. 249 | */ 250 | 251 | /* make sure that the event is relevant */ 252 | if (evt.type != PropertyNotify) 253 | return (0); 254 | 255 | /* skip unless the property has a new value */ 256 | if (evt.xproperty.state != PropertyNewValue) 257 | return (0); 258 | 259 | /* check size and format of the property */ 260 | XGetWindowProperty(dpy, 261 | win, 262 | pty, 263 | 0, 264 | 0, 265 | False, 266 | AnyPropertyType, 267 | type, &pty_format, &pty_items, &pty_size, (unsigned char **) &buffer); 268 | 269 | if (pty_size == 0) { 270 | /* no more data, exit from loop */ 271 | if (xcverb >= ODEBUG) { 272 | fprintf(stderr, "INCR transfer complete\n"); 273 | } 274 | XFree(buffer); 275 | XDeleteProperty(dpy, win, pty); 276 | *context = XCLIB_XCOUT_NONE; 277 | 278 | /* this means that an INCR transfer is now 279 | * complete, return 1 280 | */ 281 | return (1); 282 | } 283 | 284 | XFree(buffer); 285 | 286 | /* if we have come this far, the property contains 287 | * text, we know the size. 288 | */ 289 | XGetWindowProperty(dpy, 290 | win, 291 | pty, 292 | 0, 293 | (long) pty_size, 294 | False, 295 | AnyPropertyType, 296 | type, &pty_format, &pty_items, &pty_size, (unsigned char **) &buffer); 297 | 298 | /* compute the size of the data buffer we received */ 299 | pty_machsize = pty_items * mach_itemsize(pty_format); 300 | 301 | /* allocate memory to accommodate data in *txt */ 302 | if (*len == 0) { 303 | *len = pty_machsize; 304 | ltxt = (unsigned char *) xcmalloc(*len); 305 | } 306 | else { 307 | *len += pty_machsize; 308 | ltxt = (unsigned char *) xcrealloc(ltxt, *len); 309 | } 310 | 311 | /* add data to ltxt */ 312 | memcpy(<xt[*len - pty_machsize], buffer, pty_machsize); 313 | 314 | *txt = ltxt; 315 | XFree(buffer); 316 | 317 | /* delete property to get the next item */ 318 | XDeleteProperty(dpy, win, pty); 319 | XFlush(dpy); 320 | return (0); 321 | } 322 | 323 | return (0); 324 | } 325 | 326 | /* put data into a selection, in response to a SelectionRequest event from 327 | * another window (and any subsequent events relating to an INCR transfer). 328 | * 329 | * Arguments are: 330 | * 331 | * A display 332 | * 333 | * A window 334 | * 335 | * The event to respond to 336 | * 337 | * A pointer to an Atom. This gets set to the property nominated by the other 338 | * app in it's SelectionRequest. Things are likely to break if you change the 339 | * value of this yourself. 340 | * 341 | * The target(UTF8_STRING or XA_STRING) to respond to 342 | * 343 | * A pointer to an array of chars to read selection data from. 344 | * 345 | * The length of the array of chars. 346 | * 347 | * In the case of an INCR transfer, the position within the array of chars 348 | * that is being processed. 349 | * 350 | * The context that event is the be processed within. 351 | */ 352 | int 353 | xcin(Display * dpy, 354 | Window * win, 355 | XEvent evt, 356 | Atom * pty, Atom target, unsigned char *txt, unsigned long len, unsigned long *pos, 357 | char *alt_txt, unsigned int *context, long *chunk_size) 358 | { 359 | unsigned long chunk_len; /* length of current chunk (for incr 360 | * transfers only) 361 | */ 362 | XEvent res; /* response to event */ 363 | static Atom inc; 364 | static Atom targets; 365 | static Atom alt_target; 366 | 367 | if (!alt_target) { 368 | alt_target = XInternAtom(dpy, "STRING", False); 369 | } 370 | 371 | 372 | if (!targets) { 373 | targets = XInternAtom(dpy, "TARGETS", False); 374 | } 375 | 376 | if (!inc) { 377 | inc = XInternAtom(dpy, "INCR", False); 378 | } 379 | 380 | /* We consider selections larger than a quarter of the maximum 381 | request size to be "large". See ICCCM section 2.5 */ 382 | if (!(*chunk_size)) { 383 | *chunk_size = XExtendedMaxRequestSize(dpy) / 4; 384 | if (!(*chunk_size)) { 385 | *chunk_size = XMaxRequestSize(dpy) / 4; 386 | } 387 | if ( xcverb >= ODEBUG ) { 388 | fprintf(stderr, 389 | "xclib: debug: INCR chunk size is %ld\n", (*chunk_size)); 390 | } 391 | } 392 | 393 | switch (*context) { 394 | case XCLIB_XCIN_NONE: 395 | if ( xcverb >= ODEBUG ) 396 | fprintf(stderr, "xclib: debug: context: XCLIB_XCIN_NONE\n"); 397 | 398 | if ( xcverb >= ODEBUG && evt.xselectionrequest.target) { 399 | char *tempstr = XGetAtomName(dpy, evt.xselectionrequest.target); 400 | fprintf(stderr, "xclib: debug: target: %s\n", tempstr); 401 | XFree(tempstr); 402 | } 403 | 404 | if (evt.type != SelectionRequest) { 405 | if ( xcverb >= ODEBUG ) { 406 | fprintf(stderr, 407 | "xclib: debug: ignoring %s event (context is NONE)\n", 408 | evtstr[evt.type]); 409 | } 410 | return (0); 411 | } 412 | /* set the window and property that is being used */ 413 | *win = evt.xselectionrequest.requestor; 414 | *pty = evt.xselectionrequest.property; 415 | 416 | /* reset position to 0 */ 417 | *pos = 0; 418 | 419 | /* put the data into a property */ 420 | if (evt.xselectionrequest.target == targets) { 421 | Atom types[3] = { targets, target, alt_target }; 422 | int types_count = alt_txt == NULL ? 2 : 3; 423 | 424 | if ( xcverb >= ODEBUG ) { 425 | fprintf(stderr, "xclib: debug: sending list of TARGETS\n"); 426 | } 427 | 428 | /* send data all at once (not using INCR) */ 429 | XChangeProperty(dpy, 430 | *win, 431 | *pty, 432 | XA_ATOM, 433 | 32, PropModeReplace, (unsigned char *) types, 434 | types_count 435 | ); 436 | } 437 | else if (evt.xselectionrequest.target == alt_target && alt_txt) { 438 | if ( xcverb >= ODEBUG ) { 439 | fprintf(stderr, "xclib: debug: sending alternative text\n"); 440 | } 441 | 442 | XChangeProperty(dpy, 443 | *win, 444 | *pty, 445 | alt_target, 446 | 8, PropModeReplace, (unsigned char *)alt_txt, 447 | (int)strlen(alt_txt)); 448 | } 449 | else if (len > *chunk_size) { 450 | /* send INCR response */ 451 | if ( xcverb >= ODEBUG ) { 452 | fprintf (stderr, "xclib: debug: Starting INCR response\n"); 453 | } 454 | XChangeProperty(dpy, *win, *pty, inc, 32, PropModeReplace, 0, 0); 455 | 456 | /* With the INCR mechanism, we need to know 457 | * when the requestor window changes (deletes) 458 | * its properties 459 | */ 460 | XSelectInput(dpy, *win, PropertyChangeMask); 461 | 462 | *context = XCLIB_XCIN_INCR; 463 | } 464 | else { 465 | /* send data all at once (not using INCR) */ 466 | if ( xcverb >= ODEBUG ) { 467 | fprintf(stderr, "xclib: debug: Sending data all at once" 468 | " (%d bytes)\n", (int) len); 469 | } 470 | 471 | XChangeProperty(dpy, 472 | *win, 473 | *pty, 474 | target, 475 | 8, PropModeReplace, (unsigned char *) txt, 476 | (int) len); 477 | } 478 | 479 | /* Perhaps FIXME: According to ICCCM section 2.5, we should 480 | confirm that XChangeProperty succeeded without any Alloc 481 | errors before replying with SelectionNotify. However, doing 482 | so would require an error handler which modifies a global 483 | variable, plus doing XSync after each XChangeProperty. */ 484 | 485 | /* set values for the response event */ 486 | res.xselection.property = *pty; 487 | res.xselection.type = SelectionNotify; 488 | res.xselection.display = evt.xselectionrequest.display; 489 | res.xselection.requestor = *win; 490 | res.xselection.selection = evt.xselectionrequest.selection; 491 | res.xselection.target = evt.xselectionrequest.target; 492 | res.xselection.time = evt.xselectionrequest.time; 493 | 494 | /* send the response event */ 495 | XSendEvent(dpy, evt.xselectionrequest.requestor, 0, 0, &res); 496 | XFlush(dpy); 497 | 498 | /* don't treat TARGETS request as contents request */ 499 | if (evt.xselectionrequest.target == targets) 500 | return (1); /* Finished with request */ 501 | 502 | /* don't treat alternative text request as contents request */ 503 | if (evt.xselectionrequest.target == alt_target) 504 | return (1); /* Finished with request */ 505 | 506 | /* if len <= chunk_size, then the data was sent all at 507 | * once and the transfer is now complete, return 1 508 | */ 509 | if (len > *chunk_size) 510 | return (0); 511 | else 512 | return (1); 513 | 514 | break; 515 | 516 | case XCLIB_XCIN_INCR: 517 | /* length of current chunk */ 518 | 519 | /* ignore non-property events */ 520 | if (evt.type != PropertyNotify) 521 | return (0); 522 | 523 | /* ignore the event unless it's to report that the 524 | * property has been deleted 525 | */ 526 | if (evt.xproperty.state != PropertyDelete) { 527 | if ( xcverb >= ODEBUG ) { 528 | if ( evt.xproperty.state == 0 ) 529 | fprintf(stderr, 530 | "xclib: debug: ignoring PropertyNewValue\n"); 531 | else 532 | fprintf(stderr, 533 | "xclib: debug: ignoring state %d\n", 534 | evt.xproperty.state); 535 | } 536 | return (0); 537 | } 538 | 539 | /* set the chunk length to the maximum size */ 540 | chunk_len = *chunk_size; 541 | 542 | /* if a chunk length of maximum size would extend 543 | * beyond the end of txt, set the length to be the 544 | * remaining length of txt 545 | */ 546 | if ((*pos + chunk_len) > len) 547 | chunk_len = len - *pos; 548 | 549 | /* if the start of the chunk is beyond the end of txt, 550 | * then we've already sent all the data, so set the 551 | * length to be zero 552 | */ 553 | if (*pos > len) 554 | chunk_len = 0; 555 | 556 | if (chunk_len) { 557 | /* put the chunk into the property */ 558 | if ( xcverb >= ODEBUG ) { 559 | fprintf(stderr, "xclib: debug: Sending chunk of " 560 | " %d bytes\n", (int) chunk_len); 561 | } 562 | XChangeProperty(dpy, 563 | *win, 564 | *pty, 565 | target, 566 | 8, PropModeReplace, &txt[*pos], 567 | (int) chunk_len); 568 | } 569 | else { 570 | /* make an empty property to show we've 571 | * finished the transfer 572 | */ 573 | if ( xcverb >= ODEBUG ) { 574 | fprintf(stderr, "xclib: debug: Signalling end of INCR\n"); 575 | } 576 | XChangeProperty(dpy, *win, *pty, target, 8, PropModeReplace, 0, 0); 577 | } 578 | XFlush(dpy); 579 | 580 | /* all data has been sent, break out of the loop */ 581 | if (!chunk_len) { 582 | if (xcverb >= ODEBUG) { 583 | fprintf(stderr, "xclib: debug: Finished INCR transfer.\n"); 584 | } 585 | *context = XCLIB_XCIN_NONE; 586 | } 587 | 588 | *pos += *chunk_size; 589 | 590 | /* if chunk_len == 0, we just finished the transfer, 591 | * return 1 592 | */ 593 | if (chunk_len > 0) 594 | return (0); 595 | else 596 | return (1); 597 | break; 598 | } 599 | return (0); 600 | } 601 | 602 | 603 | /* xcfetchname(): a utility for finding the name of a given X window. 604 | * (Like XFetchName but recursively walks up tree of parent windows.) 605 | * Sets namep to point to the string of the name (must be freed with XFree). 606 | * Returns 0 if it works. Not 0, otherwise. 607 | * [See also, xcnamestr() wrapper below.] 608 | */ 609 | int 610 | xcfetchname(Display *display, Window w, char **namep) { 611 | *namep = NULL; 612 | if (w == None) 613 | return 1; /* No window, no name. */ 614 | 615 | XFetchName(display, w, namep); 616 | if (*namep) 617 | return 0; /* Hurrah! It worked on the first try. */ 618 | 619 | /* Otherwise, recursively try the parent windows */ 620 | Window p = w; 621 | Window dummy, *dummyp; 622 | unsigned int n; 623 | while (!*namep && p != None) { 624 | if (!XQueryTree(display, p, &dummy, &p, &dummyp, &n)) 625 | break; 626 | if (p != None) { 627 | XFetchName(display, p, namep); 628 | } 629 | } 630 | return (*namep == NULL); 631 | } 632 | 633 | 634 | /* A convenience wrapper for xcfetchname() that returns a string so it can be 635 | * used within printf calls with no need to later XFree anything. 636 | * It also smoothes over problems by returning the ID number if no name exists. 637 | * 638 | * Given a Window ID number, e.g., 0xfa1afe1, return 639 | * either the window name followed by the ID in parens, IFF it can be found, 640 | * otherwise, the string "window id 0xfa1afe1". 641 | * 642 | * Example output: "'Falafel' (0xfa1afe1)" 643 | * Example output: "window id 0xfa1afe1" 644 | * 645 | * String is statically allocated and is updated at each call. 646 | */ 647 | char xcname[4096]; 648 | char * 649 | xcnamestr(Display *display, Window w) { 650 | char *window_name; 651 | xcfetchname(display, w, &window_name); 652 | if (window_name && window_name[0]) { 653 | snprintf( xcname, sizeof(xcname)-1, "'%s' (0x%lx)", window_name, w); 654 | } 655 | else { 656 | snprintf( xcname, sizeof(xcname)-1, "window id 0x%lx", w ); 657 | } 658 | if (window_name) 659 | XFree(window_name); 660 | 661 | xcname[sizeof(xcname) - 1] = '\0'; /* Ensure NULL termination */ 662 | return xcname; 663 | } 664 | 665 | 666 | /* Xlib Error handler that saves last error event */ 667 | /* Usage: XSetErrorHandler(xchandler); */ 668 | int xcerrflag = False; 669 | XErrorEvent xcerrevt; 670 | int xchandler(Display *dpy, XErrorEvent *evt) { 671 | xcerrflag = True; 672 | xcerrevt = *evt; 673 | 674 | int len=255; 675 | char buf[len+1]; 676 | XGetErrorText(dpy, evt->error_code, buf, len); 677 | if (xcverb >= OVERBOSE) { 678 | fprintf(stderr, "\tXErrorHandler: XError (type %d): %s\n", 679 | evt->type, buf); 680 | } 681 | if (xcverb >= ODEBUG) { 682 | fprintf(stderr, 683 | "\t\tEvent Type: %d\n" 684 | "\t\tResource ID: 0x%lx\n" 685 | "\t\tSerial Num: %lu\n" 686 | "\t\tError code: %u\n" 687 | "\t\tRequest op code: %u major, %u minor\n", 688 | evt->type, 689 | evt->resourceid, 690 | evt->serial, 691 | evt->error_code, 692 | evt->request_code, 693 | evt->minor_code); 694 | } 695 | 696 | return 0; 697 | } 698 | -------------------------------------------------------------------------------- /xclib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * xclib.h - header file for functions in xclib.c 5 | * Copyright (C) 2001 Kim Saunders 6 | * Copyright (C) 2007-2008 Peter Åstrand 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #include 23 | 24 | /* global verbosity output level */ 25 | extern int xcverb; 26 | 27 | /* global error flags from xchandler() */ 28 | extern int xcerrflag; 29 | extern XErrorEvent xcerrevt; 30 | 31 | /* output level constants for xcverb */ 32 | #define OSILENT 0 33 | #define OQUIET 1 34 | #define OVERBOSE 2 35 | #define ODEBUG 9 36 | 37 | /* xcout() contexts */ 38 | #define XCLIB_XCOUT_NONE 0 /* no context */ 39 | #define XCLIB_XCOUT_SENTCONVSEL 1 /* sent a request */ 40 | #define XCLIB_XCOUT_INCR 2 /* in an incr loop */ 41 | #define XCLIB_XCOUT_BAD_TARGET 3 /* given target failed */ 42 | 43 | /* xcin() contexts */ 44 | #define XCLIB_XCIN_NONE 0 45 | #define XCLIB_XCIN_SELREQ 1 46 | #define XCLIB_XCIN_INCR 2 47 | 48 | /* functions in xclib.c */ 49 | extern int xcout( 50 | Display*, 51 | Window, 52 | XEvent, 53 | Atom, 54 | Atom, 55 | Atom*, 56 | unsigned char**, 57 | unsigned long*, 58 | unsigned int* 59 | ); 60 | extern int xcin( 61 | Display*, 62 | Window*, 63 | XEvent, 64 | Atom*, 65 | Atom, 66 | unsigned char*, 67 | unsigned long, 68 | unsigned long*, 69 | char*, 70 | unsigned int*, 71 | long* 72 | ); 73 | extern void *xcmalloc(size_t); 74 | extern void *xcrealloc(void*, size_t); 75 | extern void *xcstrdup(const char *); 76 | extern void xcmemcheck(void*); 77 | extern int xcfetchname(Display *, Window, char **); 78 | extern char *xcnamestr(Display *, Window); 79 | 80 | 81 | /* volatile prevents compiler from causing dead-store elimination with optimization enabled */ 82 | typedef void *(*memset_t)(void *, int, size_t); 83 | static volatile memset_t memset_func = memset; 84 | void xcmemzero(void *ptr, size_t len); 85 | int xchandler(Display *, XErrorEvent *); 86 | 87 | /* Table of event names from event numbers */ 88 | extern const char *evtstr[LASTEvent]; 89 | -------------------------------------------------------------------------------- /xclip-copyfile: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | if [ "x$1" = "x" ]; then 4 | echo "Usage: [options] $0 file..." >&2 5 | echo "-p Copy path information; preserve tree structure" 6 | exit 1 7 | fi 8 | archive=`mktemp` || exit 1 9 | trap 'rm -f "${archive}"' 1 2 3 15 10 | if [ "x$1" = "x-p" ]; then 11 | tar cf "${archive}" "$@" 12 | else 13 | flags="cf" 14 | for file in "$@"; do 15 | filedir=`dirname "${file}"` 16 | filename=`basename "${file}"` 17 | tar "${flags}" "${archive}" -C "${filedir}" "${filename}" 18 | flags="rf" 19 | done 20 | fi 21 | gzip -c "${archive}" | xclip -selection secondary -loops 1 -i 22 | rm "${archive}" 23 | -------------------------------------------------------------------------------- /xclip-copyfile.1: -------------------------------------------------------------------------------- 1 | .\"· 2 | .\" 3 | .\" xclip-copyfile.1 4 | .\" Copyright (C) 2009 Maximilian Gass 5 | .\" 6 | .\" This program is free software; you can redistribute it and/or modify 7 | .\" it under the terms of the GNU General Public License as published by 8 | .\" the Free Software Foundation; either version 2 of the License, or 9 | .\" (at your option) any later version. 10 | .\" 11 | .\" This program 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 14 | .\" GNU General Public License for more details. 15 | .\" You should have received a copy of the GNU General Public License 16 | .\" along with this program; if not, write to the Free Software 17 | .\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | .\" 19 | .TH XCLIP-COPYFILE 1 20 | .SH NAME 21 | xclip\-copyfile, xclip\-cutfile, xclip\-pastefile - copy and move files via the X clipboard 22 | .SH SYNOPSIS 23 | .B xclip\-copyfile 24 | [\-p] FILES... 25 | 26 | .B xclip\-cutfile 27 | [\-p] FILES... 28 | 29 | .B xclip\-pastefile 30 | .SH DESCRIPTION 31 | .B xclip\-copyfile 32 | copies files into the X clipboard, recursing into directories. 33 | 34 | .B xclip\-cutfile 35 | copies the files, but also deletes them afterwards. 36 | .TP 37 | \fB\-p\fR 38 | preserve path formation 39 | 40 | .PP 41 | .B xclip\-pastefile 42 | pastes the files out of the clipboard 43 | .SH EXAMPLES 44 | 45 | .B Copying a file to a remote host 46 | 47 | .nf 48 | [maggie.lkpg.cendio.se ~]$ echo "A file created on ${HOSTNAME}" > file1 49 | [maggie.lkpg.cendio.se ~]$ xclip-copyfile file1 50 | [sofie.homeip.net ~/doc]$ xclip-pastefile 51 | file1 52 | [sofie.homeip.net ~/doc]$ cat file1 53 | A file created on maggie.lkpg.cendio.se 54 | 55 | 56 | .B Copying an entire tree structure 57 | 58 | .nf 59 | [sofie.homeip.net ~]$ xclip-copyfile doc 60 | [maggie.lkpg.cendio.se ~/tmp]$ xclip-pastefile 61 | doc/ 62 | doc/letter-mom-april.txt 63 | doc/file1 64 | doc/letter-dad-march.txt 65 | 66 | 67 | .B Copying files with preserved path information 68 | 69 | .nf 70 | [maggie.lkpg.cendio.se ~]$ xclip-copyfile \-p /etc/sysconfig/grub 71 | tar: Removing leading `/' from member names 72 | [sofie.homeip.net ~/tmp]$ xclip-pastefile 73 | etc/sysconfig/grub 74 | [sofie.homeip.net ~/tmp]$ ls etc/sysconfig/grub 75 | etc/sysconfig/grub 76 | 77 | 78 | .B Moving files 79 | 80 | .nf 81 | [sofie.homeip.net ~]$ ls letter-brother-may.txt 82 | letter-brother-may.txt 83 | [sofie.homeip.net ~]$ xclip-cutfile letter-brother-may.txt 84 | [sofie.homeip.net ~]$ ls letter-brother-may.txt 85 | ls: cannot access letter-brother-may.txt: No such file or directory 86 | [sofie.homeip.net ~]$ cd doc 87 | [sofie.homeip.net ~/doc]$ xclip-pastefile 88 | letter-brother-may.txt 89 | 90 | .SH AUTHORS 91 | 92 | This manual page was written by Maximilian Gass for 93 | the Debian project. It may be used for everything else, of course. 94 | -------------------------------------------------------------------------------- /xclip-cutfile: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # FIXME: We shouldn't remove the files until xclip has successfully 3 | # transferred the data. With the current process model, this is not 4 | # very easy, though. 5 | set -e 6 | if [ "x$1" = "x" ]; then 7 | echo "Usage: [options] $0 file..." >&2 8 | echo "-p Copy path information; preserve tree structure" 9 | exit 1 10 | fi 11 | xclip-copyfile "$@" 12 | if [ "x$1" = "x-p" ]; then 13 | shift 14 | fi 15 | rm -- "$@" 16 | -------------------------------------------------------------------------------- /xclip-pastefile: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | if [ "x$1" != "x" ]; then 4 | echo "Usage: $0" >&2 5 | exit 1 6 | fi 7 | xclip -selection secondary -o | gunzip -c | tar xvf - 8 | -------------------------------------------------------------------------------- /xclip.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" 3 | .\" xclip.man - xclip manpage 4 | .\" Copyright (C) 2001 Kim Saunders 5 | .\" Copyright (C) 2007-2008 Peter Åstrand 6 | .\" 7 | .\" This program is free software; you can redistribute it and/or modify 8 | .\" it under the terms of the GNU General Public License as published by 9 | .\" the Free Software Foundation; either version 2 of the License, or 10 | .\" (at your option) any later version. 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 | .\" You should have received a copy of the GNU General Public License 17 | .\" along with this program; if not, write to the Free Software 18 | .\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | .\" 20 | .TH XCLIP 1 21 | .SH NAME 22 | xclip \- command line interface to X selections (clipboard) 23 | .SH SYNOPSIS 24 | .B xclip 25 | [OPTION] [FILE]... 26 | .SH DESCRIPTION 27 | Reads from standard in, or from one or more files, and makes the data available as an X selection for pasting into X applications. Prints current X selection to standard out. 28 | .TP 29 | \fB\-i\fR, \fB\-in\fR 30 | read text into X selection from standard input or files (default) 31 | .TP 32 | \fB\-o\fR, \fB\-out\fR 33 | print the selection to standard out (generally for piping to a file or program) 34 | .TP 35 | \fB\-f\fR, \fB\-filter\fR 36 | when xclip is invoked in the in mode with output level set to silent (the defaults), the filter option will cause xclip to print the text piped to standard in back to standard out unmodified 37 | .TP 38 | \fB\-r\fR, \fB\-rmlastnl\fR 39 | when the last character of the selection is a newline character, remove it. Newline characters that are not the last character in the selection are not affected. If the selection does not end with a newline character, this option has no effect. This option is useful for copying one-line output of programs like \fBpwd\fR to the clipboard to paste it again into the command prompt without executing the line immediately due to the newline character \fBpwd\fR appends. 40 | .TP 41 | \fB\-l\fR \fIn\fR, \fB\-loops\fR \fIn\fR 42 | number of X selection requests (pastes into X applications) to wait for before exiting, with a value of 0 (default) causing xclip to wait for an unlimited number of requests until another application (possibly another invocation of xclip) takes ownership of the selection. 43 | .TP 44 | \fB\-t\fR \fIt\fR, \fB\-target\fR \fIt\fR 45 | specify a particular data format using the given target atom. With \fB\-o\fR the 46 | special target atom name "TARGETS" can be used to get a list of valid target 47 | atoms for this selection. The default target is "STRING". For more information 48 | about target atoms refer to ICCCM section 2.6.2 49 | .TP 50 | \fB\-alt-text\fR \fIt\fR 51 | specify an alternative text to put into the target atom "STRING". Some applications refuse to paste text unless this atom is provided in addition to other text targets such as "text/html". 52 | .TP 53 | \fB\-d\fR, \fB\-display\fR 54 | X display to use (e.g. "localhost:0"), xclip defaults to the value in $\fBDISPLAY\fR if this option is omitted 55 | .TP 56 | \fB\-h\fR, \fB\-help\fR 57 | show quick summary of options 58 | .TP 59 | \fB\-selection\fR 60 | specify which X selection to use, options are "primary" to use XA_PRIMARY (default), "secondary" for XA_SECONDARY or "clipboard" for XA_CLIPBOARD 61 | .TP 62 | \fB\-version\fR 63 | show version information 64 | .TP 65 | \fB\-silent\fR 66 | fork into the background to wait for requests, no informational output, errors only (default) 67 | .TP 68 | \fB\-quiet\fR 69 | show informational messages on the terminal and run in the foreground 70 | .TP 71 | \fB\-verbose\fR 72 | provide a running commentary of what xclip is doing 73 | .TP 74 | \fB\-noutf8\fR 75 | operate in legacy (i.e. non UTF-8) mode for backwards compatibility 76 | (Use this option only when really necessary, as the old behavior was broken) 77 | .TP 78 | \fB\-sensitive\fR 79 | clear sensitive data from selection buffer after being pasted once. 80 | This is currently implemented as -wait 50. See \fBNOTES\fR 81 | .TP 82 | \fB\-wait\fR \fIn\fR 83 | after the first paste, wait for \fIn\fR milliseconds. If a subsequent paste 84 | request arrives before the timer expires, reset the timer. Once the timer 85 | expires, the selection buffer is cleared so the data cannot be pasted again. 86 | 87 | .PP 88 | xclip reads text from standard in or files and makes it available to other X applications for pasting as an X selection (traditionally with the middle mouse button). It reads from all files specified, or from standard in if no files are specified. xclip can also print the contents of a selection to standard out with the 89 | .B 90 | \-o 91 | option. 92 | 93 | xclip was designed to allow tighter integration of X applications and command line programs. The default action is to silently wait in the background for X selection requests (pastes) until another X application places data in the clipboard, at which point xclip exits silently. You can use the \fB\-verbose\fR option to see if and when xclip actually receives selection requests from other X applications. 94 | 95 | Options can be abbreviated as long as they remain unambiguous. For example, it is possible to use \fB\-d\fR or \fB\-disp\fR instead of \fB\-display\fR. However, \fB\-v\fR couldn't be used because it is ambiguous (it could be short for \fB\-verbose\fR or \fB\-version\fR), so it would be interpreted as a filename. 96 | 97 | Note that only the first character of the selection specified with the \fB\-selection\fR option is important. This means that "p", "sec" and "clip" would have the same effect as using "primary", "secondary" or "clipboard" respectively. 98 | 99 | .SH EXAMPLES 100 | .PP 101 | I hate man pages without examples! 102 | 103 | .B 104 | uptime | xclip 105 | .PP 106 | Put your uptime in the X selection. Then middle click in an X application to paste. 107 | 108 | .B xclip -o > helloworld.c 109 | .PP 110 | Put the contents of the selection into a file. 111 | 112 | .B xclip -t text/html index.html 113 | .PP 114 | Middle click in an X application supporting HTML to paste the contents of the given file as HTML. 115 | 116 | .B xclip -loops 10 -verbose /etc/motd 117 | .PP 118 | Exit after /etc/motd (message of the day) has been pasted 10 times. Show how many selection requests (pastes) have been processed. 119 | 120 | .SH NOTES 121 | 122 | Using the \fB\-sensitive\fR option will clear the selection buffer of the 123 | sensitive information 50 milliseconds after it has been pasted, effectively only 124 | allowing the selection to be pasted once. In some instances this may be too low 125 | and will prevent pasting. If this is the case, or if the user needs to be able 126 | to paste more than once for some other reason, they may use \fB\-wait\fR \fIn\fR 127 | instead. \fB\-wait\fR is the same as \fB\-sensitive\fR, except it allows one to 128 | adjust the time to wait before clearing the selection to be \fIn\fR 129 | milliseconds. 130 | .PP 131 | Ideally, \fB\-sensitive\fR would allow exactly one paste and not need a timeout, 132 | but due to subtleties in the way the X clipboard protocol works, doing so is not 133 | as simple as it may seem. 134 | 135 | .SH ENVIRONMENT 136 | .TP 137 | .SM 138 | \fBDISPLAY\fR 139 | X display to use if none is specified with the 140 | .B 141 | \-display 142 | option. 143 | 144 | .SH REPORTING BUGS 145 | Please report any bugs, problems, queries, experiences, etc. directly to the author. 146 | 147 | .SH AUTHORS 148 | Kim Saunders 149 | Peter Åstrand 150 | .br 151 | -------------------------------------------------------------------------------- /xclip.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * xclip.c - command line interface to X server selections 5 | * Copyright (C) 2001 Kim Saunders 6 | * Copyright (C) 2007-2008 Peter Åstrand 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #ifdef HAVE_ICONV 27 | #include 28 | #include 29 | #endif 30 | #include 31 | #include 32 | #include 33 | #include "xcdef.h" 34 | #include "xcprint.h" 35 | #include "xclib.h" 36 | 37 | /* command line option table for XrmParseCommand() */ 38 | XrmOptionDescRec opt_tab[18]; 39 | int opt_tab_size; 40 | 41 | /* Options that get set on the command line */ 42 | int sloop = 0; /* number of loops */ 43 | char *sdisp = NULL; /* X display to connect to */ 44 | Atom sseln = XA_PRIMARY; /* X selection to work with */ 45 | Atom target = XA_STRING; 46 | char *alt_text = NULL; /* Text to put into textual targets */ 47 | int wait = 0; /* wait: stop xclip after wait msec 48 | after last 'paste event', start counting 49 | after first 'paste event' */ 50 | 51 | /* Flags for command line options */ 52 | static int fdiri = T; /* direction is in */ 53 | static int ffilt = F; /* filter mode */ 54 | static int frmnl = F; /* remove (single) newline character at the very end if present */ 55 | static int fsecm = F; /* zero out selection buffer before exiting */ 56 | 57 | Display *dpy; /* connection to X11 display */ 58 | XrmDatabase opt_db = NULL; /* database for options */ 59 | 60 | char **fil_names; /* names of files to read */ 61 | int fil_number = 0; /* number of files to read */ 62 | int fil_current = 0; 63 | FILE *fil_handle = NULL; 64 | 65 | /* variables to hold Xrm database record and type */ 66 | XrmValue rec_val; 67 | char *rec_typ; 68 | 69 | int tempi = 0; 70 | 71 | struct requestor 72 | { 73 | Window cwin; 74 | Atom pty; 75 | unsigned int context; 76 | unsigned long sel_pos; 77 | int finished; 78 | long chunk_size; 79 | struct requestor *next; 80 | }; 81 | 82 | static struct requestor *requestors; 83 | 84 | static struct requestor *get_requestor(Window win) 85 | { 86 | struct requestor *requestor; 87 | 88 | if (requestors) { 89 | for (requestor = requestors; requestor != NULL; requestor = requestor->next) { 90 | if (requestor->cwin == win) { 91 | if (xcverb >= OVERBOSE) { 92 | fprintf(stderr, 93 | " = Reusing requestor for %s\n", 94 | xcnamestr(dpy, win) ); 95 | } 96 | 97 | return requestor; 98 | } 99 | } 100 | } 101 | 102 | if (xcverb >= OVERBOSE) { 103 | fprintf(stderr, " + Creating new requestor for %s\n", 104 | xcnamestr(dpy, win) ); 105 | } 106 | 107 | requestor = (struct requestor *)calloc(1, sizeof(struct requestor)); 108 | if (!requestor) { 109 | errmalloc(); 110 | } else { 111 | requestor->context = XCLIB_XCIN_NONE; 112 | } 113 | 114 | if (!requestors) { 115 | requestors = requestor; 116 | } else { 117 | requestor->next = requestors; 118 | requestors = requestor; 119 | } 120 | 121 | return requestor; 122 | } 123 | 124 | static void del_requestor(struct requestor *requestor) 125 | { 126 | struct requestor *reqitr; 127 | 128 | if (!requestor) { 129 | return; 130 | } 131 | 132 | if (xcverb >= OVERBOSE) { 133 | fprintf(stderr, 134 | " - Deleting requestor for %s\n", 135 | xcnamestr(dpy, requestor->cwin) ); 136 | } 137 | 138 | if (requestors == requestor) { 139 | requestors = requestors->next; 140 | } else { 141 | for (reqitr = requestors; reqitr != NULL; reqitr = reqitr->next) { 142 | if (reqitr->next == requestor) { 143 | reqitr->next = reqitr->next->next; 144 | break; 145 | } 146 | } 147 | } 148 | 149 | free(requestor); 150 | } 151 | 152 | int clean_requestors() { 153 | /* Remove any requestors for which the X window has disappeared */ 154 | if (xcverb >= ODEBUG) { 155 | fprintf(stderr, "xclip: debug: checking for requestors whose window has closed\n"); 156 | } 157 | struct requestor *r = requestors; 158 | Window win; 159 | XWindowAttributes dummy; 160 | while (r) { 161 | win = r->cwin; 162 | 163 | // check if window exists by seeing if XGetWindowAttributes works. 164 | // note: this triggers X's BadWindow error and runs xchandler(). 165 | if ( !XGetWindowAttributes(dpy, win, &dummy) ) { 166 | if (xcverb >= OVERBOSE) { 167 | fprintf(stderr, " ! Found obsolete requestor 0x%lx\n", win); 168 | } 169 | del_requestor(r); 170 | } 171 | r = r -> next; 172 | } 173 | return 0; 174 | } 175 | 176 | /* Use XrmParseCommand to parse command line options to option variable */ 177 | static void 178 | doOptMain(int argc, char *argv[]) 179 | { 180 | /* Initialise resource manager and parse options into database */ 181 | XrmInitialize(); 182 | 183 | if (argc > 1 && !strcmp(argv[1], "--help")) 184 | { 185 | prhelp(argv[0]); 186 | exit(0); 187 | } 188 | 189 | XrmParseCommand(&opt_db, opt_tab, opt_tab_size, PACKAGE_NAME, &argc, 190 | argv); 191 | 192 | /* set output level */ 193 | if (XrmGetResource(opt_db, "xclip.olevel", "Xclip.Olevel", &rec_typ, &rec_val) 194 | ) { 195 | /* set verbose flag according to option */ 196 | switch (rec_val.addr[0]) { 197 | case 'S': 198 | xcverb = OSILENT; break; 199 | case 'Q': 200 | xcverb = OQUIET; break; 201 | case 'V': 202 | xcverb = OVERBOSE; break; 203 | case 'D': 204 | xcverb = ODEBUG; break; 205 | } 206 | } 207 | if (xcverb == ODEBUG) 208 | fprintf(stderr, "xclip: debug: Debugging enabled.\n"); 209 | 210 | /* set direction flag (in or out) */ 211 | if (XrmGetResource(opt_db, "xclip.direction", "Xclip.Direction", &rec_typ, &rec_val) 212 | ) { 213 | if (strcmp(rec_val.addr, "I") == 0) 214 | fdiri = T; 215 | if (strcmp(rec_val.addr, "O") == 0) 216 | fdiri = F; 217 | } 218 | 219 | /* set filter mode */ 220 | if (XrmGetResource(opt_db, "xclip.filter", "Xclip.Filter", &rec_typ, &rec_val) 221 | ) { 222 | /* filter mode only allowed in silent mode */ 223 | if (xcverb == OSILENT) 224 | ffilt = T; 225 | } 226 | 227 | /* set "remove last newline character if present" mode */ 228 | if (XrmGetResource(opt_db, "xclip.rmlastnl", "Xclip.RmLastNl", &rec_typ, &rec_val) 229 | ) { 230 | frmnl = T; 231 | } 232 | 233 | /* check for -help and -version */ 234 | if (XrmGetResource(opt_db, "xclip.print", "Xclip.Print", &rec_typ, &rec_val) 235 | ) { 236 | if (strcmp(rec_val.addr, "H") == 0) 237 | prhelp(argv[0]); 238 | if (strcmp(rec_val.addr, "V") == 0) 239 | prversion(); 240 | } 241 | 242 | /* check for -display */ 243 | if (XrmGetResource(opt_db, "xclip.display", "Xclip.Display", &rec_typ, &rec_val) 244 | ) { 245 | sdisp = rec_val.addr; 246 | if (xcverb >= OVERBOSE) /* print in verbose or debug mode only */ 247 | fprintf(stderr, "Display: %s\n", sdisp); 248 | } 249 | 250 | /* check for -loops */ 251 | if (XrmGetResource(opt_db, "xclip.loops", "Xclip.Loops", &rec_typ, &rec_val) 252 | ) { 253 | sloop = atoi(rec_val.addr); 254 | if (xcverb >= OVERBOSE) 255 | fprintf(stderr, "Loops: %i\n", sloop); 256 | } 257 | 258 | /* check for -sensitive */ 259 | if (XrmGetResource(opt_db, "xclip.sensitive", "Xclip.Sensitive", &rec_typ, &rec_val) 260 | ) { 261 | wait = 50; 262 | fsecm = T; 263 | if (xcverb >= OVERBOSE) { 264 | fprintf(stderr, "Sensitive Mode Implies -wait 1\n"); 265 | fprintf(stderr, "Sensitive Buffers Will Be Zeroed At Exit\n"); 266 | } 267 | } 268 | 269 | if (XrmGetResource(opt_db, "xclip.wait", "Xclip.Wait", &rec_typ, &rec_val) 270 | ) { 271 | wait = atoi(rec_val.addr); 272 | if (xcverb >= OVERBOSE) 273 | fprintf(stderr, "wait: %i msec\n", wait); 274 | } 275 | 276 | /* check for -alt-text */ 277 | if (XrmGetResource(opt_db, "xclip.alt-text", "Xclip.Alt-text", &rec_typ, &rec_val) 278 | ) { 279 | alt_text = rec_val.addr; 280 | if (xcverb >= OVERBOSE) /* print in verbose or debug mode only */ 281 | fprintf(stderr, "Alternative text: %s\n", alt_text); 282 | } 283 | 284 | /* Read remaining options (filenames) */ 285 | while ((fil_number + 1) < argc) { 286 | if (fil_number > 0) { 287 | fil_names = xcrealloc(fil_names, (fil_number + 1) * sizeof(char *) 288 | ); 289 | } 290 | else { 291 | fil_names = xcmalloc(sizeof(char *)); 292 | } 293 | fil_names[fil_number] = argv[fil_number + 1]; 294 | fil_number++; 295 | } 296 | 297 | /* If filenames were given on the command line, 298 | * default to reading input (unless -o was used). 299 | */ 300 | if (fil_number > 0) { 301 | if (!XrmGetResource(opt_db, "xclip.direction", "Xclip.Direction", &rec_typ, &rec_val)) { 302 | fdiri = T; /* Direction is input */ 303 | } 304 | } 305 | } 306 | 307 | /* process selection command line option */ 308 | static void 309 | doOptSel(void) 310 | { 311 | /* set selection to work with */ 312 | if (XrmGetResource(opt_db, "xclip.selection", "Xclip.Selection", &rec_typ, &rec_val) 313 | ) { 314 | switch (tolower(rec_val.addr[0])) { 315 | case 'p': 316 | sseln = XA_PRIMARY; 317 | break; 318 | case 's': 319 | sseln = XA_SECONDARY; 320 | break; 321 | case 'c': 322 | sseln = XA_CLIPBOARD(dpy); 323 | break; 324 | case 'b': 325 | sseln = XA_STRING; 326 | break; 327 | } 328 | 329 | if (xcverb >= OVERBOSE) { 330 | fprintf(stderr, "Using selection: "); 331 | 332 | if (sseln == XA_PRIMARY) 333 | fprintf(stderr, "XA_PRIMARY"); 334 | if (sseln == XA_SECONDARY) 335 | fprintf(stderr, "XA_SECONDARY"); 336 | if (sseln == XA_CLIPBOARD(dpy)) 337 | fprintf(stderr, "XA_CLIPBOARD"); 338 | if (sseln == XA_STRING) 339 | fprintf(stderr, "XA_STRING"); 340 | 341 | fprintf(stderr, "\n"); 342 | } 343 | } 344 | } 345 | 346 | /* process noutf8 and target command line options */ 347 | static void 348 | doOptTarget(void) 349 | { 350 | /* check for -noutf8 */ 351 | if (XrmGetResource(opt_db, "xclip.noutf8", "Xclip.noutf8", &rec_typ, &rec_val) 352 | ) { 353 | if (xcverb >= OVERBOSE) /* print in verbose or debug mode only */ 354 | fprintf(stderr, "Using old UNICODE instead of UTF8.\n"); 355 | } 356 | else if (XrmGetResource(opt_db, "xclip.target", "Xclip.Target", &rec_typ, &rec_val) 357 | ) { 358 | target = XInternAtom(dpy, rec_val.addr, False); 359 | if (xcverb >= OVERBOSE) 360 | fprintf(stderr, "Using target: %s\n", rec_val.addr); 361 | } 362 | else { 363 | target = XA_UTF8_STRING(dpy); 364 | if (xcverb >= OVERBOSE) 365 | fprintf(stderr, "Using target: UTF8_STRING.\n"); 366 | } 367 | } 368 | 369 | static int 370 | doIn(Window win, const char *progname) 371 | { 372 | unsigned char *sel_buf = NULL; /* buffer for selection data */ 373 | unsigned long sel_len = 0; /* length of sel_buf */ 374 | unsigned long sel_all = 0; /* allocated size of sel_buf */ 375 | XEvent evt; /* X Event Structures */ 376 | int dloop = 0; /* done loops counter */ 377 | int x11_fd; /* fd on which XEvents appear */ 378 | fd_set in_fds; 379 | struct timeval tv; 380 | 381 | /* ConnectionNumber is a macro, it can't fail */ 382 | x11_fd = ConnectionNumber(dpy); 383 | 384 | 385 | /* in mode */ 386 | sel_all = 16; /* Reasonable ballpark figure */ 387 | sel_buf = xcmalloc(sel_all * sizeof(char)); 388 | 389 | /* Put chars into inc from stdin or files until we hit EOF */ 390 | do { 391 | if (fil_number == 0 || strcmp(fil_names[fil_current], "-") == 0) { 392 | /* read from stdin if no files specified */ 393 | fil_handle = stdin; 394 | } 395 | else { 396 | if ((fil_handle = fopen(fil_names[fil_current], "r")) == NULL) { 397 | err: 398 | errperror(3, progname, ": ", 399 | fil_number ? fil_names[fil_current] : "(stdin)"); 400 | return EXIT_FAILURE; 401 | } 402 | else { 403 | /* file opened successfully. 404 | */ 405 | if (xcverb >= ODEBUG) 406 | fprintf(stderr, "Reading %s...\n", fil_names[fil_current]); 407 | } 408 | } 409 | 410 | for (;;) { 411 | size_t rd = fread(sel_buf + sel_len, sizeof(char), sel_all - sel_len, fil_handle); 412 | if (rd != sel_all - sel_len) { 413 | if (feof(fil_handle)) { 414 | sel_len += rd; 415 | break; 416 | } 417 | if (errno == EINTR) 418 | clearerr(fil_handle); 419 | else 420 | goto err; 421 | } 422 | sel_len += rd; 423 | 424 | /* If sel_buf is full (used elems = 425 | * allocated elems) 426 | */ 427 | if (sel_len == sel_all) { 428 | /* double the number of 429 | * allocated elements 430 | */ 431 | sel_all *= 2; 432 | sel_buf = (unsigned char *) xcrealloc(sel_buf, sel_all * sizeof(char) ); 433 | if (xcverb >= ODEBUG) { 434 | fprintf(stderr, "xclip: debug: Increased buffersize to %ld\n", sel_all); 435 | } 436 | } 437 | } 438 | 439 | if (fil_handle && (fil_handle != stdin)) { 440 | fclose(fil_handle); 441 | fil_handle = NULL; 442 | } 443 | } while (++fil_current < fil_number); 444 | 445 | /* if there are no files being read from (i.e., input 446 | * is from stdin not files, and we are in filter mode, 447 | * spit all the input back out to stdout 448 | */ 449 | if ((fil_number == 0) && ffilt) { 450 | fwrite(sel_buf, sizeof(char), sel_len, stdout); 451 | fclose(stdout); 452 | } 453 | 454 | if (fil_names) { 455 | free(fil_names); 456 | fil_names = NULL; 457 | } 458 | 459 | /* remove the last newline character if necessary */ 460 | if (frmnl && sel_len && sel_buf[sel_len - 1] == '\n') { 461 | sel_len--; 462 | } 463 | 464 | /* Handle cut buffer if needed */ 465 | if (sseln == XA_STRING) { 466 | XStoreBuffer(dpy, (char *) sel_buf, (int) sel_len, 0); 467 | XSetSelectionOwner(dpy, sseln, None, CurrentTime); 468 | xcmemzero(sel_buf,sel_len); 469 | return EXIT_SUCCESS; 470 | } 471 | 472 | /* take control of the selection so that we receive 473 | * SelectionRequest events from other windows 474 | */ 475 | /* FIXME: Should not use CurrentTime, according to ICCCM section 2.1 */ 476 | XSetSelectionOwner(dpy, sseln, win, CurrentTime); 477 | 478 | /* Double-check SetSelectionOwner did not "merely appear to succeed". */ 479 | Window owner = XGetSelectionOwner(dpy, sseln); 480 | if (owner != win) { 481 | fprintf(stderr, "xclip: error: Failed to take ownership of selection.\n"); 482 | return EXIT_FAILURE; 483 | } 484 | 485 | /* fork into the background, exit parent process if we 486 | * are in silent mode 487 | */ 488 | if (xcverb == OSILENT) { 489 | pid_t pid; 490 | 491 | pid = fork(); 492 | /* exit the parent process; */ 493 | if (pid) { 494 | XSetSelectionOwner(dpy, sseln, None, CurrentTime); 495 | xcmemzero(sel_buf,sel_len); 496 | exit(EXIT_SUCCESS); 497 | } 498 | } 499 | 500 | /* print a message saying what we're waiting for */ 501 | if (xcverb > OSILENT) { 502 | if (sloop == 1) 503 | fprintf(stderr, "Waiting for one selection request.\n"); 504 | 505 | if (sloop < 1) 506 | fprintf(stderr, 507 | "Waiting for selection requests, Control-C to quit\n"); 508 | 509 | if (sloop > 1) 510 | fprintf(stderr, 511 | "Waiting for %i selection request%s, Control-C to quit\n", 512 | sloop, (sloop==1)?"":"s"); 513 | } 514 | 515 | /* Avoid making the current directory in use, in case it will need to be umounted */ 516 | if (chdir("/") == -1) { 517 | errperror(3, progname, ": ", "chdir to \"/\""); 518 | return EXIT_FAILURE; 519 | } 520 | 521 | /* Jump into the middle of two while loops */ 522 | goto start; 523 | 524 | /* loop and wait for the expected number of 525 | * SelectionRequest events 526 | */ 527 | while (dloop < sloop || sloop < 1) { 528 | if (xcverb >= ODEBUG) 529 | fprintf(stderr, "\n========\n"); 530 | 531 | /* print messages about what we're waiting for 532 | * if not in silent mode 533 | */ 534 | if (xcverb > OSILENT) { 535 | if (sloop > 1) 536 | fprintf(stderr, " Waiting for selection request %i of %i.\n", dloop + 1, sloop); 537 | 538 | if (sloop == 1) 539 | fprintf(stderr, " Waiting for a selection request.\n"); 540 | 541 | if (sloop < 1) 542 | fprintf(stderr, " Waiting for selection request number %i\n", dloop + 1); 543 | } 544 | 545 | /* wait for a SelectionRequest (paste) event */ 546 | while (1) { 547 | struct requestor *requestor; 548 | Window requestor_id; 549 | int finished; 550 | 551 | if (!XPending(dpy) && wait > 0) { 552 | tv.tv_sec = wait/1000; 553 | tv.tv_usec = (wait%1000)*1000; 554 | 555 | /* build fd_set */ 556 | FD_ZERO(&in_fds); 557 | FD_SET(x11_fd, &in_fds); 558 | if (!select(x11_fd + 1, &in_fds, 0, 0, &tv)) { 559 | XSetSelectionOwner(dpy, sseln, None, CurrentTime); 560 | xcmemzero(sel_buf,sel_len); 561 | return EXIT_SUCCESS; 562 | } 563 | } 564 | 565 | start: 566 | 567 | XNextEvent(dpy, &evt); 568 | 569 | if (xcverb >= ODEBUG) 570 | fprintf(stderr, "\n"); 571 | 572 | if (xcverb >= ODEBUG) { 573 | fprintf(stderr, "xclip: debug: Received %s event\n", 574 | evtstr[evt.type]); 575 | } 576 | 577 | switch (evt.type) { 578 | case SelectionRequest: 579 | requestor_id = evt.xselectionrequest.requestor; 580 | requestor = get_requestor(requestor_id); 581 | /* FIXME: ICCCM 2.2: check evt.time and refuse requests from 582 | * outside the period of time we have owned the selection. */ 583 | break; 584 | case PropertyNotify: 585 | requestor_id = evt.xproperty.window; 586 | requestor = get_requestor(requestor_id); 587 | break; 588 | case SelectionClear: 589 | if (xcverb >= OVERBOSE) { 590 | fprintf(stderr, "Lost selection ownership. "); 591 | requestor_id = XGetSelectionOwner(dpy, sseln); 592 | if (requestor_id == None) 593 | fprintf(stderr, "(Some other client cleared the selection).\n"); 594 | else 595 | fprintf(stderr, "(%s did a copy).\n", xcnamestr(dpy, requestor_id) ); 596 | } 597 | /* If the client loses ownership(SelectionClear event) 598 | * while it has a transfer in progress, it must continue to 599 | * service the ongoing transfer until it is completed. 600 | * See ICCCM section 2.2. 601 | */ 602 | /* Set dloop to force exit after all transfers finish. */ 603 | dloop = sloop; 604 | /* remove requestors for dead windows */ 605 | clean_requestors(); 606 | /* if there are no more in-progress transfers, force exit */ 607 | if (!requestors) { 608 | if (xcverb >= OVERBOSE) { 609 | fprintf(stderr, "Exiting.\n"); 610 | } 611 | return EXIT_SUCCESS; 612 | } 613 | else { 614 | if (xcverb >= OVERBOSE) { 615 | struct requestor *r = requestors; 616 | int i=0; 617 | fprintf(stderr, "Requestors: "); 618 | while (r) { 619 | fprintf(stderr, "0x%lx\t", r->cwin); 620 | r = r->next; 621 | i++; 622 | } 623 | fprintf(stderr, "\n"); 624 | fprintf(stderr, 625 | "Still transferring data to %d requestor%s.\n", 626 | i, (i==1)?"":"s"); 627 | } 628 | } 629 | continue; /* Wait for INCR PropertyNotify events */ 630 | default: 631 | /* Ignore all other event types */ 632 | if (xcverb >= ODEBUG) { 633 | fprintf(stderr, 634 | "xclip: debug: Ignoring X event type %d (%s)\n", 635 | evt.type, evtstr[evt.type]); 636 | } 637 | continue; 638 | } 639 | 640 | if (xcverb >= ODEBUG) { 641 | fprintf(stderr, "xclip: debug: event was sent by %s\n", 642 | xcnamestr(dpy, requestor_id) ); 643 | requestor_id=0; 644 | } 645 | 646 | finished = xcin(dpy, &(requestor->cwin), evt, &(requestor->pty), 647 | target, sel_buf, sel_len, &(requestor->sel_pos), 648 | alt_text, &(requestor->context), 649 | &(requestor->chunk_size)); 650 | 651 | if (finished) { 652 | del_requestor(requestor); 653 | break; 654 | } 655 | if (requestor->cwin == 0) { 656 | del_requestor(requestor); 657 | break; 658 | } 659 | } 660 | 661 | dloop++; /* increment loop counter */ 662 | } 663 | 664 | XSetSelectionOwner(dpy, sseln, None, CurrentTime); 665 | xcmemzero(sel_buf,sel_len); 666 | 667 | return EXIT_SUCCESS; 668 | } 669 | 670 | static void 671 | printSelBuf(FILE * fout, Atom sel_type, unsigned char *sel_buf, size_t sel_len) 672 | { 673 | #ifdef HAVE_ICONV 674 | Atom html = XInternAtom(dpy, "text/html", True); 675 | #endif 676 | 677 | if (xcverb >= OVERBOSE) { /* print in verbose mode only */ 678 | char *atom_name = XGetAtomName(dpy, sel_type); 679 | fprintf(stderr, "Type is %s.\n", atom_name); 680 | XFree(atom_name); 681 | } 682 | 683 | if (sel_type == XA_INTEGER) { 684 | /* if the buffer contains integers, print them */ 685 | long *long_buf = (long *) sel_buf; 686 | size_t long_len = sel_len / sizeof(long); 687 | while (long_len--) 688 | fprintf(fout, "%ld\n", *long_buf++); 689 | return; 690 | } 691 | 692 | if (sel_type == XA_ATOM) { 693 | /* if the buffer contains atoms, print their names */ 694 | Atom *atom_buf = (Atom *) sel_buf; 695 | size_t atom_len = sel_len / sizeof(Atom); 696 | while (atom_len--) { 697 | char *atom_name = XGetAtomName(dpy, *atom_buf++); 698 | fprintf(fout, "%s\n", atom_name); 699 | XFree(atom_name); 700 | } 701 | return; 702 | } 703 | 704 | #ifdef HAVE_ICONV 705 | if (html != None && sel_type == html) { 706 | /* if the buffer contains UCS-2 (UTF-16), convert to 707 | * UTF-8. Mozilla-based browsers do this for the 708 | * text/html target. 709 | */ 710 | iconv_t cd; 711 | char *sel_charset = NULL; 712 | if (sel_buf[0] == 0xFF && sel_buf[1] == 0xFE) 713 | sel_charset = "UTF-16LE"; 714 | else if (sel_buf[0] == 0xFE && sel_buf[1] == 0xFF) 715 | sel_charset = "UTF-16BE"; 716 | 717 | if (sel_charset != NULL && (cd = iconv_open("UTF-8", sel_charset)) != (iconv_t) - 1) { 718 | char *out_buf_start = malloc(sel_len), *in_buf = (char *) sel_buf + 2, 719 | *out_buf = out_buf_start; 720 | size_t in_bytesleft = sel_len - 2, out_bytesleft = sel_len; 721 | 722 | while (iconv(cd, &in_buf, &in_bytesleft, &out_buf, &out_bytesleft) == -1 723 | && errno == E2BIG) { 724 | fwrite(out_buf_start, sizeof(char), sel_len - out_bytesleft, fout); 725 | out_buf = out_buf_start; 726 | out_bytesleft = sel_len; 727 | } 728 | if (out_buf != out_buf_start) 729 | fwrite(out_buf_start, sizeof(char), sel_len - out_bytesleft, fout); 730 | 731 | free(out_buf_start); 732 | iconv_close(cd); 733 | return; 734 | } 735 | } 736 | #endif 737 | 738 | /* otherwise, print the raw buffer out */ 739 | fwrite(sel_buf, sizeof(char), sel_len, fout); 740 | } 741 | 742 | static int 743 | doOut(Window win) 744 | { 745 | Atom sel_type = None; 746 | unsigned char *sel_buf = NULL; /* buffer for selection data */ 747 | unsigned long sel_len = 0; /* length of sel_buf */ 748 | XEvent evt; /* X Event Structures */ 749 | unsigned int context = XCLIB_XCOUT_NONE; 750 | 751 | if (sseln == XA_STRING) 752 | sel_buf = (unsigned char *) XFetchBuffer(dpy, (int *) &sel_len, 0); 753 | else { 754 | while (1) { 755 | /* only get an event if xcout() is doing something */ 756 | if (context != XCLIB_XCOUT_NONE) 757 | XNextEvent(dpy, &evt); 758 | 759 | /* fetch the selection, or part of it */ 760 | xcout(dpy, win, evt, sseln, target, &sel_type, &sel_buf, &sel_len, &context); 761 | 762 | if (context == XCLIB_XCOUT_BAD_TARGET) { 763 | if (target == XA_UTF8_STRING(dpy)) { 764 | /* fallback is needed. set XA_STRING to target and restart the loop. */ 765 | context = XCLIB_XCOUT_NONE; 766 | target = XA_STRING; 767 | continue; 768 | } 769 | else { 770 | /* no fallback available, exit with failure */ 771 | if (fsecm) { 772 | /* If user requested -sensitive, then prevent further pastes (even though we failed to paste) */ 773 | XSetSelectionOwner(dpy, sseln, None, CurrentTime); 774 | /* Clear memory buffer */ 775 | xcmemzero(sel_buf,sel_len); 776 | } 777 | free(sel_buf); 778 | errconvsel(dpy, target, sseln); 779 | // errconvsel does not return but exits with EXIT_FAILURE 780 | } 781 | } 782 | 783 | /* only continue if xcout() is doing something */ 784 | if (context == XCLIB_XCOUT_NONE) 785 | break; 786 | } 787 | } 788 | 789 | /* remove the last newline character if necessary */ 790 | if (frmnl && sel_len && sel_buf[sel_len - 1] == '\n') { 791 | sel_len--; 792 | } 793 | 794 | if (sel_len) { 795 | /* only print the buffer out, and free it, if it's not 796 | * empty 797 | */ 798 | printSelBuf(stdout, sel_type, sel_buf, sel_len); 799 | 800 | if (fsecm) { 801 | /* If user requested -sensitive, then prevent further pastes */ 802 | XSetSelectionOwner(dpy, sseln, None, CurrentTime); 803 | /* Clear memory buffer */ 804 | xcmemzero(sel_buf,sel_len); 805 | } 806 | 807 | if (sseln == XA_STRING) { 808 | XFree(sel_buf); 809 | } 810 | else { 811 | free(sel_buf); 812 | } 813 | } 814 | 815 | return EXIT_SUCCESS; 816 | } 817 | 818 | int 819 | main(int argc, char *argv[]) 820 | { 821 | /* Declare variables */ 822 | Window win; /* Window */ 823 | int exit_code; 824 | 825 | /* As a convenience to command-line users, default to -o if stdin 826 | * is a tty. Will be overridden by -i or if user specifies a 827 | * filename as input. 828 | */ 829 | if (isatty(0)) { 830 | fdiri = F; /* direction is out */ 831 | } 832 | 833 | /* set up option table. I can't figure out a better way than this to 834 | * do it while sticking to pure ANSI C. The option and specifier 835 | * members have a type of volatile char *, so they need to be allocated 836 | * by strdup or malloc, you can't set them to a string constant at 837 | * declare time, this is not pure ANSI C apparently, although it does 838 | * work with gcc 839 | */ 840 | 841 | int i=0; 842 | /* loop option entry */ 843 | opt_tab[i].option = xcstrdup("-loops"); 844 | opt_tab[i].specifier = xcstrdup(".loops"); 845 | opt_tab[i].argKind = XrmoptionSepArg; 846 | opt_tab[i].value = (XPointer) NULL; 847 | i++; 848 | 849 | /* display option entry */ 850 | opt_tab[i].option = xcstrdup("-display"); 851 | opt_tab[i].specifier = xcstrdup(".display"); 852 | opt_tab[i].argKind = XrmoptionSepArg; 853 | opt_tab[i].value = (XPointer) NULL; 854 | i++; 855 | 856 | /* selection option entry */ 857 | opt_tab[i].option = xcstrdup("-selection"); 858 | opt_tab[i].specifier = xcstrdup(".selection"); 859 | opt_tab[i].argKind = XrmoptionSepArg; 860 | opt_tab[i].value = (XPointer) NULL; 861 | i++; 862 | 863 | /* filter option entry */ 864 | opt_tab[i].option = xcstrdup("-filter"); 865 | opt_tab[i].specifier = xcstrdup(".filter"); 866 | opt_tab[i].argKind = XrmoptionNoArg; 867 | opt_tab[i].value = (XPointer) xcstrdup(ST); 868 | i++; 869 | 870 | /* in option entry */ 871 | opt_tab[i].option = xcstrdup("-in"); 872 | opt_tab[i].specifier = xcstrdup(".direction"); 873 | opt_tab[i].argKind = XrmoptionNoArg; 874 | opt_tab[i].value = (XPointer) xcstrdup("I"); 875 | i++; 876 | 877 | /* out option entry */ 878 | opt_tab[i].option = xcstrdup("-out"); 879 | opt_tab[i].specifier = xcstrdup(".direction"); 880 | opt_tab[i].argKind = XrmoptionNoArg; 881 | opt_tab[i].value = (XPointer) xcstrdup("O"); 882 | i++; 883 | 884 | /* version option entry */ 885 | opt_tab[i].option = xcstrdup("-version"); 886 | opt_tab[i].specifier = xcstrdup(".print"); 887 | opt_tab[i].argKind = XrmoptionNoArg; 888 | opt_tab[i].value = (XPointer) xcstrdup("V"); 889 | i++; 890 | 891 | /* help option entry */ 892 | opt_tab[i].option = xcstrdup("-help"); 893 | opt_tab[i].specifier = xcstrdup(".print"); 894 | opt_tab[i].argKind = XrmoptionNoArg; 895 | opt_tab[i].value = (XPointer) xcstrdup("H"); 896 | i++; 897 | 898 | /* silent option entry */ 899 | opt_tab[i].option = xcstrdup("-silent"); 900 | opt_tab[i].specifier = xcstrdup(".olevel"); 901 | opt_tab[i].argKind = XrmoptionNoArg; 902 | opt_tab[i].value = (XPointer) xcstrdup("S"); 903 | i++; 904 | 905 | /* quiet option entry */ 906 | opt_tab[i].option = xcstrdup("-quiet"); 907 | opt_tab[i].specifier = xcstrdup(".olevel"); 908 | opt_tab[i].argKind = XrmoptionNoArg; 909 | opt_tab[i].value = (XPointer) xcstrdup("Q"); 910 | i++; 911 | 912 | /* verbose option entry */ 913 | opt_tab[i].option = xcstrdup("-verbose"); 914 | opt_tab[i].specifier = xcstrdup(".olevel"); 915 | opt_tab[i].argKind = XrmoptionNoArg; 916 | opt_tab[i].value = (XPointer) xcstrdup("V"); 917 | i++; 918 | 919 | /* debug option entry */ 920 | opt_tab[i].option = xcstrdup("-debug"); 921 | opt_tab[i].specifier = xcstrdup(".olevel"); 922 | opt_tab[i].argKind = XrmoptionNoArg; 923 | opt_tab[i].value = (XPointer) xcstrdup("D"); 924 | i++; 925 | 926 | /* utf8 option entry */ 927 | opt_tab[i].option = xcstrdup("-noutf8"); 928 | opt_tab[i].specifier = xcstrdup(".noutf8"); 929 | opt_tab[i].argKind = XrmoptionNoArg; 930 | opt_tab[i].value = (XPointer) xcstrdup("N"); 931 | i++; 932 | 933 | /* target option entry */ 934 | opt_tab[i].option = xcstrdup("-target"); 935 | opt_tab[i].specifier = xcstrdup(".target"); 936 | opt_tab[i].argKind = XrmoptionSepArg; 937 | opt_tab[i].value = (XPointer) NULL; 938 | i++; 939 | 940 | /* alt-text option entry */ 941 | opt_tab[i].option = xcstrdup("-alt-text"); 942 | opt_tab[i].specifier = xcstrdup(".alt-text"); 943 | opt_tab[i].argKind = XrmoptionSepArg; 944 | opt_tab[i].value = (XPointer) NULL; 945 | i++; 946 | 947 | /* "remove newline if it is the last character" entry */ 948 | opt_tab[i].option = xcstrdup("-rmlastnl"); 949 | opt_tab[i].specifier = xcstrdup(".rmlastnl"); 950 | opt_tab[i].argKind = XrmoptionNoArg; 951 | opt_tab[i].value = (XPointer) xcstrdup(ST); 952 | i++; 953 | 954 | /* sensitive mode for pasting passwords */ 955 | opt_tab[i].option = xcstrdup("-sensitive"); 956 | opt_tab[i].specifier = xcstrdup(".sensitive"); 957 | opt_tab[i].argKind = XrmoptionNoArg; 958 | opt_tab[i].value = (XPointer) xcstrdup("s"); 959 | i++; 960 | 961 | /* wait option entry */ 962 | opt_tab[i].option = xcstrdup("-wait"); 963 | opt_tab[i].specifier = xcstrdup(".wait"); 964 | opt_tab[i].argKind = XrmoptionSepArg; 965 | opt_tab[i].value = (XPointer) NULL; 966 | i++; 967 | 968 | /* save size of opt_tab for doOptMain to use */ 969 | opt_tab_size = i; 970 | if ( ( sizeof(opt_tab) / sizeof(opt_tab[0]) ) < opt_tab_size ) { 971 | fprintf(stderr, 972 | "xclip: programming error: opt_tab declared to hold %ld options, but %d defined\n", 973 | sizeof(opt_tab) / sizeof(opt_tab[0]), opt_tab_size); 974 | return EXIT_FAILURE; 975 | } 976 | 977 | 978 | /* parse command line options */ 979 | doOptMain(argc, argv); 980 | 981 | /* Connect to the X server. */ 982 | if ((dpy = XOpenDisplay(sdisp))) { 983 | /* successful */ 984 | if (xcverb >= ODEBUG) 985 | fprintf(stderr, "Connected to X server.\n"); 986 | } 987 | else { 988 | /* couldn't connect to X server. Print error and exit */ 989 | errxdisplay(sdisp); 990 | } 991 | 992 | /* parse selection command line option */ 993 | doOptSel(); 994 | 995 | /* parse noutf8 and target command line options */ 996 | doOptTarget(); 997 | 998 | /* Create a window to trap events */ 999 | win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0, 0, 0); 1000 | 1001 | /* get events about property changes */ 1002 | XSelectInput(dpy, win, PropertyChangeMask); 1003 | 1004 | /* If we get an X error, catch it instead of barfing */ 1005 | XSetErrorHandler(xchandler); 1006 | 1007 | if (fdiri) 1008 | exit_code = doIn(win, argv[0]); 1009 | else 1010 | exit_code = doOut(win); 1011 | 1012 | /* Disconnect from the X server */ 1013 | XCloseDisplay(dpy); 1014 | 1015 | /* exit */ 1016 | return exit_code; 1017 | } 1018 | -------------------------------------------------------------------------------- /xclip.spec: -------------------------------------------------------------------------------- 1 | Name: xclip 2 | Version: 0.13 3 | Release: 1%{?dist} 4 | License: GPLv2+ 5 | Group: Applications/System 6 | Summary: Command line clipboard grabber 7 | URL: https://github.com/astrand/xclip 8 | Source0: https://github.com/astrand/xclip/archive/%{version}.tar.gz 9 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) 10 | BuildRequires: libXmu-devel, libICE-devel, libX11-devel, libXext-devel 11 | Packager: Peter Åstrand 12 | 13 | %description 14 | xclip is a command line utility that is designed to run on any system with an 15 | X11 implementation. It provides an interface to X selections ("the clipboard") 16 | from the command line. It can read data from standard in or a file and place it 17 | in an X selection for pasting into other X applications. xclip can also print 18 | an X selection to standard out, which can then be redirected to a file or 19 | another program. 20 | 21 | %prep 22 | %setup -q 23 | 24 | %build 25 | %configure 26 | make CDEBUGFLAGS="$RPM_OPT_FLAGS" %{?_smp_mflags} 27 | 28 | %install 29 | rm -rf $RPM_BUILD_ROOT 30 | make DESTDIR=$RPM_BUILD_ROOT install 31 | make DESTDIR=$RPM_BUILD_ROOT install.man 32 | 33 | %clean 34 | rm -rf $RPM_BUILD_ROOT 35 | 36 | %files 37 | %defattr(-,root,root,-) 38 | %doc COPYING README ChangeLog 39 | %{_bindir}/xclip 40 | %{_bindir}/xclip-copyfile 41 | %{_bindir}/xclip-cutfile 42 | %{_bindir}/xclip-pastefile 43 | %{_mandir}/man1/xclip.1* 44 | %{_mandir}/man1/xclip-copyfile.1* 45 | -------------------------------------------------------------------------------- /xcprint.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * xcprint.c - functions to print help, version, errors, etc 5 | * Copyright (C) 2001 Kim Saunders 6 | * Copyright (C) 2007-2008 Peter Åstrand 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "xcdef.h" 27 | #include "xclib.h" 28 | #include "xcprint.h" 29 | 30 | /* print the help screen. argument is argv[0] from main() */ 31 | void 32 | prhelp(char *name) 33 | { 34 | fprintf(stderr, 35 | "Usage: %s [OPTION] [FILE]...\n" 36 | "Access an X server selection for reading or writing.\n" 37 | "\n" 38 | " -i, -in read text into X selection from stdin or files [DEFAULT]\n" 39 | " -f, -filter text piped in to selection will also be printed out\n" 40 | " -o, -out prints the selection to standard out\n" 41 | " -selection primary [DEFAULT], clipboard, secondary, or buffer-cut\n" 42 | " -t, -target specify target atom: image/jpeg, UTF8_STRING [DEFAULT]\n" 43 | " -alt-text specify text representation for STRING target\n" 44 | " -silent errors only, (run in background) [DEFAULT]\n" 45 | " -quiet minimal output (foreground)\n" 46 | " -verbose running commentary (foreground)\n" 47 | " -debug garrulous verbiage (foreground)\n" 48 | " -sensitive only allow copied data to be pasted once\n" 49 | " -l, -loops number of selection requests to wait for before exiting\n" 50 | " -wait n exit n milliseconds pasting, timer restarts on each paste\n" 51 | " -noutf8 don't treat text as utf-8, use old unicode\n" 52 | " -r, -rmlastnl remove the last newline character if present\n" 53 | " -d, -display X display to connect to (eg localhost:0\")\n" 54 | " -version version information\n" 55 | " -h, -help this usage information\n" 56 | "\n" "Report bugs to \n", name); 57 | exit(EXIT_SUCCESS); 58 | } 59 | 60 | 61 | /* A function to print the software version info */ 62 | void 63 | prversion(void) 64 | { 65 | fprintf(stderr, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION); 66 | fprintf(stderr, "Copyright (C) 2001-2008 Kim Saunders et al.\n"); 67 | fprintf(stderr, "Distributed under the terms of the GNU GPL\n"); 68 | exit(EXIT_SUCCESS); 69 | } 70 | 71 | /* failure message for malloc() problems */ 72 | void 73 | errmalloc(void) 74 | { 75 | fprintf(stderr, "xclip: Error: Could not allocate memory.\n"); 76 | exit(EXIT_FAILURE); 77 | } 78 | 79 | /* failure to connect to X11 display */ 80 | void 81 | errxdisplay(char *display) 82 | { 83 | /* if the display wasn't specified, read it from the environment 84 | * just like XOpenDisplay would 85 | */ 86 | if (display == NULL) 87 | display = getenv("DISPLAY"); 88 | 89 | fprintf(stderr, "xclip: Error: Can't open display: %s\n", display ? display : "(null)"); 90 | exit(EXIT_FAILURE); 91 | } 92 | 93 | /* a wrapper for perror that joins multiple prefixes together. Arguments 94 | * are an integer, and any number of strings. The integer needs to be set to 95 | * the number of strings that follow. 96 | */ 97 | void 98 | errperror(int prf_tot, ...) 99 | { 100 | va_list ap; /* argument pointer */ 101 | char *msg_all; /* all messages so far */ 102 | char *msg_cur; /* current message string */ 103 | int prf_cur; /* current prefix number */ 104 | 105 | /* start off with an empty string */ 106 | msg_all = xcstrdup(""); 107 | 108 | /* start looping through the variable arguments */ 109 | va_start(ap, prf_tot); 110 | 111 | /* loop through each of the arguments */ 112 | for (prf_cur = 0; prf_cur < prf_tot; prf_cur++) { 113 | /* get the current argument */ 114 | msg_cur = va_arg(ap, char *); 115 | 116 | /* realloc msg_all so it's big enough for itself, the current 117 | * argument, and a null terminator 118 | */ 119 | msg_all = (char *) xcrealloc(msg_all, strlen(msg_all) + strlen(msg_cur) + sizeof(char) 120 | ); 121 | 122 | /* append the current message to the total message */ 123 | strcat(msg_all, msg_cur); 124 | } 125 | va_end(ap); 126 | 127 | perror(msg_all); 128 | 129 | /* free the complete string */ 130 | free(msg_all); 131 | } 132 | 133 | 134 | /* failure to convert selection */ 135 | void 136 | errconvsel(Display *display, Atom target, Atom selection) 137 | { 138 | Window w = None; 139 | char *selection_name = XGetAtomName(display, selection); /* E.g., "PRIMARY" */ 140 | 141 | if (!selection_name) 142 | exit(EXIT_FAILURE); /* Invalid selection Atom */ 143 | 144 | w = XGetSelectionOwner(display, selection); 145 | if (w == None) { 146 | fprintf(stderr, "xclip: Error: There is no owner for the %s selection\n", 147 | selection_name); 148 | } 149 | else { 150 | /* Show the name of the window that holds the selection */ 151 | fprintf(stderr, "xclip: Error: %s", xcnamestr(display, w)); 152 | 153 | char *atom_name = XGetAtomName(display, target); 154 | if (atom_name) { 155 | fprintf(stderr, " cannot convert %s selection to target '%s'\n", 156 | selection_name, atom_name); 157 | XFree(atom_name); 158 | } 159 | else { 160 | /* Should never happen. */ 161 | fprintf(stderr, " cannot convert to NULL target.\n"); 162 | } 163 | } 164 | 165 | if (selection_name) 166 | XFree(selection_name); 167 | 168 | exit(EXIT_FAILURE); 169 | } 170 | -------------------------------------------------------------------------------- /xcprint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * xcprint.h - header file for functions in xcprint.c 5 | * Copyright (C) 2001 Kim Saunders 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 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 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | /* functions in xcprint.c */ 22 | extern void prhelp(char *); 23 | extern void prversion(void); 24 | extern void errmalloc(void); 25 | extern void errxdisplay(char *); 26 | extern void errperror(int, ...); 27 | extern void errconvsel(Display *display, Atom target, Atom selection); 28 | -------------------------------------------------------------------------------- /xctest: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # 3 | # 4 | # 5 | # xctest - shell script to test xclip 6 | # Copyright (C) 2001 Kim Saunders 7 | # 8 | # This program is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | 21 | cleanup() { 22 | # quietly remove temp files 23 | rm "$tempi" "$tempo" 2>/dev/null 24 | # Kill any remaining xclip processes 25 | killall xclip 2>/dev/null 26 | } 27 | trap cleanup EXIT HUP INT 28 | 29 | 30 | 31 | if sleep 0.1 2>/dev/null; then 32 | delay=0.1 # seconds to wait before running xclip -o 33 | else 34 | delay=1 35 | fi 36 | 37 | # test to make sure ./xclip exists 38 | if [ ! -x xclip ]; then 39 | echo "Error: xclip doesn't exist in the current directory." 40 | exit 41 | fi 42 | 43 | checker="" 44 | 45 | for param in "$@"; do 46 | case $param in 47 | --valgrind) checker="valgrind --num-callers=8";; 48 | esac 49 | done 50 | 51 | echo "Testing whether xclip exits correctly when the selection is lost" 52 | echo "hello" | ./xclip -q -i 2>/dev/null & 53 | sleep "$delay" 54 | echo "goodbye" | ./xclip -i 55 | sleep "$delay" 56 | if ps $! >/dev/null; then 57 | echo "FAIL: Zombie xclip yet lives! Killing." 58 | killall xclip 59 | exit 1 60 | else 61 | echo "PASS: xclip exited correctly after losing selection" 62 | fi 63 | 64 | # temp file names (in and out) 65 | tempi=`mktemp` || exit 1 66 | tempo=`mktemp` || exit 1 67 | 68 | # test xclip on different amounts of data (2^fold) to bring out any errors 69 | c=0 # Number of folds completed. 70 | lines=1 # Current file size (2 to the c power). 71 | printf '%s' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_ ' > "$tempi" 72 | printf '%s\n' 'abcdefghijklmnopqrstuvwzyz!@#$%^&*()' >> "$tempi" 73 | for fold in 1 4 7 10 13; do 74 | # double size of file by two 75 | while [ "$c" -lt "$fold" ]; do 76 | cat "$tempi" "$tempi" > "$tempo" && mv "$tempo" "$tempi" 77 | lines=$(( 2 * lines )) 78 | c=$(( c + 1 )) 79 | done 80 | 81 | # test piping the file to xclip, using all selections 82 | echo "Piping a $lines line file to xclip" 83 | for sel in primary secondary clipboard buffer; do 84 | printf '%s' " Using the $sel selection " 85 | cat "$tempi" | $checker ./xclip -sel "$sel" -i 86 | sleep "$delay" 87 | $checker ./xclip -sel "$sel" -o > "$tempo" 88 | if diff "$tempi" "$tempo"; then 89 | echo "PASS" 90 | else 91 | echo "FAIL" 92 | exit 1 93 | fi 94 | done 95 | echo 96 | 97 | # test piping the file to xclip 98 | echo Piping a $lines line file to xclip using - 99 | for sel in primary secondary clipboard buffer 100 | do 101 | echo -n " Using the $sel selection " 102 | cat $tempi | $checker ./xclip -sel $sel -i - 103 | sleep $delay 104 | $checker ./xclip -sel $sel -o > $tempo 105 | if diff $tempi $tempo; then 106 | echo "PASS" 107 | else 108 | echo "FAIL" 109 | exit 1 110 | fi 111 | done 112 | echo 113 | 114 | # test xclip reading the file 115 | echo "Reading a $lines line file with xclip" 116 | for sel in primary secondary clipboard buffer; do 117 | printf '%s' " Using the $sel selection " 118 | $checker ./xclip -sel "$sel" -i "$tempi" 119 | sleep "$delay" 120 | $checker ./xclip -sel "$sel" -o > "$tempo" 121 | if diff "$tempi" "$tempo"; then 122 | echo "PASS" 123 | else 124 | echo "FAIL" 125 | exit 1 126 | fi 127 | done 128 | echo 129 | 130 | # test xclip filtering a file 131 | echo "Filtering a $lines line file through xclip" 132 | for sel in primary secondary clipboard buffer; do 133 | printf '%s' " Using the $sel selection " 134 | $checker ./xclip -sel "$sel" -f < "$tempi" > "$tempo" 135 | sleep "$delay" 136 | if diff "$tempi" "$tempo"; then 137 | echo "PASS" 138 | else 139 | echo "FAIL" 140 | exit 1 141 | fi 142 | done 143 | echo 144 | 145 | done 146 | 147 | # test xclip on files >1MB to force INCR mode 148 | for i in 1 2 16; do 149 | dd if=/dev/zero bs=1024 count=$((i*1024)) of="$tempi" >/dev/null 2>&1 150 | echo "Binary file large enough to force INCR mode ($i MB)" 151 | for sel in primary secondary clipboard buffer; do 152 | printf '%s' " Using the $sel selection " 153 | $checker ./xclip -sel "$sel" -i -t image/jpeg < "$tempi" 154 | sleep "$delay" 155 | $checker ./xclip -sel "$sel" -o -t image/jpeg > "$tempo" 156 | if diff "$tempi" "$tempo"; then 157 | echo "PASS" 158 | else 159 | echo "FAIL" 160 | exit 1 161 | fi 162 | done 163 | done 164 | 165 | # Kill any remain xclip processes 166 | killall xclip 167 | 168 | # quietly remove temp files 169 | rm "$tempi" "$tempo" 2>/dev/null 170 | --------------------------------------------------------------------------------