mirror of
https://github.com/tmux/tmux.git
synced 2026-09-16 18:21:58 +00:00
Compare commits
961 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e418b62d2 | ||
|
|
78a2145a47 | ||
|
|
dbe50934b1 | ||
|
|
166267c87a | ||
|
|
132a63d1da | ||
|
|
4e612612dc | ||
|
|
6c2ef75681 | ||
|
|
84291b021f | ||
|
|
81f88f8517 | ||
|
|
4eafb27b89 | ||
|
|
4fc4644652 | ||
|
|
e7f414416f | ||
|
|
3b8e25fef4 | ||
|
|
64e83caf04 | ||
|
|
762e503978 | ||
|
|
c809aea278 | ||
|
|
1596f9c9f5 | ||
|
|
2f28d9a168 | ||
|
|
baac29debc | ||
|
|
2c4df765c5 | ||
|
|
2d9afa6348 | ||
|
|
bae5c14941 | ||
|
|
9cf8de099c | ||
|
|
f98aaf544d | ||
|
|
78afc24736 | ||
|
|
83e4534387 | ||
|
|
dabaae1534 | ||
|
|
cc87db74c7 | ||
|
|
aa1f0653e9 | ||
|
|
8771b6051f | ||
|
|
bbd4768bb6 | ||
|
|
cb237b5193 | ||
|
|
85d72b9952 | ||
|
|
a04c33c42d | ||
|
|
529afada82 | ||
|
|
a532f4868f | ||
|
|
e1d37c37b5 | ||
|
|
ae5e0e8c05 | ||
|
|
bbea0ef439 | ||
|
|
a134c43f4d | ||
|
|
e0ebae4481 | ||
|
|
1fbc51b69f | ||
|
|
42f3e7f7ce | ||
|
|
e163cbacec | ||
|
|
0ec6870902 | ||
|
|
55421ede70 | ||
|
|
3acd247f5d | ||
|
|
59151704b4 | ||
|
|
343ee5ece1 | ||
|
|
0256ee77c2 | ||
|
|
72f5415fc8 | ||
|
|
ef8e9df02f | ||
|
|
306ee0eddb | ||
|
|
3d9e6bf454 | ||
|
|
0fc6cb4099 | ||
|
|
5744021ac9 | ||
|
|
54be05e5e4 | ||
|
|
c9e22ab67b | ||
|
|
4063f968c6 | ||
|
|
8388c53a47 | ||
|
|
3a72f3beb8 | ||
|
|
35709a30ee | ||
|
|
f9a683cf39 | ||
|
|
d7a2b52da8 | ||
|
|
f43adc364a | ||
|
|
6beebbe074 | ||
|
|
019f8eb278 | ||
|
|
580f9ced08 | ||
|
|
642cc15b99 | ||
|
|
cfeade6055 | ||
|
|
390207cdf1 | ||
|
|
c97b2b95e6 | ||
|
|
a3bf632276 | ||
|
|
5368ee32dd | ||
|
|
e89f02bd8f | ||
|
|
ae6a749d3a | ||
|
|
0759030ee8 | ||
|
|
35f4c8b333 | ||
|
|
97ac32f536 | ||
|
|
2f3ef88dbf | ||
|
|
9725a0b9bf | ||
|
|
b368e89bea | ||
|
|
3269833caa | ||
|
|
922f7d1645 | ||
|
|
a1873fef61 | ||
|
|
0eff3b6b97 | ||
|
|
f6557d1ea2 | ||
|
|
718eb2b4cc | ||
|
|
cd6c01e42b | ||
|
|
0b773dd792 | ||
|
|
b68ab3a4b4 | ||
|
|
d8c9f88fe7 | ||
|
|
f6398ba51c | ||
|
|
67dbf01eeb | ||
|
|
7c71064b64 | ||
|
|
4d91ff8d8d | ||
|
|
e778f7f805 | ||
|
|
3bff7a9e62 | ||
|
|
705c2ac55a | ||
|
|
3f3d65e452 | ||
|
|
a9721ea268 | ||
|
|
d876bb8cf3 | ||
|
|
b17dcc6773 | ||
|
|
e3ee2b327b | ||
|
|
74b91d6dec | ||
|
|
7a3b7ae812 | ||
|
|
35df67c893 | ||
|
|
290303e64f | ||
|
|
f8ab7a5158 | ||
|
|
decaaf4b55 | ||
|
|
b9d228c72f | ||
|
|
11e48c3fa9 | ||
|
|
c40302a7ff | ||
|
|
964e22cfef | ||
|
|
55db69e3b2 | ||
|
|
99b08ecde5 | ||
|
|
4ecf93487e | ||
|
|
f066933418 | ||
|
|
481d8299ca | ||
|
|
3b19536df9 | ||
|
|
2212157b61 | ||
|
|
7ebeed1ae7 | ||
|
|
7769097915 | ||
|
|
595b0cb471 | ||
|
|
c50c3629e6 | ||
|
|
887b6f4da7 | ||
|
|
9c6cfcd2e9 | ||
|
|
658c7d1dbf | ||
|
|
ecfe6e4e7a | ||
|
|
f53c4e7525 | ||
|
|
3690c64e88 | ||
|
|
c489f786b6 | ||
|
|
5c40cc43b2 | ||
|
|
54ae850322 | ||
|
|
a9b9d2f6d3 | ||
|
|
f00f92e7e3 | ||
|
|
bbe26df83d | ||
|
|
daf9988b3a | ||
|
|
ee67452772 | ||
|
|
781364f7f9 | ||
|
|
84d016ddcf | ||
|
|
0241fdac1a | ||
|
|
d62bae442b | ||
|
|
9cc8947a43 | ||
|
|
bff68fa079 | ||
|
|
00c59041ea | ||
|
|
a77b81f0e5 | ||
|
|
f839588c69 | ||
|
|
27d719cd4d | ||
|
|
7a15dc6772 | ||
|
|
bfd7f468ce | ||
|
|
cca1e77f95 | ||
|
|
cc81287665 | ||
|
|
ca95153b45 | ||
|
|
eb330a6df6 | ||
|
|
b498979d4d | ||
|
|
f047b3f8e7 | ||
|
|
c67787536b | ||
|
|
3cfc96d4de | ||
|
|
91a8c66537 | ||
|
|
5c3a4746b7 | ||
|
|
b8e0004ff2 | ||
|
|
4e0aabd8a7 | ||
|
|
143a177055 | ||
|
|
d45a9cad8c | ||
|
|
285a3b7522 | ||
|
|
d4255818c4 | ||
|
|
f714f3ee78 | ||
|
|
36bc351557 | ||
|
|
d5ee330d20 | ||
|
|
634e9d6213 | ||
|
|
9aa9a92f72 | ||
|
|
8c51c0fdbd | ||
|
|
24e4a545a2 | ||
|
|
c5fb5e8bb0 | ||
|
|
b8434182c9 | ||
|
|
e1f942f26a | ||
|
|
91b85efabb | ||
|
|
0057905ca0 | ||
|
|
572e26deb8 | ||
|
|
caff9a135f | ||
|
|
ce24b92758 | ||
|
|
f5a086ac98 | ||
|
|
cb1025e0e8 | ||
|
|
a46cdb8bbc | ||
|
|
34e2035bad | ||
|
|
a9ba7b8ecb | ||
|
|
962d647993 | ||
|
|
a8520ba59e | ||
|
|
f12d7b4e67 | ||
|
|
bbea6e6375 | ||
|
|
b24b8424b1 | ||
|
|
35bd1a4c02 | ||
|
|
818352c3cd | ||
|
|
742efe989f | ||
|
|
4cea1c7189 | ||
|
|
18ddda48d2 | ||
|
|
5651519f5d | ||
|
|
281e8ff766 | ||
|
|
dbc0710bc9 | ||
|
|
8f28f31b78 | ||
|
|
3f651d9fa9 | ||
|
|
18fced7e7f | ||
|
|
f1f0158741 | ||
|
|
3d6c542e34 | ||
|
|
c3036116de | ||
|
|
9e3653a612 | ||
|
|
27a00d1bfd | ||
|
|
800837ff3f | ||
|
|
bfbfb6dbf3 | ||
|
|
8fb1b1d412 | ||
|
|
af98467d0d | ||
|
|
f9d50d580c | ||
|
|
496805476e | ||
|
|
962e565591 | ||
|
|
862625a4bf | ||
|
|
2d8aade74b | ||
|
|
2aad2cfc53 | ||
|
|
ad94405dac | ||
|
|
518fcf7e03 | ||
|
|
1fbd00e1e8 | ||
|
|
cae229cadc | ||
|
|
9d3dcdbc38 | ||
|
|
d52fabce72 | ||
|
|
637d4c3083 | ||
|
|
1e96d9a87f | ||
|
|
49172b256c | ||
|
|
9a94f48663 | ||
|
|
2e9c6c2586 | ||
|
|
92522473b0 | ||
|
|
56200ca044 | ||
|
|
524f283cc6 | ||
|
|
a2acf0f7cf | ||
|
|
d85f1b942d | ||
|
|
8da41bdc2b | ||
|
|
4a926e489b | ||
|
|
746dd91e86 | ||
|
|
763dec881a | ||
|
|
2a5715fad5 | ||
|
|
ec58272b95 | ||
|
|
f90d3af403 | ||
|
|
c2659401b0 | ||
|
|
9840d4a4a3 | ||
|
|
fc6d94a9f8 | ||
|
|
61a7be0eab | ||
|
|
e4a439aa0c | ||
|
|
b844cafb9c | ||
|
|
1d9522a7a6 | ||
|
|
ffe80579df | ||
|
|
bcd17cf99a | ||
|
|
bc15723f7f | ||
|
|
7a0cc03532 | ||
|
|
d36f6783c7 | ||
|
|
d339ab51eb | ||
|
|
fee70031f6 | ||
|
|
303edb71bd | ||
|
|
314f0ae964 | ||
|
|
0835980ef1 | ||
|
|
baf55e4616 | ||
|
|
dd62c2f946 | ||
|
|
638cecf43c | ||
|
|
a97cfe513d | ||
|
|
9de3c0495f | ||
|
|
67e6f8245b | ||
|
|
31c93c483a | ||
|
|
86d4d5689c | ||
|
|
663e82bc19 | ||
|
|
51109e3f72 | ||
|
|
a11363e9e7 | ||
|
|
cc57913d7a | ||
|
|
057d169492 | ||
|
|
e5a2a25faf | ||
|
|
147521b757 | ||
|
|
31d77e29b6 | ||
|
|
4b0ff07bcb | ||
|
|
0ee18d4421 | ||
|
|
21da45e5c3 | ||
|
|
d5ed967f58 | ||
|
|
42dafcc62a | ||
|
|
cad282ebb7 | ||
|
|
7f2ac9c871 | ||
|
|
87aaff5fae | ||
|
|
b411010237 | ||
|
|
d2d86ac360 | ||
|
|
a827725a8d | ||
|
|
3badbc50e0 | ||
|
|
cd60de443e | ||
|
|
95e40115a2 | ||
|
|
66c324d7ef | ||
|
|
6b056eb53f | ||
|
|
8cfdcf9a6f | ||
|
|
0917cd7010 | ||
|
|
bdd78ce38e | ||
|
|
7497db6e37 | ||
|
|
43e2942fa0 | ||
|
|
51bc2f3b76 | ||
|
|
483683c197 | ||
|
|
c95d341220 | ||
|
|
be2c6f3b5e | ||
|
|
2d5736f297 | ||
|
|
1a51193899 | ||
|
|
8b51abef08 | ||
|
|
cbb49e8c84 | ||
|
|
dc12da4573 | ||
|
|
7af58f74b0 | ||
|
|
1081876810 | ||
|
|
2ff0dd3fef | ||
|
|
a30fc69f86 | ||
|
|
022b5cf193 | ||
|
|
7620c03b72 | ||
|
|
6324dae114 | ||
|
|
e0237c6b8c | ||
|
|
1cf3e02bfb | ||
|
|
6ca5405db9 | ||
|
|
fa31f2a3eb | ||
|
|
d03f9454b9 | ||
|
|
616fb1cbcf | ||
|
|
b7d1e6257c | ||
|
|
b101ffaed6 | ||
|
|
f7dad4f38f | ||
|
|
b88c08f860 | ||
|
|
cc47f4d1c2 | ||
|
|
3909d7e92f | ||
|
|
d70edfa0a0 | ||
|
|
d22ab85b84 | ||
|
|
5c30b145df | ||
|
|
e446cba6a9 | ||
|
|
8a0b4e0d8c | ||
|
|
02a9cdff57 | ||
|
|
f516f8a1d4 | ||
|
|
bef4865d91 | ||
|
|
fd62f419ac | ||
|
|
7fa6f320ed | ||
|
|
19f3fb131b | ||
|
|
551e8fcd24 | ||
|
|
04b4952f0e | ||
|
|
0d77555c97 | ||
|
|
67141fb4bb | ||
|
|
2efa762c2b | ||
|
|
6c2dd193cf | ||
|
|
881bec958e | ||
|
|
8899c751e5 | ||
|
|
d0caf0a322 | ||
|
|
91b5108eae | ||
|
|
2c7f73f9c4 | ||
|
|
5310592967 | ||
|
|
41bddae907 | ||
|
|
d9d2b2f1ee | ||
|
|
1e208abd93 | ||
|
|
d32088b58a | ||
|
|
6d37cc94a7 | ||
|
|
55722a7ed7 | ||
|
|
d2fa20a390 | ||
|
|
bcbad050d4 | ||
|
|
27698c468b | ||
|
|
49bb43047d | ||
|
|
77ce0a837d | ||
|
|
bbbfa8f360 | ||
|
|
d781d2eaa1 | ||
|
|
f33b14bda6 | ||
|
|
e603549563 | ||
|
|
e80e0c761a | ||
|
|
9e804202b6 | ||
|
|
0c678b1e1a | ||
|
|
4cb29deb93 | ||
|
|
5413953d30 | ||
|
|
50e51b4513 | ||
|
|
ee0647aba6 | ||
|
|
35be70f1f0 | ||
|
|
dbb23d2182 | ||
|
|
478eaea982 | ||
|
|
0800e51d41 | ||
|
|
5ff385f8a9 | ||
|
|
5b3c642195 | ||
|
|
bd6e201926 | ||
|
|
08779aa2a3 | ||
|
|
09bd686327 | ||
|
|
9316476a73 | ||
|
|
00946007d8 | ||
|
|
bc47bc7c22 | ||
|
|
dc693601f4 | ||
|
|
f1f9c63cdb | ||
|
|
0cc4f0fd76 | ||
|
|
0dc1b5adfb | ||
|
|
a76e6eca6b | ||
|
|
8c7278b53a | ||
|
|
50a3b4c777 | ||
|
|
3094ca1da5 | ||
|
|
23ad10c849 | ||
|
|
c9fb989a31 | ||
|
|
8356578a54 | ||
|
|
0310404155 | ||
|
|
03f8690f9c | ||
|
|
4cc3de4f84 | ||
|
|
fedd4440f0 | ||
|
|
55cedc24fa | ||
|
|
c9162837a0 | ||
|
|
f218463976 | ||
|
|
1f0c54f7ea | ||
|
|
d3522c328c | ||
|
|
7e50eb0e83 | ||
|
|
5b455abecc | ||
|
|
7d41761e84 | ||
|
|
25f6d8b1e9 | ||
|
|
5a33616e65 | ||
|
|
1cf17b06ae | ||
|
|
aa03706ed0 | ||
|
|
d8794e2b30 | ||
|
|
b7939eb266 | ||
|
|
19b9a34c48 | ||
|
|
f016e08153 | ||
|
|
7b1c503086 | ||
|
|
5865001e4a | ||
|
|
62944da74b | ||
|
|
588013bb44 | ||
|
|
615c27c117 | ||
|
|
3c3d9ce3a9 | ||
|
|
66011fe48b | ||
|
|
d7f59eccaf | ||
|
|
e652213855 | ||
|
|
f70150a663 | ||
|
|
fe52f76913 | ||
|
|
0d9c3c895c | ||
|
|
6525bb7cef | ||
|
|
0790e74f84 | ||
|
|
195a9cfd88 | ||
|
|
ecbf8d76d0 | ||
|
|
818745a605 | ||
|
|
26aacd0e32 | ||
|
|
8e06739e26 | ||
|
|
ab1f2ef71c | ||
|
|
d2e09cb259 | ||
|
|
bf8ea85bd7 | ||
|
|
9c0aeaff40 | ||
|
|
95b4bb51c6 | ||
|
|
1e5f93b7b6 | ||
|
|
b89d46bb00 | ||
|
|
97d61131df | ||
|
|
5721767921 | ||
|
|
a443531280 | ||
|
|
ad083677c5 | ||
|
|
426467856d | ||
|
|
844042744e | ||
|
|
65b3a95be8 | ||
|
|
ca95950148 | ||
|
|
6234d79852 | ||
|
|
a5d8b92012 | ||
|
|
890cfc6dc3 | ||
|
|
0e6fc2e88b | ||
|
|
c8ccd420be | ||
|
|
ff4f6b9066 | ||
|
|
7cffa2de78 | ||
|
|
e2afaaea75 | ||
|
|
75d3974c12 | ||
|
|
583f12ea71 | ||
|
|
3de7a8ad8d | ||
|
|
f6c9052082 | ||
|
|
f226804149 | ||
|
|
cf94486e32 | ||
|
|
035a2f35d4 | ||
|
|
9b7732eac4 | ||
|
|
5f9dac8abc | ||
|
|
ccd4dd7ff2 | ||
|
|
77417b7cbe | ||
|
|
6a7cd79a63 | ||
|
|
baa3b51b3e | ||
|
|
abeba4910c | ||
|
|
356d0aedbd | ||
|
|
45f23f3a59 | ||
|
|
6ef7375ade | ||
|
|
00030aabf7 | ||
|
|
f72832cc08 | ||
|
|
b5c33ca2b7 | ||
|
|
d607399850 | ||
|
|
d005803934 | ||
|
|
a22ec275b4 | ||
|
|
188f963fe0 | ||
|
|
9c5df33325 | ||
|
|
74f60951cc | ||
|
|
54202fcaad | ||
|
|
fe645c5bcc | ||
|
|
86c15d7ae9 | ||
|
|
3c36d5e433 | ||
|
|
1c7e164c22 | ||
|
|
ce7eb22e3a | ||
|
|
739a97140f | ||
|
|
99ed397e9c | ||
|
|
d2c7668bc2 | ||
|
|
7abf3e8bdf | ||
|
|
506b4db762 | ||
|
|
21c27fdcae | ||
|
|
672e89a640 | ||
|
|
4b810ae493 | ||
|
|
52e2a7d990 | ||
|
|
2e5e9c0298 | ||
|
|
afa05ae15e | ||
|
|
f58b8d0d6a | ||
|
|
5c73d3878d | ||
|
|
ef0a7e328c | ||
|
|
cc117b5048 | ||
|
|
faebe7a70a | ||
|
|
01962e25dc | ||
|
|
ff207eb583 | ||
|
|
8e922ab690 | ||
|
|
1a3db6b65e | ||
|
|
987e05ff31 | ||
|
|
2fc123cf4a | ||
|
|
3b57077d01 | ||
|
|
33c1ba1549 | ||
|
|
bd16b22dac | ||
|
|
0929d8ddfa | ||
|
|
9d6c69ebde | ||
|
|
1bcd360dfe | ||
|
|
1f2210a3ce | ||
|
|
2fe1378d3a | ||
|
|
796539c60b | ||
|
|
700936b2ad | ||
|
|
a28dbe3a59 | ||
|
|
820df0f551 | ||
|
|
ee9cf1bbaa | ||
|
|
52917abe21 | ||
|
|
a40f98df0a | ||
|
|
2c78a5aceb | ||
|
|
02a8e3fd34 | ||
|
|
322adfbdde | ||
|
|
194d0a0e25 | ||
|
|
b2d6ebaa10 | ||
|
|
bfecbb0685 | ||
|
|
e4c552f5a5 | ||
|
|
04f32073c0 | ||
|
|
e9afd2bb5e | ||
|
|
55d660a548 | ||
|
|
dfaf47d97c | ||
|
|
640e1a7643 | ||
|
|
2a0b078e15 | ||
|
|
0af04295f3 | ||
|
|
3542bfa5b8 | ||
|
|
e3a54ed0f4 | ||
|
|
ec4b5b52af | ||
|
|
a0dfef3b04 | ||
|
|
6db6a30ab5 | ||
|
|
bfa2f73335 | ||
|
|
1decccace7 | ||
|
|
ee53d49059 | ||
|
|
0dac7fe434 | ||
|
|
a6690032ad | ||
|
|
f949f9a23a | ||
|
|
00cef3e6be | ||
|
|
3f4a8713c9 | ||
|
|
7c188aec3c | ||
|
|
f0dec832b8 | ||
|
|
ca74fa1db0 | ||
|
|
987986631d | ||
|
|
1d89233047 | ||
|
|
348f16093c | ||
|
|
2a3ec87887 | ||
|
|
b52dcff745 | ||
|
|
f372112a8d | ||
|
|
72117debf7 | ||
|
|
2f3c71595b | ||
|
|
113aaf37fc | ||
|
|
768042d29d | ||
|
|
db274f9c39 | ||
|
|
66279c124e | ||
|
|
b335419505 | ||
|
|
3c9e10139f | ||
|
|
34898c89cd | ||
|
|
40600eebfa | ||
|
|
12497ecade | ||
|
|
9e21f426c0 | ||
|
|
c77d49f67e | ||
|
|
33cfe8b809 | ||
|
|
0d0ef5d0d2 | ||
|
|
d65bac979d | ||
|
|
c1667bd85e | ||
|
|
815f7ecffb | ||
|
|
44c0443983 | ||
|
|
3051076dd1 | ||
|
|
d90b414223 | ||
|
|
8cb2805eb7 | ||
|
|
e5ab5995db | ||
|
|
e774b89062 | ||
|
|
29db8ac36e | ||
|
|
be2d4aa434 | ||
|
|
1e61e52400 | ||
|
|
4bdfbfa854 | ||
|
|
2c08960f4e | ||
|
|
1a419609e3 | ||
|
|
f812b8d304 | ||
|
|
ff6eefd7c7 | ||
|
|
0c5abfefd3 | ||
|
|
e560a09db0 | ||
|
|
9bf8ca5856 | ||
|
|
410abb5afb | ||
|
|
482aa937b1 | ||
|
|
b4ba6e49af | ||
|
|
010394ab63 | ||
|
|
7cbb96528c | ||
|
|
aa420cd54a | ||
|
|
d5302ec327 | ||
|
|
f31a2d229c | ||
|
|
35ad72e56f | ||
|
|
f501817154 | ||
|
|
449f255f3e | ||
|
|
21d890e6df | ||
|
|
feb3b90596 | ||
|
|
0ff2676a25 | ||
|
|
3e28777ecb | ||
|
|
7516f8e94f | ||
|
|
ac574b6782 | ||
|
|
50dafd6187 | ||
|
|
d4f129b513 | ||
|
|
9a72317c4f | ||
|
|
b21b1ee9af | ||
|
|
c62fe6dac8 | ||
|
|
9dc136f445 | ||
|
|
418bf148e0 | ||
|
|
408721ae37 | ||
|
|
b1b6850fa9 | ||
|
|
d73196750f | ||
|
|
093754db3f | ||
|
|
7cc15969ff | ||
|
|
b53cf70262 | ||
|
|
1dadd6c9ae | ||
|
|
a7a94cb86f | ||
|
|
3d6954f0f0 | ||
|
|
267efefdfa | ||
|
|
6a3170386e | ||
|
|
4d83eef756 | ||
|
|
44b7a2d1f9 | ||
|
|
c32570c602 | ||
|
|
9702ef3f91 | ||
|
|
b2194ac549 | ||
|
|
b5413dacc7 | ||
|
|
aa33757e45 | ||
|
|
a0065bea04 | ||
|
|
5c89d835a6 | ||
|
|
cfb906a0ce | ||
|
|
af36d7c430 | ||
|
|
0c9165fc71 | ||
|
|
fa63088dce | ||
|
|
0b7235c5f0 | ||
|
|
ca0f0419e6 | ||
|
|
3520e833a4 | ||
|
|
bb4866047a | ||
|
|
2070731af1 | ||
|
|
a5909b450c | ||
|
|
94bafa5aaf | ||
|
|
7325da3052 | ||
|
|
e6d275b371 | ||
|
|
f4c0fe2ede | ||
|
|
12452f4427 | ||
|
|
1370791734 | ||
|
|
0646814235 | ||
|
|
84775130a0 | ||
|
|
4ce893ebc0 | ||
|
|
3ae0d560be | ||
|
|
06c84dba59 | ||
|
|
d90e7623c6 | ||
|
|
b13005e802 | ||
|
|
05b2893b9f | ||
|
|
1bf2023ed4 | ||
|
|
6f9bcb7fee | ||
|
|
6d94909c08 | ||
|
|
86153fbba9 | ||
|
|
4f38af01e0 | ||
|
|
a6588d6918 | ||
|
|
720d1e831d | ||
|
|
206f492401 | ||
|
|
fa5f3cef3d | ||
|
|
c70d0a6a69 | ||
|
|
6549aaf393 | ||
|
|
6378c87d15 | ||
|
|
4a0eff1296 | ||
|
|
9c07903ae9 | ||
|
|
32b7b3a6f7 | ||
|
|
041bbf8bdf | ||
|
|
701f6b4b2f | ||
|
|
bddd019a04 | ||
|
|
865117a05f | ||
|
|
e6bac234db | ||
|
|
9f1fac9142 | ||
|
|
9831175a2d | ||
|
|
7e43953937 | ||
|
|
28481e984b | ||
|
|
30e4f119d3 | ||
|
|
01da87c112 | ||
|
|
e7f15d09be | ||
|
|
cbb3c4bfed | ||
|
|
d24993aeab | ||
|
|
d858ad1179 | ||
|
|
96244dd727 | ||
|
|
b38b5d3df2 | ||
|
|
ad3e6ff054 | ||
|
|
522652913f | ||
|
|
43e88c892d | ||
|
|
d82d9468b4 | ||
|
|
d7f75ac985 | ||
|
|
1dbceaa790 | ||
|
|
77ca59acac | ||
|
|
7be0613657 | ||
|
|
b9ad9186fe | ||
|
|
3f4b154b70 | ||
|
|
ff73c95547 | ||
|
|
aa0d05f676 | ||
|
|
545832e9fa | ||
|
|
a0ac2a5d63 | ||
|
|
833c7fbf6d | ||
|
|
faf2a44890 | ||
|
|
d194ceb604 | ||
|
|
37a2c98d3d | ||
|
|
79b02998a6 | ||
|
|
1ce1e7ef27 | ||
|
|
7499d925da | ||
|
|
367f17a4ff | ||
|
|
3d2b26dcfe | ||
|
|
6106a0f2c4 | ||
|
|
1926c1b683 | ||
|
|
6cc1a607fc | ||
|
|
1905afb3d8 | ||
|
|
345a45083d | ||
|
|
3a3babf597 | ||
|
|
f367e3a6c8 | ||
|
|
f2283b0cb5 | ||
|
|
26081ac125 | ||
|
|
36fba4cc54 | ||
|
|
58b4286edb | ||
|
|
b0b6a6f665 | ||
|
|
63e5989f53 | ||
|
|
9da5707d3e | ||
|
|
55292b72d1 | ||
|
|
06b1ad6241 | ||
|
|
1efe41b9b9 | ||
|
|
1198eed632 | ||
|
|
0772fe822a | ||
|
|
f53fac1b56 | ||
|
|
68f2ac9296 | ||
|
|
b4f8340f16 | ||
|
|
d2f73c17d5 | ||
|
|
5db914b745 | ||
|
|
cd3d2910ee | ||
|
|
de7653f5a4 | ||
|
|
b905039ed2 | ||
|
|
f0a85d0469 | ||
|
|
ac2779f4d8 | ||
|
|
68ffe65499 | ||
|
|
3e14e7c48b | ||
|
|
b526e678b5 | ||
|
|
d3c39375d5 | ||
|
|
a7991dcbad | ||
|
|
47dff97834 | ||
|
|
2905395695 | ||
|
|
4bf38da4d4 | ||
|
|
9b37b9285e | ||
|
|
dfdced2ab1 | ||
|
|
c2a95a372f | ||
|
|
ef923d28ff | ||
|
|
53b0e0bc02 | ||
|
|
096c4b3e63 | ||
|
|
b8189d6ee3 | ||
|
|
f41dc91357 | ||
|
|
ef0c12ad9e | ||
|
|
9e1f110db0 | ||
|
|
483b2b3edb | ||
|
|
34a35b0f09 | ||
|
|
aca3ffb30a | ||
|
|
c3c4524def | ||
|
|
f101762d1b | ||
|
|
a541be3951 | ||
|
|
b7d640e764 | ||
|
|
969f6a60c3 | ||
|
|
6703cb85d9 | ||
|
|
111e16e772 | ||
|
|
3eb93383a3 | ||
|
|
817b621d20 | ||
|
|
5eb30c1543 | ||
|
|
d4b8635f50 | ||
|
|
4e4fe3eb39 | ||
|
|
882fb4d295 | ||
|
|
eaf70c955b | ||
|
|
3543d79048 | ||
|
|
94783addfc | ||
|
|
91c0de60b4 | ||
|
|
21f7db4c4d | ||
|
|
f224d61f37 | ||
|
|
d938ab5dd7 | ||
|
|
9a8f46e554 | ||
|
|
27ee0c9c3b | ||
|
|
251a87e2d2 | ||
|
|
084e6ee9ec | ||
|
|
18331e39bf | ||
|
|
250c88efdc | ||
|
|
9a377485be | ||
|
|
47a56c11f2 | ||
|
|
c4b9716873 | ||
|
|
ec119b2f9e | ||
|
|
5d1a6acc84 | ||
|
|
80eb460fc9 | ||
|
|
ef68debc8d | ||
|
|
4c12ac9fb8 | ||
|
|
244bb726e2 | ||
|
|
6ab268c7bb | ||
|
|
0c9f8ff189 | ||
|
|
dd7d04be95 | ||
|
|
58392d29da | ||
|
|
9260f5dc96 | ||
|
|
62a6c16b43 | ||
|
|
31e8d4676a | ||
|
|
d3cbe00f78 | ||
|
|
97fe3563fa | ||
|
|
37ad1e2f6d | ||
|
|
00894d188d | ||
|
|
2a5eba7899 | ||
|
|
bf30492d57 | ||
|
|
e00853ee82 | ||
|
|
e75f3a0060 | ||
|
|
eece41547e | ||
|
|
c311202b73 | ||
|
|
e149d29803 | ||
|
|
190ddda572 | ||
|
|
6b470c5222 | ||
|
|
6b32d195e8 | ||
|
|
bec6ce54c1 | ||
|
|
106d1c3538 | ||
|
|
ae8f2208c9 | ||
|
|
5c3cf2f08b | ||
|
|
102f34090d | ||
|
|
99790c90aa | ||
|
|
6d792e4123 | ||
|
|
98e322d5a5 | ||
|
|
01edce40f3 | ||
|
|
0549f87ccc | ||
|
|
72cd0eac29 | ||
|
|
f0c68533c4 | ||
|
|
9e4a9c51cc | ||
|
|
6874ec0dcc | ||
|
|
252f41818e | ||
|
|
d361f21065 | ||
|
|
feb090abb3 | ||
|
|
db771ec6e3 | ||
|
|
6f7db82b18 | ||
|
|
67cc7f6dc6 | ||
|
|
db978db271 | ||
|
|
363f35f076 | ||
|
|
49b7276f2a | ||
|
|
f57131e11b | ||
|
|
420af9e108 | ||
|
|
ceaf9b7452 | ||
|
|
5fd45b3892 | ||
|
|
64d82d5988 | ||
|
|
0f308bd18f | ||
|
|
1365f1ce52 | ||
|
|
7fc4e54efe | ||
|
|
c98c08c232 | ||
|
|
990c724bd8 | ||
|
|
b82c7b40b0 | ||
|
|
70299c6646 | ||
|
|
ea6c5053c8 | ||
|
|
3f4fd45d5c | ||
|
|
7c7e88253e | ||
|
|
bb94a5437d | ||
|
|
273f9b2027 | ||
|
|
b6d0b4be30 | ||
|
|
2dce45f427 | ||
|
|
a3ede3106a | ||
|
|
dd9722184b | ||
|
|
a854e36f2b | ||
|
|
be594ff8a4 | ||
|
|
c66628e52b | ||
|
|
350a151ee4 | ||
|
|
d35458e3fe | ||
|
|
d6883c0266 | ||
|
|
563ed05353 | ||
|
|
f527412d9b | ||
|
|
713cacab1e | ||
|
|
846f813565 | ||
|
|
c26d71d3e9 | ||
|
|
c8677d3272 | ||
|
|
596ea62dc3 | ||
|
|
1fe30bb2e8 | ||
|
|
809d659e64 | ||
|
|
09f4e43189 | ||
|
|
679bbdcf8f | ||
|
|
a0c79aa87b | ||
|
|
46f3846659 | ||
|
|
bbc3cc558c | ||
|
|
c8bd42de16 | ||
|
|
62e15e905b | ||
|
|
125a7b9177 | ||
|
|
895044c52b | ||
|
|
40c01c2d37 | ||
|
|
911d768b71 | ||
|
|
71a503e40c | ||
|
|
487b0ee124 | ||
|
|
eaec0a48f4 | ||
|
|
fdbc6cdea5 | ||
|
|
9623ec3ee4 | ||
|
|
63582c154c | ||
|
|
914815e70f | ||
|
|
354926a956 | ||
|
|
df303770ea | ||
|
|
a269c33a54 | ||
|
|
eb04f9314b | ||
|
|
a9d0461839 | ||
|
|
71aa4fe767 | ||
|
|
cfd3c02306 | ||
|
|
35104059ed | ||
|
|
934035db71 | ||
|
|
8ff65230e1 | ||
|
|
cb00e869ea | ||
|
|
f8b56fdc3f | ||
|
|
2d8b6fcf23 | ||
|
|
6ddee22f81 | ||
|
|
66c738bc10 | ||
|
|
bcc47add38 | ||
|
|
d326c51d79 | ||
|
|
940fdf7ed0 | ||
|
|
4f5d6d97d3 | ||
|
|
00412b570b | ||
|
|
6a35b8ad07 | ||
|
|
735082b7c2 | ||
|
|
5b7bdc82c8 | ||
|
|
a3dea81b49 | ||
|
|
486221f206 | ||
|
|
9528d7470b | ||
|
|
933d6b90ed | ||
|
|
a869693405 | ||
|
|
114977dd25 | ||
|
|
aba8ffbe7b | ||
|
|
455a2b3705 | ||
|
|
e0638c48cd | ||
|
|
41f6b691e3 | ||
|
|
0f30fa34e3 | ||
|
|
e486f5ffdc | ||
|
|
5a68730e2f | ||
|
|
16b44d2a5b | ||
|
|
34775fc235 | ||
|
|
f2fd8c854a | ||
|
|
9f2a853d87 | ||
|
|
7a78cdf78c | ||
|
|
2df15ad08c | ||
|
|
780a87be9a | ||
|
|
1e303b6a9d | ||
|
|
8d2aee34ab | ||
|
|
05116cefe6 | ||
|
|
ce4be58eef | ||
|
|
8d6eb4be40 | ||
|
|
38c38f1c64 | ||
|
|
ddf6af79e3 | ||
|
|
826ba515be | ||
|
|
729bded8bf | ||
|
|
b95a06d2d4 | ||
|
|
157d748949 | ||
|
|
1c1f4c1219 | ||
|
|
17bab32794 | ||
|
|
25b1cc1e8e | ||
|
|
89adec0ca5 | ||
|
|
f95d055e04 | ||
|
|
7b148f7b5b | ||
|
|
9bd039d1bc | ||
|
|
7c30056d96 |
5
.github/CONTRIBUTING.md
vendored
5
.github/CONTRIBUTING.md
vendored
@@ -77,3 +77,8 @@ The log files are:
|
|||||||
- `tmux-out*.log`: output log file.
|
- `tmux-out*.log`: output log file.
|
||||||
|
|
||||||
Please attach the log files to your issue.
|
Please attach the log files to your issue.
|
||||||
|
|
||||||
|
## What does it mean if an issue is closed?
|
||||||
|
|
||||||
|
All it means is that work on the issue is not planned for the near future. See
|
||||||
|
the issue's comments to find out if contributions would be welcome.
|
||||||
|
|||||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
@@ -1,3 +1,12 @@
|
|||||||
|
---
|
||||||
|
name: Use this issue template
|
||||||
|
about: Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Issue description
|
### Issue description
|
||||||
|
|
||||||
Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
|
Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
|
||||||
@@ -14,9 +23,11 @@ built from the latest code in Git.
|
|||||||
|
|
||||||
### Required information
|
### Required information
|
||||||
|
|
||||||
Please provide the following information:
|
Please provide the following information. These are **required**. Note that bug reports without logs may be ignored or closed without comment.
|
||||||
|
|
||||||
* tmux version (`tmux -V`).
|
* tmux version (`tmux -V`).
|
||||||
* Platform (`uname -sp`).
|
* Platform (`uname -sp`).
|
||||||
* $TERM inside and outside of tmux (`echo $TERM`).
|
* Terminal in use (xterm, rxvt, etc).
|
||||||
|
* $TERM *inside* tmux (`echo $TERM`).
|
||||||
|
* $TERM *outside* tmux (`echo $TERM`).
|
||||||
* Logs from tmux (`tmux kill-server; tmux -vv new`).
|
* Logs from tmux (`tmux kill-server; tmux -vv new`).
|
||||||
2
.github/README.md
vendored
2
.github/README.md
vendored
@@ -79,7 +79,7 @@ A small example configuration is in `example_tmux.conf`.
|
|||||||
|
|
||||||
And a bash(1) completion file at:
|
And a bash(1) completion file at:
|
||||||
|
|
||||||
https://github.com/imomaliev/tmux-bash-completion
|
https://github.com/scop/bash-completion/blob/main/completions-core/tmux.bash
|
||||||
|
|
||||||
For debugging, run tmux with `-v` or `-vv` to generate server and client log
|
For debugging, run tmux with `-v` or `-vv` to generate server and client log
|
||||||
files in the current directory.
|
files in the current directory.
|
||||||
|
|||||||
11
.github/copilot-instructions.md
vendored
Normal file
11
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
For pull request code reviews in this repository, do not leave any review comments under any circumstances.
|
||||||
|
|
||||||
|
If asked to review a pull request, produce no comments.
|
||||||
|
|
||||||
|
Do not comment on pull requests in this repository.
|
||||||
|
|
||||||
|
For pull request code reviews in this repository, do not leave a pull request overview.
|
||||||
|
|
||||||
|
Do not leave inline review comments.
|
||||||
|
|
||||||
|
If asked to review a pull request, provide no summary, no overview, and no code comments.
|
||||||
2
.github/workflows/lock.yml
vendored
2
.github/workflows/lock.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
action:
|
action:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: dessant/lock-threads@v5
|
- uses: dessant/lock-threads@v6
|
||||||
with:
|
with:
|
||||||
github-token: ${{ github.token }}
|
github-token: ${{ github.token }}
|
||||||
issue-inactive-days: '30'
|
issue-inactive-days: '30'
|
||||||
|
|||||||
35
.gitignore
vendored
35
.gitignore
vendored
@@ -1,23 +1,24 @@
|
|||||||
*.o
|
|
||||||
*~
|
|
||||||
*.diff
|
|
||||||
*.patch
|
|
||||||
*.core
|
*.core
|
||||||
core
|
*.dSYM
|
||||||
tags
|
*.diff
|
||||||
|
*.o
|
||||||
|
*.patch
|
||||||
|
*.swp
|
||||||
|
*~
|
||||||
.deps/
|
.deps/
|
||||||
compat/.dirstamp
|
.dirstamp
|
||||||
aclocal.m4
|
|
||||||
autom4te.cache/
|
|
||||||
config.log
|
|
||||||
config.status
|
|
||||||
etc/
|
|
||||||
tmux
|
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
configure
|
aclocal.m4
|
||||||
tmux.1.*
|
autom4te.cache/
|
||||||
*.dSYM
|
|
||||||
cmd-parse.c
|
cmd-parse.c
|
||||||
|
compat/.dirstamp
|
||||||
|
config.log
|
||||||
|
config.status
|
||||||
|
configure
|
||||||
|
core
|
||||||
|
etc/
|
||||||
fuzz/*-fuzzer
|
fuzz/*-fuzzer
|
||||||
.dirstamp
|
tags
|
||||||
|
tmux
|
||||||
|
tmux.1.*
|
||||||
|
|||||||
1
.mailmap
1
.mailmap
@@ -29,6 +29,7 @@ Ted Unangst <tedu@openbsd.org> tedu <tedu>
|
|||||||
Theo de Raadt <deraadt@openbsd.org> Theo Deraadt <deraadt@openbsd.org>
|
Theo de Raadt <deraadt@openbsd.org> Theo Deraadt <deraadt@openbsd.org>
|
||||||
Theo de Raadt <deraadt@openbsd.org> deraadt <deraadt>
|
Theo de Raadt <deraadt@openbsd.org> deraadt <deraadt>
|
||||||
Thomas Adam <thomas@xteddy.org> Thomas <thomas@xteddy.org>
|
Thomas Adam <thomas@xteddy.org> Thomas <thomas@xteddy.org>
|
||||||
|
Thomas Adam <thomas@xteddy.org> Thomas Adam <thomas.adam22@gmail.com>
|
||||||
Thomas Adam <thomas@xteddy.org> Thomas Adam <thomas.adam@smoothwall.net>
|
Thomas Adam <thomas@xteddy.org> Thomas Adam <thomas.adam@smoothwall.net>
|
||||||
Thomas Adam <thomas@xteddy.org> n6tadam <n6tadam@xteddy.org>
|
Thomas Adam <thomas@xteddy.org> n6tadam <n6tadam@xteddy.org>
|
||||||
Tim van der Molen <tim@openbsd.org> tim <tim>
|
Tim van der Molen <tim@openbsd.org> tim <tim>
|
||||||
|
|||||||
576
CHANGES
576
CHANGES
@@ -1,3 +1,575 @@
|
|||||||
|
CHANGES FROM 3.7 to 3.7a
|
||||||
|
|
||||||
|
* Fix crash in break-pane when no name is provided.
|
||||||
|
|
||||||
|
* Scrollbar options are now cached rather than being looked up for every redraw
|
||||||
|
(issue 5298).
|
||||||
|
|
||||||
|
* Only forbid #( in names, allow #[, empty names, : and .
|
||||||
|
|
||||||
|
CHANGES FROM 3.6b TO 3.7
|
||||||
|
|
||||||
|
* Add floating panes. These are panes which sit above the layout ("tiled
|
||||||
|
panes") like popups but unlike popups are not modal and behave like panes (so
|
||||||
|
the same escape sequence support). Floating panes are created with the
|
||||||
|
new-pane command, bound to * by default.
|
||||||
|
|
||||||
|
This is an early release of this feature and they are relatively limited.
|
||||||
|
Currently floating panes can only be moved and resized using the mouse. The
|
||||||
|
default second status line (if status-format is set to 2) has changed to show
|
||||||
|
a list of panes. Many obvious features are not yet available for floating
|
||||||
|
panes (notably the ability to swap floating panes, resize them using
|
||||||
|
resize-pane, change them between floating and tiles, and restore custom
|
||||||
|
layouts with floating panes).
|
||||||
|
|
||||||
|
Mostly written by Michael Grant with help from Dane Jensen; testing and fixes
|
||||||
|
from others.
|
||||||
|
|
||||||
|
* Allow run-shell arguments after a shell command to be expanded as #{1}, #{2}
|
||||||
|
and so on (from Rasmus Thystrup Karstensen in issue 5121).
|
||||||
|
|
||||||
|
* Add -g to kill-session to kill all sessions in a session group (issue 5157
|
||||||
|
from github at jiku dot jp).
|
||||||
|
|
||||||
|
* Tighten up read-only checks on attach-session, detach-client and
|
||||||
|
switch-client so that a user should be able to only detach their own client
|
||||||
|
(reported by John Walker).
|
||||||
|
|
||||||
|
* Increase escape delay if the buffer contains a partial paste end, fixes
|
||||||
|
issues with at least Windows Terminal (from jing dot empty at gmail.com issue
|
||||||
|
5088).
|
||||||
|
|
||||||
|
* When mode-keys is set to vi, do not allow the cursor to go into the invisible
|
||||||
|
extra cell to the right of the visible text; this is closer to what vi(1)
|
||||||
|
does (from Max Vim in issue 5070).
|
||||||
|
|
||||||
|
* Add a five second limit on pasting for terminals which mysteriously lose the
|
||||||
|
end sequence if the paste is too big (that is, Terminal.app) (reported by
|
||||||
|
Garri Djavadyan in issue 4527).
|
||||||
|
|
||||||
|
* Show file open errors more sensibly (reported by Meriel Luna Mittelbach in
|
||||||
|
issue 5081).
|
||||||
|
|
||||||
|
* Update supported features list for Foot terminal (from Meriel Luna Mittelbach
|
||||||
|
in issue 5079).
|
||||||
|
|
||||||
|
* Turn off the "is this a paste" guessing if the terminal supports bracket
|
||||||
|
pasting instead (issue 5031).
|
||||||
|
|
||||||
|
* Check FIONREAD for all panes not just piped panes.
|
||||||
|
|
||||||
|
* Add emacs-style recentre-top-bottom command to copy mode (issue 5053 from
|
||||||
|
sinyax75 at gmail dot com).
|
||||||
|
|
||||||
|
* Allow the indicator in tree mode to be customized by two new options:
|
||||||
|
tree-mode-preview-format and tree-mode-preview-style.
|
||||||
|
|
||||||
|
* Fix control client hang on exit after toggling no-output (issue 5049 from
|
||||||
|
Aaron Campbell). Also various other control mode fixes.
|
||||||
|
|
||||||
|
* Add support for line numbers in copy mode. There is a new
|
||||||
|
copy-mode-line-numbers option which may be set to off, default (tmux's normal
|
||||||
|
line numbering where 0 is the top visible line), absolute (first line in
|
||||||
|
history is 1), relative (relative to the cursor) and hybrid (current line is
|
||||||
|
absolute, others relative). Also adds copy-mode-line-number-style and
|
||||||
|
copy-mode-current-line-number-style to set the style of the line numbers.
|
||||||
|
When copy mode is entered with the mouse, line numbers stay off. From Leo
|
||||||
|
Henon in issue 5025.
|
||||||
|
|
||||||
|
* Make C-[ have the same bindings as Escape for terminals with extended
|
||||||
|
keys where they are different (issue 5035 from Eric Nicolas).
|
||||||
|
|
||||||
|
* Sanitize paste buffer names in paste_set and paste_rename (issue 5032 from
|
||||||
|
Barrett Ruth).
|
||||||
|
|
||||||
|
* Do not hang in run-shell when job_run fails (from Barrett Ruth in issue
|
||||||
|
5037).
|
||||||
|
|
||||||
|
* Add ability to forward progress bar to outside terminal (issue 4972
|
||||||
|
from Eric Dorland).
|
||||||
|
|
||||||
|
* Translate keypad keys to text in prompt input (from Barrett Ruth in issue
|
||||||
|
4996).
|
||||||
|
|
||||||
|
* Sanitize pane titles and window and session names more consistently and
|
||||||
|
strictly, prevents C0 characters and other invisible characters causing
|
||||||
|
problems (reported by Chris Monardo in issue 4999).
|
||||||
|
|
||||||
|
* Make clock visible on terminals without colours (from Manuel Einfalt in issue
|
||||||
|
5001).
|
||||||
|
|
||||||
|
* Add detach to default session menu (suggested by Przemyslaw Sztoch).
|
||||||
|
|
||||||
|
* Include window format variables for pane notifications (issue 5007 from Saul
|
||||||
|
Nogueras).
|
||||||
|
|
||||||
|
* Limit precision to 100 for formats to stop silly formats from running out of
|
||||||
|
memory, reported by z1281552865 at gmail dot com. Also various other similar
|
||||||
|
changes, mostly found by OSS-Fuzz.
|
||||||
|
|
||||||
|
* Add WAYLAND_DISPLAY to default update-environment (issue 4965). Also some
|
||||||
|
additional XDG_* variables (issue 5169).
|
||||||
|
|
||||||
|
* Add -C flag to command-prompt to match display-message -C (do not freeze
|
||||||
|
panes) (from Barrett Ruth in issue 4978).
|
||||||
|
|
||||||
|
* Cache user from getpwuid because it can be very expensive on some
|
||||||
|
platforms (from Ben Maurer in issue 4973).
|
||||||
|
|
||||||
|
* Add remain-on-exit key to keep pane around until a key is pressed (from
|
||||||
|
Michael Grant).
|
||||||
|
|
||||||
|
* Add some new mouse ranges called "control0" to "control9" and use to add some
|
||||||
|
mouse controls to the pane state line (from Dane Jensen with some bits from
|
||||||
|
Michael Grant).
|
||||||
|
|
||||||
|
* Handle OSC 9;4 progress bar sequence and store in format variables (from Eric
|
||||||
|
Dorland in issue 4954).
|
||||||
|
|
||||||
|
* Correctly size buffer used for parsing clipboard sequences (from Michal
|
||||||
|
Majchrowicz).
|
||||||
|
|
||||||
|
* Limit MSG_COMMAND argument to between 0 and 1000 to prevent a misbehaving
|
||||||
|
client from crashing the server (from Michal Majchrowicz).
|
||||||
|
|
||||||
|
* Reorganize host keys are represented internally so they can be built more
|
||||||
|
easily (from Dane Jensen in issue 4953).
|
||||||
|
|
||||||
|
* Add new fuzzers for command parsing, formats and styles (from David
|
||||||
|
Korczynski in issue 4957). Also fix various issues shown from these.
|
||||||
|
|
||||||
|
* Add bracket_paste_flag format flag (from George Nachman in issue 4951).
|
||||||
|
|
||||||
|
* Use \- for hyphens in tmux.1 to cause newer groff versions to render them
|
||||||
|
correctly (from Keith Thompson in issue 4948).
|
||||||
|
|
||||||
|
* Various minor code improvements and fixes from Pavel Lavrukhin (issue 4936
|
||||||
|
and others).
|
||||||
|
|
||||||
|
* Use window options for cursor-style to avoid crash when no pane (from Arden
|
||||||
|
Packeer in issue 4942).
|
||||||
|
|
||||||
|
* Fix issue where popup window gets overwritten by background updates (from
|
||||||
|
Conor Taylor in issue 4920).
|
||||||
|
|
||||||
|
* Protect against overflow when scrollbar is off screen (from san65384 at gmail
|
||||||
|
dot com in issue 4933).
|
||||||
|
|
||||||
|
* Copy hyperlinks when redrawing popup so they do not vanish (from Antoine
|
||||||
|
Gaudreau Simard in issue 4925).
|
||||||
|
|
||||||
|
* Work around systemd killing panes early during system shutdown by creating
|
||||||
|
dependencies from the panes to the service which started tmux (issue 4926
|
||||||
|
from Dmitry Torokhov).
|
||||||
|
|
||||||
|
* Allow codepoint-widths to accept ranges (from san65384 at gmail dot com in
|
||||||
|
issue 4930).
|
||||||
|
|
||||||
|
* Add a short builtin help text for each mode accessible with C-h (based on
|
||||||
|
code from Patrick Motard in issue 4751).
|
||||||
|
|
||||||
|
* Draw message as one format, allowing prompts and messages to occupy only a
|
||||||
|
portion of the status bar, overlaying the normal status content rather than
|
||||||
|
replacing the entire line. A new message-format option now controls the
|
||||||
|
entire message (like status-format). The message-style option now need to
|
||||||
|
include "fill" in order to cover the whole width (the default has
|
||||||
|
"fill=yellow"). From Conor Taylor in issue 4861.
|
||||||
|
|
||||||
|
* Add next/previous variables for windows in W: loop (from Conor Taylor in
|
||||||
|
issue 4856).
|
||||||
|
|
||||||
|
* Various bug and memory leak fixes from Renaud Allard (issue 4916).
|
||||||
|
|
||||||
|
* Add pane_pipe_pid with pipe file descriptor.
|
||||||
|
|
||||||
|
* Make -c work with new-session -A (from Jody Frankowski in issue 4906).
|
||||||
|
|
||||||
|
* Allow copy mode to work for readonly clients, except for copy commands (from
|
||||||
|
Dane Jensen).
|
||||||
|
|
||||||
|
* Pass paste buffer through vis(3) when pasting to prevent buffers containing
|
||||||
|
for example the bracket end sequence causing issues, a new -S flag disables
|
||||||
|
(reported by Mason Davis).
|
||||||
|
|
||||||
|
* Add sorting (-O flag) and a custom format (-F) to list-keys (from Dane Jensen
|
||||||
|
in issue 4845).
|
||||||
|
|
||||||
|
* Add scroll-exit-on, scroll-exit-off, scroll-exit-toggle commands to copy mode
|
||||||
|
(from xcdnlgd at hotmail dot com in issue 4884).
|
||||||
|
|
||||||
|
* Respond to DECRQM 2026 (from David Turnbull in issue 4887) and various others
|
||||||
|
(from Ayman Bagabas in issue 5118).
|
||||||
|
|
||||||
|
* Fix various memory leaks reported by Huihui Huang (issue 4872).
|
||||||
|
|
||||||
|
* Pass which clipboard is set through to the terminal (from Axel Lindskog in
|
||||||
|
issue 4858).
|
||||||
|
|
||||||
|
* Reuse extended entry when clearing RGB cell, to prevent memory growth when
|
||||||
|
cells are repeatedly cleared (from Michael K Darling in issue 4862).
|
||||||
|
|
||||||
|
* Do not write before buffer when parsing empty clipboard or palette replies,
|
||||||
|
or try to allocate zero bytes with an empty clipboard sequence (reported by
|
||||||
|
DongHan Kim).
|
||||||
|
|
||||||
|
* Various bug fixes and code improvements from Conor Taylor (issue 4848).
|
||||||
|
|
||||||
|
* Clear search counts when clearing marks in case of repeated search (reported
|
||||||
|
by Daniel Pereira in issue 4817).
|
||||||
|
|
||||||
|
* Make OSC 52 work in popups (from gogongxt at 163 dot com in issue 4797).
|
||||||
|
|
||||||
|
* Refresh copy mode when style changes (from Josh Cooper in issue 4830).
|
||||||
|
|
||||||
|
* Make sorting code common and add -O for sorting to the list commands (from
|
||||||
|
Dane Jensen in issue 4813).
|
||||||
|
|
||||||
|
* Do not treat cells as empty unless the background colour stays the same,
|
||||||
|
fixes invisible clock in clock mode (reported by Theo Buehler).
|
||||||
|
|
||||||
|
* When history-limit is changed, apply to existing panes, not just new
|
||||||
|
ones (issue 4705).
|
||||||
|
|
||||||
|
* Reevaluate menu and popup styles on each draw to allow them to change when
|
||||||
|
options change (from Josh Cooper in issues 4828 and 4829).
|
||||||
|
|
||||||
|
* Handle theme keys earlier so they are processed even if a popup is open (from
|
||||||
|
Josh Cooper in issue 4827).
|
||||||
|
|
||||||
|
* Fix window-size=latest not resizing on switch-client in session groups (from
|
||||||
|
Ilya Grigoriev in issue 4818).
|
||||||
|
|
||||||
|
* Add -e flag to command-prompt to close if empty (from Dane Jensen in issue
|
||||||
|
4812).
|
||||||
|
|
||||||
|
* Correctly draw indicators when pane-border-indicators is set to both
|
||||||
|
(reported by Ilya Grigoriev in issue 4780).
|
||||||
|
|
||||||
|
* Remember last pane or type of location for double and triple clicks and
|
||||||
|
correctly handle it changes between first and second or second and third
|
||||||
|
(issue 4795 from Shaobo Song).
|
||||||
|
|
||||||
|
* Add paste to the default pane menu (issue 4763).
|
||||||
|
|
||||||
|
* Reduce request timeout to 500 milliseconds to match the extended escape-time,
|
||||||
|
and discard palette requests if receiving a reply for a different index.
|
||||||
|
|
||||||
|
* Extend escape timeout if there are active forwarded requests not just
|
||||||
|
tmux's own requests (issue 4793).
|
||||||
|
|
||||||
|
* Correct redrawing of wide characters when overwritten (reported by Jake
|
||||||
|
Stewart in issue 4737).
|
||||||
|
|
||||||
|
* If cannot find a terminator for palette responses, treat as a partial key not
|
||||||
|
complete (issue 4749).
|
||||||
|
|
||||||
|
* Do not send theme unless it has changed, and do not send immediately when
|
||||||
|
updates are enabled (issue 5787).
|
||||||
|
|
||||||
|
* Do not use ;;s in list-keys output as it is confusing and cannot be
|
||||||
|
parsed on input (from Patrick Motard in issue 4750).
|
||||||
|
|
||||||
|
* Redraw pane borders when entering or leaving alternate screen (from Mike
|
||||||
|
Jonkmans in issue 4788).
|
||||||
|
|
||||||
|
* Add focus-follows-mouse option (from Barry Wasdell in issue 4771).
|
||||||
|
|
||||||
|
* Add selection_mode format variable for copy mode (from Mike Jonkmans in issue
|
||||||
|
4773).
|
||||||
|
|
||||||
|
* Add prompt-command-cursor-style (from Joshua Cooper in issue 4765).
|
||||||
|
|
||||||
|
* With status-keys vi, move the cursor left by one when pressing Escape to
|
||||||
|
enter command mode, like vi (issue 4767 from Joshua Cooper).
|
||||||
|
|
||||||
|
* Add {current}/{active} for -t for current window or active pane (from Manuel
|
||||||
|
Einfalt, issue 4766).
|
||||||
|
|
||||||
|
* Add support for applications to use synchronized output mode (DECSET 2026) to
|
||||||
|
prevent screen tearing during rapid updates (from Chris Lloyd in issue 4744).
|
||||||
|
|
||||||
|
* Do not set a default prompt cursor colour because some terminals (urxvt, st)
|
||||||
|
do not support the reset sequence (issue 4759).
|
||||||
|
|
||||||
|
* Add a scroll-to-mouse command for copy mode to scroll to the mouse position
|
||||||
|
and bind to the scrollbar, brings the scrollbar keys into line with the other
|
||||||
|
mouse keys (from Michael Grant in issue 4731).
|
||||||
|
|
||||||
|
* Bump the maximum number of SIXEL images to 20.
|
||||||
|
|
||||||
|
* Fix key code for M-BSpace (issue 4717).
|
||||||
|
|
||||||
|
* Fix calculation of scaled SIXEL size (from nincsnevem662 at gmail dot com in
|
||||||
|
issue 4739). Also various other fixes and improvements for SIXEL.
|
||||||
|
|
||||||
|
* Fix a race between fork and pane_current_path, most noticeable on systems
|
||||||
|
where starting processes is slow (issue 4719).
|
||||||
|
|
||||||
|
* Fix mouse position calculation on scrollbar with pane status line at the top
|
||||||
|
(issue 4738 from Michael Grant).
|
||||||
|
|
||||||
|
* Do not read outside buffer if format is a single #, and do not loop forever
|
||||||
|
if UTF-8 is unfinished in a format (reported by Giorgi Kobakhia in issue
|
||||||
|
4735).
|
||||||
|
|
||||||
|
* Add a missing skin tone character (from Jake Stewart in issue 4736).
|
||||||
|
|
||||||
|
* Allow UTF-8 characters to be combined in either order (reported by Jake
|
||||||
|
Stewart in issue 4726).
|
||||||
|
|
||||||
|
* Do not show scrollbar when entering copy mode from a pane in the alternate
|
||||||
|
screen (issue 4728 from Michael Grant).
|
||||||
|
|
||||||
|
* Fix the size calculation for left-right windows used to spread out cells
|
||||||
|
horizontally evenly (from Michael Grant in issue 4724).
|
||||||
|
|
||||||
|
* Add a get-clipboard option which when enabled (the default is off) and a
|
||||||
|
clipboard is requested from a pane, requests it from the terminal and
|
||||||
|
forwards to the requesting pane; also remove the now-redundant
|
||||||
|
forward-to-pane ability from "refresh-client -l" (issue 4275).
|
||||||
|
|
||||||
|
* Fix the noattr attribute in styles, used by the default mode-style (issue
|
||||||
|
4713).
|
||||||
|
|
||||||
|
* Do not remove TERM for commands run from config file (regression reported by
|
||||||
|
Dennis Eriksen).
|
||||||
|
|
||||||
|
* Add seconds options for clock mode (from augustus7613 dot mail at pm dot me,
|
||||||
|
issue 4697; later improved by Joao Pedro in issue 4760).
|
||||||
|
|
||||||
|
CHANGES FROM 3.6a TO 3.6b
|
||||||
|
|
||||||
|
* Remove images from the correct list when they are removed while in the
|
||||||
|
alternate screen (reported by xlabai at tencent dot com).
|
||||||
|
|
||||||
|
CHANGES FROM 3.6 TO 3.6a
|
||||||
|
|
||||||
|
* Fix a buffer overread and an infinite loop in format processing (reported by
|
||||||
|
Giorgi Kobakhia, issue 4735).
|
||||||
|
|
||||||
|
* Allow drag in alternate screen again (issue 4743 reported by Brad King).
|
||||||
|
|
||||||
|
* Fix y offset of mouse if status at top (issue 4738 from Michael Grant).
|
||||||
|
|
||||||
|
* Add a missing skin tone (from Jake Stewart, issue 4736).
|
||||||
|
|
||||||
|
* Allow characters to be combined in either order (issue 4726, reported by Jake
|
||||||
|
Stewart).
|
||||||
|
|
||||||
|
* Fix horizontal mouse resizing when pane status lines are on (from Michael
|
||||||
|
Grant, issue 4720).
|
||||||
|
|
||||||
|
* Fix noattr so it does not delete attributes set in the style itself (issue
|
||||||
|
4713).
|
||||||
|
|
||||||
|
* Newer libevents do not allow event_del on a zero'd event (issue 4706).
|
||||||
|
|
||||||
|
* Place cursor on correct line if message-line is not 0 (issue 4707).
|
||||||
|
|
||||||
|
* Fix compile error on FreeBSD (from Yasuhiro Kimura, issue 4701).
|
||||||
|
|
||||||
|
CHANGES FROM 3.5a TO 3.6
|
||||||
|
|
||||||
|
* Add seconds options for clock mode (issue 4697).
|
||||||
|
|
||||||
|
* Add a resize callback for menus so that they are correctly moved on resize
|
||||||
|
(issue 4696).
|
||||||
|
|
||||||
|
* Make -v to source-file pass through to subsequent source-file commands (issue
|
||||||
|
4216).
|
||||||
|
|
||||||
|
* If display-popup is used inside a popup, modify that popup (issue 4678).
|
||||||
|
|
||||||
|
* Add selection-mode command to expilcitly set the selection mode in copy mode
|
||||||
|
(issue 3842).
|
||||||
|
|
||||||
|
* Save and restore images in alternate screen (issue 3732).
|
||||||
|
|
||||||
|
* Ignore Hangul filler character (issue 3998).
|
||||||
|
|
||||||
|
* Improve handling of regional indicators and emoji modifiers (issue 3998).
|
||||||
|
|
||||||
|
* Preserve marked pane with swap-window and move-window (issue 3443).
|
||||||
|
|
||||||
|
* Set and check COLORTERM as a hint for RGB colour.
|
||||||
|
|
||||||
|
* If tmux receives a palette request (OSC 4) in a pane and the palette entry
|
||||||
|
has not been set, send a request to the most recently used client and
|
||||||
|
forward any response instead (based on change from Tim Culverhouse, issue
|
||||||
|
4665).
|
||||||
|
|
||||||
|
* Add -l flag to command-prompt to disable splitting into multiple prompts
|
||||||
|
(issue 4483).
|
||||||
|
|
||||||
|
* Don't enter copy mode on mouse wheel in alternate screen (issue 3705).
|
||||||
|
|
||||||
|
* Add commands to centre the cursor in copy mode (issue 4662).
|
||||||
|
|
||||||
|
* Support case insensitive search in modes in the same way as copy mode
|
||||||
|
(like emacs, so all-lowercase means case insensitive) (issue 4396).
|
||||||
|
|
||||||
|
* Fix the logic of the no-detached case for the detach-on-destroy option (from
|
||||||
|
Martin Louazel, issue 4649).
|
||||||
|
|
||||||
|
* Add buffer_full format variable (from Mohammad AlSaleh, issue 4630).
|
||||||
|
|
||||||
|
* Introduce a new window option, tiled-layout-max-columns, which configures the
|
||||||
|
maximum number of columns in the tiled layout.
|
||||||
|
|
||||||
|
* Add support for DECRQSS SP q (report cursor style), DECRQM ?12 (report cursor
|
||||||
|
blink state) and DECRQM ?2004, ?1004, ?1006 (report mouse state) ( rom
|
||||||
|
Andrea Alberti, issue 4618).
|
||||||
|
|
||||||
|
* Fix missing argument from OSC 4 reply (issue 4596).
|
||||||
|
|
||||||
|
* Add -k flag to display-popup which allows any key to dismiss the popup once
|
||||||
|
the command has exited (from Meriel Luna Mittelbach, issue 4612).
|
||||||
|
|
||||||
|
* Add nicer default second and third status lines (from Michael Grant, issue
|
||||||
|
4490).
|
||||||
|
|
||||||
|
* Add a pane-border-lines "spaces" value to use spaces for pane borders (issue
|
||||||
|
4587).
|
||||||
|
|
||||||
|
* Replace invalid UTF-8 characters with the placeholder instead of ignoring
|
||||||
|
them (issue 4514).
|
||||||
|
|
||||||
|
* Fix incorrect handling of Korean Hangul Jamo characters (from Roy Jung, issue
|
||||||
|
4546).
|
||||||
|
|
||||||
|
* Allow uppercase letters in gray/grey color names (from Pavel Roskin, issue
|
||||||
|
4560).
|
||||||
|
|
||||||
|
* Add sorting to W, P, L loop operators (from Michael Grant, issue 4516).
|
||||||
|
|
||||||
|
* Detect support for OSC 52 using the device attributes report (from James
|
||||||
|
Holderness, issue 4539).
|
||||||
|
|
||||||
|
* Add noattr for styles and use in mode-style to allow whether attributes are
|
||||||
|
ignored or used to be configured (issue 4498).
|
||||||
|
|
||||||
|
* Add a set-default style attribute which replaces the current default colours
|
||||||
|
and attributes completely.
|
||||||
|
|
||||||
|
* Add -E to run-shell to forward stderr as well as stdout (issue 4246).
|
||||||
|
|
||||||
|
* Add an option variation-selector-always-wide to instruct tmux not to
|
||||||
|
always interpret VS16 as a wide character and assume the terminal does
|
||||||
|
likewise.
|
||||||
|
|
||||||
|
* Switch to getopt_long from OpenSSH (from Koichi Murase, issue 4492).
|
||||||
|
|
||||||
|
* Add more features for boolean expressions in formats: 1) extend && and || to
|
||||||
|
support arbitrarily many arguments and 2) add ! and !! for not and not-not
|
||||||
|
(from David Mandelberg).
|
||||||
|
|
||||||
|
* Do not mistake other DCS sequences for SIXEL sequences (from James
|
||||||
|
Holderness, issue 4488).
|
||||||
|
|
||||||
|
* Improve #? conditional expression in formats: add support for else if and
|
||||||
|
default empty string if no else value (from David Mandelberg, issue 4451).
|
||||||
|
|
||||||
|
* Add default-client-command to set the command used if tmux is run without a
|
||||||
|
command; the default stays new-session (from David Mandelberg, issue
|
||||||
|
4422).
|
||||||
|
|
||||||
|
* Add S-Up and S-Down to move windows in tree mode (from David Mandelberg,
|
||||||
|
issue 4415).
|
||||||
|
|
||||||
|
* Add mode 2031 support to automatically report dark or light theme. tmux will
|
||||||
|
guess the theme from the background colour on terminals which do not
|
||||||
|
themselves support the escape sequence (from Jonathan Slenders, issue 4353).
|
||||||
|
|
||||||
|
* Add -M flag to capture-pane to use the copy mode screen (issue 4358).
|
||||||
|
|
||||||
|
* Align index numbers in trees (from David Mandelberg, issue 4360).
|
||||||
|
|
||||||
|
* Add display-message -C flag to update pane while message is displayed (from
|
||||||
|
Vitaly Ostrosablin, issue 4363).
|
||||||
|
|
||||||
|
* Make list-commands command show only one command if an argument is given
|
||||||
|
(from Ilya Grigoriev, issue 4352).
|
||||||
|
|
||||||
|
* Count line numbers correctly inside strings in configuration files (reported
|
||||||
|
by Pedro Navarro, issue 4325).
|
||||||
|
|
||||||
|
* Map bright black (colour 8) to white (7) if the background is black on
|
||||||
|
terminals with only eight colours so the text is not invisible (from Dmytro
|
||||||
|
Bagrii, issue 4322).
|
||||||
|
|
||||||
|
* New codepoint-widths option allowing users to override the width of
|
||||||
|
individual Unicode codepoints.
|
||||||
|
|
||||||
|
* Add a nesting limit to source-file (from Fadi Afani, issue 4223).
|
||||||
|
|
||||||
|
* Add copy-mode-position-style and copy-mode-selection-style options for copy
|
||||||
|
mode.
|
||||||
|
|
||||||
|
* Add no-detach-on-destroy client option (issue 4242).
|
||||||
|
|
||||||
|
* Add input-buffer-size option (from Ken Lau).
|
||||||
|
|
||||||
|
* Add support for a scrollbar at the side of each pane. New options
|
||||||
|
pane-scrollbars turn them on or off, pane-scrollbars-position sets the
|
||||||
|
position (left or right), and pane-scrollbars-style to set the colours (from
|
||||||
|
Michael Grant, issue 4221).
|
||||||
|
|
||||||
|
* Allow control characters to be entered at the command prompt by prefixing
|
||||||
|
with C-v (from Alexander Arch, issue 4206).
|
||||||
|
|
||||||
|
* Do not attempt to search for zero length strings (from Alexander Arch, issue
|
||||||
|
4209).
|
||||||
|
|
||||||
|
* Preserve tabs for copying and capture-pane (from Alexander Arch, issue
|
||||||
|
4201).
|
||||||
|
|
||||||
|
* Increase the maximum for repeat-time.
|
||||||
|
|
||||||
|
* Adjust how Ctrl and Meta keys are sent to use standard representation if
|
||||||
|
available in mode 1 (from Stanislav Kljuhhin, issue 4188).
|
||||||
|
|
||||||
|
* Allow attributes in menu style (from Japin Li, issue 4194).
|
||||||
|
|
||||||
|
* Add a sixel_support format variable which is 1 if SIXEL is supported, always
|
||||||
|
0 on OpenBSD (requested by Misaki Masa, issue 4177).
|
||||||
|
|
||||||
|
* Add prompt-cursor-colour and prompt-cursor-style to set the style of the
|
||||||
|
cursor in the command prompt and remove the emulated cursor (from Alexander
|
||||||
|
Arch, issue 4170).
|
||||||
|
|
||||||
|
* Add initial-repeat-time option to allow the first repeat time to be increased
|
||||||
|
and later reduced (from David le Blanc, issue 4164).
|
||||||
|
|
||||||
|
* Send focus events to pane when entering or leaving popup (issue 3991).
|
||||||
|
|
||||||
|
* Add copy-mode-position-format to configure the position indicator.
|
||||||
|
|
||||||
|
* Add -y flag to disable confirmation prompts in modes (issue 4152).
|
||||||
|
|
||||||
|
* Add -C and -P flags to the copy commands in copy mode: -C prevents the
|
||||||
|
commands from sending the text to the clipboard and -P prevents them from
|
||||||
|
adding the text as a paste buffer (issue 4153).
|
||||||
|
|
||||||
|
* Preserve transparency and raster attribute dimensions when sending a SIXEL
|
||||||
|
image, and avoid collapsing empty lines (issue 4149).
|
||||||
|
|
||||||
|
* Bypass permission check for Cygwin (based on a change by Yuya Adachi via
|
||||||
|
Rafael Kitover, issue 4148).
|
||||||
|
|
||||||
|
* Add MSYSTEM to default update-environment (for Cgywin).
|
||||||
|
|
||||||
|
* Set client stdout file descriptor also for Cgywin (from Michael Wild via Rafael
|
||||||
|
Kitover, issue 4148).
|
||||||
|
|
||||||
|
* Use global cursor style and colour options for modes instead of default
|
||||||
|
(issue 4117).
|
||||||
|
|
||||||
|
* Fix pasting so it does not interpret keys but instead copies the input
|
||||||
|
without interpretation (reported by Mark Kelly).
|
||||||
|
|
||||||
|
* Try to query window pixel size from the outside terminal if the values
|
||||||
|
returned by TIOCGWINSZ are zero (Dmitry Galchinsky, issue 4099).
|
||||||
|
|
||||||
CHANGES FROM 3.5 TO 3.5a
|
CHANGES FROM 3.5 TO 3.5a
|
||||||
|
|
||||||
* Do not translate BSpace as Unicode with extended keys.
|
* Do not translate BSpace as Unicode with extended keys.
|
||||||
@@ -8,7 +580,7 @@ CHANGES FROM 3.5 TO 3.5a
|
|||||||
default-shell only applies now to popups.
|
default-shell only applies now to popups.
|
||||||
|
|
||||||
* Fix grey colour without a number suffix in styles.
|
* Fix grey colour without a number suffix in styles.
|
||||||
|
|
||||||
CHANGES FROM 3.4 TO 3.5
|
CHANGES FROM 3.4 TO 3.5
|
||||||
|
|
||||||
* Revamp extended keys support to more closely match xterm and support mode 2
|
* Revamp extended keys support to more closely match xterm and support mode 2
|
||||||
@@ -400,7 +972,7 @@ CHANGES FROM 3.2 TO 3.2a
|
|||||||
* Do not expand the filename given to -f so it can contain colons.
|
* Do not expand the filename given to -f so it can contain colons.
|
||||||
|
|
||||||
* Fixes for problems with extended keys and modifiers, scroll region,
|
* Fixes for problems with extended keys and modifiers, scroll region,
|
||||||
source-file, crosscompiling, format modifiers and other minor issues.
|
source-file, cross compiling, format modifiers and other minor issues.
|
||||||
|
|
||||||
CHANGES FROM 3.1c TO 3.2
|
CHANGES FROM 3.1c TO 3.2
|
||||||
|
|
||||||
|
|||||||
7
COPYING
7
COPYING
@@ -1,9 +1,4 @@
|
|||||||
THIS IS FOR INFORMATION ONLY, CODE IS UNDER THE LICENCE AT THE TOP OF ITS FILE.
|
Copyright (c) Various Authors
|
||||||
|
|
||||||
The README, CHANGES, FAQ and TODO files are licensed under the ISC license. All
|
|
||||||
other files have a license and copyright notice at their start, typically:
|
|
||||||
|
|
||||||
Copyright (c) <author>
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software for any
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
|||||||
47
Makefile.am
47
Makefile.am
@@ -20,21 +20,31 @@ LDADD = $(LIBOBJS)
|
|||||||
|
|
||||||
# Set flags for gcc.
|
# Set flags for gcc.
|
||||||
if IS_GCC
|
if IS_GCC
|
||||||
AM_CFLAGS += -std=gnu99 -O2
|
AM_CFLAGS += -std=gnu99
|
||||||
|
if IS_OPTIMIZED
|
||||||
|
AM_CFLAGS += -O2
|
||||||
|
else
|
||||||
|
AM_CFLAGS += -O0
|
||||||
|
endif
|
||||||
if IS_DEBUG
|
if IS_DEBUG
|
||||||
AM_CFLAGS += -g
|
AM_CFLAGS += -g3 -ggdb
|
||||||
AM_CFLAGS += -Wno-long-long -Wall -W -Wformat=2
|
AM_CFLAGS += -Wno-long-long -Wall -W -Wformat=2 -Wno-use-after-free
|
||||||
AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
|
AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
|
||||||
AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
|
AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
|
||||||
AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
|
AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wno-cast-align
|
||||||
AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
|
AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
|
||||||
AM_CFLAGS += -Wno-unused-result -Wno-format-y2k
|
AM_CFLAGS += -Wno-unused-result -Wno-format-y2k -Wno-unknown-warning-option
|
||||||
|
AM_CFLAGS += -Wno-maybe-uninitialized
|
||||||
if IS_DARWIN
|
if IS_DARWIN
|
||||||
AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align
|
AM_CFLAGS += -Wno-deprecated-declarations -Wno-macro-redefined
|
||||||
endif
|
endif
|
||||||
AM_CPPFLAGS += -DDEBUG
|
AM_CPPFLAGS += -DDEBUG
|
||||||
endif
|
endif
|
||||||
AM_CPPFLAGS += -iquote.
|
AM_CPPFLAGS += -iquote.
|
||||||
|
if IS_ASAN
|
||||||
|
AM_CFLAGS += -fsanitize=address
|
||||||
|
AM_LDFLAGS += -fsanitize=address
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Set flags for Solaris.
|
# Set flags for Solaris.
|
||||||
@@ -66,6 +76,11 @@ if IS_HAIKU
|
|||||||
AM_CPPFLAGS += -D_BSD_SOURCE
|
AM_CPPFLAGS += -D_BSD_SOURCE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Set flags for Cygwin.
|
||||||
|
if IS_CYGWIN
|
||||||
|
AM_CPPFLAGS += -DTMUX_SOCK_PERM=0
|
||||||
|
endif
|
||||||
|
|
||||||
# List of sources.
|
# List of sources.
|
||||||
dist_tmux_SOURCES = \
|
dist_tmux_SOURCES = \
|
||||||
alerts.c \
|
alerts.c \
|
||||||
@@ -95,6 +110,7 @@ dist_tmux_SOURCES = \
|
|||||||
cmd-kill-window.c \
|
cmd-kill-window.c \
|
||||||
cmd-list-buffers.c \
|
cmd-list-buffers.c \
|
||||||
cmd-list-clients.c \
|
cmd-list-clients.c \
|
||||||
|
cmd-list-commands.c \
|
||||||
cmd-list-keys.c \
|
cmd-list-keys.c \
|
||||||
cmd-list-panes.c \
|
cmd-list-panes.c \
|
||||||
cmd-list-sessions.c \
|
cmd-list-sessions.c \
|
||||||
@@ -178,6 +194,7 @@ dist_tmux_SOURCES = \
|
|||||||
server-fn.c \
|
server-fn.c \
|
||||||
server.c \
|
server.c \
|
||||||
session.c \
|
session.c \
|
||||||
|
sort.c \
|
||||||
spawn.c \
|
spawn.c \
|
||||||
status.c \
|
status.c \
|
||||||
style.c \
|
style.c \
|
||||||
@@ -185,6 +202,7 @@ dist_tmux_SOURCES = \
|
|||||||
tmux.h \
|
tmux.h \
|
||||||
tmux-protocol.h \
|
tmux-protocol.h \
|
||||||
tty-acs.c \
|
tty-acs.c \
|
||||||
|
tty-draw.c \
|
||||||
tty-features.c \
|
tty-features.c \
|
||||||
tty-keys.c \
|
tty-keys.c \
|
||||||
tty-term.c \
|
tty-term.c \
|
||||||
@@ -222,10 +240,21 @@ if ENABLE_SIXEL
|
|||||||
dist_tmux_SOURCES += image.c image-sixel.c
|
dist_tmux_SOURCES += image.c image-sixel.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Add bits for fuzzing if enabled.
|
||||||
if NEED_FUZZING
|
if NEED_FUZZING
|
||||||
check_PROGRAMS = fuzz/input-fuzzer
|
check_PROGRAMS = \
|
||||||
|
fuzz/input-fuzzer \
|
||||||
|
fuzz/cmd-parse-fuzzer \
|
||||||
|
fuzz/format-fuzzer \
|
||||||
|
fuzz/style-fuzzer
|
||||||
fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
||||||
fuzz_input_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
fuzz_input_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
||||||
|
fuzz_cmd_parse_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
||||||
|
fuzz_cmd_parse_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
||||||
|
fuzz_format_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
||||||
|
fuzz_format_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
||||||
|
fuzz_style_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
||||||
|
fuzz_style_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Install tmux.1 in the right format.
|
# Install tmux.1 in the right format.
|
||||||
@@ -240,3 +269,7 @@ install-exec-hook:
|
|||||||
$(mkdir_p) $(DESTDIR)$(mandir)/man1
|
$(mkdir_p) $(DESTDIR)$(mandir)/man1
|
||||||
$(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \
|
$(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \
|
||||||
$(DESTDIR)$(mandir)/man1/tmux.1
|
$(DESTDIR)$(mandir)/man1/tmux.1
|
||||||
|
|
||||||
|
# And uninstall it.
|
||||||
|
uninstall-hook:
|
||||||
|
rm -f $(DESTDIR)$(mandir)/man1/tmux.1
|
||||||
|
|||||||
3
README
3
README
@@ -36,6 +36,7 @@ autoconf, automake and pkg-config:
|
|||||||
$ cd tmux
|
$ cd tmux
|
||||||
$ sh autogen.sh
|
$ sh autogen.sh
|
||||||
$ ./configure && make
|
$ ./configure && make
|
||||||
|
$ sudo make install
|
||||||
|
|
||||||
* Contributing
|
* Contributing
|
||||||
|
|
||||||
@@ -65,7 +66,7 @@ Also see the tmux FAQ at:
|
|||||||
|
|
||||||
A bash(1) completion file is at:
|
A bash(1) completion file is at:
|
||||||
|
|
||||||
https://github.com/imomaliev/tmux-bash-completion
|
https://github.com/scop/bash-completion/blob/main/completions/tmux
|
||||||
|
|
||||||
For debugging, run tmux with -v and -vv to generate server and client log files
|
For debugging, run tmux with -v and -vv to generate server and client log files
|
||||||
in the current directory.
|
in the current directory.
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ tmuxのドキュメントについてはtmux.1マニュアルをご覧くださ
|
|||||||
サンプル設定は本リポジトリのexample_tmux.confに
|
サンプル設定は本リポジトリのexample_tmux.confに
|
||||||
また、bash-completionファイルは下記にあります。
|
また、bash-completionファイルは下記にあります。
|
||||||
|
|
||||||
https://github.com/imomaliev/tmux-bash-completion
|
https://github.com/scop/bash-completion/blob/main/completions/tmux
|
||||||
|
|
||||||
「-v」や「-vv」を指定することでデバッグモードでの起動が可能です。カレントディレクトリにサーバーやクライアントのログファイルが生成されます。
|
「-v」や「-vv」を指定することでデバッグモードでの起動が可能です。カレントディレクトリにサーバーやクライアントのログファイルが生成されます。
|
||||||
|
|
||||||
|
|||||||
32
SYNCING
32
SYNCING
@@ -1,17 +1,17 @@
|
|||||||
Preamble
|
Preamble
|
||||||
========
|
========
|
||||||
|
|
||||||
Tmux portable relies on repositories "tmux" and "tmux-openbsd".
|
Tmux portable relies on repositories "tmux" and "tmux-obsd".
|
||||||
Here's a description of them:
|
Here's a description of them:
|
||||||
|
|
||||||
* "tmux" is the portable version, the one which contains code for other
|
* "tmux" is the portable version, the one which contains code for other
|
||||||
operating systems, and autotools, etc., which isn't found or needed in the
|
operating systems, and autotools, etc., which isn't found or needed in the
|
||||||
OpenBSD base system.
|
OpenBSD base system.
|
||||||
|
|
||||||
* "tmux-openbsd" is the version of tmux in OpenBSD base system which provides
|
* "tmux-obsd" is the version of tmux in OpenBSD base system which provides
|
||||||
the basis of the portable tmux version.
|
the basis of the portable tmux version.
|
||||||
|
|
||||||
Note: The "tmux-openbsd" repository is actually handled by "git cvsimport"
|
Note: The "tmux-obsd" repository is actually handled by "git cvsimport"
|
||||||
running at 15 minute intervals, so a commit made to OpenBSD's tmux CVS
|
running at 15 minute intervals, so a commit made to OpenBSD's tmux CVS
|
||||||
repository will take at least that long to appear in this git repository.
|
repository will take at least that long to appear in this git repository.
|
||||||
(It might take longer, depending on the CVS mirror used to import the
|
(It might take longer, depending on the CVS mirror used to import the
|
||||||
@@ -34,11 +34,11 @@ this information has ever been set before.
|
|||||||
Cloning repositories
|
Cloning repositories
|
||||||
====================
|
====================
|
||||||
|
|
||||||
This involves having both tmux and tmux-openbsd cloned, as in:
|
This involves having both tmux and tmux-obsd cloned, as in:
|
||||||
|
|
||||||
% cd /some/where/useful
|
% cd /some/where/useful
|
||||||
% git clone https://github.com/tmux/tmux.git
|
% git clone https://github.com/tmux/tmux.git
|
||||||
% git clone https://github.com/ThomasAdam/tmux-openbsd.git
|
% git clone https://github.com/ThomasAdam/tmux-obsd.git
|
||||||
|
|
||||||
Note that you do not need additional checkouts to manage the sync -- an
|
Note that you do not need additional checkouts to manage the sync -- an
|
||||||
existing clone of either repositories will suffice. So if you already have
|
existing clone of either repositories will suffice. So if you already have
|
||||||
@@ -47,30 +47,30 @@ these checkouts existing, skip that.
|
|||||||
Adding in git-remotes
|
Adding in git-remotes
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
Because the portable "tmux" git repository and the "tmux-openbsd"
|
Because the portable "tmux" git repository and the "tmux-obsd"
|
||||||
repository do not inherently share any history between each other, the
|
repository do not inherently share any history between each other, the
|
||||||
history has been faked between them. This "faking of history" is something
|
history has been faked between them. This "faking of history" is something
|
||||||
which has to be told to git for the purposes of comparing the "tmux" and
|
which has to be told to git for the purposes of comparing the "tmux" and
|
||||||
"tmux-openbsd" repositories for syncing. To do this, we must reference the
|
"tmux-obsd" repositories for syncing. To do this, we must reference the
|
||||||
clone of the "tmux-openbsd" repository from the "tmux" repository, as
|
clone of the "tmux-obsd" repository from the "tmux" repository, as
|
||||||
shown by the following command:
|
shown by the following command:
|
||||||
|
|
||||||
% cd /path/to/tmux
|
% cd /path/to/tmux
|
||||||
% git remote add obsd-tmux file:///path/to/tmux-openbsd
|
% git remote add obsd-tmux file:///path/to/tmux-obsd
|
||||||
|
|
||||||
So that now, the remote "obsd-tmux" can be used to reference branches and
|
So that now, the remote "obsd-tmux" can be used to reference branches and
|
||||||
commits from the "tmux-openbsd" repository, but from the context of the
|
commits from the "tmux-obsd" repository, but from the context of the
|
||||||
portable "tmux" repository, which makes sense because it's the "tmux"
|
portable "tmux" repository, which makes sense because it's the "tmux"
|
||||||
repository which will have the updates applied to them.
|
repository which will have the updates applied to them.
|
||||||
|
|
||||||
Fetching updates
|
Fetching updates
|
||||||
================
|
================
|
||||||
|
|
||||||
To ensure the latest commits from "tmux-openbsd" can be found from within
|
To ensure the latest commits from "tmux-obsd" can be found from within
|
||||||
"tmux", we have to ensure the "master" branch from "tmux-openbsd" is
|
"tmux", we have to ensure the "master" branch from "tmux-obsd" is
|
||||||
up-to-date first, and then reference that update in "tmux", as in:
|
up-to-date first, and then reference that update in "tmux", as in:
|
||||||
|
|
||||||
% cd /path/to/tmux-openbsd
|
% cd /path/to/tmux-obsd
|
||||||
% git checkout master
|
% git checkout master
|
||||||
% git pull
|
% git pull
|
||||||
|
|
||||||
@@ -82,9 +82,9 @@ Then back in "tmux":
|
|||||||
Creating the necessary branches
|
Creating the necessary branches
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
Now that "tmux" can see commits and branches from "tmux-openbsd" by way
|
Now that "tmux" can see commits and branches from "tmux-obsd" by way
|
||||||
of the remote name "obsd-tmux", we can now create the master branch from
|
of the remote name "obsd-tmux", we can now create the master branch from
|
||||||
"tmux-openbsd" in the "tmux" repository:
|
"tmux-obsd" in the "tmux" repository:
|
||||||
|
|
||||||
% git checkout -b obsd-master obsd-tmux/master
|
% git checkout -b obsd-master obsd-tmux/master
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ Adding in the fake history points
|
|||||||
=================================
|
=================================
|
||||||
|
|
||||||
To tie both the "master" branch from "tmux" and the "obsd-master"
|
To tie both the "master" branch from "tmux" and the "obsd-master"
|
||||||
branch from "tmux-openbsd" together, the fake history points added to the
|
branch from "tmux-obsd" together, the fake history points added to the
|
||||||
"tmux" repository need to be added. To do this, we must add an
|
"tmux" repository need to be added. To do this, we must add an
|
||||||
additional refspec line, as in:
|
additional refspec line, as in:
|
||||||
|
|
||||||
|
|||||||
8
alerts.c
8
alerts.c
@@ -315,11 +315,11 @@ alerts_set_message(struct winlink *wl, const char *type, const char *option)
|
|||||||
if (visual == VISUAL_OFF)
|
if (visual == VISUAL_OFF)
|
||||||
continue;
|
continue;
|
||||||
if (c->session->curw == wl) {
|
if (c->session->curw == wl) {
|
||||||
status_message_set(c, -1, 1, 0, "%s in current window",
|
status_message_set(c, -1, 1, 0, 0,
|
||||||
type);
|
"%s in current window", type);
|
||||||
} else {
|
} else {
|
||||||
status_message_set(c, -1, 1, 0, "%s in window %d", type,
|
status_message_set(c, -1, 1, 0, 0,
|
||||||
wl->idx);
|
"%s in window %d", type, wl->idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ attributes_tostring(int attr)
|
|||||||
if (attr == 0)
|
if (attr == 0)
|
||||||
return ("none");
|
return ("none");
|
||||||
|
|
||||||
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||||
(attr & GRID_ATTR_CHARSET) ? "acs," : "",
|
(attr & GRID_ATTR_CHARSET) ? "acs," : "",
|
||||||
(attr & GRID_ATTR_BRIGHT) ? "bright," : "",
|
(attr & GRID_ATTR_BRIGHT) ? "bright," : "",
|
||||||
(attr & GRID_ATTR_DIM) ? "dim," : "",
|
(attr & GRID_ATTR_DIM) ? "dim," : "",
|
||||||
@@ -45,7 +45,8 @@ attributes_tostring(int attr)
|
|||||||
(attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "",
|
(attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "",
|
||||||
(attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "",
|
(attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "",
|
||||||
(attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "",
|
(attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "",
|
||||||
(attr & GRID_ATTR_OVERLINE) ? "overline," : "");
|
(attr & GRID_ATTR_OVERLINE) ? "overline," : "",
|
||||||
|
(attr & GRID_ATTR_NOATTR) ? "noattr," : "");
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
buf[len - 1] = '\0';
|
buf[len - 1] = '\0';
|
||||||
|
|
||||||
|
|||||||
8
cfg.c
8
cfg.c
@@ -221,10 +221,14 @@ cfg_add_cause(const char *fmt, ...)
|
|||||||
void
|
void
|
||||||
cfg_print_causes(struct cmdq_item *item)
|
cfg_print_causes(struct cmdq_item *item)
|
||||||
{
|
{
|
||||||
u_int i;
|
struct client *c = cmdq_get_client(item);
|
||||||
|
u_int i;
|
||||||
|
|
||||||
for (i = 0; i < cfg_ncauses; i++) {
|
for (i = 0; i < cfg_ncauses; i++) {
|
||||||
cmdq_print(item, "%s", cfg_causes[i]);
|
if (c != NULL && (c->flags & CLIENT_CONTROL))
|
||||||
|
control_write(c, "%%config-error %s", cfg_causes[i]);
|
||||||
|
else
|
||||||
|
cmdq_print(item, "%s", cfg_causes[i]);
|
||||||
free(cfg_causes[i]);
|
free(cfg_causes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
|||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
char *cwd, *cause;
|
char *cwd, *cause;
|
||||||
enum msgtype msgtype;
|
enum msgtype msgtype;
|
||||||
|
uid_t uid;
|
||||||
|
|
||||||
if (RB_EMPTY(&sessions)) {
|
if (RB_EMPTY(&sessions)) {
|
||||||
cmdq_error(item, "no sessions");
|
cmdq_error(item, "no sessions");
|
||||||
@@ -106,8 +107,16 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
|||||||
}
|
}
|
||||||
if (fflag)
|
if (fflag)
|
||||||
server_client_set_flags(c, fflag);
|
server_client_set_flags(c, fflag);
|
||||||
if (rflag)
|
if (rflag) {
|
||||||
|
if (c->flags & CLIENT_READONLY) {
|
||||||
|
uid = proc_get_peer_uid(c->peer);
|
||||||
|
if (uid != getuid()) {
|
||||||
|
cmdq_error(item, "client is read-only");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
c->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
|
c->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
|
||||||
|
}
|
||||||
|
|
||||||
c->last_session = c->session;
|
c->last_session = c->session;
|
||||||
if (c->session != NULL) {
|
if (c->session != NULL) {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const struct cmd_entry cmd_bind_key_entry = {
|
|||||||
|
|
||||||
.args = { "nrN:T:", 1, -1, cmd_bind_key_args_parse },
|
.args = { "nrN:T:", 1, -1, cmd_bind_key_args_parse },
|
||||||
.usage = "[-nr] [-T key-table] [-N note] key "
|
.usage = "[-nr] [-T key-table] [-N note] key "
|
||||||
"[command [arguments]]",
|
"[command [argument ...]]",
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK,
|
.flags = CMD_AFTERHOOK,
|
||||||
.exec = cmd_bind_key_exec
|
.exec = cmd_bind_key_exec
|
||||||
|
|||||||
@@ -58,9 +58,14 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct session *dst_s = target->s;
|
struct session *dst_s = target->s;
|
||||||
struct window_pane *wp = source->wp;
|
struct window_pane *wp = source->wp;
|
||||||
struct window *w = wl->window;
|
struct window *w = wl->window;
|
||||||
char *name, *cause, *cp;
|
char *newname, *cause, *cp;
|
||||||
int idx = target->idx, before;
|
int idx = target->idx, before;
|
||||||
const char *template;
|
const char *template, *name = args_get(args, 'n');
|
||||||
|
|
||||||
|
if (name != NULL && !check_name(name)) {
|
||||||
|
cmdq_error(item, "invalid window name: %s", name);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
before = args_has(args, 'b');
|
before = args_has(args, 'b');
|
||||||
if (args_has(args, 'a') || before) {
|
if (args_has(args, 'a') || before) {
|
||||||
@@ -73,19 +78,22 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
server_unzoom_window(w);
|
server_unzoom_window(w);
|
||||||
|
|
||||||
if (window_count_panes(w) == 1) {
|
if (window_count_panes(w, 1) == 1) {
|
||||||
if (server_link_window(src_s, wl, dst_s, idx, 0,
|
if (server_link_window(src_s, wl, dst_s, idx, 0,
|
||||||
!args_has(args, 'd'), &cause) != 0) {
|
!args_has(args, 'd'), &cause) != 0) {
|
||||||
cmdq_error(item, "%s", cause);
|
cmdq_error(item, "%s", cause);
|
||||||
free(cause);
|
free(cause);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
if (args_has(args, 'n')) {
|
if (name != NULL) {
|
||||||
window_set_name(w, args_get(args, 'n'));
|
window_set_name(w, name, 0);
|
||||||
options_set_number(w->options, "automatic-rename", 0);
|
options_set_number(w->options, "automatic-rename", 0);
|
||||||
}
|
}
|
||||||
server_unlink_window(src_s, wl);
|
server_unlink_window(src_s, wl);
|
||||||
return (CMD_RETURN_NORMAL);
|
wl = winlink_find_by_window(&dst_s->windows, w);
|
||||||
|
if (wl == NULL)
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
|
if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
|
||||||
cmdq_error(item, "index in use: %d", idx);
|
cmdq_error(item, "index in use: %d", idx);
|
||||||
@@ -93,23 +101,25 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TAILQ_REMOVE(&w->panes, wp, entry);
|
TAILQ_REMOVE(&w->panes, wp, entry);
|
||||||
|
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||||
server_client_remove_pane(wp);
|
server_client_remove_pane(wp);
|
||||||
window_lost_pane(w, wp);
|
window_lost_pane(w, wp);
|
||||||
layout_close_pane(wp);
|
layout_close_pane(wp);
|
||||||
|
|
||||||
w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel);
|
w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel);
|
||||||
options_set_parent(wp->options, w->options);
|
options_set_parent(wp->options, w->options);
|
||||||
wp->flags |= PANE_STYLECHANGED;
|
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
|
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
|
||||||
|
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||||
w->active = wp;
|
w->active = wp;
|
||||||
w->latest = tc;
|
w->latest = tc;
|
||||||
|
|
||||||
if (!args_has(args, 'n')) {
|
if (name == NULL) {
|
||||||
name = default_window_name(w);
|
newname = default_window_name(w);
|
||||||
window_set_name(w, name);
|
window_set_name(w, newname, 0);
|
||||||
free(name);
|
free(newname);
|
||||||
} else {
|
} else {
|
||||||
window_set_name(w, args_get(args, 'n'));
|
window_set_name(w, name, 0);
|
||||||
options_set_number(w->options, "automatic-rename", 0);
|
options_set_number(w->options, "automatic-rename", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,6 +142,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (src_s != dst_s)
|
if (src_s != dst_s)
|
||||||
server_status_session_group(dst_s);
|
server_status_session_group(dst_s);
|
||||||
|
|
||||||
|
out:
|
||||||
if (args_has(args, 'P')) {
|
if (args_has(args, 'P')) {
|
||||||
if ((template = args_get(args, 'F')) == NULL)
|
if ((template = args_get(args, 'F')) == NULL)
|
||||||
template = BREAK_PANE_TEMPLATE;
|
template = BREAK_PANE_TEMPLATE;
|
||||||
|
|||||||
@@ -29,18 +29,21 @@
|
|||||||
|
|
||||||
static enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmdq_item *);
|
static enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmdq_item *);
|
||||||
|
|
||||||
static char *cmd_capture_pane_append(char *, size_t *, char *, size_t);
|
static char *cmd_capture_pane_append(char *, size_t *, const char *,
|
||||||
|
size_t);
|
||||||
static char *cmd_capture_pane_pending(struct args *, struct window_pane *,
|
static char *cmd_capture_pane_pending(struct args *, struct window_pane *,
|
||||||
size_t *);
|
size_t *);
|
||||||
static char *cmd_capture_pane_history(struct args *, struct cmdq_item *,
|
static char *cmd_capture_pane_history(struct args *, struct cmdq_item *,
|
||||||
struct window_pane *, size_t *);
|
struct window_pane *, size_t *);
|
||||||
|
static char *cmd_capture_pane_hyperlinks(struct grid *, struct screen *,
|
||||||
|
u_int, u_int *, u_int *, size_t *);
|
||||||
|
|
||||||
const struct cmd_entry cmd_capture_pane_entry = {
|
const struct cmd_entry cmd_capture_pane_entry = {
|
||||||
.name = "capture-pane",
|
.name = "capture-pane",
|
||||||
.alias = "capturep",
|
.alias = "capturep",
|
||||||
|
|
||||||
.args = { "ab:CeE:JNpPqS:Tt:", 0, 0, NULL },
|
.args = { "ab:CeE:FHJLMNpPqS:Tt:", 0, 0, NULL },
|
||||||
.usage = "[-aCeJNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
|
.usage = "[-aCeFHJLMNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
|
||||||
"[-S start-line] " CMD_TARGET_PANE_USAGE,
|
"[-S start-line] " CMD_TARGET_PANE_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
@@ -63,7 +66,8 @@ const struct cmd_entry cmd_clear_history_entry = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen)
|
cmd_capture_pane_append(char *buf, size_t *len, const char *line,
|
||||||
|
size_t linelen)
|
||||||
{
|
{
|
||||||
buf = xrealloc(buf, *len + linelen + 1);
|
buf = xrealloc(buf, *len + linelen + 1);
|
||||||
memcpy(buf + *len, line, linelen);
|
memcpy(buf + *len, line, linelen);
|
||||||
@@ -103,18 +107,62 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
|
|||||||
return (buf);
|
return (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
cmd_capture_pane_hyperlinks(struct grid *gd, struct screen *s, u_int py,
|
||||||
|
u_int *links, u_int *nlinks, size_t *len)
|
||||||
|
{
|
||||||
|
const struct grid_line *gl = grid_peek_line(gd, py);
|
||||||
|
struct grid_cell gc;
|
||||||
|
const char *uri;
|
||||||
|
char *line = xstrdup("");
|
||||||
|
u_int i, j;
|
||||||
|
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
if (s->hyperlinks == NULL || (~gl->flags & GRID_LINE_HYPERLINK))
|
||||||
|
return (line);
|
||||||
|
|
||||||
|
for (i = 0; i < gl->cellused; i++) {
|
||||||
|
grid_get_cell(gd, i, py, &gc);
|
||||||
|
if (gc.link == 0)
|
||||||
|
continue;
|
||||||
|
for (j = 0; j < *nlinks; j++) {
|
||||||
|
if (links[j] == gc.link)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (j != *nlinks)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!hyperlinks_get(s->hyperlinks, gc.link, &uri, NULL, NULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (*nlinks == gd->sx)
|
||||||
|
break;
|
||||||
|
links[(*nlinks)++] = gc.link;
|
||||||
|
|
||||||
|
if (*len != 0)
|
||||||
|
line = cmd_capture_pane_append(line, len, " ", 1);
|
||||||
|
line = cmd_capture_pane_append(line, len, uri, strlen(uri));
|
||||||
|
}
|
||||||
|
return (line);
|
||||||
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
||||||
struct window_pane *wp, size_t *len)
|
struct window_pane *wp, size_t *len)
|
||||||
{
|
{
|
||||||
struct grid *gd;
|
struct grid *gd;
|
||||||
const struct grid_line *gl;
|
const struct grid_line *gl;
|
||||||
struct grid_cell *gc = NULL;
|
struct screen *s;
|
||||||
int n, join_lines, flags = 0;
|
struct grid_cell *gc = NULL;
|
||||||
u_int i, sx, top, bottom, tmp;
|
struct window_mode_entry *wme;
|
||||||
char *cause, *buf, *line;
|
int n, join_lines, number_lines, flags = 0;
|
||||||
const char *Sflag, *Eflag;
|
int show_flags, hyperlinks;
|
||||||
size_t linelen;
|
u_int *links = NULL, nlinks = 0;
|
||||||
|
u_int i, sx, top, bottom, tmp;
|
||||||
|
char *cause, *buf = NULL, *line, b[64], *cp;
|
||||||
|
const char *Sflag, *Eflag;
|
||||||
|
size_t linelen;
|
||||||
|
|
||||||
sx = screen_size_x(&wp->base);
|
sx = screen_size_x(&wp->base);
|
||||||
if (args_has(args, 'a')) {
|
if (args_has(args, 'a')) {
|
||||||
@@ -126,8 +174,20 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
|||||||
}
|
}
|
||||||
return (xstrdup(""));
|
return (xstrdup(""));
|
||||||
}
|
}
|
||||||
} else
|
s = &wp->base;
|
||||||
|
} else if (args_has(args, 'M')) {
|
||||||
|
wme = TAILQ_FIRST(&wp->modes);
|
||||||
|
if (wme != NULL && wme->mode->get_screen != NULL) {
|
||||||
|
s = wme->mode->get_screen (wme);
|
||||||
|
gd = s->grid;
|
||||||
|
} else {
|
||||||
|
s = &wp->base;
|
||||||
|
gd = wp->base.grid;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s = &wp->base;
|
||||||
gd = wp->base.grid;
|
gd = wp->base.grid;
|
||||||
|
}
|
||||||
|
|
||||||
Sflag = args_get(args, 'S');
|
Sflag = args_get(args, 'S');
|
||||||
if (Sflag != NULL && strcmp(Sflag, "-") == 0)
|
if (Sflag != NULL && strcmp(Sflag, "-") == 0)
|
||||||
@@ -138,7 +198,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
|||||||
if (cause != NULL) {
|
if (cause != NULL) {
|
||||||
top = gd->hsize;
|
top = gd->hsize;
|
||||||
free(cause);
|
free(cause);
|
||||||
} else if (n < 0 && (u_int) -n > gd->hsize)
|
} else if (n < 0 && (u_int)-n > gd->hsize)
|
||||||
top = 0;
|
top = 0;
|
||||||
else
|
else
|
||||||
top = gd->hsize + n;
|
top = gd->hsize + n;
|
||||||
@@ -155,7 +215,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
|||||||
if (cause != NULL) {
|
if (cause != NULL) {
|
||||||
bottom = gd->hsize + gd->sy - 1;
|
bottom = gd->hsize + gd->sy - 1;
|
||||||
free(cause);
|
free(cause);
|
||||||
} else if (n < 0 && (u_int) -n > gd->hsize)
|
} else if (n < 0 && (u_int)-n > gd->hsize)
|
||||||
bottom = 0;
|
bottom = 0;
|
||||||
else
|
else
|
||||||
bottom = gd->hsize + n;
|
bottom = gd->hsize + n;
|
||||||
@@ -178,12 +238,57 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
|||||||
flags |= GRID_STRING_EMPTY_CELLS;
|
flags |= GRID_STRING_EMPTY_CELLS;
|
||||||
if (!join_lines && !args_has(args, 'N'))
|
if (!join_lines && !args_has(args, 'N'))
|
||||||
flags |= GRID_STRING_TRIM_SPACES;
|
flags |= GRID_STRING_TRIM_SPACES;
|
||||||
|
number_lines = args_has(args, 'L');
|
||||||
|
show_flags = args_has(args, 'F');
|
||||||
|
hyperlinks = args_has(args, 'H');
|
||||||
|
if (hyperlinks)
|
||||||
|
links = xreallocarray(NULL, gd->sx, sizeof *links);
|
||||||
|
|
||||||
buf = NULL;
|
|
||||||
for (i = top; i <= bottom; i++) {
|
for (i = top; i <= bottom; i++) {
|
||||||
line = grid_string_cells(gd, 0, i, sx, &gc, flags, wp->screen);
|
if (hyperlinks) {
|
||||||
linelen = strlen(line);
|
line = cmd_capture_pane_hyperlinks(gd, s, i, links,
|
||||||
|
&nlinks, &linelen);
|
||||||
|
} else {
|
||||||
|
line = grid_string_cells(gd, 0, i, sx, &gc, flags, s);
|
||||||
|
linelen = strlen(line);
|
||||||
|
}
|
||||||
|
if (hyperlinks && linelen == 0) {
|
||||||
|
free(line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number_lines) {
|
||||||
|
if (i >= gd->hsize)
|
||||||
|
n = i - gd->hsize;
|
||||||
|
else
|
||||||
|
n = (int)i - (int)gd->hsize;
|
||||||
|
n = snprintf(b, sizeof b, "%d ", n);
|
||||||
|
if (n >= 0)
|
||||||
|
buf = cmd_capture_pane_append(buf, len, b, n);
|
||||||
|
}
|
||||||
|
if (show_flags) {
|
||||||
|
cp = b;
|
||||||
|
*cp = '\0';
|
||||||
|
|
||||||
|
gl = grid_peek_line(gd, i);
|
||||||
|
if (gl->flags & GRID_LINE_DEAD)
|
||||||
|
*cp++ = 'D';
|
||||||
|
if (gl->flags & GRID_LINE_HYPERLINK)
|
||||||
|
*cp++ = 'H';
|
||||||
|
if (gl->flags & GRID_LINE_START_OUTPUT)
|
||||||
|
*cp++ = 'O';
|
||||||
|
if (gl->flags & GRID_LINE_START_PROMPT)
|
||||||
|
*cp++ = 'P';
|
||||||
|
if (gl->flags & GRID_LINE_WRAPPED)
|
||||||
|
*cp++ = 'W';
|
||||||
|
if (gl->flags & GRID_LINE_EXTENDED)
|
||||||
|
*cp++ = 'X';
|
||||||
|
if (b == cp)
|
||||||
|
*cp++ = '-';
|
||||||
|
*cp++ = ' ';
|
||||||
|
*cp = '\0';
|
||||||
|
buf = cmd_capture_pane_append(buf, len, b, strlen (b));
|
||||||
|
}
|
||||||
buf = cmd_capture_pane_append(buf, len, line, linelen);
|
buf = cmd_capture_pane_append(buf, len, line, linelen);
|
||||||
|
|
||||||
gl = grid_peek_line(gd, i);
|
gl = grid_peek_line(gd, i);
|
||||||
@@ -192,6 +297,9 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
|
|||||||
|
|
||||||
free(line);
|
free(line);
|
||||||
}
|
}
|
||||||
|
free(links);
|
||||||
|
if (buf == NULL)
|
||||||
|
buf = xstrdup("");
|
||||||
return (buf);
|
return (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +322,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
if (args_has(args, 'P'))
|
if (args_has(args, 'P') && !args_has(args, 'H'))
|
||||||
buf = cmd_capture_pane_pending(args, wp, &len);
|
buf = cmd_capture_pane_pending(args, wp, &len);
|
||||||
else
|
else
|
||||||
buf = cmd_capture_pane_history(args, item, wp, &len);
|
buf = cmd_capture_pane_history(args, item, wp, &len);
|
||||||
@@ -234,8 +342,8 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
file_print_buffer(c, buf, len);
|
file_print_buffer(c, buf, len);
|
||||||
file_print(c, "\n");
|
file_print(c, "\n");
|
||||||
free(buf);
|
|
||||||
}
|
}
|
||||||
|
free(buf);
|
||||||
} else {
|
} else {
|
||||||
bufname = NULL;
|
bufname = NULL;
|
||||||
if (args_has(args, 'b'))
|
if (args_has(args, 'b'))
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const struct cmd_entry cmd_choose_tree_entry = {
|
|||||||
.name = "choose-tree",
|
.name = "choose-tree",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:f:GK:NO:rst:wZ", 0, 1, cmd_choose_tree_args_parse },
|
.args = { "F:f:GK:NO:rst:wyZ", 0, 1, cmd_choose_tree_args_parse },
|
||||||
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
|
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
|
||||||
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ const struct cmd_entry cmd_choose_client_entry = {
|
|||||||
.name = "choose-client",
|
.name = "choose-client",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:f:K:NO:rt:Z", 0, 1, cmd_choose_tree_args_parse },
|
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
|
||||||
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
|
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
|
||||||
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ const struct cmd_entry cmd_choose_buffer_entry = {
|
|||||||
.name = "choose-buffer",
|
.name = "choose-buffer",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:f:K:NO:rt:Z", 0, 1, cmd_choose_tree_args_parse },
|
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
|
||||||
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
|
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
|
||||||
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ const struct cmd_entry cmd_customize_mode_entry = {
|
|||||||
.name = "customize-mode",
|
.name = "customize-mode",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:f:Nt:Z", 0, 0, NULL },
|
.args = { "F:f:Nt:yZ", 0, 0, NULL },
|
||||||
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
|
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
@@ -98,6 +98,13 @@ cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
struct window_pane *wp = target->wp;
|
struct window_pane *wp = target->wp;
|
||||||
const struct window_mode *mode;
|
const struct window_mode *mode;
|
||||||
|
enum sort_order order;
|
||||||
|
|
||||||
|
order = sort_order_from_string(args_get(args, 'O'));
|
||||||
|
if (order == SORT_END && args_has(args, 'O')) {
|
||||||
|
cmdq_error(item, "invalid sort order");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
if (cmd_get_entry(self) == &cmd_choose_buffer_entry) {
|
if (cmd_get_entry(self) == &cmd_choose_buffer_entry) {
|
||||||
if (paste_is_empty())
|
if (paste_is_empty())
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ const struct cmd_entry cmd_command_prompt_entry = {
|
|||||||
.name = "command-prompt",
|
.name = "command-prompt",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "1bFkiI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
|
.args = { "1CbeFiklI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
|
||||||
.usage = "[-1bFkiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
|
.usage = "[-1CbeFiklN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
|
||||||
" [-T type] [template]",
|
" [-T prompt-type] [template]",
|
||||||
|
|
||||||
.flags = CMD_CLIENT_TFLAG,
|
.flags = CMD_CLIENT_TFLAG,
|
||||||
.exec = cmd_command_prompt_exec
|
.exec = cmd_command_prompt_exec
|
||||||
@@ -84,7 +84,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct client *tc = cmdq_get_target_client(item);
|
struct client *tc = cmdq_get_target_client(item);
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
const char *type, *s, *input;
|
const char *type, *s, *input;
|
||||||
struct cmd_command_prompt_cdata *cdata;
|
struct cmd_command_prompt_cdata *cdata;
|
||||||
char *tmp, *prompts, *prompt, *next_prompt;
|
char *tmp, *prompts, *prompt, *next_prompt;
|
||||||
char *inputs = NULL, *next_input;
|
char *inputs = NULL, *next_input;
|
||||||
u_int count = args_count(args);
|
u_int count = args_count(args);
|
||||||
@@ -117,27 +117,33 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
next_input = inputs = xstrdup(s);
|
next_input = inputs = xstrdup(s);
|
||||||
else
|
else
|
||||||
next_input = NULL;
|
next_input = NULL;
|
||||||
while ((prompt = strsep(&next_prompt, ",")) != NULL) {
|
if (args_has(args, 'l')) {
|
||||||
cdata->prompts = xreallocarray(cdata->prompts, cdata->count + 1,
|
cdata->prompts = xcalloc(1, sizeof *cdata->prompts);
|
||||||
sizeof *cdata->prompts);
|
cdata->prompts[0].prompt = prompts;
|
||||||
if (!space)
|
cdata->prompts[0].input = inputs;
|
||||||
tmp = xstrdup(prompt);
|
cdata->count = 1;
|
||||||
else
|
} else {
|
||||||
xasprintf(&tmp, "%s ", prompt);
|
while ((prompt = strsep(&next_prompt, ",")) != NULL) {
|
||||||
cdata->prompts[cdata->count].prompt = tmp;
|
cdata->prompts = xreallocarray(cdata->prompts,
|
||||||
|
cdata->count + 1, sizeof *cdata->prompts);
|
||||||
|
if (!space)
|
||||||
|
tmp = xstrdup(prompt);
|
||||||
|
else
|
||||||
|
xasprintf(&tmp, "%s ", prompt);
|
||||||
|
cdata->prompts[cdata->count].prompt = tmp;
|
||||||
|
|
||||||
if (next_input != NULL) {
|
if (next_input != NULL) {
|
||||||
input = strsep(&next_input, ",");
|
input = strsep(&next_input, ",");
|
||||||
if (input == NULL)
|
if (input == NULL)
|
||||||
|
input = "";
|
||||||
|
} else
|
||||||
input = "";
|
input = "";
|
||||||
} else
|
cdata->prompts[cdata->count].input = xstrdup(input);
|
||||||
input = "";
|
cdata->count++;
|
||||||
cdata->prompts[cdata->count].input = xstrdup(input);
|
}
|
||||||
|
free(inputs);
|
||||||
cdata->count++;
|
free(prompts);
|
||||||
}
|
}
|
||||||
free(inputs);
|
|
||||||
free(prompts);
|
|
||||||
|
|
||||||
if ((type = args_get(args, 'T')) != NULL) {
|
if ((type = args_get(args, 'T')) != NULL) {
|
||||||
cdata->prompt_type = status_prompt_type(type);
|
cdata->prompt_type = status_prompt_type(type);
|
||||||
@@ -157,6 +163,10 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
cdata->flags |= PROMPT_INCREMENTAL;
|
cdata->flags |= PROMPT_INCREMENTAL;
|
||||||
else if (args_has(args, 'k'))
|
else if (args_has(args, 'k'))
|
||||||
cdata->flags |= PROMPT_KEY;
|
cdata->flags |= PROMPT_KEY;
|
||||||
|
else if (args_has(args, 'e'))
|
||||||
|
cdata->flags |= PROMPT_BSPACE_EXIT;
|
||||||
|
if (args_has(args, 'C'))
|
||||||
|
cdata->flags |= PROMPT_NOFREEZE;
|
||||||
status_prompt_set(tc, target, cdata->prompts[0].prompt,
|
status_prompt_set(tc, target, cdata->prompts[0].prompt,
|
||||||
cdata->prompts[0].input, cmd_command_prompt_callback,
|
cdata->prompts[0].input, cmd_command_prompt_callback,
|
||||||
cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type);
|
cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type);
|
||||||
@@ -228,7 +238,7 @@ out:
|
|||||||
static void
|
static void
|
||||||
cmd_command_prompt_free(void *data)
|
cmd_command_prompt_free(void *data)
|
||||||
{
|
{
|
||||||
struct cmd_command_prompt_cdata *cdata = data;
|
struct cmd_command_prompt_cdata *cdata = data;
|
||||||
u_int i;
|
u_int i;
|
||||||
|
|
||||||
for (i = 0; i < cdata->count; i++) {
|
for (i = 0; i < cdata->count; i++) {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ const struct cmd_entry cmd_confirm_before_entry = {
|
|||||||
.alias = "confirm",
|
.alias = "confirm",
|
||||||
|
|
||||||
.args = { "bc:p:t:y", 1, 1, cmd_confirm_before_args_parse },
|
.args = { "bc:p:t:y", 1, 1, cmd_confirm_before_args_parse },
|
||||||
.usage = "[-by] [-c confirm_key] [-p prompt] " CMD_TARGET_CLIENT_USAGE
|
.usage = "[-by] [-c confirm-key] [-p prompt] " CMD_TARGET_CLIENT_USAGE
|
||||||
" command",
|
" command",
|
||||||
|
|
||||||
.flags = CMD_CLIENT_TFLAG,
|
.flags = CMD_CLIENT_TFLAG,
|
||||||
@@ -92,6 +92,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
cdata->confirm_key = confirm_key[0];
|
cdata->confirm_key = confirm_key[0];
|
||||||
else {
|
else {
|
||||||
cmdq_error(item, "invalid confirm key");
|
cmdq_error(item, "invalid confirm key");
|
||||||
|
cmd_list_free(cdata->cmdlist);
|
||||||
free(cdata);
|
free(cdata);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
@@ -130,7 +131,7 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
|
|||||||
|
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
if (s[0] != cdata->confirm_key && (s[0] != '\0' || !cdata->default_yes))
|
if (s[0] != cdata->confirm_key && (s[0] != '\r' || !cdata->default_yes))
|
||||||
goto out;
|
goto out;
|
||||||
retcode = 0;
|
retcode = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -30,13 +30,13 @@ const struct cmd_entry cmd_copy_mode_entry = {
|
|||||||
.name = "copy-mode",
|
.name = "copy-mode",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "deHMs:t:uq", 0, 0, NULL },
|
.args = { "deHMqSs:t:u", 0, 0, NULL },
|
||||||
.usage = "[-deHMuq] [-s src-pane] " CMD_TARGET_PANE_USAGE,
|
.usage = "[-deHMqSu] [-s src-pane] " CMD_TARGET_PANE_USAGE,
|
||||||
|
|
||||||
.source = { 's', CMD_FIND_PANE, 0 },
|
.source = { 's', CMD_FIND_PANE, 0 },
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK,
|
.flags = CMD_AFTERHOOK|CMD_READONLY,
|
||||||
.exec = cmd_copy_mode_exec
|
.exec = cmd_copy_mode_exec
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,6 +63,8 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct client *c = cmdq_get_client(item);
|
struct client *c = cmdq_get_client(item);
|
||||||
struct session *s;
|
struct session *s;
|
||||||
struct window_pane *wp = target->wp, *swp;
|
struct window_pane *wp = target->wp, *swp;
|
||||||
|
u_int tty_ox, tty_oy, tty_sx, tty_sy;
|
||||||
|
int line_numbers;
|
||||||
|
|
||||||
if (args_has(args, 'q')) {
|
if (args_has(args, 'q')) {
|
||||||
window_pane_reset_mode_all(wp);
|
window_pane_reset_mode_all(wp);
|
||||||
@@ -85,14 +87,25 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
swp = source->wp;
|
swp = source->wp;
|
||||||
else
|
else
|
||||||
swp = wp;
|
swp = wp;
|
||||||
|
line_numbers = 1;
|
||||||
|
if (event != NULL && KEYC_IS_MOUSE(event->key))
|
||||||
|
line_numbers = 0;
|
||||||
if (!window_pane_set_mode(wp, swp, &window_copy_mode, NULL, args)) {
|
if (!window_pane_set_mode(wp, swp, &window_copy_mode, NULL, args)) {
|
||||||
|
window_copy_set_line_numbers(wp, line_numbers);
|
||||||
if (args_has(args, 'M'))
|
if (args_has(args, 'M'))
|
||||||
window_copy_start_drag(c, &event->m);
|
window_copy_start_drag(c, &event->m);
|
||||||
}
|
} else
|
||||||
|
window_copy_set_line_numbers(wp, line_numbers);
|
||||||
if (args_has(args, 'u'))
|
if (args_has(args, 'u'))
|
||||||
window_copy_pageup(wp, 0);
|
window_copy_pageup(wp, 0);
|
||||||
if (args_has(args, 'd'))
|
if (args_has(args, 'd'))
|
||||||
window_copy_pagedown(wp, 0, args_has(args, 'e'));
|
window_copy_pagedown(wp, 0, args_has(args, 'e'));
|
||||||
|
if (args_has(args, 'S')) {
|
||||||
|
tty_window_offset(&c->tty, &tty_ox, &tty_oy, &tty_sx, &tty_sy);
|
||||||
|
window_copy_scroll(wp, c->tty.mouse_slider_mpos, event->m.y,
|
||||||
|
tty_oy, args_has(args, 'e'));
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
{
|
{
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct cmd_find_state *source = cmdq_get_source(item);
|
struct cmd_find_state *source = cmdq_get_source(item);
|
||||||
|
struct client *c = cmdq_get_client(item);
|
||||||
struct client *tc = cmdq_get_target_client(item), *loop;
|
struct client *tc = cmdq_get_target_client(item), *loop;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
enum msgtype msgtype;
|
enum msgtype msgtype;
|
||||||
@@ -69,6 +70,13 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c->flags & CLIENT_READONLY) {
|
||||||
|
if (args_has(args, 's') || args_has(args, 'a') || c != tc) {
|
||||||
|
cmdq_error(item, "client is read-only");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (args_has(args, 'P'))
|
if (args_has(args, 'P'))
|
||||||
msgtype = MSG_DETACHKILL;
|
msgtype = MSG_DETACHKILL;
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ const struct cmd_entry cmd_display_menu_entry = {
|
|||||||
.args = { "b:c:C:H:s:S:MOt:T:x:y:", 1, -1, cmd_display_menu_args_parse },
|
.args = { "b:c:C:H:s:S:MOt:T:x:y:", 1, -1, cmd_display_menu_args_parse },
|
||||||
.usage = "[-MO] [-b border-lines] [-c target-client] "
|
.usage = "[-MO] [-b border-lines] [-c target-client] "
|
||||||
"[-C starting-choice] [-H selected-style] [-s style] "
|
"[-C starting-choice] [-H selected-style] [-s style] "
|
||||||
"[-S border-style] " CMD_TARGET_PANE_USAGE "[-T title] "
|
"[-S border-style] " CMD_TARGET_PANE_USAGE " [-T title] "
|
||||||
"[-x position] [-y position] name key command ...",
|
"[-x position] [-y position] name [key] [command] ...",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
@@ -54,12 +54,12 @@ const struct cmd_entry cmd_display_popup_entry = {
|
|||||||
.name = "display-popup",
|
.name = "display-popup",
|
||||||
.alias = "popup",
|
.alias = "popup",
|
||||||
|
|
||||||
.args = { "Bb:Cc:d:e:Eh:s:S:t:T:w:x:y:", 0, -1, NULL },
|
.args = { "Bb:Cc:d:e:Eh:kNs:S:t:T:w:x:y:", 0, -1, NULL },
|
||||||
.usage = "[-BCE] [-b border-lines] [-c target-client] "
|
.usage = "[-BCEkN] [-b border-lines] [-c target-client] "
|
||||||
"[-d start-directory] [-e environment] [-h height] "
|
"[-d start-directory] [-e environment] [-h height] "
|
||||||
"[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE
|
"[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE
|
||||||
"[-T title] [-w width] [-x position] [-y position] "
|
" [-T title] [-w width] [-x position] [-y position] "
|
||||||
"[shell-command]",
|
"[shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ cmd_display_menu_args_parse(struct args *args, u_int idx, __unused char **cause)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item,
|
cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
|
||||||
struct args *args, u_int *px, u_int *py, u_int w, u_int h)
|
struct args *args, u_int *px, u_int *py, u_int w, u_int h)
|
||||||
{
|
{
|
||||||
struct tty *tty = &tc->tty;
|
struct tty *tty = &tc->tty;
|
||||||
@@ -294,7 +294,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
const char *border_style = args_get(args, 'S');
|
const char *border_style = args_get(args, 'S');
|
||||||
const char *selected_style = args_get(args, 'H');
|
const char *selected_style = args_get(args, 'H');
|
||||||
enum box_lines lines = BOX_LINES_DEFAULT;
|
enum box_lines lines = BOX_LINES_DEFAULT;
|
||||||
char *title, *cause;
|
char *title, *cause = NULL;
|
||||||
int flags = 0, starting_choice = 0;
|
int flags = 0, starting_choice = 0;
|
||||||
u_int px, py, i, count = args_count(args);
|
u_int px, py, i, count = args_count(args);
|
||||||
struct options *o = target->s->curw->window->options;
|
struct options *o = target->s->curw->window->options;
|
||||||
@@ -312,8 +312,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
&cause);
|
&cause);
|
||||||
if (cause != NULL) {
|
if (cause != NULL) {
|
||||||
cmdq_error(item, "starting choice %s", cause);
|
cmdq_error(item, "starting choice %s", cause);
|
||||||
free(cause);
|
goto fail;
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,8 +333,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
if (count - i < 2) {
|
if (count - i < 2) {
|
||||||
cmdq_error(item, "not enough arguments");
|
cmdq_error(item, "not enough arguments");
|
||||||
menu_free(menu);
|
goto fail;
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
}
|
||||||
key = args_string(args, i++);
|
key = args_string(args, i++);
|
||||||
|
|
||||||
@@ -347,17 +345,13 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
if (menu == NULL) {
|
if (menu == NULL) {
|
||||||
cmdq_error(item, "invalid menu arguments");
|
cmdq_error(item, "invalid menu arguments");
|
||||||
return (CMD_RETURN_ERROR);
|
goto fail;
|
||||||
}
|
|
||||||
if (menu->count == 0) {
|
|
||||||
menu_free(menu);
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
|
||||||
if (!cmd_display_menu_get_position(tc, item, args, &px, &py,
|
|
||||||
menu->width + 4, menu->count + 2)) {
|
|
||||||
menu_free(menu);
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
}
|
||||||
|
if (menu->count == 0)
|
||||||
|
goto out;
|
||||||
|
if (!cmd_display_menu_get_pos(tc, item, args, &px, &py, menu->width + 4,
|
||||||
|
menu->count + 2))
|
||||||
|
goto out;
|
||||||
|
|
||||||
value = args_get(args, 'b');
|
value = args_get(args, 'b');
|
||||||
if (value != NULL) {
|
if (value != NULL) {
|
||||||
@@ -366,8 +360,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
&cause);
|
&cause);
|
||||||
if (lines == -1) {
|
if (lines == -1) {
|
||||||
cmdq_error(item, "menu-border-lines %s", cause);
|
cmdq_error(item, "menu-border-lines %s", cause);
|
||||||
free(cause);
|
goto fail;
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,8 +370,17 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
flags |= MENU_NOMOUSE;
|
flags |= MENU_NOMOUSE;
|
||||||
if (menu_display(menu, flags, starting_choice, item, px, py, tc, lines,
|
if (menu_display(menu, flags, starting_choice, item, px, py, tc, lines,
|
||||||
style, selected_style, border_style, target, NULL, NULL) != 0)
|
style, selected_style, border_style, target, NULL, NULL) != 0)
|
||||||
return (CMD_RETURN_NORMAL);
|
goto out;
|
||||||
return (CMD_RETURN_WAIT);
|
return (CMD_RETURN_WAIT);
|
||||||
|
|
||||||
|
out:
|
||||||
|
menu_free(menu);
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
free(cause);
|
||||||
|
menu_free(menu);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
@@ -392,8 +394,10 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
const char *value, *shell, *shellcmd = NULL;
|
const char *value, *shell, *shellcmd = NULL;
|
||||||
const char *style = args_get(args, 's');
|
const char *style = args_get(args, 's');
|
||||||
const char *border_style = args_get(args, 'S');
|
const char *border_style = args_get(args, 'S');
|
||||||
char *cwd, *cause = NULL, **argv = NULL, *title;
|
char *cwd = NULL, *cause = NULL, **argv = NULL;
|
||||||
int flags = 0, argc = 0;
|
char *title = NULL;
|
||||||
|
int modify = popup_present(tc);
|
||||||
|
int flags = -1, argc = 0;
|
||||||
enum box_lines lines = BOX_LINES_DEFAULT;
|
enum box_lines lines = BOX_LINES_DEFAULT;
|
||||||
u_int px, py, w, h, count = args_count(args);
|
u_int px, py, w, h, count = args_count(args);
|
||||||
struct args_value *av;
|
struct args_value *av;
|
||||||
@@ -405,36 +409,66 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
server_client_clear_overlay(tc);
|
server_client_clear_overlay(tc);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
if (tc->overlay_draw != NULL)
|
if (!modify && tc->overlay_draw != NULL)
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
h = tty->sy / 2;
|
if (!modify) {
|
||||||
if (args_has(args, 'h')) {
|
h = tty->sy / 2;
|
||||||
h = args_percentage(args, 'h', 1, tty->sy, tty->sy, &cause);
|
if (args_has(args, 'h')) {
|
||||||
if (cause != NULL) {
|
h = args_percentage(args, 'h', 1, tty->sy, tty->sy,
|
||||||
cmdq_error(item, "height %s", cause);
|
&cause);
|
||||||
free(cause);
|
if (cause != NULL) {
|
||||||
return (CMD_RETURN_ERROR);
|
cmdq_error(item, "height %s", cause);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w = tty->sx / 2;
|
||||||
|
if (args_has(args, 'w')) {
|
||||||
|
w = args_percentage(args, 'w', 1, tty->sx, tty->sx,
|
||||||
|
&cause);
|
||||||
|
if (cause != NULL) {
|
||||||
|
cmdq_error(item, "width %s", cause);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w > tty->sx)
|
||||||
|
w = tty->sx;
|
||||||
|
if (h > tty->sy)
|
||||||
|
h = tty->sy;
|
||||||
|
if (!cmd_display_menu_get_pos(tc, item, args, &px, &py, w, h))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
value = args_get(args, 'd');
|
||||||
|
if (value != NULL)
|
||||||
|
cwd = format_single_from_target(item, value);
|
||||||
|
else
|
||||||
|
cwd = xstrdup(server_client_get_cwd(tc, s));
|
||||||
|
if (count == 0) {
|
||||||
|
shellcmd = options_get_string(s->options,
|
||||||
|
"default-command");
|
||||||
|
} else if (count == 1)
|
||||||
|
shellcmd = args_string(args, 0);
|
||||||
|
if (count <= 1 && (shellcmd == NULL || *shellcmd == '\0')) {
|
||||||
|
shellcmd = NULL;
|
||||||
|
shell = options_get_string(s->options, "default-shell");
|
||||||
|
if (!checkshell(shell))
|
||||||
|
shell = _PATH_BSHELL;
|
||||||
|
cmd_append_argv(&argc, &argv, shell);
|
||||||
|
} else
|
||||||
|
args_to_vector(args, &argc, &argv);
|
||||||
|
|
||||||
|
if (args_has(args, 'e') >= 1) {
|
||||||
|
env = environ_create();
|
||||||
|
av = args_first_value(args, 'e');
|
||||||
|
while (av != NULL) {
|
||||||
|
environ_put(env, av->string, 0);
|
||||||
|
av = args_next_value(av);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w = tty->sx / 2;
|
|
||||||
if (args_has(args, 'w')) {
|
|
||||||
w = args_percentage(args, 'w', 1, tty->sx, tty->sx, &cause);
|
|
||||||
if (cause != NULL) {
|
|
||||||
cmdq_error(item, "width %s", cause);
|
|
||||||
free(cause);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (w > tty->sx)
|
|
||||||
w = tty->sx;
|
|
||||||
if (h > tty->sy)
|
|
||||||
h = tty->sy;
|
|
||||||
if (!cmd_display_menu_get_position(tc, item, args, &px, &py, w, h))
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
|
|
||||||
value = args_get(args, 'b');
|
value = args_get(args, 'b');
|
||||||
if (args_has(args, 'B'))
|
if (args_has(args, 'B'))
|
||||||
lines = BOX_LINES_NONE;
|
lines = BOX_LINES_NONE;
|
||||||
@@ -444,35 +478,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
&cause);
|
&cause);
|
||||||
if (cause != NULL) {
|
if (cause != NULL) {
|
||||||
cmdq_error(item, "popup-border-lines %s", cause);
|
cmdq_error(item, "popup-border-lines %s", cause);
|
||||||
free(cause);
|
goto fail;
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value = args_get(args, 'd');
|
|
||||||
if (value != NULL)
|
|
||||||
cwd = format_single_from_target(item, value);
|
|
||||||
else
|
|
||||||
cwd = xstrdup(server_client_get_cwd(tc, s));
|
|
||||||
if (count == 0)
|
|
||||||
shellcmd = options_get_string(s->options, "default-command");
|
|
||||||
else if (count == 1)
|
|
||||||
shellcmd = args_string(args, 0);
|
|
||||||
if (count <= 1 && (shellcmd == NULL || *shellcmd == '\0')) {
|
|
||||||
shellcmd = NULL;
|
|
||||||
shell = options_get_string(s->options, "default-shell");
|
|
||||||
if (!checkshell(shell))
|
|
||||||
shell = _PATH_BSHELL;
|
|
||||||
cmd_append_argv(&argc, &argv, shell);
|
|
||||||
} else
|
|
||||||
args_to_vector(args, &argc, &argv);
|
|
||||||
|
|
||||||
if (args_has(args, 'e') >= 1) {
|
|
||||||
env = environ_create();
|
|
||||||
av = args_first_value(args, 'e');
|
|
||||||
while (av != NULL) {
|
|
||||||
environ_put(env, av->string, 0);
|
|
||||||
av = args_next_value(av);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,23 +486,49 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
title = format_single_from_target(item, args_get(args, 'T'));
|
title = format_single_from_target(item, args_get(args, 'T'));
|
||||||
else
|
else
|
||||||
title = xstrdup("");
|
title = xstrdup("");
|
||||||
if (args_has(args, 'E') > 1)
|
|
||||||
|
if (args_has(args, 'N') || !modify)
|
||||||
|
flags = 0;
|
||||||
|
if (args_has(args, 'E') > 1) {
|
||||||
|
if (flags == -1)
|
||||||
|
flags = 0;
|
||||||
flags |= POPUP_CLOSEEXITZERO;
|
flags |= POPUP_CLOSEEXITZERO;
|
||||||
else if (args_has(args, 'E'))
|
} else if (args_has(args, 'E')) {
|
||||||
|
if (flags == -1)
|
||||||
|
flags = 0;
|
||||||
flags |= POPUP_CLOSEEXIT;
|
flags |= POPUP_CLOSEEXIT;
|
||||||
if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc,
|
|
||||||
argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0) {
|
|
||||||
cmd_free_argv(argc, argv);
|
|
||||||
if (env != NULL)
|
|
||||||
environ_free(env);
|
|
||||||
free(cwd);
|
|
||||||
free(title);
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
}
|
||||||
if (env != NULL)
|
if (args_has(args, 'k')) {
|
||||||
environ_free(env);
|
if (flags == -1)
|
||||||
|
flags = 0;
|
||||||
|
flags |= POPUP_CLOSEANYKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modify) {
|
||||||
|
popup_modify(tc, title, style, border_style, lines, flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc,
|
||||||
|
argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0)
|
||||||
|
goto out;
|
||||||
|
environ_free(env);
|
||||||
free(cwd);
|
free(cwd);
|
||||||
free(title);
|
free(title);
|
||||||
cmd_free_argv(argc, argv);
|
cmd_free_argv(argc, argv);
|
||||||
return (CMD_RETURN_WAIT);
|
return (CMD_RETURN_WAIT);
|
||||||
|
|
||||||
|
out:
|
||||||
|
cmd_free_argv(argc, argv);
|
||||||
|
environ_free(env);
|
||||||
|
free(cwd);
|
||||||
|
free(title);
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
free(cause);
|
||||||
|
cmd_free_argv(argc, argv);
|
||||||
|
environ_free(env);
|
||||||
|
free(cwd);
|
||||||
|
free(title);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ const struct cmd_entry cmd_display_message_entry = {
|
|||||||
.name = "display-message",
|
.name = "display-message",
|
||||||
.alias = "display",
|
.alias = "display",
|
||||||
|
|
||||||
.args = { "ac:d:lINpt:F:v", 0, 1, NULL },
|
.args = { "aCc:d:lINpt:F:v", 0, 1, NULL },
|
||||||
.usage = "[-aIlNpv] [-c target-client] [-d delay] [-F format] "
|
.usage = "[-aCIlNpv] [-c target-client] [-d delay] [-F format] "
|
||||||
CMD_TARGET_PANE_USAGE " [message]",
|
CMD_TARGET_PANE_USAGE " [message]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||||
@@ -69,6 +69,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
const char *template;
|
const char *template;
|
||||||
char *msg, *cause;
|
char *msg, *cause;
|
||||||
int delay = -1, flags, Nflag = args_has(args, 'N');
|
int delay = -1, flags, Nflag = args_has(args, 'N');
|
||||||
|
int Cflag = args_has(args, 'C');
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
u_int count = args_count(args);
|
u_int count = args_count(args);
|
||||||
struct evbuffer *evb;
|
struct evbuffer *evb;
|
||||||
@@ -130,6 +131,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
if (args_has(args, 'a')) {
|
if (args_has(args, 'a')) {
|
||||||
format_each(ft, cmd_display_message_each, item);
|
format_each(ft, cmd_display_message_each, item);
|
||||||
|
format_free(ft);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,10 +152,9 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
server_client_print(tc, 0, evb);
|
server_client_print(tc, 0, evb);
|
||||||
evbuffer_free(evb);
|
evbuffer_free(evb);
|
||||||
} else if (tc != NULL)
|
} else if (tc != NULL)
|
||||||
status_message_set(tc, delay, 0, Nflag, "%s", msg);
|
status_message_set(tc, delay, 0, Nflag, Cflag, "%s", msg);
|
||||||
free(msg);
|
free(msg);
|
||||||
|
|
||||||
format_free(ft);
|
format_free(ft);
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,27 @@ cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
|
|||||||
return (ARGS_PARSE_COMMANDS_OR_STRING);
|
return (ARGS_PARSE_COMMANDS_OR_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_display_panes_put(struct screen_redraw_ctx *ctx,
|
||||||
|
struct window_pane *wp, u_int cx, u_int cy, const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct client *c = ctx->c;
|
||||||
|
struct tty *tty = &c->tty;
|
||||||
|
struct visible_ranges *r;
|
||||||
|
struct visible_range *ri;
|
||||||
|
u_int i, j;
|
||||||
|
|
||||||
|
r = screen_redraw_get_visible_ranges(wp, ctx->ox + cx, ctx->oy + cy,
|
||||||
|
len, NULL);
|
||||||
|
for (i = 0; i < r->used; i++) {
|
||||||
|
ri = &r->ranges[i];
|
||||||
|
for (j = ri->px; j < ri->px + ri->nx; j++) {
|
||||||
|
tty_cursor(tty, j - ctx->ox, cy);
|
||||||
|
tty_putn(tty, &buf[j - ri->px], 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
||||||
struct window_pane *wp)
|
struct window_pane *wp)
|
||||||
@@ -66,14 +87,15 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
|||||||
struct window *w = wp->window;
|
struct window *w = wp->window;
|
||||||
struct grid_cell fgc, bgc;
|
struct grid_cell fgc, bgc;
|
||||||
u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy;
|
u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy;
|
||||||
|
u_int cx, cy;
|
||||||
int colour, active_colour;
|
int colour, active_colour;
|
||||||
char buf[16], lbuf[16], rbuf[16], *ptr;
|
char buf[16], lbuf[16], rbuf[16], *ptr;
|
||||||
size_t len, llen, rlen;
|
size_t len, llen, rlen;
|
||||||
|
|
||||||
if (wp->xoff + wp->sx <= ctx->ox ||
|
if (wp->xoff + (int)wp->sx <= ctx->ox ||
|
||||||
wp->xoff >= ctx->ox + ctx->sx ||
|
wp->xoff >= ctx->ox + (int)ctx->sx ||
|
||||||
wp->yoff + wp->sy <= ctx->oy ||
|
wp->yoff + (int)wp->sy <= ctx->oy ||
|
||||||
wp->yoff >= ctx->oy + ctx->sy)
|
wp->yoff >= ctx->oy + (int)ctx->sy)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
|
if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
|
||||||
@@ -147,13 +169,17 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
|||||||
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
|
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
|
||||||
if (sx >= len + llen + 1) {
|
if (sx >= len + llen + 1) {
|
||||||
len += llen + 1;
|
len += llen + 1;
|
||||||
tty_cursor(tty, xoff + px - len / 2, yoff + py);
|
cx = xoff + px - len / 2;
|
||||||
tty_putn(tty, buf, len, len);
|
cy = yoff + py;
|
||||||
tty_putn(tty, " ", 1, 1);
|
cmd_display_panes_put(ctx, wp, cx, cy, buf, len);
|
||||||
tty_putn(tty, lbuf, llen, llen);
|
cx += len;
|
||||||
|
cmd_display_panes_put(ctx, wp, cx, cy, " ", 1);
|
||||||
|
cx++;
|
||||||
|
cmd_display_panes_put(ctx, wp, cx, cy, lbuf, llen);
|
||||||
} else {
|
} else {
|
||||||
tty_cursor(tty, xoff + px - len / 2, yoff + py);
|
cx = xoff + px - len / 2;
|
||||||
tty_putn(tty, buf, len, len);
|
cy = yoff + py;
|
||||||
|
cmd_display_panes_put(ctx, wp, cx, cy, buf, len);
|
||||||
}
|
}
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -169,9 +195,11 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
|||||||
|
|
||||||
for (j = 0; j < 5; j++) {
|
for (j = 0; j < 5; j++) {
|
||||||
for (i = px; i < px + 5; i++) {
|
for (i = px; i < px + 5; i++) {
|
||||||
tty_cursor(tty, xoff + i, yoff + py + j);
|
if (!window_clock_table[idx][j][i - px])
|
||||||
if (window_clock_table[idx][j][i - px])
|
continue;
|
||||||
tty_putc(tty, ' ');
|
cx = xoff + i;
|
||||||
|
cy = yoff + py + j;
|
||||||
|
cmd_display_panes_put(ctx, wp, cx, cy, " ", 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
px += 6;
|
px += 6;
|
||||||
@@ -181,13 +209,14 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
|||||||
goto out;
|
goto out;
|
||||||
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
|
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
|
||||||
if (rlen != 0 && sx >= rlen) {
|
if (rlen != 0 && sx >= rlen) {
|
||||||
tty_cursor(tty, xoff + sx - rlen, yoff);
|
cx = xoff + sx - rlen;
|
||||||
tty_putn(tty, rbuf, rlen, rlen);
|
cy = yoff;
|
||||||
|
cmd_display_panes_put(ctx, wp, cx, cy, rbuf, rlen);
|
||||||
}
|
}
|
||||||
if (llen != 0) {
|
if (llen != 0) {
|
||||||
tty_cursor(tty, xoff + sx / 2 + len * 3 - llen - 1,
|
cx = xoff + sx / 2 + len * 3 - llen - 1;
|
||||||
yoff + py + 5);
|
cy = yoff + py + 5;
|
||||||
tty_putn(tty, lbuf, llen, llen);
|
cmd_display_panes_put(ctx, wp, cx, cy, lbuf, llen);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|||||||
15
cmd-find.c
15
cmd-find.c
@@ -924,6 +924,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
|
|||||||
const char *target, enum cmd_find_type type, int flags)
|
const char *target, enum cmd_find_type type, int flags)
|
||||||
{
|
{
|
||||||
struct mouse_event *m;
|
struct mouse_event *m;
|
||||||
|
struct client *c;
|
||||||
struct cmd_find_state current;
|
struct cmd_find_state current;
|
||||||
char *colon, *period, *copy = NULL, tmp[256];
|
char *colon, *period, *copy = NULL, tmp[256];
|
||||||
const char *session, *window, *pane, *s;
|
const char *session, *window, *pane, *s;
|
||||||
@@ -990,6 +991,20 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
|
|||||||
if (target == NULL || *target == '\0')
|
if (target == NULL || *target == '\0')
|
||||||
goto current;
|
goto current;
|
||||||
|
|
||||||
|
if (strcmp(target, "@") == 0 ||
|
||||||
|
strcmp(target, "{active}") == 0 ||
|
||||||
|
strcmp(target, "{current}") == 0) {
|
||||||
|
c = cmdq_get_client(item);
|
||||||
|
if (c == NULL) {
|
||||||
|
cmdq_error(item, "no current client");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
fs->wl = c->session->curw;
|
||||||
|
fs->wp = c->session->curw->window->active;
|
||||||
|
fs->w = c->session->curw->window;
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
/* Mouse target is a plain = or {mouse}. */
|
/* Mouse target is a plain = or {mouse}. */
|
||||||
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
|
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
|
||||||
m = &cmdq_get_event(item)->m;
|
m = &cmdq_get_event(item)->m;
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
-1) == NULL) {
|
-1) == NULL) {
|
||||||
cmdq_error(item, "failed to run command: %s", shellcmd);
|
cmdq_error(item, "failed to run command: %s", shellcmd);
|
||||||
free(shellcmd);
|
free(shellcmd);
|
||||||
free(cdata);
|
cmd_if_shell_free(cdata);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
free(shellcmd);
|
free(shellcmd);
|
||||||
@@ -157,7 +157,7 @@ cmd_if_shell_callback(struct job *job)
|
|||||||
if (cmdlist == NULL) {
|
if (cmdlist == NULL) {
|
||||||
if (cdata->item == NULL) {
|
if (cdata->item == NULL) {
|
||||||
*error = toupper((u_char)*error);
|
*error = toupper((u_char)*error);
|
||||||
status_message_set(c, -1, 1, 0, "%s", error);
|
status_message_set(c, -1, 1, 0, 0, "%s", error);
|
||||||
} else
|
} else
|
||||||
cmdq_error(cdata->item, "%s", error);
|
cmdq_error(cdata->item, "%s", error);
|
||||||
free(error);
|
free(error);
|
||||||
|
|||||||
@@ -71,11 +71,8 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct window *src_w, *dst_w;
|
struct window *src_w, *dst_w;
|
||||||
struct window_pane *src_wp, *dst_wp;
|
struct window_pane *src_wp, *dst_wp;
|
||||||
char *cause = NULL;
|
char *cause = NULL;
|
||||||
int size, dst_idx;
|
int flags = 0, dst_idx;
|
||||||
int flags;
|
|
||||||
enum layout_type type;
|
|
||||||
struct layout_cell *lc;
|
struct layout_cell *lc;
|
||||||
u_int curval = 0;
|
|
||||||
|
|
||||||
dst_s = target->s;
|
dst_s = target->s;
|
||||||
dst_wl = target->wl;
|
dst_wl = target->wl;
|
||||||
@@ -94,66 +91,30 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
type = LAYOUT_TOPBOTTOM;
|
lc = layout_get_tiled_cell(item, args, dst_w, dst_wp, flags, &cause);
|
||||||
if (args_has(args, 'h'))
|
|
||||||
type = LAYOUT_LEFTRIGHT;
|
|
||||||
|
|
||||||
/* If the 'p' flag is dropped then this bit can be moved into 'l'. */
|
|
||||||
if (args_has(args, 'l') || args_has(args, 'p')) {
|
|
||||||
if (args_has(args, 'f')) {
|
|
||||||
if (type == LAYOUT_TOPBOTTOM)
|
|
||||||
curval = dst_w->sy;
|
|
||||||
else
|
|
||||||
curval = dst_w->sx;
|
|
||||||
} else {
|
|
||||||
if (type == LAYOUT_TOPBOTTOM)
|
|
||||||
curval = dst_wp->sy;
|
|
||||||
else
|
|
||||||
curval = dst_wp->sx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size = -1;
|
|
||||||
if (args_has(args, 'l')) {
|
|
||||||
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
|
|
||||||
item, &cause);
|
|
||||||
} else if (args_has(args, 'p')) {
|
|
||||||
size = args_strtonum_and_expand(args, 'l', 0, 100, item,
|
|
||||||
&cause);
|
|
||||||
if (cause == NULL)
|
|
||||||
size = curval * size / 100;
|
|
||||||
}
|
|
||||||
if (cause != NULL) {
|
if (cause != NULL) {
|
||||||
cmdq_error(item, "size %s", cause);
|
cmdq_error(item, "size or position %s", cause);
|
||||||
free(cause);
|
free(cause);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = 0;
|
|
||||||
if (args_has(args, 'b'))
|
|
||||||
flags |= SPAWN_BEFORE;
|
|
||||||
if (args_has(args, 'f'))
|
|
||||||
flags |= SPAWN_FULLSIZE;
|
|
||||||
|
|
||||||
lc = layout_split_pane(dst_wp, type, size, flags);
|
|
||||||
if (lc == NULL) {
|
|
||||||
cmdq_error(item, "create pane failed: pane too small");
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
layout_close_pane(src_wp);
|
layout_close_pane(src_wp);
|
||||||
|
|
||||||
server_client_remove_pane(src_wp);
|
server_client_remove_pane(src_wp);
|
||||||
window_lost_pane(src_w, src_wp);
|
window_lost_pane(src_w, src_wp);
|
||||||
TAILQ_REMOVE(&src_w->panes, src_wp, entry);
|
TAILQ_REMOVE(&src_w->panes, src_wp, entry);
|
||||||
|
TAILQ_REMOVE(&src_w->z_index, src_wp, zentry);
|
||||||
|
|
||||||
src_wp->window = dst_w;
|
src_wp->window = dst_w;
|
||||||
options_set_parent(src_wp->options, dst_w->options);
|
options_set_parent(src_wp->options, dst_w->options);
|
||||||
src_wp->flags |= PANE_STYLECHANGED;
|
src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
if (flags & SPAWN_BEFORE)
|
if (flags & SPAWN_BEFORE) {
|
||||||
TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry);
|
TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry);
|
||||||
else
|
TAILQ_INSERT_BEFORE(dst_wp, src_wp, zentry);
|
||||||
|
} else {
|
||||||
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
|
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
|
||||||
|
TAILQ_INSERT_AFTER(&dst_w->z_index, dst_wp, src_wp, zentry);
|
||||||
|
}
|
||||||
layout_assign_pane(lc, src_wp, 0);
|
layout_assign_pane(lc, src_wp, 0);
|
||||||
colour_palette_from_option(&src_wp->palette, src_wp->options);
|
colour_palette_from_option(&src_wp->palette, src_wp->options);
|
||||||
|
|
||||||
@@ -170,7 +131,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
} else
|
} else
|
||||||
server_status_session(dst_s);
|
server_status_session(dst_s);
|
||||||
|
|
||||||
if (window_count_panes(src_w) == 0)
|
if (window_count_panes(src_w, 1) == 0)
|
||||||
server_kill_window(src_w, 1);
|
server_kill_window(src_w, 1);
|
||||||
else
|
else
|
||||||
notify_window("window-layout-changed", src_w);
|
notify_window("window-layout-changed", src_w);
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wp == NULL) {
|
||||||
|
cmdq_error(item, "no active pane to kill");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
server_kill_pane(wp);
|
server_kill_pane(wp);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ const struct cmd_entry cmd_kill_session_entry = {
|
|||||||
.name = "kill-session",
|
.name = "kill-session",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "aCt:", 0, 0, NULL },
|
.args = { "aCgt:", 0, 0, NULL },
|
||||||
.usage = "[-aC] " CMD_TARGET_SESSION_USAGE,
|
.usage = "[-aCg] " CMD_TARGET_SESSION_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_SESSION, 0 },
|
.target = { 't', CMD_FIND_SESSION, 0 },
|
||||||
|
|
||||||
@@ -48,6 +48,7 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
struct session *s = target->s, *sloop, *stmp;
|
struct session *s = target->s, *sloop, *stmp;
|
||||||
|
struct session_group *sg;
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
|
|
||||||
if (args_has(args, 'C')) {
|
if (args_has(args, 'C')) {
|
||||||
@@ -63,6 +64,12 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
session_destroy(sloop, 1, __func__);
|
session_destroy(sloop, 1, __func__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (args_has(args, 'g') &&
|
||||||
|
(sg = session_group_contains(s)) != NULL) {
|
||||||
|
TAILQ_FOREACH_SAFE(sloop, &sg->sessions, gentry, stmp) {
|
||||||
|
server_destroy_session(sloop);
|
||||||
|
session_destroy(sloop, 1, __func__);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
server_destroy_session(s);
|
server_destroy_session(s);
|
||||||
session_destroy(s, 1, __func__);
|
session_destroy(s, 1, __func__);
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ const struct cmd_entry cmd_list_buffers_entry = {
|
|||||||
.name = "list-buffers",
|
.name = "list-buffers",
|
||||||
.alias = "lsb",
|
.alias = "lsb",
|
||||||
|
|
||||||
.args = { "F:f:", 0, 0, NULL },
|
.args = { "F:f:O:r", 0, 0, NULL },
|
||||||
.usage = "[-F format] [-f filter]",
|
.usage = "[-F format] [-f filter] [-O order]",
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK,
|
.flags = CMD_AFTERHOOK,
|
||||||
.exec = cmd_list_buffers_exec
|
.exec = cmd_list_buffers_exec
|
||||||
@@ -46,21 +46,30 @@ const struct cmd_entry cmd_list_buffers_entry = {
|
|||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
|
cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
|
||||||
{
|
{
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer **l;
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
const char *template, *filter;
|
const char *template, *filter;
|
||||||
char *line, *expanded;
|
char *line, *expanded;
|
||||||
int flag;
|
int flag;
|
||||||
|
u_int i, n;
|
||||||
|
struct sort_criteria sort_crit;
|
||||||
|
|
||||||
if ((template = args_get(args, 'F')) == NULL)
|
if ((template = args_get(args, 'F')) == NULL)
|
||||||
template = LIST_BUFFERS_TEMPLATE;
|
template = LIST_BUFFERS_TEMPLATE;
|
||||||
filter = args_get(args, 'f');
|
filter = args_get(args, 'f');
|
||||||
|
|
||||||
pb = NULL;
|
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||||
while ((pb = paste_walk(pb)) != NULL) {
|
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
|
||||||
|
cmdq_error(item, "invalid sort order");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
sort_crit.reversed = args_has(args, 'r');
|
||||||
|
|
||||||
|
l = sort_get_buffers(&n, &sort_crit);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||||
format_defaults_paste_buffer(ft, pb);
|
format_defaults_paste_buffer(ft, l[i]);
|
||||||
|
|
||||||
if (filter != NULL) {
|
if (filter != NULL) {
|
||||||
expanded = format_expand(ft, filter);
|
expanded = format_expand(ft, filter);
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ const struct cmd_entry cmd_list_clients_entry = {
|
|||||||
.name = "list-clients",
|
.name = "list-clients",
|
||||||
.alias = "lsc",
|
.alias = "lsc",
|
||||||
|
|
||||||
.args = { "F:f:t:", 0, 0, NULL },
|
.args = { "F:f:O:rt:", 0, 0, NULL },
|
||||||
.usage = "[-F format] [-f filter] " CMD_TARGET_SESSION_USAGE,
|
.usage = "[-F format] [-f filter] [-O order]" CMD_TARGET_SESSION_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_SESSION, 0 },
|
.target = { 't', CMD_FIND_SESSION, 0 },
|
||||||
|
|
||||||
@@ -53,15 +53,16 @@ const struct cmd_entry cmd_list_clients_entry = {
|
|||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
|
cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
|
||||||
{
|
{
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
struct client *c;
|
struct client **l;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
const char *template, *filter;
|
const char *template, *filter;
|
||||||
u_int idx;
|
u_int i, n;
|
||||||
char *line, *expanded;
|
char *line, *expanded;
|
||||||
int flag;
|
int flag;
|
||||||
|
struct sort_criteria sort_crit;
|
||||||
|
|
||||||
if (args_has(args, 't'))
|
if (args_has(args, 't'))
|
||||||
s = target->s;
|
s = target->s;
|
||||||
@@ -72,14 +73,21 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
template = LIST_CLIENTS_TEMPLATE;
|
template = LIST_CLIENTS_TEMPLATE;
|
||||||
filter = args_get(args, 'f');
|
filter = args_get(args, 'f');
|
||||||
|
|
||||||
idx = 0;
|
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||||
TAILQ_FOREACH(c, &clients, entry) {
|
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
|
||||||
if (c->session == NULL || (s != NULL && s != c->session))
|
cmdq_error(item, "invalid sort order");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
sort_crit.reversed = args_has(args, 'r');
|
||||||
|
|
||||||
|
l = sort_get_clients(&n, &sort_crit);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (l[i]->session == NULL || (s != NULL && s != l[i]->session))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||||
format_add(ft, "line", "%u", idx);
|
format_add(ft, "line", "%u", i);
|
||||||
format_defaults(ft, c, NULL, NULL, NULL);
|
format_defaults(ft, l[i], NULL, NULL, NULL);
|
||||||
|
|
||||||
if (filter != NULL) {
|
if (filter != NULL) {
|
||||||
expanded = format_expand(ft, filter);
|
expanded = format_expand(ft, filter);
|
||||||
@@ -94,8 +102,6 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
format_free(ft);
|
format_free(ft);
|
||||||
|
|
||||||
idx++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|||||||
107
cmd-list-commands.c
Normal file
107
cmd-list-commands.c
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/* $OpenBSD$ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tmux.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List all commands.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LIST_COMMANDS_TEMPLATE \
|
||||||
|
"#{command_list_name}" \
|
||||||
|
"#{?command_list_alias, (#{command_list_alias}),} " \
|
||||||
|
"#{command_list_usage}"
|
||||||
|
|
||||||
|
static enum cmd_retval cmd_list_commands(struct cmd *, struct cmdq_item *);
|
||||||
|
|
||||||
|
const struct cmd_entry cmd_list_commands_entry = {
|
||||||
|
.name = "list-commands",
|
||||||
|
.alias = "lscm",
|
||||||
|
|
||||||
|
.args = { "F:", 0, 1, NULL },
|
||||||
|
.usage = "[-F format] [command]",
|
||||||
|
|
||||||
|
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
|
||||||
|
.exec = cmd_list_commands
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_list_single_command(const struct cmd_entry *entry, struct format_tree *ft,
|
||||||
|
const char *template, struct cmdq_item *item)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
char *line;
|
||||||
|
|
||||||
|
format_add(ft, "command_list_name", "%s", entry->name);
|
||||||
|
if (entry->alias != NULL)
|
||||||
|
s = entry->alias;
|
||||||
|
else
|
||||||
|
s = "";
|
||||||
|
format_add(ft, "command_list_alias", "%s", s);
|
||||||
|
if (entry->usage != NULL)
|
||||||
|
s = entry->usage;
|
||||||
|
else
|
||||||
|
s = "";
|
||||||
|
format_add(ft, "command_list_usage", "%s", s);
|
||||||
|
|
||||||
|
line = format_expand(ft, template);
|
||||||
|
if (*line != '\0')
|
||||||
|
cmdq_print(item, "%s", line);
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum cmd_retval
|
||||||
|
cmd_list_commands(struct cmd *self, struct cmdq_item *item)
|
||||||
|
{
|
||||||
|
struct args *args = cmd_get_args(self);
|
||||||
|
const struct cmd_entry **entryp;
|
||||||
|
const struct cmd_entry *entry;
|
||||||
|
struct format_tree *ft;
|
||||||
|
const char *template, *command;
|
||||||
|
char *cause;
|
||||||
|
|
||||||
|
if ((template = args_get(args, 'F')) == NULL)
|
||||||
|
template = LIST_COMMANDS_TEMPLATE;
|
||||||
|
|
||||||
|
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||||
|
format_defaults(ft, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
command = args_string(args, 0);
|
||||||
|
if (command == NULL) {
|
||||||
|
for (entryp = cmd_table; *entryp != NULL; entryp++)
|
||||||
|
cmd_list_single_command(*entryp, ft, template, item);
|
||||||
|
} else {
|
||||||
|
entry = cmd_find(command, &cause);
|
||||||
|
if (entry != NULL)
|
||||||
|
cmd_list_single_command(entry, ft, template, item);
|
||||||
|
else {
|
||||||
|
cmdq_error(item, "%s", cause);
|
||||||
|
free(cause);
|
||||||
|
format_free(ft);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
format_free(ft);
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
429
cmd-list-keys.c
429
cmd-list-keys.c
@@ -27,121 +27,140 @@
|
|||||||
* List key bindings.
|
* List key bindings.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmdq_item *);
|
#define LIST_KEYS_TEMPLATE \
|
||||||
|
"#{?notes_only," \
|
||||||
|
"#{key_prefix} " \
|
||||||
|
"#{p|#{key_string_width}:key_string} " \
|
||||||
|
"#{?key_note,#{key_note},#{key_command}}" \
|
||||||
|
"," \
|
||||||
|
"bind-key #{?key_has_repeat,#{?key_repeat,-r, },} " \
|
||||||
|
"-T #{p|#{key_table_width}:key_table} " \
|
||||||
|
"#{p|#{key_string_width}:#{q|a:key_string}} " \
|
||||||
|
"#{key_command}}"
|
||||||
|
|
||||||
static enum cmd_retval cmd_list_keys_commands(struct cmd *,
|
static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmdq_item *);
|
||||||
struct cmdq_item *);
|
|
||||||
|
|
||||||
const struct cmd_entry cmd_list_keys_entry = {
|
const struct cmd_entry cmd_list_keys_entry = {
|
||||||
.name = "list-keys",
|
.name = "list-keys",
|
||||||
.alias = "lsk",
|
.alias = "lsk",
|
||||||
|
|
||||||
.args = { "1aNP:T:", 0, 1, NULL },
|
.args = { "1aF:NO:P:rT:", 0, 1, NULL },
|
||||||
.usage = "[-1aN] [-P prefix-string] [-T key-table] [key]",
|
.usage = "[-1aNr] [-F format] [-O order] [-P prefix-string]"
|
||||||
|
"[-T key-table] [key]",
|
||||||
|
|
||||||
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
|
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
|
||||||
.exec = cmd_list_keys_exec
|
.exec = cmd_list_keys_exec
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct cmd_entry cmd_list_commands_entry = {
|
static char *
|
||||||
.name = "list-commands",
|
cmd_list_keys_get_prefix(struct args *args)
|
||||||
.alias = "lscm",
|
{
|
||||||
|
key_code prefix;
|
||||||
|
|
||||||
.args = { "F:", 0, 1, NULL },
|
if (args_has(args, 'P'))
|
||||||
.usage = "[-F format] [command]",
|
return (xstrdup(args_get(args, 'P')));
|
||||||
|
|
||||||
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
|
prefix = options_get_number(global_s_options, "prefix");
|
||||||
.exec = cmd_list_keys_exec
|
if (prefix == KEYC_NONE)
|
||||||
};
|
return (xstrdup(""));
|
||||||
|
return (xstrdup(key_string_lookup_key(prefix, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
static u_int
|
static u_int
|
||||||
cmd_list_keys_get_width(const char *tablename, key_code only)
|
cmd_list_keys_get_width(struct key_binding **l, u_int n)
|
||||||
{
|
{
|
||||||
struct key_table *table;
|
u_int i, width, keywidth = 0;
|
||||||
struct key_binding *bd;
|
|
||||||
u_int width, keywidth = 0;
|
|
||||||
|
|
||||||
table = key_bindings_get_table(tablename, 0);
|
for (i = 0; i < n; i++) {
|
||||||
if (table == NULL)
|
width = utf8_cstrwidth(key_string_lookup_key(l[i]->key, 0));
|
||||||
return (0);
|
|
||||||
bd = key_bindings_first(table);
|
|
||||||
while (bd != NULL) {
|
|
||||||
if ((only != KEYC_UNKNOWN && bd->key != only) ||
|
|
||||||
KEYC_IS_MOUSE(bd->key) ||
|
|
||||||
bd->note == NULL ||
|
|
||||||
*bd->note == '\0') {
|
|
||||||
bd = key_bindings_next(table, bd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
width = utf8_cstrwidth(key_string_lookup_key(bd->key, 0));
|
|
||||||
if (width > keywidth)
|
if (width > keywidth)
|
||||||
keywidth = width;
|
keywidth = width;
|
||||||
|
|
||||||
bd = key_bindings_next(table, bd);
|
|
||||||
}
|
}
|
||||||
return (keywidth);
|
return (keywidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static u_int
|
||||||
cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
|
cmd_list_keys_get_table_width(struct key_binding **l, u_int n)
|
||||||
const char *tablename, u_int keywidth, key_code only, const char *prefix)
|
|
||||||
{
|
{
|
||||||
struct client *tc = cmdq_get_target_client(item);
|
u_int i, width, tablewidth = 0;
|
||||||
struct key_table *table;
|
|
||||||
struct key_binding *bd;
|
|
||||||
const char *key;
|
|
||||||
char *tmp, *note;
|
|
||||||
int found = 0;
|
|
||||||
|
|
||||||
table = key_bindings_get_table(tablename, 0);
|
for (i = 0; i < n; i++) {
|
||||||
if (table == NULL)
|
width = utf8_cstrwidth(l[i]->tablename);
|
||||||
return (0);
|
if (width > tablewidth)
|
||||||
bd = key_bindings_first(table);
|
tablewidth = width;
|
||||||
while (bd != NULL) {
|
|
||||||
if ((only != KEYC_UNKNOWN && bd->key != only) ||
|
|
||||||
KEYC_IS_MOUSE(bd->key) ||
|
|
||||||
((bd->note == NULL || *bd->note == '\0') &&
|
|
||||||
!args_has(args, 'a'))) {
|
|
||||||
bd = key_bindings_next(table, bd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
found = 1;
|
|
||||||
key = key_string_lookup_key(bd->key, 0);
|
|
||||||
|
|
||||||
if (bd->note == NULL || *bd->note == '\0')
|
|
||||||
note = cmd_list_print(bd->cmdlist, 1);
|
|
||||||
else
|
|
||||||
note = xstrdup(bd->note);
|
|
||||||
tmp = utf8_padcstr(key, keywidth + 1);
|
|
||||||
if (args_has(args, '1') && tc != NULL) {
|
|
||||||
status_message_set(tc, -1, 1, 0, "%s%s%s", prefix, tmp,
|
|
||||||
note);
|
|
||||||
} else
|
|
||||||
cmdq_print(item, "%s%s%s", prefix, tmp, note);
|
|
||||||
free(tmp);
|
|
||||||
free(note);
|
|
||||||
|
|
||||||
if (args_has(args, '1'))
|
|
||||||
break;
|
|
||||||
bd = key_bindings_next(table, bd);
|
|
||||||
}
|
}
|
||||||
return (found);
|
return (tablewidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static struct key_binding **
|
||||||
cmd_list_keys_get_prefix(struct args *args, key_code *prefix)
|
cmd_list_keys_get_root_and_prefix(u_int *n, struct sort_criteria *sort_crit)
|
||||||
|
{
|
||||||
|
const char *tables[] = { "prefix", "root" };
|
||||||
|
struct key_table *t;
|
||||||
|
struct key_binding **lt;
|
||||||
|
u_int i, ltsz, len = 0, offset = 0;
|
||||||
|
static struct key_binding **l = NULL;
|
||||||
|
static u_int lsz = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(tables); i++) {
|
||||||
|
t = key_bindings_get_table(tables[i], 0);
|
||||||
|
lt = sort_get_key_bindings_table(t, <sz, sort_crit);
|
||||||
|
len += ltsz;
|
||||||
|
if (lsz <= len) {
|
||||||
|
lsz = len + 100;
|
||||||
|
l = xreallocarray(l, lsz, sizeof *l);
|
||||||
|
}
|
||||||
|
memcpy(l + offset, lt, ltsz * sizeof *l);
|
||||||
|
offset += ltsz;
|
||||||
|
}
|
||||||
|
|
||||||
|
*n = len;
|
||||||
|
return (l);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_list_keys_filter_key_list(int filter_notes, int filter_key, key_code only,
|
||||||
|
struct key_binding **l, u_int *n)
|
||||||
|
{
|
||||||
|
key_code key;
|
||||||
|
u_int i, j = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < *n; i++) {
|
||||||
|
key = l[i]->key & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
|
||||||
|
if (filter_key && only != key)
|
||||||
|
continue;
|
||||||
|
if (filter_notes && l[i]->note == NULL)
|
||||||
|
continue;
|
||||||
|
l[j++] = l[i];
|
||||||
|
}
|
||||||
|
*n = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_list_keys_format_add_key_binding(struct format_tree *ft,
|
||||||
|
const struct key_binding *bd, const char *prefix)
|
||||||
{
|
{
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
*prefix = options_get_number(global_s_options, "prefix");
|
if (bd->flags & KEY_BINDING_REPEAT)
|
||||||
if (!args_has(args, 'P')) {
|
format_add(ft, "key_repeat", "1");
|
||||||
if (*prefix != KEYC_NONE)
|
else
|
||||||
xasprintf(&s, "%s ", key_string_lookup_key(*prefix, 0));
|
format_add(ft, "key_repeat", "0");
|
||||||
else
|
|
||||||
s = xstrdup("");
|
if (bd->note != NULL)
|
||||||
} else
|
format_add(ft, "key_note", "%s", bd->note);
|
||||||
s = xstrdup(args_get(args, 'P'));
|
else
|
||||||
return (s);
|
format_add(ft, "key_note", "%s", "");
|
||||||
|
|
||||||
|
format_add(ft, "key_prefix", "%s", prefix);
|
||||||
|
format_add(ft, "key_table", "%s", bd->tablename);
|
||||||
|
|
||||||
|
format_add(ft, "key_string", "%s", key_string_lookup_key(bd->key, 0));
|
||||||
|
|
||||||
|
s = cmd_list_print(bd->cmdlist, CMD_LIST_PRINT_ESCAPED|
|
||||||
|
CMD_LIST_PRINT_NO_GROUPS);
|
||||||
|
format_add(ft, "key_command", "%s", s);
|
||||||
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
@@ -149,16 +168,16 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
{
|
{
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct client *tc = cmdq_get_target_client(item);
|
struct client *tc = cmdq_get_target_client(item);
|
||||||
struct key_table *table;
|
struct format_tree *ft;
|
||||||
struct key_binding *bd;
|
struct key_table *table = NULL;
|
||||||
const char *tablename, *r, *keystr;
|
struct key_binding **l;
|
||||||
char *key, *cp, *tmp, *start, *empty;
|
key_code only = KEYC_UNKNOWN;
|
||||||
key_code prefix, only = KEYC_UNKNOWN;
|
const char *template, *tablename, *keystr;
|
||||||
int repeat, width, tablewidth, keywidth, found = 0;
|
char *line;
|
||||||
size_t tmpsize, tmpused, cplen;
|
char *prefix = NULL;
|
||||||
|
u_int i, n;
|
||||||
if (cmd_get_entry(self) == &cmd_list_commands_entry)
|
int single, notes_only, filter_notes, filter_key;
|
||||||
return (cmd_list_keys_commands(self, item));
|
struct sort_criteria sort_crit;
|
||||||
|
|
||||||
if ((keystr = args_string(args, 0)) != NULL) {
|
if ((keystr = args_string(args, 0)) != NULL) {
|
||||||
only = key_string_lookup_string(keystr);
|
only = key_string_lookup_string(keystr);
|
||||||
@@ -169,204 +188,66 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
|
only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
tablename = args_get(args, 'T');
|
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||||
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
|
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
|
||||||
cmdq_error(item, "table %s doesn't exist", tablename);
|
cmdq_error(item, "invalid sort order");
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
sort_crit.reversed = args_has(args, 'r');
|
||||||
|
|
||||||
if (args_has(args, 'N')) {
|
if ((tablename = args_get(args, 'T')) != NULL) {
|
||||||
if (tablename == NULL) {
|
table = key_bindings_get_table(tablename, 0);
|
||||||
start = cmd_list_keys_get_prefix(args, &prefix);
|
if (table == NULL) {
|
||||||
keywidth = cmd_list_keys_get_width("root", only);
|
cmdq_error(item, "table %s doesn't exist", tablename);
|
||||||
if (prefix != KEYC_NONE) {
|
return (CMD_RETURN_ERROR);
|
||||||
width = cmd_list_keys_get_width("prefix", only);
|
|
||||||
if (width == 0)
|
|
||||||
prefix = KEYC_NONE;
|
|
||||||
else if (width > keywidth)
|
|
||||||
keywidth = width;
|
|
||||||
}
|
|
||||||
empty = utf8_padcstr("", utf8_cstrwidth(start));
|
|
||||||
|
|
||||||
found = cmd_list_keys_print_notes(item, args, "root",
|
|
||||||
keywidth, only, empty);
|
|
||||||
if (prefix != KEYC_NONE) {
|
|
||||||
if (cmd_list_keys_print_notes(item, args,
|
|
||||||
"prefix", keywidth, only, start))
|
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
free(empty);
|
|
||||||
} else {
|
|
||||||
if (args_has(args, 'P'))
|
|
||||||
start = xstrdup(args_get(args, 'P'));
|
|
||||||
else
|
|
||||||
start = xstrdup("");
|
|
||||||
keywidth = cmd_list_keys_get_width(tablename, only);
|
|
||||||
found = cmd_list_keys_print_notes(item, args, tablename,
|
|
||||||
keywidth, only, start);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
free(start);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
repeat = 0;
|
prefix = cmd_list_keys_get_prefix(args);
|
||||||
tablewidth = keywidth = 0;
|
single = args_has(args, '1');
|
||||||
table = key_bindings_first_table();
|
notes_only = args_has(args, 'N');
|
||||||
while (table != NULL) {
|
|
||||||
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
|
|
||||||
table = key_bindings_next_table(table);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bd = key_bindings_first(table);
|
|
||||||
while (bd != NULL) {
|
|
||||||
if (only != KEYC_UNKNOWN && bd->key != only) {
|
|
||||||
bd = key_bindings_next(table, bd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
key = args_escape(key_string_lookup_key(bd->key, 0));
|
|
||||||
|
|
||||||
if (bd->flags & KEY_BINDING_REPEAT)
|
if ((template = args_get(args, 'F')) == NULL)
|
||||||
repeat = 1;
|
template = LIST_KEYS_TEMPLATE;
|
||||||
|
|
||||||
width = utf8_cstrwidth(table->name);
|
if (table)
|
||||||
if (width > tablewidth)
|
l = sort_get_key_bindings_table(table, &n, &sort_crit);
|
||||||
tablewidth = width;
|
else if (notes_only)
|
||||||
width = utf8_cstrwidth(key);
|
l = cmd_list_keys_get_root_and_prefix(&n, &sort_crit);
|
||||||
if (width > keywidth)
|
else
|
||||||
keywidth = width;
|
l = sort_get_key_bindings(&n, &sort_crit);
|
||||||
|
|
||||||
free(key);
|
filter_notes = notes_only && !args_has(args, 'a');
|
||||||
bd = key_bindings_next(table, bd);
|
filter_key = only != KEYC_UNKNOWN;
|
||||||
}
|
if (filter_notes || filter_key) {
|
||||||
table = key_bindings_next_table(table);
|
cmd_list_keys_filter_key_list(filter_notes, filter_key, only, l,
|
||||||
}
|
&n);
|
||||||
|
|
||||||
tmpsize = 256;
|
|
||||||
tmp = xmalloc(tmpsize);
|
|
||||||
|
|
||||||
table = key_bindings_first_table();
|
|
||||||
while (table != NULL) {
|
|
||||||
if (tablename != NULL && strcmp(table->name, tablename) != 0) {
|
|
||||||
table = key_bindings_next_table(table);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bd = key_bindings_first(table);
|
|
||||||
while (bd != NULL) {
|
|
||||||
if (only != KEYC_UNKNOWN && bd->key != only) {
|
|
||||||
bd = key_bindings_next(table, bd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
found = 1;
|
|
||||||
key = args_escape(key_string_lookup_key(bd->key, 0));
|
|
||||||
|
|
||||||
if (!repeat)
|
|
||||||
r = "";
|
|
||||||
else if (bd->flags & KEY_BINDING_REPEAT)
|
|
||||||
r = "-r ";
|
|
||||||
else
|
|
||||||
r = " ";
|
|
||||||
tmpused = xsnprintf(tmp, tmpsize, "%s-T ", r);
|
|
||||||
|
|
||||||
cp = utf8_padcstr(table->name, tablewidth);
|
|
||||||
cplen = strlen(cp) + 1;
|
|
||||||
while (tmpused + cplen + 1 >= tmpsize) {
|
|
||||||
tmpsize *= 2;
|
|
||||||
tmp = xrealloc(tmp, tmpsize);
|
|
||||||
}
|
|
||||||
strlcat(tmp, cp, tmpsize);
|
|
||||||
tmpused = strlcat(tmp, " ", tmpsize);
|
|
||||||
free(cp);
|
|
||||||
|
|
||||||
cp = utf8_padcstr(key, keywidth);
|
|
||||||
cplen = strlen(cp) + 1;
|
|
||||||
while (tmpused + cplen + 1 >= tmpsize) {
|
|
||||||
tmpsize *= 2;
|
|
||||||
tmp = xrealloc(tmp, tmpsize);
|
|
||||||
}
|
|
||||||
strlcat(tmp, cp, tmpsize);
|
|
||||||
tmpused = strlcat(tmp, " ", tmpsize);
|
|
||||||
free(cp);
|
|
||||||
|
|
||||||
cp = cmd_list_print(bd->cmdlist, 1);
|
|
||||||
cplen = strlen(cp);
|
|
||||||
while (tmpused + cplen + 1 >= tmpsize) {
|
|
||||||
tmpsize *= 2;
|
|
||||||
tmp = xrealloc(tmp, tmpsize);
|
|
||||||
}
|
|
||||||
strlcat(tmp, cp, tmpsize);
|
|
||||||
free(cp);
|
|
||||||
|
|
||||||
if (args_has(args, '1') && tc != NULL) {
|
|
||||||
status_message_set(tc, -1, 1, 0, "bind-key %s",
|
|
||||||
tmp);
|
|
||||||
} else
|
|
||||||
cmdq_print(item, "bind-key %s", tmp);
|
|
||||||
free(key);
|
|
||||||
|
|
||||||
if (args_has(args, '1'))
|
|
||||||
break;
|
|
||||||
bd = key_bindings_next(table, bd);
|
|
||||||
}
|
|
||||||
table = key_bindings_next_table(table);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (only != KEYC_UNKNOWN && !found) {
|
|
||||||
cmdq_error(item, "unknown key: %s", args_string(args, 0));
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum cmd_retval
|
|
||||||
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
|
|
||||||
{
|
|
||||||
struct args *args = cmd_get_args(self);
|
|
||||||
const struct cmd_entry **entryp;
|
|
||||||
const struct cmd_entry *entry;
|
|
||||||
struct format_tree *ft;
|
|
||||||
const char *template, *s, *command;
|
|
||||||
char *line;
|
|
||||||
|
|
||||||
if ((template = args_get(args, 'F')) == NULL) {
|
|
||||||
template = "#{command_list_name}"
|
|
||||||
"#{?command_list_alias, (#{command_list_alias}),} "
|
|
||||||
"#{command_list_usage}";
|
|
||||||
}
|
}
|
||||||
|
if (single)
|
||||||
|
n = 1;
|
||||||
|
|
||||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||||
format_defaults(ft, NULL, NULL, NULL, NULL);
|
format_defaults(ft, NULL, NULL, NULL, NULL);
|
||||||
|
format_add(ft, "notes_only", "%d", notes_only);
|
||||||
command = args_string(args, 0);
|
format_add(ft, "key_has_repeat", "%d", key_bindings_has_repeat(l, n));
|
||||||
for (entryp = cmd_table; *entryp != NULL; entryp++) {
|
format_add(ft, "key_string_width", "%u", cmd_list_keys_get_width(l, n));
|
||||||
entry = *entryp;
|
format_add(ft, "key_table_width", "%u",
|
||||||
if (command != NULL &&
|
cmd_list_keys_get_table_width(l, n));
|
||||||
(strcmp(entry->name, command) != 0 &&
|
for (i = 0; i < n; i++) {
|
||||||
(entry->alias == NULL ||
|
cmd_list_keys_format_add_key_binding(ft, l[i], prefix);
|
||||||
strcmp(entry->alias, command) != 0)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
format_add(ft, "command_list_name", "%s", entry->name);
|
|
||||||
if (entry->alias != NULL)
|
|
||||||
s = entry->alias;
|
|
||||||
else
|
|
||||||
s = "";
|
|
||||||
format_add(ft, "command_list_alias", "%s", s);
|
|
||||||
if (entry->usage != NULL)
|
|
||||||
s = entry->usage;
|
|
||||||
else
|
|
||||||
s = "";
|
|
||||||
format_add(ft, "command_list_usage", "%s", s);
|
|
||||||
|
|
||||||
line = format_expand(ft, template);
|
line = format_expand(ft, template);
|
||||||
if (*line != '\0')
|
if ((single && tc != NULL) || n == 1)
|
||||||
|
status_message_set(tc, -1, 1, 0, 0, "%s", line);
|
||||||
|
else if (*line != '\0')
|
||||||
cmdq_print(item, "%s", line);
|
cmdq_print(item, "%s", line);
|
||||||
free(line);
|
free(line);
|
||||||
}
|
|
||||||
|
|
||||||
|
if (single)
|
||||||
|
break;
|
||||||
|
}
|
||||||
format_free(ft);
|
format_free(ft);
|
||||||
|
free(prefix);
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,8 +38,9 @@ const struct cmd_entry cmd_list_panes_entry = {
|
|||||||
.name = "list-panes",
|
.name = "list-panes",
|
||||||
.alias = "lsp",
|
.alias = "lsp",
|
||||||
|
|
||||||
.args = { "asF:f:t:", 0, 0, NULL },
|
.args = { "aF:f:O:rst:", 0, 0, NULL },
|
||||||
.usage = "[-as] [-F format] [-f filter] " CMD_TARGET_WINDOW_USAGE,
|
.usage = "[-asr] [-F format] [-f filter] [-O order]"
|
||||||
|
CMD_TARGET_WINDOW_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_WINDOW, 0 },
|
.target = { 't', CMD_FIND_WINDOW, 0 },
|
||||||
|
|
||||||
@@ -54,6 +55,13 @@ cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
struct session *s = target->s;
|
struct session *s = target->s;
|
||||||
struct winlink *wl = target->wl;
|
struct winlink *wl = target->wl;
|
||||||
|
enum sort_order order;
|
||||||
|
|
||||||
|
order = sort_order_from_string(args_get(args, 'O'));
|
||||||
|
if (order == SORT_END && args_has(args, 'O')) {
|
||||||
|
cmdq_error(item, "invalid sort order");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
if (args_has(args, 'a'))
|
if (args_has(args, 'a'))
|
||||||
cmd_list_panes_server(self, item);
|
cmd_list_panes_server(self, item);
|
||||||
@@ -89,34 +97,41 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
|
|||||||
struct cmdq_item *item, int type)
|
struct cmdq_item *item, int type)
|
||||||
{
|
{
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct window_pane *wp;
|
struct window_pane *wp, **l;
|
||||||
u_int n;
|
u_int i, n;
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
const char *template, *filter;
|
const char *template, *filter;
|
||||||
char *line, *expanded;
|
char *line, *expanded;
|
||||||
int flag;
|
int flag;
|
||||||
|
struct sort_criteria sort_crit;
|
||||||
|
|
||||||
template = args_get(args, 'F');
|
template = args_get(args, 'F');
|
||||||
if (template == NULL) {
|
if (template == NULL) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0:
|
case 0:
|
||||||
template = "#{pane_index}: "
|
template = "#{pane_index}: "
|
||||||
"[#{pane_width}x#{pane_height}] [history "
|
"[#{pane_width}x#{pane_height}"
|
||||||
|
"#{?pane_floating_flag, "
|
||||||
|
"#{pane_x}#,#{pane_y}#,#{pane_z}}] [history "
|
||||||
"#{history_size}/#{history_limit}, "
|
"#{history_size}/#{history_limit}, "
|
||||||
"#{history_bytes} bytes] #{pane_id}"
|
"#{history_bytes} bytes] #{pane_id}"
|
||||||
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
|
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
template = "#{window_index}.#{pane_index}: "
|
template = "#{window_index}.#{pane_index}: "
|
||||||
"[#{pane_width}x#{pane_height}] [history "
|
"[#{pane_width}x#{pane_height}"
|
||||||
|
"#{?pane_floating_flag, "
|
||||||
|
"#{pane_x}#,#{pane_y}#,#{pane_z}}] [history "
|
||||||
"#{history_size}/#{history_limit}, "
|
"#{history_size}/#{history_limit}, "
|
||||||
"#{history_bytes} bytes] #{pane_id}"
|
"#{history_bytes} bytes] #{pane_id}"
|
||||||
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
|
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
template = "#{session_name}:#{window_index}."
|
template = "#{session_name}:#{window_index}."
|
||||||
"#{pane_index}: [#{pane_width}x#{pane_height}] "
|
"#{pane_index}: [#{pane_width}x#{pane_height}"
|
||||||
"[history #{history_size}/#{history_limit}, "
|
"#{?pane_floating_flag, "
|
||||||
|
"#{pane_x}#,#{pane_y}#,#{pane_z}}] [history "
|
||||||
|
"#{history_size}/#{history_limit}, "
|
||||||
"#{history_bytes} bytes] #{pane_id}"
|
"#{history_bytes} bytes] #{pane_id}"
|
||||||
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
|
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
|
||||||
break;
|
break;
|
||||||
@@ -124,8 +139,12 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
|
|||||||
}
|
}
|
||||||
filter = args_get(args, 'f');
|
filter = args_get(args, 'f');
|
||||||
|
|
||||||
n = 0;
|
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||||
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
|
sort_crit.reversed = args_has(args, 'r');
|
||||||
|
|
||||||
|
l = sort_get_panes_window(wl->window, &n, &sort_crit);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
wp = l[i];
|
||||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||||
format_add(ft, "line", "%u", n);
|
format_add(ft, "line", "%u", n);
|
||||||
format_defaults(ft, NULL, s, wl, wp);
|
format_defaults(ft, NULL, s, wl, wp);
|
||||||
@@ -143,6 +162,5 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
format_free(ft);
|
format_free(ft);
|
||||||
n++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ const struct cmd_entry cmd_list_sessions_entry = {
|
|||||||
.name = "list-sessions",
|
.name = "list-sessions",
|
||||||
.alias = "ls",
|
.alias = "ls",
|
||||||
|
|
||||||
.args = { "F:f:", 0, 0, NULL },
|
.args = { "F:f:O:r", 0, 0, NULL },
|
||||||
.usage = "[-F format] [-f filter]",
|
.usage = "[-r] [-F format] [-f filter] [-O order]",
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK,
|
.flags = CMD_AFTERHOOK,
|
||||||
.exec = cmd_list_sessions_exec
|
.exec = cmd_list_sessions_exec
|
||||||
@@ -52,23 +52,31 @@ const struct cmd_entry cmd_list_sessions_entry = {
|
|||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
|
cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
|
||||||
{
|
{
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct session *s;
|
struct session **l;
|
||||||
u_int n;
|
u_int n, i;
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
const char *template, *filter;
|
const char *template, *filter;
|
||||||
char *line, *expanded;
|
char *line, *expanded;
|
||||||
int flag;
|
int flag;
|
||||||
|
struct sort_criteria sort_crit;
|
||||||
|
|
||||||
if ((template = args_get(args, 'F')) == NULL)
|
if ((template = args_get(args, 'F')) == NULL)
|
||||||
template = LIST_SESSIONS_TEMPLATE;
|
template = LIST_SESSIONS_TEMPLATE;
|
||||||
filter = args_get(args, 'f');
|
filter = args_get(args, 'f');
|
||||||
|
|
||||||
n = 0;
|
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||||
RB_FOREACH(s, sessions, &sessions) {
|
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
|
||||||
|
cmdq_error(item, "invalid sort order");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
sort_crit.reversed = args_has(args, 'r');
|
||||||
|
|
||||||
|
l = sort_get_sessions(&n, &sort_crit);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||||
format_add(ft, "line", "%u", n);
|
format_add(ft, "line", "%u", i);
|
||||||
format_defaults(ft, NULL, s, NULL, NULL);
|
format_defaults(ft, NULL, l[i], NULL, NULL);
|
||||||
|
|
||||||
if (filter != NULL) {
|
if (filter != NULL) {
|
||||||
expanded = format_expand(ft, filter);
|
expanded = format_expand(ft, filter);
|
||||||
@@ -83,7 +91,6 @@ cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
format_free(ft);
|
format_free(ft);
|
||||||
n++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|||||||
@@ -41,16 +41,13 @@
|
|||||||
|
|
||||||
static enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmdq_item *);
|
static enum cmd_retval cmd_list_windows_exec(struct cmd *, struct cmdq_item *);
|
||||||
|
|
||||||
static void cmd_list_windows_server(struct cmd *, struct cmdq_item *);
|
|
||||||
static void cmd_list_windows_session(struct cmd *, struct session *,
|
|
||||||
struct cmdq_item *, int);
|
|
||||||
|
|
||||||
const struct cmd_entry cmd_list_windows_entry = {
|
const struct cmd_entry cmd_list_windows_entry = {
|
||||||
.name = "list-windows",
|
.name = "list-windows",
|
||||||
.alias = "lsw",
|
.alias = "lsw",
|
||||||
|
|
||||||
.args = { "F:f:at:", 0, 0, NULL },
|
.args = { "aF:f:O:rt:", 0, 0, NULL },
|
||||||
.usage = "[-a] [-F format] [-f filter] " CMD_TARGET_SESSION_USAGE,
|
.usage = "[-ar] [-F format] [-f filter] [-O order]"
|
||||||
|
CMD_TARGET_SESSION_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_SESSION, 0 },
|
.target = { 't', CMD_FIND_SESSION, 0 },
|
||||||
|
|
||||||
@@ -63,51 +60,38 @@ cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
{
|
{
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
|
struct winlink *wl, **l;
|
||||||
if (args_has(args, 'a'))
|
struct session *s;
|
||||||
cmd_list_windows_server(self, item);
|
u_int i, n;
|
||||||
else
|
|
||||||
cmd_list_windows_session(self, target->s, item, 0);
|
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
cmd_list_windows_server(struct cmd *self, struct cmdq_item *item)
|
|
||||||
{
|
|
||||||
struct session *s;
|
|
||||||
|
|
||||||
RB_FOREACH(s, sessions, &sessions)
|
|
||||||
cmd_list_windows_session(self, s, item, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
cmd_list_windows_session(struct cmd *self, struct session *s,
|
|
||||||
struct cmdq_item *item, int type)
|
|
||||||
{
|
|
||||||
struct args *args = cmd_get_args(self);
|
|
||||||
struct winlink *wl;
|
|
||||||
u_int n;
|
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
const char *template, *filter;
|
const char *template, *filter;
|
||||||
char *line, *expanded;
|
char *line, *expanded;
|
||||||
int flag;
|
int flag;
|
||||||
|
struct sort_criteria sort_crit;
|
||||||
|
|
||||||
template = args_get(args, 'F');
|
template = args_get(args, 'F');
|
||||||
if (template == NULL) {
|
|
||||||
switch (type) {
|
|
||||||
case 0:
|
|
||||||
template = LIST_WINDOWS_TEMPLATE;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
template = LIST_WINDOWS_WITH_SESSION_TEMPLATE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filter = args_get(args, 'f');
|
filter = args_get(args, 'f');
|
||||||
|
|
||||||
n = 0;
|
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
|
||||||
|
cmdq_error(item, "invalid sort order");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
sort_crit.reversed = args_has(args, 'r');
|
||||||
|
|
||||||
|
if (args_has(args, 'a')) {
|
||||||
|
l = sort_get_winlinks(&n, &sort_crit);
|
||||||
|
if (template == NULL)
|
||||||
|
template = LIST_WINDOWS_WITH_SESSION_TEMPLATE;
|
||||||
|
} else {
|
||||||
|
l = sort_get_winlinks_session(target->s, &n, &sort_crit);
|
||||||
|
if (template == NULL)
|
||||||
|
template = LIST_WINDOWS_TEMPLATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
wl = l[i];
|
||||||
|
s = wl->session;
|
||||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||||
format_add(ft, "line", "%u", n);
|
format_add(ft, "line", "%u", n);
|
||||||
format_defaults(ft, NULL, s, wl, NULL);
|
format_defaults(ft, NULL, s, wl, NULL);
|
||||||
@@ -125,6 +109,7 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
format_free(ft);
|
format_free(ft);
|
||||||
n++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
cmdq_error(item, "%s: %s", path, strerror(error));
|
cmdq_error(item, "%s: %s", strerror(error), path);
|
||||||
else if (bsize != 0) {
|
else if (bsize != 0) {
|
||||||
copy = xmalloc(bsize);
|
copy = xmalloc(bsize);
|
||||||
memcpy(copy, bdata, bsize);
|
memcpy(copy, bdata, bsize);
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const struct cmd_entry cmd_new_session_entry = {
|
|||||||
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] "
|
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] "
|
||||||
"[-f flags] [-n window-name] [-s session-name] "
|
"[-f flags] [-n window-name] [-s session-name] "
|
||||||
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] "
|
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] "
|
||||||
"[shell-command]",
|
"[shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
||||||
|
|
||||||
@@ -77,8 +77,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct termios tio, *tiop;
|
struct termios tio, *tiop;
|
||||||
struct session_group *sg = NULL;
|
struct session_group *sg = NULL;
|
||||||
const char *errstr, *template, *group, *tmp;
|
const char *errstr, *template, *group, *tmp;
|
||||||
char *cause, *cwd = NULL, *cp, *newname = NULL;
|
char *cause, *cwd = NULL, *cp, *ename;
|
||||||
char *name, *prefix = NULL;
|
char *wname = NULL, *sname = NULL, *prefix = NULL;
|
||||||
int detached, already_attached, is_control = 0;
|
int detached, already_attached, is_control = 0;
|
||||||
u_int sx, sy, dsx, dsy, count = args_count(args);
|
u_int sx, sy, dsx, dsy, count = args_count(args);
|
||||||
struct spawn_context sc = { 0 };
|
struct spawn_context sc = { 0 };
|
||||||
@@ -99,32 +99,43 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = args_get(args, 's');
|
if ((tmp = args_get(args, 'n')) != NULL) {
|
||||||
if (tmp != NULL) {
|
ename = format_single(item, tmp, c, NULL, NULL, NULL);
|
||||||
name = format_single(item, tmp, c, NULL, NULL, NULL);
|
if (!check_name(ename)) {
|
||||||
newname = session_check_name(name);
|
cmdq_error(item, "invalid window name: %s", ename);
|
||||||
if (newname == NULL) {
|
free(ename);
|
||||||
cmdq_error(item, "invalid session: %s", name);
|
|
||||||
free(name);
|
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
free(name);
|
wname = clean_name(ename, 0);
|
||||||
|
free(ename);
|
||||||
|
}
|
||||||
|
if ((tmp = args_get(args, 's')) != NULL) {
|
||||||
|
ename = format_single(item, tmp, c, NULL, NULL, NULL);
|
||||||
|
if (!check_name(ename)) {
|
||||||
|
cmdq_error(item, "invalid session name: %s", ename);
|
||||||
|
free(ename);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
sname = clean_name(ename, 0);
|
||||||
|
free(ename);
|
||||||
}
|
}
|
||||||
if (args_has(args, 'A')) {
|
if (args_has(args, 'A')) {
|
||||||
if (newname != NULL)
|
if (sname != NULL)
|
||||||
as = session_find(newname);
|
as = session_find(sname);
|
||||||
else
|
else
|
||||||
as = target->s;
|
as = target->s;
|
||||||
if (as != NULL) {
|
if (as != NULL) {
|
||||||
retval = cmd_attach_session(item, as->name,
|
retval = cmd_attach_session(item, as->name,
|
||||||
args_has(args, 'D'), args_has(args, 'X'), 0, NULL,
|
args_has(args, 'D'), args_has(args, 'X'), 0,
|
||||||
args_has(args, 'E'), args_get(args, 'f'));
|
args_get(args, 'c'), args_has(args, 'E'),
|
||||||
free(newname);
|
args_get(args, 'f'));
|
||||||
|
free(wname);
|
||||||
|
free(sname);
|
||||||
return (retval);
|
return (retval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (newname != NULL && session_find(newname) != NULL) {
|
if (sname != NULL && session_find(sname) != NULL) {
|
||||||
cmdq_error(item, "duplicate session: %s", newname);
|
cmdq_error(item, "duplicate session: %s", sname);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,12 +152,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
else if (groupwith != NULL)
|
else if (groupwith != NULL)
|
||||||
prefix = xstrdup(groupwith->name);
|
prefix = xstrdup(groupwith->name);
|
||||||
else {
|
else {
|
||||||
prefix = session_check_name(group);
|
if (!check_name(group)) {
|
||||||
if (prefix == NULL) {
|
cmdq_error(item,
|
||||||
cmdq_error(item, "invalid session group: %s",
|
"invalid session group name: %s", group);
|
||||||
group);
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
prefix = clean_name(group, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +286,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
environ_put(env, av->string, 0);
|
environ_put(env, av->string, 0);
|
||||||
av = args_next_value(av);
|
av = args_next_value(av);
|
||||||
}
|
}
|
||||||
s = session_create(prefix, newname, cwd, env, oo, tiop);
|
s = session_create(prefix, sname, cwd, env, oo, tiop);
|
||||||
|
|
||||||
/* Spawn the initial window. */
|
/* Spawn the initial window. */
|
||||||
sc.item = item;
|
sc.item = item;
|
||||||
@@ -283,7 +294,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (!detached)
|
if (!detached)
|
||||||
sc.tc = c;
|
sc.tc = c;
|
||||||
|
|
||||||
sc.name = args_get(args, 'n');
|
sc.name = wname;
|
||||||
args_to_vector(args, &sc.argc, &sc.argv);
|
args_to_vector(args, &sc.argc, &sc.argv);
|
||||||
|
|
||||||
sc.idx = -1;
|
sc.idx = -1;
|
||||||
@@ -356,7 +367,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (sc.argv != NULL)
|
if (sc.argv != NULL)
|
||||||
cmd_free_argv(sc.argc, sc.argv);
|
cmd_free_argv(sc.argc, sc.argv);
|
||||||
free(cwd);
|
free(cwd);
|
||||||
free(newname);
|
free(wname);
|
||||||
|
free(sname);
|
||||||
free(prefix);
|
free(prefix);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
@@ -364,7 +376,8 @@ fail:
|
|||||||
if (sc.argv != NULL)
|
if (sc.argv != NULL)
|
||||||
cmd_free_argv(sc.argc, sc.argv);
|
cmd_free_argv(sc.argc, sc.argv);
|
||||||
free(cwd);
|
free(cwd);
|
||||||
free(newname);
|
free(wname);
|
||||||
|
free(sname);
|
||||||
free(prefix);
|
free(prefix);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ const struct cmd_entry cmd_new_window_entry = {
|
|||||||
|
|
||||||
.args = { "abc:de:F:kn:PSt:", 0, -1, NULL },
|
.args = { "abc:de:F:kn:PSt:", 0, -1, NULL },
|
||||||
.usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] "
|
.usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] "
|
||||||
"[-n window-name] " CMD_TARGET_WINDOW_USAGE " [shell-command]",
|
"[-n window-name] " CMD_TARGET_WINDOW_USAGE
|
||||||
|
" [shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
|
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
|
||||||
|
|
||||||
@@ -60,7 +61,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct session *s = target->s;
|
struct session *s = target->s;
|
||||||
struct winlink *wl = target->wl, *new_wl = NULL;
|
struct winlink *wl = target->wl, *new_wl = NULL;
|
||||||
int idx = target->idx, before;
|
int idx = target->idx, before;
|
||||||
char *cause = NULL, *cp, *expanded;
|
char *cause = NULL, *cp, *expanded, *wname = NULL;
|
||||||
const char *template, *name;
|
const char *template, *name;
|
||||||
struct cmd_find_state fs;
|
struct cmd_find_state fs;
|
||||||
struct args_value *av;
|
struct args_value *av;
|
||||||
@@ -70,8 +71,18 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
* name already exists, select it.
|
* name already exists, select it.
|
||||||
*/
|
*/
|
||||||
name = args_get(args, 'n');
|
name = args_get(args, 'n');
|
||||||
if (args_has(args, 'S') && name != NULL && target->idx == -1) {
|
if (name != NULL) {
|
||||||
expanded = format_single(item, name, c, s, NULL, NULL);
|
expanded = format_single(item, name, c, s, NULL, NULL);
|
||||||
|
if (!check_name(expanded)) {
|
||||||
|
cmdq_error(item, "invalid window name: %s", expanded);
|
||||||
|
free(expanded);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
wname = clean_name(expanded, 0);
|
||||||
|
free(expanded);
|
||||||
|
}
|
||||||
|
if (args_has(args, 'S') && wname != NULL && target->idx == -1) {
|
||||||
|
expanded = format_single(item, wname, c, s, NULL, NULL);
|
||||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||||
if (strcmp(wl->window->name, expanded) != 0)
|
if (strcmp(wl->window->name, expanded) != 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -79,12 +90,14 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
new_wl = wl;
|
new_wl = wl;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
cmdq_error(item, "multiple windows named %s", name);
|
cmdq_error(item, "multiple windows named %s", wname);
|
||||||
|
free(wname);
|
||||||
free(expanded);
|
free(expanded);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
free(expanded);
|
free(expanded);
|
||||||
if (new_wl != NULL) {
|
if (new_wl != NULL) {
|
||||||
|
free(wname);
|
||||||
if (args_has(args, 'd'))
|
if (args_has(args, 'd'))
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
if (session_set_current(s, new_wl) == 0)
|
if (session_set_current(s, new_wl) == 0)
|
||||||
@@ -107,7 +120,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
sc.s = s;
|
sc.s = s;
|
||||||
sc.tc = tc;
|
sc.tc = tc;
|
||||||
|
|
||||||
sc.name = args_get(args, 'n');
|
sc.name = wname;
|
||||||
args_to_vector(args, &sc.argc, &sc.argv);
|
args_to_vector(args, &sc.argc, &sc.argv);
|
||||||
sc.environ = environ_create();
|
sc.environ = environ_create();
|
||||||
|
|
||||||
@@ -129,10 +142,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if ((new_wl = spawn_window(&sc, &cause)) == NULL) {
|
if ((new_wl = spawn_window(&sc, &cause)) == NULL) {
|
||||||
cmdq_error(item, "create window failed: %s", cause);
|
cmdq_error(item, "create window failed: %s", cause);
|
||||||
free(cause);
|
free(cause);
|
||||||
if (sc.argv != NULL)
|
goto fail;
|
||||||
cmd_free_argv(sc.argc, sc.argv);
|
|
||||||
environ_free(sc.environ);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
}
|
||||||
if (!args_has(args, 'd') || new_wl == s->curw) {
|
if (!args_has(args, 'd') || new_wl == s->curw) {
|
||||||
cmd_find_from_winlink(current, new_wl, 0);
|
cmd_find_from_winlink(current, new_wl, 0);
|
||||||
@@ -155,5 +165,13 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (sc.argv != NULL)
|
if (sc.argv != NULL)
|
||||||
cmd_free_argv(sc.argc, sc.argv);
|
cmd_free_argv(sc.argc, sc.argv);
|
||||||
environ_free(sc.environ);
|
environ_free(sc.environ);
|
||||||
|
free(wname);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (sc.argv != NULL)
|
||||||
|
cmd_free_argv(sc.argc, sc.argv);
|
||||||
|
environ_free(sc.environ);
|
||||||
|
free(wname);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
62
cmd-parse.y
62
cmd-parse.y
@@ -32,11 +32,13 @@
|
|||||||
|
|
||||||
static int yylex(void);
|
static int yylex(void);
|
||||||
static int yyparse(void);
|
static int yyparse(void);
|
||||||
static int printflike(1,2) yyerror(const char *, ...);
|
static void printflike(1,2) yyerror(const char *, ...);
|
||||||
|
|
||||||
static char *yylex_token(int);
|
static char *yylex_token(int);
|
||||||
static char *yylex_format(void);
|
static char *yylex_format(void);
|
||||||
|
|
||||||
|
#define CMD_PARSE_MAX_ENVIRON_LEN 16384
|
||||||
|
|
||||||
struct cmd_parse_scope {
|
struct cmd_parse_scope {
|
||||||
int flag;
|
int flag;
|
||||||
TAILQ_ENTRY (cmd_parse_scope) entry;
|
TAILQ_ENTRY (cmd_parse_scope) entry;
|
||||||
@@ -223,9 +225,20 @@ assignment : EQUALS
|
|||||||
{
|
{
|
||||||
struct cmd_parse_state *ps = &parse_state;
|
struct cmd_parse_state *ps = &parse_state;
|
||||||
int flags = ps->input->flags;
|
int flags = ps->input->flags;
|
||||||
|
int flag = 1;
|
||||||
|
struct cmd_parse_scope *scope;
|
||||||
|
|
||||||
if ((~flags & CMD_PARSE_PARSEONLY) &&
|
if (ps->scope != NULL) {
|
||||||
(ps->scope == NULL || ps->scope->flag))
|
flag = ps->scope->flag;
|
||||||
|
TAILQ_FOREACH(scope, &ps->stack, entry)
|
||||||
|
flag = flag && scope->flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($1) > CMD_PARSE_MAX_ENVIRON_LEN) {
|
||||||
|
yyerror("environment variable is too long");
|
||||||
|
YYABORT;
|
||||||
|
}
|
||||||
|
if ((~flags & CMD_PARSE_PARSEONLY) && flag)
|
||||||
environ_put(global_environ, $1, 0);
|
environ_put(global_environ, $1, 0);
|
||||||
free($1);
|
free($1);
|
||||||
}
|
}
|
||||||
@@ -234,9 +247,20 @@ hidden_assignment : HIDDEN EQUALS
|
|||||||
{
|
{
|
||||||
struct cmd_parse_state *ps = &parse_state;
|
struct cmd_parse_state *ps = &parse_state;
|
||||||
int flags = ps->input->flags;
|
int flags = ps->input->flags;
|
||||||
|
int flag = 1;
|
||||||
|
struct cmd_parse_scope *scope;
|
||||||
|
|
||||||
if ((~flags & CMD_PARSE_PARSEONLY) &&
|
if (ps->scope != NULL) {
|
||||||
(ps->scope == NULL || ps->scope->flag))
|
flag = ps->scope->flag;
|
||||||
|
TAILQ_FOREACH(scope, &ps->stack, entry)
|
||||||
|
flag = flag && scope->flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($2) > CMD_PARSE_MAX_ENVIRON_LEN) {
|
||||||
|
yyerror("environment variable is too long");
|
||||||
|
YYABORT;
|
||||||
|
}
|
||||||
|
if ((~flags & CMD_PARSE_PARSEONLY) && flag)
|
||||||
environ_put(global_environ, $2, ENVIRON_HIDDEN);
|
environ_put(global_environ, $2, ENVIRON_HIDDEN);
|
||||||
free($2);
|
free($2);
|
||||||
}
|
}
|
||||||
@@ -744,7 +768,7 @@ static int
|
|||||||
cmd_parse_expand_alias(struct cmd_parse_command *cmd,
|
cmd_parse_expand_alias(struct cmd_parse_command *cmd,
|
||||||
struct cmd_parse_input *pi, struct cmd_parse_result *pr)
|
struct cmd_parse_input *pi, struct cmd_parse_result *pr)
|
||||||
{
|
{
|
||||||
struct cmd_parse_argument *arg, *arg1, *first;
|
struct cmd_parse_argument *first;
|
||||||
struct cmd_parse_commands *cmds;
|
struct cmd_parse_commands *cmds;
|
||||||
struct cmd_parse_command *last;
|
struct cmd_parse_command *last;
|
||||||
char *alias, *name, *cause;
|
char *alias, *name, *cause;
|
||||||
@@ -784,10 +808,7 @@ cmd_parse_expand_alias(struct cmd_parse_command *cmd,
|
|||||||
TAILQ_REMOVE(&cmd->arguments, first, entry);
|
TAILQ_REMOVE(&cmd->arguments, first, entry);
|
||||||
cmd_parse_free_argument(first);
|
cmd_parse_free_argument(first);
|
||||||
|
|
||||||
TAILQ_FOREACH_SAFE(arg, &cmd->arguments, entry, arg1) {
|
TAILQ_CONCAT(&last->arguments, &cmd->arguments, entry);
|
||||||
TAILQ_REMOVE(&cmd->arguments, arg, entry);
|
|
||||||
TAILQ_INSERT_TAIL(&last->arguments, arg, entry);
|
|
||||||
}
|
|
||||||
cmd_parse_log_commands(cmds, __func__);
|
cmd_parse_log_commands(cmds, __func__);
|
||||||
|
|
||||||
pi->flags |= CMD_PARSE_NOALIAS;
|
pi->flags |= CMD_PARSE_NOALIAS;
|
||||||
@@ -835,7 +856,7 @@ cmd_parse_build_command(struct cmd_parse_command *cmd,
|
|||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
add = cmd_parse(values, count, pi->file, pi->line, &cause);
|
add = cmd_parse(values, count, pi->file, pi->line, pi->flags, &cause);
|
||||||
if (add == NULL) {
|
if (add == NULL) {
|
||||||
pr->status = CMD_PARSE_ERROR;
|
pr->status = CMD_PARSE_ERROR;
|
||||||
pr->error = cmd_parse_get_error(pi->file, pi->line, cause);
|
pr->error = cmd_parse_get_error(pi->file, pi->line, cause);
|
||||||
@@ -1113,7 +1134,7 @@ cmd_parse_from_arguments(struct args_value *values, u_int count,
|
|||||||
return (&pr);
|
return (&pr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int printflike(1, 2)
|
static void printflike(1, 2)
|
||||||
yyerror(const char *fmt, ...)
|
yyerror(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
struct cmd_parse_state *ps = &parse_state;
|
struct cmd_parse_state *ps = &parse_state;
|
||||||
@@ -1122,7 +1143,7 @@ yyerror(const char *fmt, ...)
|
|||||||
char *error;
|
char *error;
|
||||||
|
|
||||||
if (ps->error != NULL)
|
if (ps->error != NULL)
|
||||||
return (0);
|
return;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
xvasprintf(&error, fmt, ap);
|
xvasprintf(&error, fmt, ap);
|
||||||
@@ -1130,7 +1151,6 @@ yyerror(const char *fmt, ...)
|
|||||||
|
|
||||||
ps->error = cmd_parse_get_error(pi->file, pi->line, error);
|
ps->error = cmd_parse_get_error(pi->file, pi->line, error);
|
||||||
free(error);
|
free(error);
|
||||||
return (0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -1594,7 +1614,9 @@ yylex_token_tilde(char **buf, size_t *len)
|
|||||||
|
|
||||||
if (*name == '\0') {
|
if (*name == '\0') {
|
||||||
envent = environ_find(global_environ, "HOME");
|
envent = environ_find(global_environ, "HOME");
|
||||||
if (envent != NULL && *envent->value != '\0')
|
if (envent != NULL &&
|
||||||
|
envent->value != NULL &&
|
||||||
|
*envent->value != '\0')
|
||||||
home = envent->value;
|
home = envent->value;
|
||||||
else if ((pw = getpwuid(getuid())) != NULL)
|
else if ((pw = getpwuid(getuid())) != NULL)
|
||||||
home = pw->pw_dir;
|
home = pw->pw_dir;
|
||||||
@@ -1613,6 +1635,7 @@ yylex_token_tilde(char **buf, size_t *len)
|
|||||||
static char *
|
static char *
|
||||||
yylex_token(int ch)
|
yylex_token(int ch)
|
||||||
{
|
{
|
||||||
|
struct cmd_parse_state *ps = &parse_state;
|
||||||
char *buf;
|
char *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
enum { START,
|
enum { START,
|
||||||
@@ -1636,9 +1659,12 @@ yylex_token(int ch)
|
|||||||
ch = '\r';
|
ch = '\r';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state == NONE && ch == '\n') {
|
if (ch == '\n') {
|
||||||
log_debug("%s: end at EOL", __func__);
|
if (state == NONE) {
|
||||||
break;
|
log_debug("%s: end at EOL", __func__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ps->input->line++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Whitespace or ; or } ends a token unless inside quotes. */
|
/* Whitespace or ; or } ends a token unless inside quotes. */
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ const struct cmd_entry cmd_paste_buffer_entry = {
|
|||||||
.name = "paste-buffer",
|
.name = "paste-buffer",
|
||||||
.alias = "pasteb",
|
.alias = "pasteb",
|
||||||
|
|
||||||
.args = { "db:prs:t:", 0, 0, NULL },
|
.args = { "db:prSs:t:", 0, 0, NULL },
|
||||||
.usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " "
|
.usage = "[-dprS] [-s separator] " CMD_BUFFER_USAGE " "
|
||||||
CMD_TARGET_PANE_USAGE,
|
CMD_TARGET_PANE_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
@@ -43,6 +43,17 @@ const struct cmd_entry cmd_paste_buffer_entry = {
|
|||||||
.exec = cmd_paste_buffer_exec
|
.exec = cmd_paste_buffer_exec
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_paste_buffer_paste(struct window_pane *wp, const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *cp;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
n = utf8_stravisx(&cp, buf, len, VIS_SAFE|VIS_NOSLASH);
|
||||||
|
bufferevent_write(wp->event, cp, n);
|
||||||
|
free(cp);
|
||||||
|
}
|
||||||
|
|
||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||||
{
|
{
|
||||||
@@ -51,7 +62,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct window_pane *wp = target->wp;
|
struct window_pane *wp = target->wp;
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer *pb;
|
||||||
const char *sepstr, *bufname, *bufdata, *bufend, *line;
|
const char *sepstr, *bufname, *bufdata, *bufend, *line;
|
||||||
size_t seplen, bufsize;
|
size_t seplen, bufsize, len;
|
||||||
int bracket = args_has(args, 'p');
|
int bracket = args_has(args, 'p');
|
||||||
|
|
||||||
if (window_pane_exited(wp)) {
|
if (window_pane_exited(wp)) {
|
||||||
@@ -93,14 +104,22 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
line = memchr(bufdata, '\n', bufend - bufdata);
|
line = memchr(bufdata, '\n', bufend - bufdata);
|
||||||
if (line == NULL)
|
if (line == NULL)
|
||||||
break;
|
break;
|
||||||
|
len = line - bufdata;
|
||||||
bufferevent_write(wp->event, bufdata, line - bufdata);
|
if (args_has(args, 'S'))
|
||||||
|
bufferevent_write(wp->event, bufdata, len);
|
||||||
|
else
|
||||||
|
cmd_paste_buffer_paste(wp, bufdata, len);
|
||||||
bufferevent_write(wp->event, sepstr, seplen);
|
bufferevent_write(wp->event, sepstr, seplen);
|
||||||
|
|
||||||
bufdata = line + 1;
|
bufdata = line + 1;
|
||||||
}
|
}
|
||||||
if (bufdata != bufend)
|
if (bufdata != bufend) {
|
||||||
bufferevent_write(wp->event, bufdata, bufend - bufdata);
|
len = bufend - bufdata;
|
||||||
|
if (args_has(args, 'S'))
|
||||||
|
bufferevent_write(wp->event, bufdata, len);
|
||||||
|
else
|
||||||
|
cmd_paste_buffer_paste(wp, bufdata, len);
|
||||||
|
}
|
||||||
|
|
||||||
if (bracket && (wp->screen->mode & MODE_BRACKETPASTE))
|
if (bracket && (wp->screen->mode & MODE_BRACKETPASTE))
|
||||||
bufferevent_write(wp->event, "\033[201~", 6);
|
bufferevent_write(wp->event, "\033[201~", 6);
|
||||||
|
|||||||
@@ -123,11 +123,13 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
/* Fork the child. */
|
/* Fork the child. */
|
||||||
sigfillset(&set);
|
sigfillset(&set);
|
||||||
sigprocmask(SIG_BLOCK, &set, &oldset);
|
sigprocmask(SIG_BLOCK, &set, &oldset);
|
||||||
switch (fork()) {
|
switch ((wp->pipe_pid = fork())) {
|
||||||
case -1:
|
case -1:
|
||||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||||
cmdq_error(item, "fork error: %s", strerror(errno));
|
cmdq_error(item, "fork error: %s", strerror(errno));
|
||||||
|
|
||||||
|
close(pipe_fd[0]);
|
||||||
|
close(pipe_fd[1]);
|
||||||
free(cmd);
|
free(cmd);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
case 0:
|
case 0:
|
||||||
@@ -136,6 +138,9 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||||
close(pipe_fd[0]);
|
close(pipe_fd[0]);
|
||||||
|
|
||||||
|
if (setpgid(0, 0) == -1)
|
||||||
|
_exit(1);
|
||||||
|
|
||||||
null_fd = open(_PATH_DEVNULL, O_WRONLY);
|
null_fd = open(_PATH_DEVNULL, O_WRONLY);
|
||||||
if (out) {
|
if (out) {
|
||||||
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
|
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
|
||||||
|
|||||||
@@ -834,9 +834,9 @@ cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
|
|||||||
|
|
||||||
/* Show message from command. */
|
/* Show message from command. */
|
||||||
void
|
void
|
||||||
cmdq_print_data(struct cmdq_item *item, int parse, struct evbuffer *evb)
|
cmdq_print_data(struct cmdq_item *item, struct evbuffer *evb)
|
||||||
{
|
{
|
||||||
server_client_print(item->client, parse, evb);
|
server_client_print(item->client, 1, evb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Show message from command. */
|
/* Show message from command. */
|
||||||
@@ -854,7 +854,7 @@ cmdq_print(struct cmdq_item *item, const char *fmt, ...)
|
|||||||
evbuffer_add_vprintf(evb, fmt, ap);
|
evbuffer_add_vprintf(evb, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
cmdq_print_data(item, 0, evb);
|
cmdq_print_data(item, evb);
|
||||||
evbuffer_free(evb);
|
evbuffer_free(evb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -892,7 +892,7 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
|
|||||||
c->retval = 1;
|
c->retval = 1;
|
||||||
} else {
|
} else {
|
||||||
*msg = toupper((u_char) *msg);
|
*msg = toupper((u_char) *msg);
|
||||||
status_message_set(c, -1, 1, 0, "%s", msg);
|
status_message_set(c, -1, 1, 0, 0, "%s", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(msg);
|
free(msg);
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ const struct cmd_entry cmd_refresh_client_entry = {
|
|||||||
.name = "refresh-client",
|
.name = "refresh-client",
|
||||||
.alias = "refresh",
|
.alias = "refresh",
|
||||||
|
|
||||||
.args = { "A:B:cC:Df:r:F:l::LRSt:U", 0, 1, NULL },
|
.args = { "A:B:cC:Df:r:F:lLRSt:U", 0, 1, NULL },
|
||||||
.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] "
|
.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] "
|
||||||
"[-C XxY] [-f flags] [-r pane:report]" CMD_TARGET_CLIENT_USAGE
|
"[-C XxY] [-f flags] [-r pane:report] " CMD_TARGET_CLIENT_USAGE
|
||||||
" [adjustment]",
|
" [adjustment]",
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
|
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
|
||||||
@@ -163,37 +163,6 @@ out:
|
|||||||
free(copy);
|
free(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum cmd_retval
|
|
||||||
cmd_refresh_client_clipboard(struct cmd *self, struct cmdq_item *item)
|
|
||||||
{
|
|
||||||
struct args *args = cmd_get_args(self);
|
|
||||||
struct client *tc = cmdq_get_target_client(item);
|
|
||||||
const char *p;
|
|
||||||
u_int i;
|
|
||||||
struct cmd_find_state fs;
|
|
||||||
|
|
||||||
p = args_get(args, 'l');
|
|
||||||
if (p == NULL) {
|
|
||||||
if (tc->flags & CLIENT_CLIPBOARDBUFFER)
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
tc->flags |= CLIENT_CLIPBOARDBUFFER;
|
|
||||||
} else {
|
|
||||||
if (cmd_find_target(&fs, item, p, CMD_FIND_PANE, 0) != 0)
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
for (i = 0; i < tc->clipboard_npanes; i++) {
|
|
||||||
if (tc->clipboard_panes[i] == fs.wp->id)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i != tc->clipboard_npanes)
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
tc->clipboard_panes = xreallocarray(tc->clipboard_panes,
|
|
||||||
tc->clipboard_npanes + 1, sizeof *tc->clipboard_panes);
|
|
||||||
tc->clipboard_panes[tc->clipboard_npanes++] = fs.wp->id;
|
|
||||||
}
|
|
||||||
tty_clipboard_query(&tc->tty);
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_refresh_report(struct tty *tty, const char *value)
|
cmd_refresh_report(struct tty *tty, const char *value)
|
||||||
{
|
{
|
||||||
@@ -284,8 +253,10 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args_has(args, 'l'))
|
if (args_has(args, 'l')) {
|
||||||
return (cmd_refresh_client_clipboard(self, item));
|
tty_clipboard_query(&tc->tty);
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
if (args_has(args, 'F')) /* -F is an alias for -f */
|
if (args_has(args, 'F')) /* -F is an alias for -f */
|
||||||
server_client_set_flags(tc, args_get(args, 'F'));
|
server_client_set_flags(tc, args_get(args, 'F'));
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
char *newname, *tmp;
|
char *newname, *tmp;
|
||||||
|
|
||||||
tmp = format_single_from_target(item, args_string(args, 0));
|
tmp = format_single_from_target(item, args_string(args, 0));
|
||||||
newname = session_check_name(tmp);
|
if (!check_name(tmp)) {
|
||||||
if (newname == NULL) {
|
cmdq_error(item, "invalid session name: %s", tmp);
|
||||||
cmdq_error(item, "invalid session: %s", tmp);
|
|
||||||
free(tmp);
|
free(tmp);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
newname = clean_name(tmp, 0);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
if (strcmp(newname, s->name) == 0) {
|
if (strcmp(newname, s->name) == 0) {
|
||||||
free(newname);
|
free(newname);
|
||||||
|
|||||||
@@ -48,15 +48,21 @@ cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
struct winlink *wl = target->wl;
|
struct winlink *wl = target->wl;
|
||||||
char *newname;
|
char *name;
|
||||||
|
|
||||||
newname = format_single_from_target(item, args_string(args, 0));
|
name = format_single_from_target(item, args_string(args, 0));
|
||||||
window_set_name(wl->window, newname);
|
if (!check_name(name)) {
|
||||||
|
cmdq_error(item, "invalid window name: %s", name);
|
||||||
|
free(name);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
window_set_name(wl->window, name, 0);
|
||||||
options_set_number(wl->window->options, "automatic-rename", 0);
|
options_set_number(wl->window->options, "automatic-rename", 0);
|
||||||
|
free(name);
|
||||||
|
|
||||||
server_redraw_window_borders(wl->window);
|
server_redraw_window_borders(wl->window);
|
||||||
server_status_window(wl->window);
|
server_status_window(wl->window);
|
||||||
free(newname);
|
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,12 @@
|
|||||||
|
|
||||||
static enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmdq_item *);
|
static enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmdq_item *);
|
||||||
|
|
||||||
static void cmd_resize_pane_mouse_update(struct client *,
|
static enum cmd_retval cmd_resize_pane_mouse_update(struct cmd *,
|
||||||
struct mouse_event *);
|
struct cmdq_item *);
|
||||||
|
static void cmd_resize_pane_mouse_update_floating(struct client *,
|
||||||
|
struct mouse_event *);
|
||||||
|
static void cmd_resize_pane_mouse_update_tiled(struct client *,
|
||||||
|
struct mouse_event *);
|
||||||
|
|
||||||
const struct cmd_entry cmd_resize_pane_entry = {
|
const struct cmd_entry cmd_resize_pane_entry = {
|
||||||
.name = "resize-pane",
|
.name = "resize-pane",
|
||||||
@@ -51,13 +55,10 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
{
|
{
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
struct key_event *event = cmdq_get_event(item);
|
|
||||||
struct window_pane *wp = target->wp;
|
struct window_pane *wp = target->wp;
|
||||||
struct winlink *wl = target->wl;
|
struct winlink *wl = target->wl;
|
||||||
struct window *w = wl->window;
|
struct window *w = wl->window;
|
||||||
struct client *c = cmdq_get_client(item);
|
const char *errstr;
|
||||||
struct session *s = target->s;
|
|
||||||
const char *errstr;
|
|
||||||
char *cause;
|
char *cause;
|
||||||
u_int adjust;
|
u_int adjust;
|
||||||
int x, y, status;
|
int x, y, status;
|
||||||
@@ -75,15 +76,8 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args_has(args, 'M')) {
|
if (args_has(args, 'M'))
|
||||||
if (!event->m.valid || cmd_mouse_window(&event->m, &s) == NULL)
|
return (cmd_resize_pane_mouse_update(self, item));
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
if (c == NULL || c->session != s)
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
|
|
||||||
cmd_resize_pane_mouse_update(c, &event->m);
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args_has(args, 'Z')) {
|
if (args_has(args, 'Z')) {
|
||||||
if (w->flags & WINDOW_ZOOMED)
|
if (w->flags & WINDOW_ZOOMED)
|
||||||
@@ -148,13 +142,168 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum cmd_retval
|
||||||
|
cmd_resize_pane_mouse_update(__unused struct cmd *self, struct cmdq_item *item)
|
||||||
|
{
|
||||||
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
|
struct key_event *event = cmdq_get_event(item);
|
||||||
|
struct window_pane *wp = target->wp;
|
||||||
|
struct winlink *wl = target->wl;
|
||||||
|
struct window *w = wl->window;
|
||||||
|
struct client *c = cmdq_get_client(item);
|
||||||
|
struct session *s = target->s;
|
||||||
|
|
||||||
|
if (!event->m.valid)
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
wp = cmd_mouse_pane(&event->m, &s, NULL);
|
||||||
|
if (wp == NULL || c == NULL || c->session != s)
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
|
if (!window_pane_is_floating(wp)) {
|
||||||
|
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update_tiled;
|
||||||
|
cmd_resize_pane_mouse_update_tiled(c, &event->m);
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
window_redraw_active_switch(w, wp);
|
||||||
|
window_set_active_pane(w, wp, 1);
|
||||||
|
|
||||||
|
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update_floating;
|
||||||
|
cmd_resize_pane_mouse_update_floating(c, &event->m);
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m)
|
cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
|
||||||
|
{
|
||||||
|
struct winlink *wl;
|
||||||
|
struct window *w;
|
||||||
|
struct window_pane *wp;
|
||||||
|
struct layout_cell *lc;
|
||||||
|
int y, ly, x, lx, sx, sy, new_sx, new_sy;
|
||||||
|
int left, right;
|
||||||
|
int new_xoff, new_yoff, resizes = 0;
|
||||||
|
|
||||||
|
wp = cmd_mouse_pane(m, NULL, &wl);
|
||||||
|
if (wp == NULL) {
|
||||||
|
c->tty.mouse_drag_update = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w = wl->window;
|
||||||
|
lc = wp->layout_cell;
|
||||||
|
sx = wp->sx;
|
||||||
|
sy = wp->sy;
|
||||||
|
left = wp->xoff - 1;
|
||||||
|
right = wp->xoff + sx;
|
||||||
|
if (window_pane_show_scrollbar(wp) &&
|
||||||
|
w->sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||||
|
left -= wp->scrollbar_style.width + wp->scrollbar_style.pad;
|
||||||
|
} else if (window_pane_show_scrollbar(wp) &&
|
||||||
|
w->sb_pos == PANE_SCROLLBARS_RIGHT) {
|
||||||
|
right += wp->scrollbar_style.width + wp->scrollbar_style.pad;
|
||||||
|
}
|
||||||
|
|
||||||
|
y = m->y + m->oy; x = m->x + m->ox;
|
||||||
|
if (m->statusat == 0 && y >= (int)m->statuslines)
|
||||||
|
y -= m->statuslines;
|
||||||
|
else if (m->statusat > 0 && y >= m->statusat)
|
||||||
|
y = m->statusat - 1;
|
||||||
|
ly = m->ly + m->oy; lx = m->lx + m->ox;
|
||||||
|
if (m->statusat == 0 && ly >= (int)m->statuslines)
|
||||||
|
ly -= m->statuslines;
|
||||||
|
else if (m->statusat > 0 && ly >= m->statusat)
|
||||||
|
ly = m->statusat - 1;
|
||||||
|
|
||||||
|
if ((lx == left || lx == left + 1) && ly == wp->yoff - 1) {
|
||||||
|
/* Top left corner. */
|
||||||
|
new_sx = lc->sx + (lx - x);
|
||||||
|
if (new_sx < PANE_MINIMUM)
|
||||||
|
new_sx = PANE_MINIMUM;
|
||||||
|
new_sy = lc->sy + (ly - y);
|
||||||
|
if (new_sy < PANE_MINIMUM)
|
||||||
|
new_sy = PANE_MINIMUM;
|
||||||
|
new_xoff = x + 1; /* because mouse is on border at xoff - 1 */
|
||||||
|
new_yoff = y + 1;
|
||||||
|
layout_set_size(lc, new_sx, new_sy, new_xoff, new_yoff);
|
||||||
|
resizes++;
|
||||||
|
} else if ((lx == right + 1 || lx == right) &&
|
||||||
|
ly == wp->yoff - 1) {
|
||||||
|
/* Top right corner. */
|
||||||
|
new_sx = x - lc->xoff;
|
||||||
|
if (new_sx < PANE_MINIMUM)
|
||||||
|
new_sx = PANE_MINIMUM;
|
||||||
|
new_sy = lc->sy + (ly - y);
|
||||||
|
if (new_sy < PANE_MINIMUM)
|
||||||
|
new_sy = PANE_MINIMUM;
|
||||||
|
new_yoff = y + 1;
|
||||||
|
layout_set_size(lc, new_sx, new_sy, lc->xoff, new_yoff);
|
||||||
|
resizes++;
|
||||||
|
} else if ((lx == left || lx == left + 1) &&
|
||||||
|
ly == wp->yoff + sy) {
|
||||||
|
/* Bottom left corner. */
|
||||||
|
new_sx = lc->sx + (lx - x);
|
||||||
|
if (new_sx < PANE_MINIMUM)
|
||||||
|
new_sx = PANE_MINIMUM;
|
||||||
|
new_sy = y - lc->yoff;
|
||||||
|
if (new_sy < PANE_MINIMUM)
|
||||||
|
return;
|
||||||
|
new_xoff = x + 1;
|
||||||
|
layout_set_size(lc, new_sx, new_sy, new_xoff, lc->yoff);
|
||||||
|
resizes++;
|
||||||
|
} else if ((lx == right + 1 || lx == right) &&
|
||||||
|
ly == wp->yoff + sy) {
|
||||||
|
/* Bottom right corner. */
|
||||||
|
new_sx = x - lc->xoff;
|
||||||
|
if (new_sx < PANE_MINIMUM)
|
||||||
|
new_sx = PANE_MINIMUM;
|
||||||
|
new_sy = y - lc->yoff;
|
||||||
|
if (new_sy < PANE_MINIMUM)
|
||||||
|
new_sy = PANE_MINIMUM;
|
||||||
|
layout_set_size(lc, new_sx, new_sy, lc->xoff, lc->yoff);
|
||||||
|
resizes++;
|
||||||
|
} else if (lx == right) {
|
||||||
|
/* Right border. */
|
||||||
|
new_sx = x - lc->xoff;
|
||||||
|
if (new_sx < PANE_MINIMUM)
|
||||||
|
return;
|
||||||
|
layout_set_size(lc, new_sx, lc->sy, lc->xoff, lc->yoff);
|
||||||
|
resizes++;
|
||||||
|
} else if (lx == left) {
|
||||||
|
/* Left border. */
|
||||||
|
new_sx = lc->sx + (lx - x);
|
||||||
|
if (new_sx < PANE_MINIMUM)
|
||||||
|
return;
|
||||||
|
new_xoff = x + 1;
|
||||||
|
layout_set_size(lc, new_sx, lc->sy, new_xoff, lc->yoff);
|
||||||
|
resizes++;
|
||||||
|
} else if (ly == wp->yoff + sy) {
|
||||||
|
/* Bottom border. */
|
||||||
|
new_sy = y - lc->yoff;
|
||||||
|
if (new_sy < PANE_MINIMUM)
|
||||||
|
return;
|
||||||
|
layout_set_size(lc, lc->sx, new_sy, lc->xoff, lc->yoff);
|
||||||
|
resizes++;
|
||||||
|
} else if (ly == wp->yoff - 1) {
|
||||||
|
/* Top border (move instead of resize). */
|
||||||
|
new_xoff = lc->xoff + (x - lx);
|
||||||
|
new_yoff = y + 1;
|
||||||
|
layout_set_size(lc, lc->sx, lc->sy, new_xoff, new_yoff);
|
||||||
|
resizes++;
|
||||||
|
}
|
||||||
|
if (resizes != 0) {
|
||||||
|
layout_fix_panes(w, NULL);
|
||||||
|
server_redraw_window(w);
|
||||||
|
server_redraw_window_borders(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_resize_pane_mouse_update_tiled(struct client *c, struct mouse_event *m)
|
||||||
{
|
{
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
struct window *w;
|
struct window *w;
|
||||||
u_int y, ly, x, lx;
|
u_int y, ly, x, lx;
|
||||||
static const int offsets[][2] = {
|
static const int offsets[][2] = {
|
||||||
{ 0, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
|
{ 0, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
|
||||||
};
|
};
|
||||||
struct layout_cell *cells[nitems(offsets)], *lc;
|
struct layout_cell *cells[nitems(offsets)], *lc;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_pane_entry = {
|
|||||||
|
|
||||||
.args = { "c:e:kt:", 0, -1, NULL },
|
.args = { "c:e:kt:", 0, -1, NULL },
|
||||||
.usage = "[-k] [-c start-directory] [-e environment] "
|
.usage = "[-k] [-c start-directory] [-e environment] "
|
||||||
CMD_TARGET_PANE_USAGE " [shell-command]",
|
CMD_TARGET_PANE_USAGE " [shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_window_entry = {
|
|||||||
|
|
||||||
.args = { "c:e:kt:", 0, -1, NULL },
|
.args = { "c:e:kt:", 0, -1, NULL },
|
||||||
.usage = "[-k] [-c start-directory] [-e environment] "
|
.usage = "[-k] [-c start-directory] [-e environment] "
|
||||||
CMD_TARGET_WINDOW_USAGE " [shell-command]",
|
CMD_TARGET_WINDOW_USAGE " [shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_WINDOW, 0 },
|
.target = { 't', CMD_FIND_WINDOW, 0 },
|
||||||
|
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ const struct cmd_entry cmd_run_shell_entry = {
|
|||||||
.name = "run-shell",
|
.name = "run-shell",
|
||||||
.alias = "run",
|
.alias = "run",
|
||||||
|
|
||||||
.args = { "bd:Ct:c:", 0, 2, cmd_run_shell_args_parse },
|
.args = { "bd:Ct:Es:c:", 0, -1, cmd_run_shell_args_parse },
|
||||||
.usage = "[-bC] [-c start-directory] [-d delay] " CMD_TARGET_PANE_USAGE
|
.usage = "[-bCE] [-c start-directory] [-d delay] " CMD_TARGET_PANE_USAGE
|
||||||
" [shell-command]",
|
" [shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||||
|
|
||||||
@@ -115,9 +115,11 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct session *s = target->s;
|
struct session *s = target->s;
|
||||||
struct window_pane *wp = target->wp;
|
struct window_pane *wp = target->wp;
|
||||||
const char *delay, *cmd;
|
const char *delay, *cmd;
|
||||||
|
struct format_tree *ft;
|
||||||
double d;
|
double d;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
char *end;
|
char *end, key[16];
|
||||||
|
u_int i;
|
||||||
int wait = !args_has(args, 'b');
|
int wait = !args_has(args, 'b');
|
||||||
|
|
||||||
if ((delay = args_get(args, 'd')) != NULL) {
|
if ((delay = args_get(args, 'd')) != NULL) {
|
||||||
@@ -132,8 +134,15 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
cdata = xcalloc(1, sizeof *cdata);
|
cdata = xcalloc(1, sizeof *cdata);
|
||||||
if (!args_has(args, 'C')) {
|
if (!args_has(args, 'C')) {
|
||||||
cmd = args_string(args, 0);
|
cmd = args_string(args, 0);
|
||||||
if (cmd != NULL)
|
if (cmd != NULL) {
|
||||||
cdata->cmd = format_single_from_target(item, cmd);
|
ft = format_create_from_target(item);
|
||||||
|
for (i = 1; i < args_count(args); i++) {
|
||||||
|
xsnprintf(key, sizeof key, "%u", i);
|
||||||
|
format_add(ft, key, "%s", args_string(args, i));
|
||||||
|
}
|
||||||
|
cdata->cmd = format_expand(ft, cmd);
|
||||||
|
format_free(ft);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cdata->state = args_make_commands_prepare(self, item, 0, NULL,
|
cdata->state = args_make_commands_prepare(self, item, 0, NULL,
|
||||||
wait, 1);
|
wait, 1);
|
||||||
@@ -158,6 +167,9 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
else
|
else
|
||||||
cdata->cwd = xstrdup(server_client_get_cwd(c, s));
|
cdata->cwd = xstrdup(server_client_get_cwd(c, s));
|
||||||
|
|
||||||
|
if (args_has(args, 'E'))
|
||||||
|
cdata->flags |= JOB_SHOWSTDERR;
|
||||||
|
|
||||||
cdata->s = s;
|
cdata->s = s;
|
||||||
if (s != NULL)
|
if (s != NULL)
|
||||||
session_add_ref(s, __func__);
|
session_add_ref(s, __func__);
|
||||||
@@ -195,8 +207,17 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
|
|||||||
}
|
}
|
||||||
if (job_run(cmd, 0, NULL, NULL, cdata->s, cdata->cwd, NULL,
|
if (job_run(cmd, 0, NULL, NULL, cdata->s, cdata->cwd, NULL,
|
||||||
cmd_run_shell_callback, cmd_run_shell_free, cdata,
|
cmd_run_shell_callback, cmd_run_shell_free, cdata,
|
||||||
cdata->flags, -1, -1) == NULL)
|
cdata->flags, -1, -1) == NULL) {
|
||||||
|
if (cdata->item == NULL)
|
||||||
|
status_message_set(c, -1, 1, 0, 0,
|
||||||
|
"failed to run command: %s", cmd);
|
||||||
|
else {
|
||||||
|
cmdq_error(cdata->item,
|
||||||
|
"failed to run command: %s", cmd);
|
||||||
|
cmdq_continue(cdata->item);
|
||||||
|
}
|
||||||
cmd_run_shell_free(cdata);
|
cmd_run_shell_free(cdata);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +225,7 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
|
|||||||
if (cmdlist == NULL) {
|
if (cmdlist == NULL) {
|
||||||
if (cdata->item == NULL) {
|
if (cdata->item == NULL) {
|
||||||
*error = toupper((u_char)*error);
|
*error = toupper((u_char)*error);
|
||||||
status_message_set(c, -1, 1, 0, "%s", error);
|
status_message_set(c, -1, 1, 0, 0, "%s", error);
|
||||||
} else
|
} else
|
||||||
cmdq_error(cdata->item, "%s", error);
|
cmdq_error(cdata->item, "%s", error);
|
||||||
free(error);
|
free(error);
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ cmd_save_buffer_done(__unused struct client *c, const char *path, int error,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
cmdq_error(item, "%s: %s", path, strerror(error));
|
cmdq_error(item, "%s: %s", strerror(error), path);
|
||||||
cmdq_continue(item);
|
cmdq_continue(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (evb == NULL)
|
if (evb == NULL)
|
||||||
fatalx("out of memory");
|
fatalx("out of memory");
|
||||||
evbuffer_add(evb, bufdata, bufsize);
|
evbuffer_add(evb, bufdata, bufsize);
|
||||||
cmdq_print_data(item, 1, evb);
|
cmdq_print_data(item, evb);
|
||||||
evbuffer_free(evb);
|
evbuffer_free(evb);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
previous = 1;
|
previous = 1;
|
||||||
|
|
||||||
oldlayout = w->old_layout;
|
oldlayout = w->old_layout;
|
||||||
w->old_layout = layout_dump(w->layout_root);
|
w->old_layout = layout_dump(w, w->layout_root);
|
||||||
|
|
||||||
if (next || previous) {
|
if (next || previous) {
|
||||||
if (next)
|
if (next)
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
* spawned without being visited (for example split-window -d).
|
* spawned without being visited (for example split-window -d).
|
||||||
*/
|
*/
|
||||||
lastwp = TAILQ_FIRST(&w->last_panes);
|
lastwp = TAILQ_FIRST(&w->last_panes);
|
||||||
if (lastwp == NULL && window_count_panes(w) == 2) {
|
if (lastwp == NULL && window_count_panes(w, 1) == 2) {
|
||||||
lastwp = TAILQ_PREV(w->active, window_panes, entry);
|
lastwp = TAILQ_PREV(w->active, window_panes, entry);
|
||||||
if (lastwp == NULL)
|
if (lastwp == NULL)
|
||||||
lastwp = TAILQ_NEXT(w->active, entry);
|
lastwp = TAILQ_NEXT(w->active, entry);
|
||||||
@@ -149,15 +149,21 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
markedwp = marked_pane.wp;
|
markedwp = marked_pane.wp;
|
||||||
|
|
||||||
if (lastwp != NULL) {
|
if (lastwp != NULL) {
|
||||||
lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
|
lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||||
|
PANE_THEMECHANGED);
|
||||||
server_redraw_window_borders(lastwp->window);
|
server_redraw_window_borders(lastwp->window);
|
||||||
server_status_window(lastwp->window);
|
server_status_window(lastwp->window);
|
||||||
}
|
}
|
||||||
if (markedwp != NULL) {
|
if (markedwp != NULL) {
|
||||||
markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
|
markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||||
|
PANE_THEMECHANGED);
|
||||||
server_redraw_window_borders(markedwp->window);
|
server_redraw_window_borders(markedwp->window);
|
||||||
server_status_window(markedwp->window);
|
server_status_window(markedwp->window);
|
||||||
}
|
}
|
||||||
|
if (window_pane_is_floating(wp)) {
|
||||||
|
window_redraw_active_switch(w, wp);
|
||||||
|
window_set_active_pane(w, wp, 1);
|
||||||
|
}
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +175,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
options_set_string(oo, "window-active-style", 0, "%s", style);
|
options_set_string(oo, "window-active-style", 0, "%s", style);
|
||||||
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
|
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
}
|
}
|
||||||
if (args_has(args, 'g')) {
|
if (args_has(args, 'g')) {
|
||||||
cmdq_print(item, "%s", options_get_string(oo, "window-style"));
|
cmdq_print(item, "%s", options_get_string(oo, "window-style"));
|
||||||
@@ -211,7 +217,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
if (args_has(args, 'T')) {
|
if (args_has(args, 'T')) {
|
||||||
title = format_single_from_target(item, args_get(args, 'T'));
|
title = format_single_from_target(item, args_get(args, 'T'));
|
||||||
if (screen_set_title(&wp->base, title)) {
|
if (screen_set_title(&wp->base, title, 0)) {
|
||||||
notify_pane("pane-title-changed", wp);
|
notify_pane("pane-title-changed", wp);
|
||||||
server_redraw_window_borders(wp->window);
|
server_redraw_window_borders(wp->window);
|
||||||
server_status_window(wp->window);
|
server_status_window(wp->window);
|
||||||
|
|||||||
@@ -35,11 +35,12 @@ const struct cmd_entry cmd_send_keys_entry = {
|
|||||||
|
|
||||||
.args = { "c:FHKlMN:Rt:X", 0, -1, NULL },
|
.args = { "c:FHKlMN:Rt:X", 0, -1, NULL },
|
||||||
.usage = "[-FHKlMRX] [-c target-client] [-N repeat-count] "
|
.usage = "[-FHKlMRX] [-c target-client] [-N repeat-count] "
|
||||||
CMD_TARGET_PANE_USAGE " key ...",
|
CMD_TARGET_PANE_USAGE " [key ...]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL,
|
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL|
|
||||||
|
CMD_READONLY,
|
||||||
.exec = cmd_send_keys_exec
|
.exec = cmd_send_keys_exec
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -73,11 +74,13 @@ cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
|
|||||||
if (args_has(args, 'K')) {
|
if (args_has(args, 'K')) {
|
||||||
if (tc == NULL)
|
if (tc == NULL)
|
||||||
return (item);
|
return (item);
|
||||||
event = xmalloc(sizeof *event);
|
event = xcalloc(1, sizeof *event);
|
||||||
event->key = key|KEYC_SENT;
|
event->key = key|KEYC_SENT;
|
||||||
memset(&event->m, 0, sizeof event->m);
|
memset(&event->m, 0, sizeof event->m);
|
||||||
if (server_client_handle_key(tc, event) == 0)
|
if (server_client_handle_key(tc, event) == 0) {
|
||||||
|
free(event->buf);
|
||||||
free(event);
|
free(event);
|
||||||
|
}
|
||||||
return (item);
|
return (item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +168,11 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
u_int count = args_count(args);
|
u_int count = args_count(args);
|
||||||
char *cause = NULL;
|
char *cause = NULL;
|
||||||
|
|
||||||
|
if (tc != NULL && tc->flags & CLIENT_READONLY && !args_has(args, 'X')) {
|
||||||
|
cmdq_error(item, "client is read-only");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
if (args_has(args, 'N')) {
|
if (args_has(args, 'N')) {
|
||||||
np = args_strtonum_and_expand(args, 'N', 1, UINT_MAX, item,
|
np = args_strtonum_and_expand(args, 'N', 1, UINT_MAX, item,
|
||||||
&cause);
|
&cause);
|
||||||
@@ -215,7 +223,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (args_has(args, 'R')) {
|
if (args_has(args, 'R')) {
|
||||||
colour_palette_clear(&wp->palette);
|
colour_palette_clear(&wp->palette);
|
||||||
input_reset(wp->ictx, 1);
|
input_reset(wp->ictx, 1);
|
||||||
wp->flags |= (PANE_STYLECHANGED|PANE_REDRAW);
|
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED|PANE_REDRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ cmd_server_access_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
pw = getpwnam(name);
|
pw = getpwnam(name);
|
||||||
if (pw == NULL) {
|
if (pw == NULL) {
|
||||||
cmdq_error(item, "unknown user: %s", name);
|
cmdq_error(item, "unknown user: %s", name);
|
||||||
|
free(name);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
free(name);
|
free(name);
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const struct cmd_entry cmd_set_buffer_entry = {
|
|||||||
|
|
||||||
.args = { "ab:t:n:w", 0, 1, NULL },
|
.args = { "ab:t:n:w", 0, 1, NULL },
|
||||||
.usage = "[-aw] " CMD_BUFFER_USAGE " [-n new-buffer-name] "
|
.usage = "[-aw] " CMD_BUFFER_USAGE " [-n new-buffer-name] "
|
||||||
CMD_TARGET_CLIENT_USAGE " data",
|
CMD_TARGET_CLIENT_USAGE " [data]",
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL,
|
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL,
|
||||||
.exec = cmd_set_buffer_exec
|
.exec = cmd_set_buffer_exec
|
||||||
@@ -57,30 +57,30 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
{
|
{
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct client *tc = cmdq_get_target_client(item);
|
struct client *tc = cmdq_get_target_client(item);
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer *pb = NULL;
|
||||||
char *bufdata, *cause;
|
char *bufname = NULL, *bufdata = NULL, *cause = NULL;
|
||||||
const char *bufname, *olddata;
|
const char *olddata;
|
||||||
size_t bufsize, newsize;
|
size_t bufsize = 0, newsize;
|
||||||
|
|
||||||
bufname = args_get(args, 'b');
|
if (args_get(args, 'b') != NULL) {
|
||||||
if (bufname == NULL)
|
bufname = xstrdup(args_get(args, 'b'));
|
||||||
pb = NULL;
|
|
||||||
else
|
|
||||||
pb = paste_get_name(bufname);
|
pb = paste_get_name(bufname);
|
||||||
|
}
|
||||||
|
|
||||||
if (cmd_get_entry(self) == &cmd_delete_buffer_entry) {
|
if (cmd_get_entry(self) == &cmd_delete_buffer_entry) {
|
||||||
if (pb == NULL) {
|
if (pb == NULL) {
|
||||||
if (bufname != NULL) {
|
if (bufname != NULL) {
|
||||||
cmdq_error(item, "unknown buffer: %s", bufname);
|
cmdq_error(item, "unknown buffer: %s", bufname);
|
||||||
return (CMD_RETURN_ERROR);
|
goto fail;
|
||||||
}
|
}
|
||||||
pb = paste_get_top(&bufname);
|
pb = paste_get_top(&bufname);
|
||||||
}
|
}
|
||||||
if (pb == NULL) {
|
if (pb == NULL) {
|
||||||
cmdq_error(item, "no buffer");
|
cmdq_error(item, "no buffer");
|
||||||
return (CMD_RETURN_ERROR);
|
goto fail;
|
||||||
}
|
}
|
||||||
paste_free(pb);
|
paste_free(pb);
|
||||||
|
free(bufname);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,32 +88,28 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (pb == NULL) {
|
if (pb == NULL) {
|
||||||
if (bufname != NULL) {
|
if (bufname != NULL) {
|
||||||
cmdq_error(item, "unknown buffer: %s", bufname);
|
cmdq_error(item, "unknown buffer: %s", bufname);
|
||||||
return (CMD_RETURN_ERROR);
|
goto fail;
|
||||||
}
|
}
|
||||||
pb = paste_get_top(&bufname);
|
pb = paste_get_top(&bufname);
|
||||||
}
|
}
|
||||||
if (pb == NULL) {
|
if (pb == NULL) {
|
||||||
cmdq_error(item, "no buffer");
|
cmdq_error(item, "no buffer");
|
||||||
return (CMD_RETURN_ERROR);
|
goto fail;
|
||||||
}
|
}
|
||||||
if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
|
if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
|
||||||
cmdq_error(item, "%s", cause);
|
cmdq_error(item, "%s", cause);
|
||||||
free(cause);
|
goto fail;
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
}
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args_count(args) != 1) {
|
if (args_count(args) != 1) {
|
||||||
cmdq_error(item, "no data specified");
|
cmdq_error(item, "no data specified");
|
||||||
return (CMD_RETURN_ERROR);
|
goto fail;
|
||||||
}
|
}
|
||||||
if ((newsize = strlen(args_string(args, 0))) == 0)
|
if ((newsize = strlen(args_string(args, 0))) == 0)
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
bufsize = 0;
|
|
||||||
bufdata = NULL;
|
|
||||||
|
|
||||||
if (args_has(args, 'a') && pb != NULL) {
|
if (args_has(args, 'a') && pb != NULL) {
|
||||||
olddata = paste_buffer_data(pb, &bufsize);
|
olddata = paste_buffer_data(pb, &bufsize);
|
||||||
bufdata = xmalloc(bufsize);
|
bufdata = xmalloc(bufsize);
|
||||||
@@ -126,12 +122,16 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
if (paste_set(bufdata, bufsize, bufname, &cause) != 0) {
|
if (paste_set(bufdata, bufsize, bufname, &cause) != 0) {
|
||||||
cmdq_error(item, "%s", cause);
|
cmdq_error(item, "%s", cause);
|
||||||
free(bufdata);
|
goto fail;
|
||||||
free(cause);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
}
|
||||||
if (args_has(args, 'w') && tc != NULL)
|
if (args_has(args, 'w') && tc != NULL)
|
||||||
tty_set_selection(&tc->tty, "", bufdata, bufsize);
|
tty_set_selection(&tc->tty, "", bufdata, bufsize);
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
free(bufdata);
|
||||||
|
free(bufname);
|
||||||
|
free(cause);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const struct cmd_entry cmd_set_environment_entry = {
|
|||||||
.alias = "setenv",
|
.alias = "setenv",
|
||||||
|
|
||||||
.args = { "Fhgrt:u", 1, 2, NULL },
|
.args = { "Fhgrt:u", 1, 2, NULL },
|
||||||
.usage = "[-Fhgru] " CMD_TARGET_SESSION_USAGE " name [value]",
|
.usage = "[-Fhgru] " CMD_TARGET_SESSION_USAGE " variable [value]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ const struct cmd_entry cmd_show_environment_entry = {
|
|||||||
.alias = "showenv",
|
.alias = "showenv",
|
||||||
|
|
||||||
.args = { "hgst:", 0, 1, NULL },
|
.args = { "hgst:", 0, 1, NULL },
|
||||||
.usage = "[-hgs] " CMD_TARGET_SESSION_USAGE " [name]",
|
.usage = "[-hgs] " CMD_TARGET_SESSION_USAGE " [variable]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const struct cmd_entry cmd_show_messages_entry = {
|
|||||||
.args = { "JTt:", 0, 0, NULL },
|
.args = { "JTt:", 0, 0, NULL },
|
||||||
.usage = "[-JT] " CMD_TARGET_CLIENT_USAGE,
|
.usage = "[-JT] " CMD_TARGET_CLIENT_USAGE,
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
|
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL,
|
||||||
.exec = cmd_show_messages_exec
|
.exec = cmd_show_messages_exec
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ cmd_show_messages_terminals(struct cmd *self, struct cmdq_item *item, int blank)
|
|||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
LIST_FOREACH(term, &tty_terms, entry) {
|
LIST_FOREACH(term, &tty_terms, entry) {
|
||||||
if (args_has(args, 't') && term != tc->tty.term)
|
if (args_has(args, 't') && tc != NULL && term != tc->tty.term)
|
||||||
continue;
|
continue;
|
||||||
if (blank) {
|
if (blank) {
|
||||||
cmdq_print(item, "%s", "");
|
cmdq_print(item, "%s", "");
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ const struct cmd_entry cmd_show_hooks_entry = {
|
|||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "gpt:w", 0, 1, NULL },
|
.args = { "gpt:w", 0, 1, NULL },
|
||||||
.usage = "[-gpw] " CMD_TARGET_PANE_USAGE,
|
.usage = "[-gpw] " CMD_TARGET_PANE_USAGE " [hook]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const struct cmd_entry cmd_show_prompt_history_entry = {
|
|||||||
.alias = "showphist",
|
.alias = "showphist",
|
||||||
|
|
||||||
.args = { "T:", 0, 0, NULL },
|
.args = { "T:", 0, 0, NULL },
|
||||||
.usage = "[-T type]",
|
.usage = "[-T prompt-type]",
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK,
|
.flags = CMD_AFTERHOOK,
|
||||||
.exec = cmd_show_prompt_history_exec
|
.exec = cmd_show_prompt_history_exec
|
||||||
@@ -43,7 +43,7 @@ const struct cmd_entry cmd_clear_prompt_history_entry = {
|
|||||||
.alias = "clearphist",
|
.alias = "clearphist",
|
||||||
|
|
||||||
.args = { "T:", 0, 0, NULL },
|
.args = { "T:", 0, 0, NULL },
|
||||||
.usage = "[-T type]",
|
.usage = "[-T prompt-type]",
|
||||||
|
|
||||||
.flags = CMD_AFTERHOOK,
|
.flags = CMD_AFTERHOOK,
|
||||||
.exec = cmd_show_prompt_history_exec
|
.exec = cmd_show_prompt_history_exec
|
||||||
@@ -60,6 +60,9 @@ cmd_show_prompt_history_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (cmd_get_entry(self) == &cmd_clear_prompt_history_entry) {
|
if (cmd_get_entry(self) == &cmd_clear_prompt_history_entry) {
|
||||||
if (typestr == NULL) {
|
if (typestr == NULL) {
|
||||||
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
|
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
|
||||||
|
for (hidx = 0; hidx < status_prompt_hsize[tidx];
|
||||||
|
hidx++)
|
||||||
|
free(status_prompt_hlist[tidx][hidx]);
|
||||||
free(status_prompt_hlist[tidx]);
|
free(status_prompt_hlist[tidx]);
|
||||||
status_prompt_hlist[tidx] = NULL;
|
status_prompt_hlist[tidx] = NULL;
|
||||||
status_prompt_hsize[tidx] = 0;
|
status_prompt_hsize[tidx] = 0;
|
||||||
@@ -70,6 +73,8 @@ cmd_show_prompt_history_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
cmdq_error(item, "invalid type: %s", typestr);
|
cmdq_error(item, "invalid type: %s", typestr);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
for (hidx = 0; hidx < status_prompt_hsize[type]; hidx++)
|
||||||
|
free(status_prompt_hlist[type][hidx]);
|
||||||
free(status_prompt_hlist[type]);
|
free(status_prompt_hlist[type]);
|
||||||
status_prompt_hlist[type] = NULL;
|
status_prompt_hlist[type] = NULL;
|
||||||
status_prompt_hsize[type] = 0;
|
status_prompt_hsize[type] = 0;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -29,6 +30,9 @@
|
|||||||
* Sources a configuration file.
|
* Sources a configuration file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define CMD_SOURCE_FILE_DEPTH_LIMIT 50
|
||||||
|
static u_int cmd_source_file_depth;
|
||||||
|
|
||||||
static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmdq_item *);
|
static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmdq_item *);
|
||||||
|
|
||||||
const struct cmd_entry cmd_source_file_entry = {
|
const struct cmd_entry cmd_source_file_entry = {
|
||||||
@@ -59,6 +63,16 @@ struct cmd_source_file_data {
|
|||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
cmd_source_file_complete_cb(struct cmdq_item *item, __unused void *data)
|
cmd_source_file_complete_cb(struct cmdq_item *item, __unused void *data)
|
||||||
{
|
{
|
||||||
|
struct client *c = cmdq_get_client(item);
|
||||||
|
|
||||||
|
if (c == NULL) {
|
||||||
|
cmd_source_file_depth--;
|
||||||
|
log_debug("%s: depth now %u", __func__, cmd_source_file_depth);
|
||||||
|
} else {
|
||||||
|
c->source_file_depth--;
|
||||||
|
log_debug("%s: depth now %u", __func__, c->source_file_depth);
|
||||||
|
}
|
||||||
|
|
||||||
cfg_print_causes(item);
|
cfg_print_causes(item);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
@@ -100,7 +114,7 @@ cmd_source_file_done(struct client *c, const char *path, int error,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
cmdq_error(item, "%s: %s", path, strerror(error));
|
cmdq_error(item, "%s: %s", strerror(error), path);
|
||||||
else if (bsize != 0) {
|
else if (bsize != 0) {
|
||||||
if (load_cfg_from_buffer(bdata, bsize, path, c, cdata->after,
|
if (load_cfg_from_buffer(bdata, bsize, path, c, cdata->after,
|
||||||
target, cdata->flags, &new_item) < 0)
|
target, cdata->flags, &new_item) < 0)
|
||||||
@@ -127,6 +141,21 @@ cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path)
|
|||||||
cdata->files[cdata->nfiles++] = xstrdup(path);
|
cdata->files[cdata->nfiles++] = xstrdup(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
cmd_source_file_quote_for_glob(const char *path)
|
||||||
|
{
|
||||||
|
char *quoted = xmalloc(2 * strlen(path) + 1), *q = quoted;
|
||||||
|
const char *p = path;
|
||||||
|
|
||||||
|
while (*p != '\0') {
|
||||||
|
if ((u_char)*p < 128 && !isalnum((u_char)*p) && *p != '/')
|
||||||
|
*q++ = '\\';
|
||||||
|
*q++ = *p++;
|
||||||
|
}
|
||||||
|
*q = '\0';
|
||||||
|
return (quoted);
|
||||||
|
}
|
||||||
|
|
||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
|
cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
|
||||||
{
|
{
|
||||||
@@ -137,9 +166,25 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
char *pattern, *cwd, *expanded = NULL;
|
char *pattern, *cwd, *expanded = NULL;
|
||||||
const char *path, *error;
|
const char *path, *error;
|
||||||
glob_t g;
|
glob_t g;
|
||||||
int result;
|
int result, parse_flags;
|
||||||
u_int i, j;
|
u_int i, j;
|
||||||
|
|
||||||
|
if (c == NULL) {
|
||||||
|
if (cmd_source_file_depth >= CMD_SOURCE_FILE_DEPTH_LIMIT) {
|
||||||
|
cmdq_error(item, "too many nested files");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
cmd_source_file_depth++;
|
||||||
|
log_debug("%s: depth now %u", __func__, cmd_source_file_depth);
|
||||||
|
} else {
|
||||||
|
if (c->source_file_depth >= CMD_SOURCE_FILE_DEPTH_LIMIT) {
|
||||||
|
cmdq_error(item, "too many nested files");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
c->source_file_depth++;
|
||||||
|
log_debug("%s: depth now %u", __func__, c->source_file_depth);
|
||||||
|
}
|
||||||
|
|
||||||
cdata = xcalloc(1, sizeof *cdata);
|
cdata = xcalloc(1, sizeof *cdata);
|
||||||
cdata->item = item;
|
cdata->item = item;
|
||||||
|
|
||||||
@@ -147,10 +192,13 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
cdata->flags |= CMD_PARSE_QUIET;
|
cdata->flags |= CMD_PARSE_QUIET;
|
||||||
if (args_has(args, 'n'))
|
if (args_has(args, 'n'))
|
||||||
cdata->flags |= CMD_PARSE_PARSEONLY;
|
cdata->flags |= CMD_PARSE_PARSEONLY;
|
||||||
if (args_has(args, 'v'))
|
if (c == NULL || ~c->flags & CLIENT_CONTROL) {
|
||||||
cdata->flags |= CMD_PARSE_VERBOSE;
|
parse_flags = cmd_get_parse_flags(self);
|
||||||
|
if (args_has(args, 'v') || (parse_flags & CMD_PARSE_VERBOSE))
|
||||||
|
cdata->flags |= CMD_PARSE_VERBOSE;
|
||||||
|
}
|
||||||
|
|
||||||
utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
|
cwd = cmd_source_file_quote_for_glob(server_client_get_cwd(c, NULL));
|
||||||
|
|
||||||
for (i = 0; i < args_count(args); i++) {
|
for (i = 0; i < args_count(args); i++) {
|
||||||
path = args_string(args, i);
|
path = args_string(args, i);
|
||||||
@@ -179,7 +227,7 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
error = strerror(ENOMEM);
|
error = strerror(ENOMEM);
|
||||||
else
|
else
|
||||||
error = strerror(EINVAL);
|
error = strerror(EINVAL);
|
||||||
cmdq_error(item, "%s: %s", path, error);
|
cmdq_error(item, "%s: %s", error, path);
|
||||||
retval = CMD_RETURN_ERROR;
|
retval = CMD_RETURN_ERROR;
|
||||||
}
|
}
|
||||||
globfree(&g);
|
globfree(&g);
|
||||||
|
|||||||
@@ -27,22 +27,41 @@
|
|||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Split a window (add a new pane).
|
* Create a new pane.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
|
#define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
|
||||||
|
|
||||||
static enum cmd_retval cmd_split_window_exec(struct cmd *,
|
static enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmdq_item *);
|
||||||
struct cmdq_item *);
|
|
||||||
|
const struct cmd_entry cmd_new_pane_entry = {
|
||||||
|
.name = "new-pane",
|
||||||
|
.alias = "newp",
|
||||||
|
|
||||||
|
.args = { "bc:de:EfF:hIkl:Lm:p:PR:s:S:t:vx:X:y:Y:Z", 0, -1, NULL },
|
||||||
|
.usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] "
|
||||||
|
"[-F format] [-l size] [-m message] [-p percentage] "
|
||||||
|
"[-s style] [-S active-border-style] "
|
||||||
|
"[-R inactive-border-style] [-x width] [-y height] "
|
||||||
|
"[-X x-position] [-Y y-position] " CMD_TARGET_PANE_USAGE " "
|
||||||
|
"[shell-command [argument ...]]",
|
||||||
|
|
||||||
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
|
.flags = 0,
|
||||||
|
.exec = cmd_split_window_exec
|
||||||
|
};
|
||||||
|
|
||||||
const struct cmd_entry cmd_split_window_entry = {
|
const struct cmd_entry cmd_split_window_entry = {
|
||||||
.name = "split-window",
|
.name = "split-window",
|
||||||
.alias = "splitw",
|
.alias = "splitw",
|
||||||
|
|
||||||
.args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL },
|
.args = { "bc:de:EfF:hIkl:m:p:PR:s:S:t:vZ", 0, -1, NULL },
|
||||||
.usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] "
|
.usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] "
|
||||||
"[-F format] [-l size] " CMD_TARGET_PANE_USAGE
|
"[-F format] [-l size] [-m message] [-p percentage] "
|
||||||
"[shell-command]",
|
"[-s style] [-S active-border-style] "
|
||||||
|
"[-R inactive-border-style] " CMD_TARGET_PANE_USAGE " "
|
||||||
|
"[shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
@@ -62,64 +81,46 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct winlink *wl = target->wl;
|
struct winlink *wl = target->wl;
|
||||||
struct window *w = wl->window;
|
struct window *w = wl->window;
|
||||||
struct window_pane *wp = target->wp, *new_wp;
|
struct window_pane *wp = target->wp, *new_wp;
|
||||||
enum layout_type type;
|
struct layout_cell *lc = NULL;
|
||||||
struct layout_cell *lc;
|
|
||||||
struct cmd_find_state fs;
|
struct cmd_find_state fs;
|
||||||
int size, flags, input;
|
int input, empty, is_floating, flags = 0;
|
||||||
const char *template;
|
const char *template, *style;
|
||||||
char *cause = NULL, *cp;
|
char *cause = NULL, *cp;
|
||||||
struct args_value *av;
|
struct args_value *av;
|
||||||
u_int count = args_count(args), curval = 0;
|
u_int count = args_count(args);
|
||||||
|
|
||||||
type = LAYOUT_TOPBOTTOM;
|
if (cmd_get_entry(self) == &cmd_new_pane_entry)
|
||||||
if (args_has(args, 'h'))
|
is_floating = !args_has(args, 'L');
|
||||||
type = LAYOUT_LEFTRIGHT;
|
else
|
||||||
|
is_floating = 0;
|
||||||
|
|
||||||
/* If the 'p' flag is dropped then this bit can be moved into 'l'. */
|
flags = is_floating ? SPAWN_FLOATING : 0;
|
||||||
if (args_has(args, 'l') || args_has(args, 'p')) {
|
|
||||||
if (args_has(args, 'f')) {
|
|
||||||
if (type == LAYOUT_TOPBOTTOM)
|
|
||||||
curval = w->sy;
|
|
||||||
else
|
|
||||||
curval = w->sx;
|
|
||||||
} else {
|
|
||||||
if (type == LAYOUT_TOPBOTTOM)
|
|
||||||
curval = wp->sy;
|
|
||||||
else
|
|
||||||
curval = wp->sx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size = -1;
|
|
||||||
if (args_has(args, 'l')) {
|
|
||||||
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
|
|
||||||
item, &cause);
|
|
||||||
} else if (args_has(args, 'p')) {
|
|
||||||
size = args_strtonum_and_expand(args, 'p', 0, 100, item,
|
|
||||||
&cause);
|
|
||||||
if (cause == NULL)
|
|
||||||
size = curval * size / 100;
|
|
||||||
}
|
|
||||||
if (cause != NULL) {
|
|
||||||
cmdq_error(item, "size %s", cause);
|
|
||||||
free(cause);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
window_push_zoom(wp->window, 1, args_has(args, 'Z'));
|
|
||||||
input = (args_has(args, 'I') && count == 0);
|
|
||||||
|
|
||||||
flags = 0;
|
|
||||||
if (args_has(args, 'b'))
|
if (args_has(args, 'b'))
|
||||||
flags |= SPAWN_BEFORE;
|
flags |= SPAWN_BEFORE;
|
||||||
if (args_has(args, 'f'))
|
if (args_has(args, 'f'))
|
||||||
flags |= SPAWN_FULLSIZE;
|
flags |= SPAWN_FULLSIZE;
|
||||||
if (input || (count == 1 && *args_string(args, 0) == '\0'))
|
|
||||||
|
input = args_has(args, 'I');
|
||||||
|
if (input)
|
||||||
|
empty = 1;
|
||||||
|
else
|
||||||
|
empty = args_has(args, 'E');
|
||||||
|
if (empty &&
|
||||||
|
count != 0 &&
|
||||||
|
(count != 1 || *args_string(args, 0) != '\0')) {
|
||||||
|
cmdq_error(item, "command cannot be given for empty pane");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
if (empty)
|
||||||
flags |= SPAWN_EMPTY;
|
flags |= SPAWN_EMPTY;
|
||||||
|
|
||||||
lc = layout_split_pane(wp, type, size, flags);
|
if (is_floating)
|
||||||
if (lc == NULL) {
|
lc = layout_get_floating_cell(item, args, w, wp, &cause);
|
||||||
cmdq_error(item, "no space for new pane");
|
else
|
||||||
|
lc = layout_get_tiled_cell(item, args, w, wp, flags, &cause);
|
||||||
|
if (cause != NULL) {
|
||||||
|
cmdq_error(item, "size or position %s", cause);
|
||||||
|
free(cause);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,11 +157,51 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
environ_free(sc.environ);
|
environ_free(sc.environ);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
style = args_get(args, 's');
|
||||||
|
if (style != NULL) {
|
||||||
|
if (options_set_string(new_wp->options, "window-style", 0,
|
||||||
|
"%s", style) == NULL) {
|
||||||
|
cmdq_error(item, "bad style: %s", style);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
options_set_string(new_wp->options, "window-active-style", 0,
|
||||||
|
"%s", style);
|
||||||
|
new_wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||||
|
PANE_THEMECHANGED);
|
||||||
|
}
|
||||||
|
style = args_get(args, 'S');
|
||||||
|
if (style != NULL) {
|
||||||
|
if (options_set_string(new_wp->options,
|
||||||
|
"pane-active-border-style", 0, "%s", style) == NULL) {
|
||||||
|
cmdq_error(item, "bad active border style: %s", style);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
style = args_get(args, 'R');
|
||||||
|
if (style != NULL) {
|
||||||
|
if (options_set_string(new_wp->options, "pane-border-style", 0,
|
||||||
|
"%s", style) == NULL) {
|
||||||
|
cmdq_error(item, "bad inactive border style: %s",
|
||||||
|
style);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (args_has(args, 'k') || args_has(args, 'm')) {
|
||||||
|
options_set_number(new_wp->options, "remain-on-exit", 3);
|
||||||
|
if (args_has(args, 'm')) {
|
||||||
|
options_set_string(new_wp->options,
|
||||||
|
"remain-on-exit-format", 0, "%s",
|
||||||
|
args_get(args, 'm'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (input) {
|
if (input) {
|
||||||
switch (window_pane_start_input(new_wp, item, &cause)) {
|
switch (window_pane_start_input(new_wp, item, &cause)) {
|
||||||
case -1:
|
case -1:
|
||||||
server_client_remove_pane(new_wp);
|
server_client_remove_pane(new_wp);
|
||||||
layout_close_pane(new_wp);
|
if (!is_floating)
|
||||||
|
layout_close_pane(new_wp);
|
||||||
window_remove_pane(wp->window, new_wp);
|
window_remove_pane(wp->window, new_wp);
|
||||||
cmdq_error(item, "%s", cause);
|
cmdq_error(item, "%s", cause);
|
||||||
free(cause);
|
free(cause);
|
||||||
@@ -175,9 +216,12 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
if (!args_has(args, 'd'))
|
if (!args_has(args, 'd'))
|
||||||
cmd_find_from_winlink_pane(current, wl, new_wp, 0);
|
cmd_find_from_winlink_pane(current, wl, new_wp, 0);
|
||||||
window_pop_zoom(wp->window);
|
|
||||||
server_redraw_window(wp->window);
|
if (!is_floating) {
|
||||||
server_status_session(s);
|
window_pop_zoom(wp->window);
|
||||||
|
server_redraw_window(wp->window);
|
||||||
|
}
|
||||||
|
server_redraw_session(s);
|
||||||
|
|
||||||
if (args_has(args, 'P')) {
|
if (args_has(args, 'P')) {
|
||||||
if ((template = args_get(args, 'F')) == NULL)
|
if ((template = args_get(args, 'F')) == NULL)
|
||||||
|
|||||||
@@ -79,6 +79,12 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (src_wp == dst_wp)
|
if (src_wp == dst_wp)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (window_pane_is_floating(src_wp) ||
|
||||||
|
window_pane_is_floating(dst_wp)) {
|
||||||
|
cmdq_error(item, "cannot swap floating panes");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
server_client_remove_pane(src_wp);
|
server_client_remove_pane(src_wp);
|
||||||
server_client_remove_pane(dst_wp);
|
server_client_remove_pane(dst_wp);
|
||||||
|
|
||||||
@@ -92,19 +98,33 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
else
|
else
|
||||||
TAILQ_INSERT_AFTER(&dst_w->panes, tmp_wp, src_wp, entry);
|
TAILQ_INSERT_AFTER(&dst_w->panes, tmp_wp, src_wp, entry);
|
||||||
|
|
||||||
|
tmp_wp = TAILQ_PREV(dst_wp, window_panes, zentry);
|
||||||
|
TAILQ_REMOVE(&dst_w->z_index, dst_wp, zentry);
|
||||||
|
TAILQ_REPLACE(&src_w->z_index, src_wp, dst_wp, zentry);
|
||||||
|
if (tmp_wp == src_wp)
|
||||||
|
tmp_wp = dst_wp;
|
||||||
|
if (tmp_wp == NULL)
|
||||||
|
TAILQ_INSERT_HEAD(&dst_w->z_index, src_wp, zentry);
|
||||||
|
else
|
||||||
|
TAILQ_INSERT_AFTER(&dst_w->z_index, tmp_wp, src_wp, zentry);
|
||||||
|
|
||||||
src_lc = src_wp->layout_cell;
|
src_lc = src_wp->layout_cell;
|
||||||
dst_lc = dst_wp->layout_cell;
|
dst_lc = dst_wp->layout_cell;
|
||||||
src_lc->wp = dst_wp;
|
src_lc->wp = dst_wp;
|
||||||
dst_wp->layout_cell = src_lc;
|
dst_wp->layout_cell = src_lc;
|
||||||
dst_lc->wp = src_wp;
|
dst_lc->wp = src_wp;
|
||||||
src_wp->layout_cell = dst_lc;
|
src_wp->layout_cell = dst_lc;
|
||||||
|
if (window_pane_is_floating(src_wp) != window_pane_is_floating(dst_wp)) {
|
||||||
|
src_wp->layout_cell->flags ^= LAYOUT_CELL_FLOATING;
|
||||||
|
dst_wp->layout_cell->flags ^= LAYOUT_CELL_FLOATING;
|
||||||
|
}
|
||||||
|
|
||||||
src_wp->window = dst_w;
|
src_wp->window = dst_w;
|
||||||
options_set_parent(src_wp->options, dst_w->options);
|
options_set_parent(src_wp->options, dst_w->options);
|
||||||
src_wp->flags |= PANE_STYLECHANGED;
|
src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
dst_wp->window = src_w;
|
dst_wp->window = src_w;
|
||||||
options_set_parent(dst_wp->options, src_w->options);
|
options_set_parent(dst_wp->options, src_w->options);
|
||||||
dst_wp->flags |= PANE_STYLECHANGED;
|
dst_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||||
|
|
||||||
sx = src_wp->sx; sy = src_wp->sy;
|
sx = src_wp->sx; sy = src_wp->sy;
|
||||||
xoff = src_wp->xoff; yoff = src_wp->yoff;
|
xoff = src_wp->xoff; yoff = src_wp->yoff;
|
||||||
@@ -132,9 +152,12 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
window_pane_stack_remove(&dst_w->last_panes, dst_wp);
|
window_pane_stack_remove(&dst_w->last_panes, dst_wp);
|
||||||
colour_palette_from_option(&src_wp->palette, src_wp->options);
|
colour_palette_from_option(&src_wp->palette, src_wp->options);
|
||||||
colour_palette_from_option(&dst_wp->palette, dst_wp->options);
|
colour_palette_from_option(&dst_wp->palette, dst_wp->options);
|
||||||
|
layout_fix_panes(src_w, NULL);
|
||||||
|
server_redraw_window(src_w);
|
||||||
}
|
}
|
||||||
server_redraw_window(src_w);
|
layout_fix_panes(dst_w, NULL);
|
||||||
server_redraw_window(dst_w);
|
server_redraw_window(dst_w);
|
||||||
|
|
||||||
notify_window("window-layout-changed", src_w);
|
notify_window("window-layout-changed", src_w);
|
||||||
if (src_w != dst_w)
|
if (src_w != dst_w)
|
||||||
notify_window("window-layout-changed", dst_w);
|
notify_window("window-layout-changed", dst_w);
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
wl_src->window = w_dst;
|
wl_src->window = w_dst;
|
||||||
TAILQ_INSERT_TAIL(&w_dst->winlinks, wl_src, wentry);
|
TAILQ_INSERT_TAIL(&w_dst->winlinks, wl_src, wentry);
|
||||||
|
|
||||||
|
if (marked_pane.wl == wl_src)
|
||||||
|
marked_pane.wl = wl_dst;
|
||||||
if (args_has(args, 'd')) {
|
if (args_has(args, 'd')) {
|
||||||
session_select(dst, wl_dst->idx);
|
session_select(dst, wl_dst->idx);
|
||||||
if (src != dst)
|
if (src != dst)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
@@ -34,9 +35,9 @@ const struct cmd_entry cmd_switch_client_entry = {
|
|||||||
.name = "switch-client",
|
.name = "switch-client",
|
||||||
.alias = "switchc",
|
.alias = "switchc",
|
||||||
|
|
||||||
.args = { "lc:EFnpt:rT:Z", 0, 0, NULL },
|
.args = { "c:EFlnO:pt:rT:Z", 0, 0, NULL },
|
||||||
.usage = "[-ElnprZ] [-c target-client] [-t target-session] "
|
.usage = "[-ElnprZ] [-c target-client] [-t target-session] "
|
||||||
"[-T key-table]",
|
"[-T key-table] [-O order]",
|
||||||
|
|
||||||
/* -t is special */
|
/* -t is special */
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
const char *tflag = args_get(args, 't');
|
const char *tflag = args_get(args, 't');
|
||||||
enum cmd_find_type type;
|
enum cmd_find_type type;
|
||||||
int flags;
|
int flags;
|
||||||
|
struct client *c = cmdq_get_client(item);
|
||||||
struct client *tc = cmdq_get_target_client(item);
|
struct client *tc = cmdq_get_target_client(item);
|
||||||
struct session *s;
|
struct session *s;
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
@@ -60,8 +62,11 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
const char *tablename;
|
const char *tablename;
|
||||||
struct key_table *table;
|
struct key_table *table;
|
||||||
|
struct sort_criteria sort_crit;
|
||||||
|
uid_t uid;
|
||||||
|
|
||||||
if (tflag != NULL && tflag[strcspn(tflag, ":.%")] != '\0') {
|
if (tflag != NULL &&
|
||||||
|
(tflag[strcspn(tflag, ":.%")] != '\0' || strcmp(tflag, "=") == 0)) {
|
||||||
type = CMD_FIND_PANE;
|
type = CMD_FIND_PANE;
|
||||||
flags = 0;
|
flags = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -75,6 +80,13 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
wp = target.wp;
|
wp = target.wp;
|
||||||
|
|
||||||
if (args_has(args, 'r')) {
|
if (args_has(args, 'r')) {
|
||||||
|
if (tc->flags & CLIENT_READONLY) {
|
||||||
|
uid = proc_get_peer_uid(c->peer);
|
||||||
|
if (uid != getuid()) {
|
||||||
|
cmdq_error(item, "client is read-only");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (tc->flags & CLIENT_READONLY)
|
if (tc->flags & CLIENT_READONLY)
|
||||||
tc->flags &= ~(CLIENT_READONLY|CLIENT_IGNORESIZE);
|
tc->flags &= ~(CLIENT_READONLY|CLIENT_IGNORESIZE);
|
||||||
else
|
else
|
||||||
@@ -94,13 +106,22 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort_crit.order = sort_order_from_string(args_get(args, 'O'));
|
||||||
|
if (sort_crit.order == SORT_END && args_has(args, 'O')) {
|
||||||
|
cmdq_error(item, "invalid sort order");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
sort_crit.reversed = args_has(args, 'r');
|
||||||
|
|
||||||
if (args_has(args, 'n')) {
|
if (args_has(args, 'n')) {
|
||||||
if ((s = session_next_session(tc->session)) == NULL) {
|
s = session_next_session(tc->session, &sort_crit);
|
||||||
|
if (s == NULL) {
|
||||||
cmdq_error(item, "can't find next session");
|
cmdq_error(item, "can't find next session");
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
} else if (args_has(args, 'p')) {
|
} else if (args_has(args, 'p')) {
|
||||||
if ((s = session_previous_session(tc->session)) == NULL) {
|
s = session_previous_session(tc->session, &sort_crit);
|
||||||
|
if (s == NULL) {
|
||||||
cmdq_error(item, "can't find previous session");
|
cmdq_error(item, "can't find previous session");
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
46
cmd.c
46
cmd.c
@@ -71,6 +71,7 @@ extern const struct cmd_entry cmd_lock_server_entry;
|
|||||||
extern const struct cmd_entry cmd_lock_session_entry;
|
extern const struct cmd_entry cmd_lock_session_entry;
|
||||||
extern const struct cmd_entry cmd_move_pane_entry;
|
extern const struct cmd_entry cmd_move_pane_entry;
|
||||||
extern const struct cmd_entry cmd_move_window_entry;
|
extern const struct cmd_entry cmd_move_window_entry;
|
||||||
|
extern const struct cmd_entry cmd_new_pane_entry;
|
||||||
extern const struct cmd_entry cmd_new_session_entry;
|
extern const struct cmd_entry cmd_new_session_entry;
|
||||||
extern const struct cmd_entry cmd_new_window_entry;
|
extern const struct cmd_entry cmd_new_window_entry;
|
||||||
extern const struct cmd_entry cmd_next_layout_entry;
|
extern const struct cmd_entry cmd_next_layout_entry;
|
||||||
@@ -163,6 +164,7 @@ const struct cmd_entry *cmd_table[] = {
|
|||||||
&cmd_lock_session_entry,
|
&cmd_lock_session_entry,
|
||||||
&cmd_move_pane_entry,
|
&cmd_move_pane_entry,
|
||||||
&cmd_move_window_entry,
|
&cmd_move_window_entry,
|
||||||
|
&cmd_new_pane_entry,
|
||||||
&cmd_new_session_entry,
|
&cmd_new_session_entry,
|
||||||
&cmd_new_window_entry,
|
&cmd_new_window_entry,
|
||||||
&cmd_next_layout_entry,
|
&cmd_next_layout_entry,
|
||||||
@@ -220,6 +222,7 @@ struct cmd {
|
|||||||
|
|
||||||
char *file;
|
char *file;
|
||||||
u_int line;
|
u_int line;
|
||||||
|
int parse_flags;
|
||||||
|
|
||||||
TAILQ_ENTRY(cmd) qentry;
|
TAILQ_ENTRY(cmd) qentry;
|
||||||
};
|
};
|
||||||
@@ -302,6 +305,8 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
|
|||||||
|
|
||||||
if (argc == 0)
|
if (argc == 0)
|
||||||
return (0);
|
return (0);
|
||||||
|
if (argc < 0 || argc > 1000)
|
||||||
|
return (-1);
|
||||||
*argv = xcalloc(argc, sizeof **argv);
|
*argv = xcalloc(argc, sizeof **argv);
|
||||||
|
|
||||||
buf[len - 1] = '\0';
|
buf[len - 1] = '\0';
|
||||||
@@ -412,6 +417,13 @@ cmd_get_source(struct cmd *cmd, const char **file, u_int *line)
|
|||||||
*line = cmd->line;
|
*line = cmd->line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get parse flags for command. */
|
||||||
|
int
|
||||||
|
cmd_get_parse_flags(struct cmd *cmd)
|
||||||
|
{
|
||||||
|
return (cmd->parse_flags);
|
||||||
|
}
|
||||||
|
|
||||||
/* Look for an alias for a command. */
|
/* Look for an alias for a command. */
|
||||||
char *
|
char *
|
||||||
cmd_get_alias(const char *name)
|
cmd_get_alias(const char *name)
|
||||||
@@ -444,7 +456,7 @@ cmd_get_alias(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Look up a command entry by name. */
|
/* Look up a command entry by name. */
|
||||||
static const struct cmd_entry *
|
const struct cmd_entry *
|
||||||
cmd_find(const char *name, char **cause)
|
cmd_find(const char *name, char **cause)
|
||||||
{
|
{
|
||||||
const struct cmd_entry **loop, *entry, *found = NULL;
|
const struct cmd_entry **loop, *entry, *found = NULL;
|
||||||
@@ -496,7 +508,7 @@ ambiguous:
|
|||||||
/* Parse a single command from an argument vector. */
|
/* Parse a single command from an argument vector. */
|
||||||
struct cmd *
|
struct cmd *
|
||||||
cmd_parse(struct args_value *values, u_int count, const char *file, u_int line,
|
cmd_parse(struct args_value *values, u_int count, const char *file, u_int line,
|
||||||
char **cause)
|
int parse_flags, char **cause)
|
||||||
{
|
{
|
||||||
const struct cmd_entry *entry;
|
const struct cmd_entry *entry;
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
@@ -525,6 +537,7 @@ cmd_parse(struct args_value *values, u_int count, const char *file, u_int line,
|
|||||||
cmd = xcalloc(1, sizeof *cmd);
|
cmd = xcalloc(1, sizeof *cmd);
|
||||||
cmd->entry = entry;
|
cmd->entry = entry;
|
||||||
cmd->args = args;
|
cmd->args = args;
|
||||||
|
cmd->parse_flags = parse_flags;
|
||||||
|
|
||||||
if (file != NULL)
|
if (file != NULL)
|
||||||
cmd->file = xstrdup(file);
|
cmd->file = xstrdup(file);
|
||||||
@@ -636,7 +649,7 @@ cmd_list_free(struct cmd_list *cmdlist)
|
|||||||
|
|
||||||
/* Copy a command list, expanding %s in arguments. */
|
/* Copy a command list, expanding %s in arguments. */
|
||||||
struct cmd_list *
|
struct cmd_list *
|
||||||
cmd_list_copy(struct cmd_list *cmdlist, int argc, char **argv)
|
cmd_list_copy(const struct cmd_list *cmdlist, int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct cmd *cmd;
|
struct cmd *cmd;
|
||||||
struct cmd_list *new_cmdlist;
|
struct cmd_list *new_cmdlist;
|
||||||
@@ -667,11 +680,16 @@ cmd_list_copy(struct cmd_list *cmdlist, int argc, char **argv)
|
|||||||
|
|
||||||
/* Get a command list as a string. */
|
/* Get a command list as a string. */
|
||||||
char *
|
char *
|
||||||
cmd_list_print(struct cmd_list *cmdlist, int escaped)
|
cmd_list_print(const struct cmd_list *cmdlist, int flags)
|
||||||
{
|
{
|
||||||
struct cmd *cmd, *next;
|
struct cmd *cmd, *next;
|
||||||
char *buf, *this;
|
char *buf, *this;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
const char *separator;
|
||||||
|
int escaped = flags & CMD_LIST_PRINT_ESCAPED;
|
||||||
|
int no_groups = flags & CMD_LIST_PRINT_NO_GROUPS;
|
||||||
|
const char *single_separator = escaped ? " \\; " : " ; ";
|
||||||
|
const char *double_separator = escaped ? " \\;\\; " : " ;; ";
|
||||||
|
|
||||||
len = 1;
|
len = 1;
|
||||||
buf = xcalloc(1, len);
|
buf = xcalloc(1, len);
|
||||||
@@ -686,17 +704,11 @@ cmd_list_print(struct cmd_list *cmdlist, int escaped)
|
|||||||
|
|
||||||
next = TAILQ_NEXT(cmd, qentry);
|
next = TAILQ_NEXT(cmd, qentry);
|
||||||
if (next != NULL) {
|
if (next != NULL) {
|
||||||
if (cmd->group != next->group) {
|
if (!no_groups && cmd->group != next->group)
|
||||||
if (escaped)
|
separator = double_separator;
|
||||||
strlcat(buf, " \\;\\; ", len);
|
else
|
||||||
else
|
separator = single_separator;
|
||||||
strlcat(buf, " ;; ", len);
|
strlcat(buf, separator, len);
|
||||||
} else {
|
|
||||||
if (escaped)
|
|
||||||
strlcat(buf, " \\; ", len);
|
|
||||||
else
|
|
||||||
strlcat(buf, " ; ", len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(this);
|
free(this);
|
||||||
@@ -764,9 +776,9 @@ cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
|
|||||||
if (m->statusat == 0 && y >= m->statuslines)
|
if (m->statusat == 0 && y >= m->statuslines)
|
||||||
y -= m->statuslines;
|
y -= m->statuslines;
|
||||||
|
|
||||||
if (x < wp->xoff || x >= wp->xoff + wp->sx)
|
if ((int)x < wp->xoff || (int)x >= wp->xoff + (int)wp->sx)
|
||||||
return (-1);
|
return (-1);
|
||||||
if (y < wp->yoff || y >= wp->yoff + wp->sy)
|
if ((int)y < wp->yoff || (int)y >= wp->yoff + (int)wp->sy)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
if (xp != NULL)
|
if (xp != NULL)
|
||||||
|
|||||||
70
colour.c
70
colour.c
@@ -182,6 +182,46 @@ colour_tostring(int c)
|
|||||||
return ("invalid");
|
return ("invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert background colour to theme. */
|
||||||
|
enum client_theme
|
||||||
|
colour_totheme(int c)
|
||||||
|
{
|
||||||
|
int r, g, b, brightness;
|
||||||
|
|
||||||
|
if (c == -1)
|
||||||
|
return (THEME_UNKNOWN);
|
||||||
|
|
||||||
|
if (c & COLOUR_FLAG_RGB) {
|
||||||
|
r = (c >> 16) & 0xff;
|
||||||
|
g = (c >> 8) & 0xff;
|
||||||
|
b = (c >> 0) & 0xff;
|
||||||
|
|
||||||
|
brightness = r + g + b;
|
||||||
|
if (brightness > 382)
|
||||||
|
return (THEME_LIGHT);
|
||||||
|
return (THEME_DARK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c & COLOUR_FLAG_256)
|
||||||
|
return (colour_totheme(colour_256toRGB(c)));
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
case 90:
|
||||||
|
return (THEME_DARK);
|
||||||
|
case 7:
|
||||||
|
case 97:
|
||||||
|
return (THEME_LIGHT);
|
||||||
|
default:
|
||||||
|
if (c >= 0 && c <= 7)
|
||||||
|
return (colour_totheme(colour_256toRGB(c)));
|
||||||
|
if (c >= 90 && c <= 97)
|
||||||
|
return (colour_totheme(colour_256toRGB(8 + c - 90)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (THEME_UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
/* Convert colour from string. */
|
/* Convert colour from string. */
|
||||||
int
|
int
|
||||||
colour_fromstring(const char *s)
|
colour_fromstring(const char *s)
|
||||||
@@ -946,7 +986,8 @@ colour_byname(const char *name)
|
|||||||
int c;
|
int c;
|
||||||
const char *errstr;
|
const char *errstr;
|
||||||
|
|
||||||
if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) {
|
if (strncasecmp(name, "grey", 4) == 0 ||
|
||||||
|
strncasecmp(name, "gray", 4) == 0) {
|
||||||
if (name[4] == '\0')
|
if (name[4] == '\0')
|
||||||
return (0xbebebe|COLOUR_FLAG_RGB);
|
return (0xbebebe|COLOUR_FLAG_RGB);
|
||||||
c = strtonum(name + 4, 0, 100, &errstr);
|
c = strtonum(name + 4, 0, 100, &errstr);
|
||||||
@@ -1041,22 +1082,22 @@ colour_palette_free(struct colour_palette *p)
|
|||||||
|
|
||||||
/* Get a colour from a palette. */
|
/* Get a colour from a palette. */
|
||||||
int
|
int
|
||||||
colour_palette_get(struct colour_palette *p, int c)
|
colour_palette_get(struct colour_palette *p, int n)
|
||||||
{
|
{
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
if (c >= 90 && c <= 97)
|
if (n >= 90 && n <= 97)
|
||||||
c = 8 + c - 90;
|
n = 8 + n - 90;
|
||||||
else if (c & COLOUR_FLAG_256)
|
else if (n & COLOUR_FLAG_256)
|
||||||
c &= ~COLOUR_FLAG_256;
|
n &= ~COLOUR_FLAG_256;
|
||||||
else if (c >= 8)
|
else if (n >= 8)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
if (p->palette != NULL && p->palette[c] != -1)
|
if (p->palette != NULL && p->palette[n] != -1)
|
||||||
return (p->palette[c]);
|
return (p->palette[n]);
|
||||||
if (p->default_palette != NULL && p->default_palette[c] != -1)
|
if (p->default_palette != NULL && p->default_palette[n] != -1)
|
||||||
return (p->default_palette[c]);
|
return (p->default_palette[n]);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1066,15 +1107,14 @@ colour_palette_set(struct colour_palette *p, int n, int c)
|
|||||||
{
|
{
|
||||||
u_int i;
|
u_int i;
|
||||||
|
|
||||||
if (p == NULL || n > 255)
|
if (p == NULL || n < 0 || n > 255)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
if (c == -1 && p->palette == NULL)
|
if (c == -1 && p->palette == NULL)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
if (c != -1 && p->palette == NULL) {
|
if (p->palette == NULL) {
|
||||||
if (p->palette == NULL)
|
p->palette = xcalloc(256, sizeof *p->palette);
|
||||||
p->palette = xcalloc(256, sizeof *p->palette);
|
|
||||||
for (i = 0; i < 256; i++)
|
for (i = 0; i < 256; i++)
|
||||||
p->palette[i] = -1;
|
p->palette[i] = -1;
|
||||||
}
|
}
|
||||||
|
|||||||
25
compat.h
25
compat.h
@@ -38,6 +38,14 @@
|
|||||||
#include <event2/bufferevent_compat.h>
|
#include <event2/bufferevent_compat.h>
|
||||||
#else
|
#else
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
|
#ifndef EVBUFFER_EOL_LF
|
||||||
|
/*
|
||||||
|
* This doesn't really work because evbuffer_readline is broken, but gets us to
|
||||||
|
* build with very old (older than 1.4.14) libevent.
|
||||||
|
*/
|
||||||
|
#define EVBUFFER_EOL_LF
|
||||||
|
#define evbuffer_readln(a, b, c) evbuffer_readline(a)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_MALLOC_TRIM
|
#ifdef HAVE_MALLOC_TRIM
|
||||||
@@ -380,7 +388,7 @@ int clock_gettime(int, struct timespec *);
|
|||||||
/* base64.c */
|
/* base64.c */
|
||||||
#undef b64_ntop
|
#undef b64_ntop
|
||||||
#undef b64_pton
|
#undef b64_pton
|
||||||
int b64_ntop(const char *, size_t, char *, size_t);
|
int b64_ntop(const u_char *, size_t, char *, size_t);
|
||||||
int b64_pton(const char *, u_char *, size_t);
|
int b64_pton(const char *, u_char *, size_t);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -442,7 +450,7 @@ void *recallocarray(void *, size_t, size_t, size_t);
|
|||||||
/* systemd.c */
|
/* systemd.c */
|
||||||
int systemd_activated(void);
|
int systemd_activated(void);
|
||||||
int systemd_create_socket(int, char **);
|
int systemd_create_socket(int, char **);
|
||||||
int systemd_move_pid_to_new_cgroup(pid_t, char **);
|
int systemd_move_to_new_cgroup(char **);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_UTF8PROC
|
#ifdef HAVE_UTF8PROC
|
||||||
@@ -455,14 +463,17 @@ int utf8proc_wctomb(char *, wchar_t);
|
|||||||
#ifdef NEED_FUZZING
|
#ifdef NEED_FUZZING
|
||||||
/* tmux.c */
|
/* tmux.c */
|
||||||
#define main __weak main
|
#define main __weak main
|
||||||
|
#define regcomp(preg, pattern, cflags) (0)
|
||||||
|
#define regexec(preg, string, nmatch, pmatch, eflags) (REG_NOMATCH)
|
||||||
|
#define regfree(preg) ((void)0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* getopt.c */
|
/* getopt.c */
|
||||||
extern int BSDopterr;
|
extern int BSDopterr;
|
||||||
extern int BSDoptind;
|
extern int BSDoptind;
|
||||||
extern int BSDoptopt;
|
extern int BSDoptopt;
|
||||||
extern int BSDoptreset;
|
extern int BSDoptreset;
|
||||||
extern char *BSDoptarg;
|
extern char *BSDoptarg;
|
||||||
int BSDgetopt(int, char *const *, const char *);
|
int BSDgetopt(int, char *const *, const char *);
|
||||||
#define getopt(ac, av, o) BSDgetopt(ac, av, o)
|
#define getopt(ac, av, o) BSDgetopt(ac, av, o)
|
||||||
#define opterr BSDopterr
|
#define opterr BSDopterr
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: base64.c,v 1.8 2015/01/16 16:48:51 deraadt Exp $ */
|
/* $OpenBSD: base64.c,v 1.15 2021/10/25 14:41:09 jca Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1996 by Internet Software Consortium.
|
* Copyright (c) 1996 by Internet Software Consortium.
|
||||||
@@ -46,15 +46,15 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <arpa/nameser.h>
|
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <resolv.h>
|
#include <resolv.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "compat.h"
|
||||||
|
|
||||||
static const char Base64[] =
|
static const char Base64[] =
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
static const char Pad64 = '=';
|
static const char Pad64 = '=';
|
||||||
@@ -107,9 +107,9 @@ static const char Pad64 = '=';
|
|||||||
end of the data is performed using the '=' character.
|
end of the data is performed using the '=' character.
|
||||||
|
|
||||||
Since all base64 input is an integral number of octets, only the
|
Since all base64 input is an integral number of octets, only the
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
following cases can arise:
|
following cases can arise:
|
||||||
|
|
||||||
(1) the final quantum of encoding input is an integral
|
(1) the final quantum of encoding input is an integral
|
||||||
multiple of 24 bits; here, the final unit of encoded
|
multiple of 24 bits; here, the final unit of encoded
|
||||||
output will be an integral multiple of 4 characters
|
output will be an integral multiple of 4 characters
|
||||||
@@ -123,15 +123,12 @@ static const char Pad64 = '=';
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
b64_ntop(src, srclength, target, targsize)
|
b64_ntop(unsigned char const *src, size_t srclength, char *target,
|
||||||
u_char const *src;
|
size_t targsize)
|
||||||
size_t srclength;
|
|
||||||
char *target;
|
|
||||||
size_t targsize;
|
|
||||||
{
|
{
|
||||||
size_t datalength = 0;
|
size_t datalength = 0;
|
||||||
u_char input[3];
|
unsigned char input[3];
|
||||||
u_char output[4];
|
unsigned char output[4];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
while (2 < srclength) {
|
while (2 < srclength) {
|
||||||
@@ -152,14 +149,14 @@ b64_ntop(src, srclength, target, targsize)
|
|||||||
target[datalength++] = Base64[output[2]];
|
target[datalength++] = Base64[output[2]];
|
||||||
target[datalength++] = Base64[output[3]];
|
target[datalength++] = Base64[output[3]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now we worry about padding. */
|
/* Now we worry about padding. */
|
||||||
if (0 != srclength) {
|
if (0 != srclength) {
|
||||||
/* Get what's left. */
|
/* Get what's left. */
|
||||||
input[0] = input[1] = input[2] = '\0';
|
input[0] = input[1] = input[2] = '\0';
|
||||||
for (i = 0; i < srclength; i++)
|
for (i = 0; i < srclength; i++)
|
||||||
input[i] = *src++;
|
input[i] = *src++;
|
||||||
|
|
||||||
output[0] = input[0] >> 2;
|
output[0] = input[0] >> 2;
|
||||||
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
|
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
|
||||||
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
|
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
|
||||||
@@ -187,13 +184,10 @@ b64_ntop(src, srclength, target, targsize)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
b64_pton(src, target, targsize)
|
b64_pton(char const *src, unsigned char *target, size_t targsize)
|
||||||
char const *src;
|
|
||||||
u_char *target;
|
|
||||||
size_t targsize;
|
|
||||||
{
|
{
|
||||||
int tarindex, state, ch;
|
int tarindex, state, ch;
|
||||||
u_char nextbyte;
|
unsigned char nextbyte;
|
||||||
char *pos;
|
char *pos;
|
||||||
|
|
||||||
state = 0;
|
state = 0;
|
||||||
@@ -207,7 +201,7 @@ b64_pton(src, target, targsize)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
pos = strchr(Base64, ch);
|
pos = strchr(Base64, ch);
|
||||||
if (pos == 0) /* A non-base64 character. */
|
if (pos == 0) /* A non-base64 character. */
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
clock_gettime(int clock, struct timespec *ts)
|
clock_gettime(__unused int clock, struct timespec *ts)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
|
|||||||
@@ -49,12 +49,12 @@
|
|||||||
|
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
|
|
||||||
#include <Availability.h>
|
#include <AvailabilityMacros.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
void daemon_darwin(void);
|
void daemon_darwin(void);
|
||||||
|
|
||||||
#ifdef __MAC_10_10
|
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
|
||||||
|
|
||||||
extern kern_return_t bootstrap_look_up_per_user(mach_port_t, const char *,
|
extern kern_return_t bootstrap_look_up_per_user(mach_port_t, const char *,
|
||||||
uid_t, mach_port_t *);
|
uid_t, mach_port_t *);
|
||||||
|
|||||||
@@ -18,13 +18,28 @@
|
|||||||
|
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#if defined(HAVE_LIBPROC_H)
|
||||||
|
#include <libproc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
|
||||||
void fatal(const char *, ...);
|
void fatal(const char *, ...);
|
||||||
void fatalx(const char *, ...);
|
void fatalx(const char *, ...);
|
||||||
|
|
||||||
#ifdef HAVE_PROC_PID
|
#if defined(HAVE_LIBPROC_H) && defined(HAVE_PROC_PIDINFO)
|
||||||
|
int
|
||||||
|
getdtablecount(void)
|
||||||
|
{
|
||||||
|
int sz;
|
||||||
|
pid_t pid = getpid();
|
||||||
|
|
||||||
|
sz = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
|
||||||
|
if (sz == -1)
|
||||||
|
return (0);
|
||||||
|
return (sz / PROC_PIDLISTFD_SIZE);
|
||||||
|
}
|
||||||
|
#elif defined(HAVE_PROC_PID)
|
||||||
int
|
int
|
||||||
getdtablecount(void)
|
getdtablecount(void)
|
||||||
{
|
{
|
||||||
|
|||||||
115
compat/getopt.c
115
compat/getopt.c
@@ -1,115 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1987, 1993, 1994
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */
|
|
||||||
|
|
||||||
#include "compat.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
int BSDopterr = 1, /* if error message should be printed */
|
|
||||||
BSDoptind = 1, /* index into parent argv vector */
|
|
||||||
BSDoptopt, /* character checked for validity */
|
|
||||||
BSDoptreset; /* reset getopt */
|
|
||||||
char *BSDoptarg; /* argument associated with option */
|
|
||||||
|
|
||||||
#define BADCH (int)'?'
|
|
||||||
#define BADARG (int)':'
|
|
||||||
#define EMSG ""
|
|
||||||
|
|
||||||
/*
|
|
||||||
* getopt --
|
|
||||||
* Parse argc/argv argument vector.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
BSDgetopt(int nargc, char *const *nargv, const char *ostr)
|
|
||||||
{
|
|
||||||
static const char *place = EMSG; /* option letter processing */
|
|
||||||
char *oli; /* option letter list index */
|
|
||||||
|
|
||||||
if (ostr == NULL)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
if (BSDoptreset || !*place) { /* update scanning pointer */
|
|
||||||
BSDoptreset = 0;
|
|
||||||
if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') {
|
|
||||||
place = EMSG;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
if (place[1] && *++place == '-') { /* found "--" */
|
|
||||||
if (place[1])
|
|
||||||
return (BADCH);
|
|
||||||
++BSDoptind;
|
|
||||||
place = EMSG;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
} /* option letter okay? */
|
|
||||||
if ((BSDoptopt = (int)*place++) == (int)':' ||
|
|
||||||
!(oli = strchr(ostr, BSDoptopt))) {
|
|
||||||
/*
|
|
||||||
* if the user didn't specify '-' as an option,
|
|
||||||
* assume it means -1.
|
|
||||||
*/
|
|
||||||
if (BSDoptopt == (int)'-')
|
|
||||||
return (-1);
|
|
||||||
if (!*place)
|
|
||||||
++BSDoptind;
|
|
||||||
if (BSDopterr && *ostr != ':')
|
|
||||||
(void)fprintf(stderr,
|
|
||||||
"%s: unknown option -- %c\n", getprogname(),
|
|
||||||
BSDoptopt);
|
|
||||||
return (BADCH);
|
|
||||||
}
|
|
||||||
if (*++oli != ':') { /* don't need argument */
|
|
||||||
BSDoptarg = NULL;
|
|
||||||
if (!*place)
|
|
||||||
++BSDoptind;
|
|
||||||
}
|
|
||||||
else { /* need an argument */
|
|
||||||
if (*place) /* no white space */
|
|
||||||
BSDoptarg = (char *)place;
|
|
||||||
else if (nargc <= ++BSDoptind) { /* no arg */
|
|
||||||
place = EMSG;
|
|
||||||
if (*ostr == ':')
|
|
||||||
return (BADARG);
|
|
||||||
if (BSDopterr)
|
|
||||||
(void)fprintf(stderr,
|
|
||||||
"%s: option requires an argument -- %c\n",
|
|
||||||
getprogname(), BSDoptopt);
|
|
||||||
return (BADCH);
|
|
||||||
}
|
|
||||||
else /* white space */
|
|
||||||
BSDoptarg = nargv[BSDoptind];
|
|
||||||
place = EMSG;
|
|
||||||
++BSDoptind;
|
|
||||||
}
|
|
||||||
return (BSDoptopt); /* dump back option letter */
|
|
||||||
}
|
|
||||||
577
compat/getopt_long.c
Normal file
577
compat/getopt_long.c
Normal file
@@ -0,0 +1,577 @@
|
|||||||
|
/* This file is obtained from OpenSSH:
|
||||||
|
* Repository: https://github.com/openssh/openssh-portable
|
||||||
|
* Commit: b5b405fee7f3e79d44e2d2971a4b6b4cc53f112e
|
||||||
|
* File: /openbsd-compat/getopt_long.c */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* Sponsored in part by the Defense Advanced Research Projects
|
||||||
|
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||||
|
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||||
|
*/
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to The NetBSD Foundation
|
||||||
|
* by Dieter Baron and Thomas Klausner.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt_long.c */
|
||||||
|
#include "compat.h"
|
||||||
|
|
||||||
|
/* The following macro constants are taken from getopt.h of OpenSSH:
|
||||||
|
* Repository: https://github.com/openssh/openssh-portable
|
||||||
|
* Commit: b5b405fee7f3e79d44e2d2971a4b6b4cc53f112e
|
||||||
|
* File: /openbsd-compat/getopt.h
|
||||||
|
*
|
||||||
|
* ---- BEGIN - Copyright notice and license of getopt.h ----
|
||||||
|
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to The NetBSD Foundation
|
||||||
|
* by Dieter Baron and Thomas Klausner.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||||
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
* ---- END ----
|
||||||
|
*/
|
||||||
|
#define no_argument 0
|
||||||
|
#define required_argument 1
|
||||||
|
#define optional_argument 2
|
||||||
|
|
||||||
|
#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET)
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <err.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
struct option {
|
||||||
|
/* name of long option */
|
||||||
|
const char *name;
|
||||||
|
/*
|
||||||
|
* one of no_argument, required_argument, and optional_argument:
|
||||||
|
* whether option takes an argument
|
||||||
|
*/
|
||||||
|
int has_arg;
|
||||||
|
/* if not NULL, set *flag to val when option found */
|
||||||
|
int *flag;
|
||||||
|
/* if flag not NULL, value to set *flag to; else return value */
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
int opterr = 1; /* if error message should be printed */
|
||||||
|
int optind = 1; /* index into parent argv vector */
|
||||||
|
int optopt = '?'; /* character checked for validity */
|
||||||
|
int optreset; /* reset getopt */
|
||||||
|
char *optarg; /* argument associated with option */
|
||||||
|
|
||||||
|
#define PRINT_ERROR ((opterr) && (*options != ':'))
|
||||||
|
|
||||||
|
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
|
||||||
|
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
|
||||||
|
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
|
||||||
|
|
||||||
|
/* return values */
|
||||||
|
#define BADCH (int)'?'
|
||||||
|
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
|
||||||
|
#define INORDER (int)1
|
||||||
|
|
||||||
|
#define EMSG (char *)""
|
||||||
|
|
||||||
|
static int getopt_internal(int, char * const *, const char *,
|
||||||
|
const struct option *, int *, int);
|
||||||
|
static int parse_long_options(char * const *, const char *,
|
||||||
|
const struct option *, int *, int);
|
||||||
|
static int gcd(int, int);
|
||||||
|
static void permute_args(int, int, int, char * const *);
|
||||||
|
|
||||||
|
static char *place = EMSG; /* option letter processing */
|
||||||
|
|
||||||
|
/* XXX: set optreset to 1 rather than these two */
|
||||||
|
static int nonopt_start = -1; /* first non option argument (for permute) */
|
||||||
|
static int nonopt_end = -1; /* first option after non options (for permute) */
|
||||||
|
|
||||||
|
/* Error messages */
|
||||||
|
static const char recargchar[] = "option requires an argument -- %c";
|
||||||
|
static const char recargstring[] = "option requires an argument -- %s";
|
||||||
|
static const char ambig[] = "ambiguous option -- %.*s";
|
||||||
|
static const char noarg[] = "option doesn't take an argument -- %.*s";
|
||||||
|
static const char illoptchar[] = "unknown option -- %c";
|
||||||
|
static const char illoptstring[] = "unknown option -- %s";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the greatest common divisor of a and b.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
gcd(int a, int b)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
c = a % b;
|
||||||
|
while (c != 0) {
|
||||||
|
a = b;
|
||||||
|
b = c;
|
||||||
|
c = a % b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exchange the block from nonopt_start to nonopt_end with the block
|
||||||
|
* from nonopt_end to opt_end (keeping the same order of arguments
|
||||||
|
* in each block).
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
permute_args(int panonopt_start, int panonopt_end, int opt_end,
|
||||||
|
char * const *nargv)
|
||||||
|
{
|
||||||
|
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
|
||||||
|
char *swap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* compute lengths of blocks and number and size of cycles
|
||||||
|
*/
|
||||||
|
nnonopts = panonopt_end - panonopt_start;
|
||||||
|
nopts = opt_end - panonopt_end;
|
||||||
|
ncycle = gcd(nnonopts, nopts);
|
||||||
|
cyclelen = (opt_end - panonopt_start) / ncycle;
|
||||||
|
|
||||||
|
for (i = 0; i < ncycle; i++) {
|
||||||
|
cstart = panonopt_end+i;
|
||||||
|
pos = cstart;
|
||||||
|
for (j = 0; j < cyclelen; j++) {
|
||||||
|
if (pos >= panonopt_end)
|
||||||
|
pos -= nnonopts;
|
||||||
|
else
|
||||||
|
pos += nopts;
|
||||||
|
swap = nargv[pos];
|
||||||
|
/* LINTED const cast */
|
||||||
|
((char **) nargv)[pos] = nargv[cstart];
|
||||||
|
/* LINTED const cast */
|
||||||
|
((char **)nargv)[cstart] = swap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parse_long_options --
|
||||||
|
* Parse long options in argc/argv argument vector.
|
||||||
|
* Returns -1 if short_too is set and the option does not match long_options.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_long_options(char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx, int short_too)
|
||||||
|
{
|
||||||
|
char *current_argv, *has_equal;
|
||||||
|
size_t current_argv_len;
|
||||||
|
int i, match;
|
||||||
|
|
||||||
|
current_argv = place;
|
||||||
|
match = -1;
|
||||||
|
|
||||||
|
optind++;
|
||||||
|
|
||||||
|
if ((has_equal = strchr(current_argv, '=')) != NULL) {
|
||||||
|
/* argument found (--option=arg) */
|
||||||
|
current_argv_len = has_equal - current_argv;
|
||||||
|
has_equal++;
|
||||||
|
} else
|
||||||
|
current_argv_len = strlen(current_argv);
|
||||||
|
|
||||||
|
for (i = 0; long_options[i].name; i++) {
|
||||||
|
/* find matching long option */
|
||||||
|
if (strncmp(current_argv, long_options[i].name,
|
||||||
|
current_argv_len))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strlen(long_options[i].name) == current_argv_len) {
|
||||||
|
/* exact match */
|
||||||
|
match = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If this is a known short option, don't allow
|
||||||
|
* a partial match of a single character.
|
||||||
|
*/
|
||||||
|
if (short_too && current_argv_len == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (match == -1) /* partial match */
|
||||||
|
match = i;
|
||||||
|
else {
|
||||||
|
/* ambiguous abbreviation */
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(ambig, (int)current_argv_len,
|
||||||
|
current_argv);
|
||||||
|
optopt = 0;
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match != -1) { /* option found */
|
||||||
|
if (long_options[match].has_arg == no_argument
|
||||||
|
&& has_equal) {
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(noarg, (int)current_argv_len,
|
||||||
|
current_argv);
|
||||||
|
/*
|
||||||
|
* XXX: GNU sets optopt to val regardless of flag
|
||||||
|
*/
|
||||||
|
if (long_options[match].flag == NULL)
|
||||||
|
optopt = long_options[match].val;
|
||||||
|
else
|
||||||
|
optopt = 0;
|
||||||
|
return (BADARG);
|
||||||
|
}
|
||||||
|
if (long_options[match].has_arg == required_argument ||
|
||||||
|
long_options[match].has_arg == optional_argument) {
|
||||||
|
if (has_equal)
|
||||||
|
optarg = has_equal;
|
||||||
|
else if (long_options[match].has_arg ==
|
||||||
|
required_argument) {
|
||||||
|
/*
|
||||||
|
* optional argument doesn't use next nargv
|
||||||
|
*/
|
||||||
|
optarg = nargv[optind++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((long_options[match].has_arg == required_argument)
|
||||||
|
&& (optarg == NULL)) {
|
||||||
|
/*
|
||||||
|
* Missing argument; leading ':' indicates no error
|
||||||
|
* should be generated.
|
||||||
|
*/
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(recargstring,
|
||||||
|
current_argv);
|
||||||
|
/*
|
||||||
|
* XXX: GNU sets optopt to val regardless of flag
|
||||||
|
*/
|
||||||
|
if (long_options[match].flag == NULL)
|
||||||
|
optopt = long_options[match].val;
|
||||||
|
else
|
||||||
|
optopt = 0;
|
||||||
|
--optind;
|
||||||
|
return (BADARG);
|
||||||
|
}
|
||||||
|
} else { /* unknown option */
|
||||||
|
if (short_too) {
|
||||||
|
--optind;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(illoptstring, current_argv);
|
||||||
|
optopt = 0;
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
if (idx)
|
||||||
|
*idx = match;
|
||||||
|
if (long_options[match].flag) {
|
||||||
|
*long_options[match].flag = long_options[match].val;
|
||||||
|
return (0);
|
||||||
|
} else
|
||||||
|
return (long_options[match].val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt_internal --
|
||||||
|
* Parse argc/argv argument vector. Called by user level routines.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
getopt_internal(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx, int flags)
|
||||||
|
{
|
||||||
|
char *oli; /* option letter list index */
|
||||||
|
int optchar, short_too;
|
||||||
|
static int posixly_correct = -1;
|
||||||
|
|
||||||
|
if (options == NULL)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX Some GNU programs (like cvs) set optind to 0 instead of
|
||||||
|
* XXX using optreset. Work around this braindamage.
|
||||||
|
*/
|
||||||
|
if (optind == 0)
|
||||||
|
optind = optreset = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable GNU extensions if POSIXLY_CORRECT is set or options
|
||||||
|
* string begins with a '+'.
|
||||||
|
*/
|
||||||
|
if (posixly_correct == -1 || optreset)
|
||||||
|
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
|
||||||
|
if (*options == '-')
|
||||||
|
flags |= FLAG_ALLARGS;
|
||||||
|
else if (posixly_correct || *options == '+')
|
||||||
|
flags &= ~FLAG_PERMUTE;
|
||||||
|
if (*options == '+' || *options == '-')
|
||||||
|
options++;
|
||||||
|
|
||||||
|
optarg = NULL;
|
||||||
|
if (optreset)
|
||||||
|
nonopt_start = nonopt_end = -1;
|
||||||
|
start:
|
||||||
|
if (optreset || !*place) { /* update scanning pointer */
|
||||||
|
optreset = 0;
|
||||||
|
if (optind >= nargc) { /* end of argument vector */
|
||||||
|
place = EMSG;
|
||||||
|
if (nonopt_end != -1) {
|
||||||
|
/* do permutation, if we have to */
|
||||||
|
permute_args(nonopt_start, nonopt_end,
|
||||||
|
optind, nargv);
|
||||||
|
optind -= nonopt_end - nonopt_start;
|
||||||
|
}
|
||||||
|
else if (nonopt_start != -1) {
|
||||||
|
/*
|
||||||
|
* If we skipped non-options, set optind
|
||||||
|
* to the first of them.
|
||||||
|
*/
|
||||||
|
optind = nonopt_start;
|
||||||
|
}
|
||||||
|
nonopt_start = nonopt_end = -1;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (*(place = nargv[optind]) != '-' ||
|
||||||
|
(place[1] == '\0' && strchr(options, '-') == NULL)) {
|
||||||
|
place = EMSG; /* found non-option */
|
||||||
|
if (flags & FLAG_ALLARGS) {
|
||||||
|
/*
|
||||||
|
* GNU extension:
|
||||||
|
* return non-option as argument to option 1
|
||||||
|
*/
|
||||||
|
optarg = nargv[optind++];
|
||||||
|
return (INORDER);
|
||||||
|
}
|
||||||
|
if (!(flags & FLAG_PERMUTE)) {
|
||||||
|
/*
|
||||||
|
* If no permutation wanted, stop parsing
|
||||||
|
* at first non-option.
|
||||||
|
*/
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
/* do permutation */
|
||||||
|
if (nonopt_start == -1)
|
||||||
|
nonopt_start = optind;
|
||||||
|
else if (nonopt_end != -1) {
|
||||||
|
permute_args(nonopt_start, nonopt_end,
|
||||||
|
optind, nargv);
|
||||||
|
nonopt_start = optind -
|
||||||
|
(nonopt_end - nonopt_start);
|
||||||
|
nonopt_end = -1;
|
||||||
|
}
|
||||||
|
optind++;
|
||||||
|
/* process next argument */
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
if (nonopt_start != -1 && nonopt_end == -1)
|
||||||
|
nonopt_end = optind;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have "-" do nothing, if "--" we are done.
|
||||||
|
*/
|
||||||
|
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
|
||||||
|
optind++;
|
||||||
|
place = EMSG;
|
||||||
|
/*
|
||||||
|
* We found an option (--), so if we skipped
|
||||||
|
* non-options, we have to permute.
|
||||||
|
*/
|
||||||
|
if (nonopt_end != -1) {
|
||||||
|
permute_args(nonopt_start, nonopt_end,
|
||||||
|
optind, nargv);
|
||||||
|
optind -= nonopt_end - nonopt_start;
|
||||||
|
}
|
||||||
|
nonopt_start = nonopt_end = -1;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check long options if:
|
||||||
|
* 1) we were passed some
|
||||||
|
* 2) the arg is not just "-"
|
||||||
|
* 3) either the arg starts with -- we are getopt_long_only()
|
||||||
|
*/
|
||||||
|
if (long_options != NULL && place != nargv[optind] &&
|
||||||
|
(*place == '-' || (flags & FLAG_LONGONLY))) {
|
||||||
|
short_too = 0;
|
||||||
|
if (*place == '-')
|
||||||
|
place++; /* --foo long option */
|
||||||
|
else if (*place != ':' && strchr(options, *place) != NULL)
|
||||||
|
short_too = 1; /* could be short option too */
|
||||||
|
|
||||||
|
optchar = parse_long_options(nargv, options, long_options,
|
||||||
|
idx, short_too);
|
||||||
|
if (optchar != -1) {
|
||||||
|
place = EMSG;
|
||||||
|
return (optchar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((optchar = (int)*place++) == (int)':' ||
|
||||||
|
(optchar == (int)'-' && *place != '\0') ||
|
||||||
|
(oli = strchr(options, optchar)) == NULL) {
|
||||||
|
/*
|
||||||
|
* If the user specified "-" and '-' isn't listed in
|
||||||
|
* options, return -1 (non-option) as per POSIX.
|
||||||
|
* Otherwise, it is an unknown option character (or ':').
|
||||||
|
*/
|
||||||
|
if (optchar == (int)'-' && *place == '\0')
|
||||||
|
return (-1);
|
||||||
|
if (!*place)
|
||||||
|
++optind;
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(illoptchar, optchar);
|
||||||
|
optopt = optchar;
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
|
||||||
|
/* -W long-option */
|
||||||
|
if (*place) /* no space */
|
||||||
|
/* NOTHING */;
|
||||||
|
else if (++optind >= nargc) { /* no arg */
|
||||||
|
place = EMSG;
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(recargchar, optchar);
|
||||||
|
optopt = optchar;
|
||||||
|
return (BADARG);
|
||||||
|
} else /* white space */
|
||||||
|
place = nargv[optind];
|
||||||
|
optchar = parse_long_options(nargv, options, long_options,
|
||||||
|
idx, 0);
|
||||||
|
place = EMSG;
|
||||||
|
return (optchar);
|
||||||
|
}
|
||||||
|
if (*++oli != ':') { /* doesn't take argument */
|
||||||
|
if (!*place)
|
||||||
|
++optind;
|
||||||
|
} else { /* takes (optional) argument */
|
||||||
|
optarg = NULL;
|
||||||
|
if (*place) /* no white space */
|
||||||
|
optarg = place;
|
||||||
|
else if (oli[1] != ':') { /* arg not optional */
|
||||||
|
if (++optind >= nargc) { /* no arg */
|
||||||
|
place = EMSG;
|
||||||
|
if (PRINT_ERROR)
|
||||||
|
warnx(recargchar, optchar);
|
||||||
|
optopt = optchar;
|
||||||
|
return (BADARG);
|
||||||
|
} else
|
||||||
|
optarg = nargv[optind];
|
||||||
|
}
|
||||||
|
place = EMSG;
|
||||||
|
++optind;
|
||||||
|
}
|
||||||
|
/* dump back option letter */
|
||||||
|
return (optchar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*
|
||||||
|
* [eventually this will replace the BSD getopt]
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getopt(int nargc, char * const *nargv, const char *options)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't pass FLAG_PERMUTE to getopt_internal() since
|
||||||
|
* the BSD getopt(3) (unlike GNU) has never done this.
|
||||||
|
*
|
||||||
|
* Furthermore, since many privileged programs call getopt()
|
||||||
|
* before dropping privileges it makes sense to keep things
|
||||||
|
* as simple (and bug-free) as possible.
|
||||||
|
*/
|
||||||
|
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* getopt_long --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getopt_long(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (getopt_internal(nargc, nargv, options, long_options, idx,
|
||||||
|
FLAG_PERMUTE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt_long_only --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getopt_long_only(int nargc, char * const *nargv, const char *options,
|
||||||
|
const struct option *long_options, int *idx)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (getopt_internal(nargc, nargv, options, long_options, idx,
|
||||||
|
FLAG_PERMUTE|FLAG_LONGONLY));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: imsg-buffer.c,v 1.18 2023/12/12 15:47:41 claudio Exp $ */
|
/* $OpenBSD: imsg-buffer.c,v 1.36 2025/08/25 08:29:49 claudio Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
||||||
@@ -45,25 +45,39 @@
|
|||||||
#undef be64toh
|
#undef be64toh
|
||||||
#define be64toh ntohll
|
#define be64toh ntohll
|
||||||
|
|
||||||
static int ibuf_realloc(struct ibuf *, size_t);
|
struct ibufqueue {
|
||||||
static void ibuf_enqueue(struct msgbuf *, struct ibuf *);
|
TAILQ_HEAD(, ibuf) bufs;
|
||||||
static void ibuf_dequeue(struct msgbuf *, struct ibuf *);
|
uint32_t queued;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct msgbuf {
|
||||||
|
struct ibufqueue bufs;
|
||||||
|
struct ibufqueue rbufs;
|
||||||
|
char *rbuf;
|
||||||
|
struct ibuf *rpmsg;
|
||||||
|
struct ibuf *(*readhdr)(struct ibuf *, void *, int *);
|
||||||
|
void *rarg;
|
||||||
|
size_t roff;
|
||||||
|
size_t hdrsize;
|
||||||
|
};
|
||||||
|
|
||||||
static void msgbuf_drain(struct msgbuf *, size_t);
|
static void msgbuf_drain(struct msgbuf *, size_t);
|
||||||
|
static void ibufq_init(struct ibufqueue *);
|
||||||
|
|
||||||
|
#define IBUF_FD_MARK_ON_STACK -2
|
||||||
|
|
||||||
struct ibuf *
|
struct ibuf *
|
||||||
ibuf_open(size_t len)
|
ibuf_open(size_t len)
|
||||||
{
|
{
|
||||||
struct ibuf *buf;
|
struct ibuf *buf;
|
||||||
|
|
||||||
if (len == 0) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
|
if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
if ((buf->buf = calloc(len, 1)) == NULL) {
|
if (len > 0) {
|
||||||
free(buf);
|
if ((buf->buf = calloc(len, 1)) == NULL) {
|
||||||
return (NULL);
|
free(buf);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
buf->size = buf->max = len;
|
buf->size = buf->max = len;
|
||||||
buf->fd = -1;
|
buf->fd = -1;
|
||||||
@@ -96,39 +110,36 @@ ibuf_dynamic(size_t len, size_t max)
|
|||||||
return (buf);
|
return (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
ibuf_realloc(struct ibuf *buf, size_t len)
|
|
||||||
{
|
|
||||||
unsigned char *b;
|
|
||||||
|
|
||||||
/* on static buffers max is eq size and so the following fails */
|
|
||||||
if (len > SIZE_MAX - buf->wpos || buf->wpos + len > buf->max) {
|
|
||||||
errno = ERANGE;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
b = recallocarray(buf->buf, buf->size, buf->wpos + len, 1);
|
|
||||||
if (b == NULL)
|
|
||||||
return (-1);
|
|
||||||
buf->buf = b;
|
|
||||||
buf->size = buf->wpos + len;
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
ibuf_reserve(struct ibuf *buf, size_t len)
|
ibuf_reserve(struct ibuf *buf, size_t len)
|
||||||
{
|
{
|
||||||
void *b;
|
void *b;
|
||||||
|
|
||||||
if (len > SIZE_MAX - buf->wpos || buf->max == 0) {
|
if (len > SIZE_MAX - buf->wpos) {
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
if (buf->fd == IBUF_FD_MARK_ON_STACK) {
|
||||||
|
/* can not grow stack buffers */
|
||||||
|
errno = EINVAL;
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (buf->wpos + len > buf->size)
|
if (buf->wpos + len > buf->size) {
|
||||||
if (ibuf_realloc(buf, len) == -1)
|
unsigned char *nb;
|
||||||
|
|
||||||
|
/* check if buffer is allowed to grow */
|
||||||
|
if (buf->wpos + len > buf->max) {
|
||||||
|
errno = ERANGE;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
|
nb = realloc(buf->buf, buf->wpos + len);
|
||||||
|
if (nb == NULL)
|
||||||
|
return (NULL);
|
||||||
|
memset(nb + buf->size, 0, buf->wpos + len - buf->size);
|
||||||
|
buf->buf = nb;
|
||||||
|
buf->size = buf->wpos + len;
|
||||||
|
}
|
||||||
|
|
||||||
b = buf->buf + buf->wpos;
|
b = buf->buf + buf->wpos;
|
||||||
buf->wpos += len;
|
buf->wpos += len;
|
||||||
@@ -140,6 +151,9 @@ ibuf_add(struct ibuf *buf, const void *data, size_t len)
|
|||||||
{
|
{
|
||||||
void *b;
|
void *b;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return (0);
|
||||||
|
|
||||||
if ((b = ibuf_reserve(buf, len)) == NULL)
|
if ((b = ibuf_reserve(buf, len)) == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
@@ -153,13 +167,6 @@ ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
|
|||||||
return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
|
return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove after tree is converted */
|
|
||||||
int
|
|
||||||
ibuf_add_buf(struct ibuf *buf, const struct ibuf *from)
|
|
||||||
{
|
|
||||||
return ibuf_add_ibuf(buf, from);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
ibuf_add_n8(struct ibuf *buf, uint64_t value)
|
ibuf_add_n8(struct ibuf *buf, uint64_t value)
|
||||||
{
|
{
|
||||||
@@ -243,12 +250,34 @@ ibuf_add_zero(struct ibuf *buf, size_t len)
|
|||||||
{
|
{
|
||||||
void *b;
|
void *b;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return (0);
|
||||||
|
|
||||||
if ((b = ibuf_reserve(buf, len)) == NULL)
|
if ((b = ibuf_reserve(buf, len)) == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
memset(b, 0, len);
|
memset(b, 0, len);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ibuf_add_strbuf(struct ibuf *buf, const char *str, size_t len)
|
||||||
|
{
|
||||||
|
char *b;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
if ((b = ibuf_reserve(buf, len)) == NULL)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
n = strlcpy(b, str, len);
|
||||||
|
if (n >= len) {
|
||||||
|
/* also covers the case where len == 0 */
|
||||||
|
errno = EOVERFLOW;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
memset(b + n, 0, len - n);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
|
ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
|
||||||
{
|
{
|
||||||
@@ -270,6 +299,8 @@ ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
|
|||||||
if ((b = ibuf_seek(buf, pos, len)) == NULL)
|
if ((b = ibuf_seek(buf, pos, len)) == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return (0);
|
||||||
memcpy(b, data, len);
|
memcpy(b, data, len);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@@ -352,6 +383,22 @@ ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value)
|
|||||||
return (ibuf_set(buf, pos, &value, sizeof(value)));
|
return (ibuf_set(buf, pos, &value, sizeof(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ibuf_set_maxsize(struct ibuf *buf, size_t max)
|
||||||
|
{
|
||||||
|
if (buf->fd == IBUF_FD_MARK_ON_STACK) {
|
||||||
|
/* can't fiddle with stack buffers */
|
||||||
|
errno = EINVAL;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (max > buf->max) {
|
||||||
|
errno = ERANGE;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
buf->max = max;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
ibuf_data(const struct ibuf *buf)
|
ibuf_data(const struct ibuf *buf)
|
||||||
{
|
{
|
||||||
@@ -367,7 +414,8 @@ ibuf_size(const struct ibuf *buf)
|
|||||||
size_t
|
size_t
|
||||||
ibuf_left(const struct ibuf *buf)
|
ibuf_left(const struct ibuf *buf)
|
||||||
{
|
{
|
||||||
if (buf->max == 0)
|
/* on stack buffers have no space left */
|
||||||
|
if (buf->fd == IBUF_FD_MARK_ON_STACK)
|
||||||
return (0);
|
return (0);
|
||||||
return (buf->max - buf->wpos);
|
return (buf->max - buf->wpos);
|
||||||
}
|
}
|
||||||
@@ -379,8 +427,8 @@ ibuf_truncate(struct ibuf *buf, size_t len)
|
|||||||
buf->wpos = buf->rpos + len;
|
buf->wpos = buf->rpos + len;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
if (buf->max == 0) {
|
if (buf->fd == IBUF_FD_MARK_ON_STACK) {
|
||||||
/* only allow to truncate down */
|
/* only allow to truncate down for stack buffers */
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@@ -396,7 +444,7 @@ ibuf_rewind(struct ibuf *buf)
|
|||||||
void
|
void
|
||||||
ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
|
ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
|
||||||
{
|
{
|
||||||
ibuf_enqueue(msgbuf, buf);
|
ibufq_push(&msgbuf->bufs, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -405,7 +453,7 @@ ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
|
|||||||
memset(buf, 0, sizeof(*buf));
|
memset(buf, 0, sizeof(*buf));
|
||||||
buf->buf = data;
|
buf->buf = data;
|
||||||
buf->size = buf->wpos = len;
|
buf->size = buf->wpos = len;
|
||||||
buf->fd = -1;
|
buf->fd = IBUF_FD_MARK_ON_STACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -440,6 +488,24 @@ ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ibuf_get_h16(struct ibuf *buf, uint16_t *value)
|
||||||
|
{
|
||||||
|
return ibuf_get(buf, value, sizeof(*value));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ibuf_get_h32(struct ibuf *buf, uint32_t *value)
|
||||||
|
{
|
||||||
|
return ibuf_get(buf, value, sizeof(*value));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ibuf_get_h64(struct ibuf *buf, uint64_t *value)
|
||||||
|
{
|
||||||
|
return ibuf_get(buf, value, sizeof(*value));
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ibuf_get_n8(struct ibuf *buf, uint8_t *value)
|
ibuf_get_n8(struct ibuf *buf, uint8_t *value)
|
||||||
{
|
{
|
||||||
@@ -476,22 +542,39 @@ ibuf_get_n64(struct ibuf *buf, uint64_t *value)
|
|||||||
return (rv);
|
return (rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
char *
|
||||||
ibuf_get_h16(struct ibuf *buf, uint16_t *value)
|
ibuf_get_string(struct ibuf *buf, size_t len)
|
||||||
{
|
{
|
||||||
return ibuf_get(buf, value, sizeof(*value));
|
char *str;
|
||||||
|
|
||||||
|
if (ibuf_size(buf) < len) {
|
||||||
|
errno = EBADMSG;
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
str = strndup(ibuf_data(buf), len);
|
||||||
|
if (str == NULL)
|
||||||
|
return (NULL);
|
||||||
|
buf->rpos += len;
|
||||||
|
return (str);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ibuf_get_h32(struct ibuf *buf, uint32_t *value)
|
ibuf_get_strbuf(struct ibuf *buf, char *str, size_t len)
|
||||||
{
|
{
|
||||||
return ibuf_get(buf, value, sizeof(*value));
|
if (len == 0) {
|
||||||
}
|
errno = EINVAL;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
if (ibuf_get(buf, str, len) == -1)
|
||||||
ibuf_get_h64(struct ibuf *buf, uint64_t *value)
|
return -1;
|
||||||
{
|
if (str[len - 1] != '\0') {
|
||||||
return ibuf_get(buf, value, sizeof(*value));
|
str[len - 1] = '\0';
|
||||||
|
errno = EOVERFLOW;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -509,20 +592,24 @@ ibuf_skip(struct ibuf *buf, size_t len)
|
|||||||
void
|
void
|
||||||
ibuf_free(struct ibuf *buf)
|
ibuf_free(struct ibuf *buf)
|
||||||
{
|
{
|
||||||
|
int save_errno = errno;
|
||||||
|
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return;
|
return;
|
||||||
if (buf->max == 0) /* if buf lives on the stack */
|
/* if buf lives on the stack abort before causing more harm */
|
||||||
abort(); /* abort before causing more harm */
|
if (buf->fd == IBUF_FD_MARK_ON_STACK)
|
||||||
if (buf->fd != -1)
|
abort();
|
||||||
|
if (buf->fd >= 0)
|
||||||
close(buf->fd);
|
close(buf->fd);
|
||||||
freezero(buf->buf, buf->size);
|
freezero(buf->buf, buf->size);
|
||||||
free(buf);
|
free(buf);
|
||||||
|
errno = save_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ibuf_fd_avail(struct ibuf *buf)
|
ibuf_fd_avail(struct ibuf *buf)
|
||||||
{
|
{
|
||||||
return (buf->fd != -1);
|
return (buf->fd >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -530,6 +617,9 @@ ibuf_fd_get(struct ibuf *buf)
|
|||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
/* negative fds are internal use and equivalent to -1 */
|
||||||
|
if (buf->fd < 0)
|
||||||
|
return (-1);
|
||||||
fd = buf->fd;
|
fd = buf->fd;
|
||||||
buf->fd = -1;
|
buf->fd = -1;
|
||||||
return (fd);
|
return (fd);
|
||||||
@@ -538,15 +628,101 @@ ibuf_fd_get(struct ibuf *buf)
|
|||||||
void
|
void
|
||||||
ibuf_fd_set(struct ibuf *buf, int fd)
|
ibuf_fd_set(struct ibuf *buf, int fd)
|
||||||
{
|
{
|
||||||
if (buf->max == 0) /* if buf lives on the stack */
|
/* if buf lives on the stack abort before causing more harm */
|
||||||
abort(); /* abort before causing more harm */
|
if (buf->fd == IBUF_FD_MARK_ON_STACK)
|
||||||
if (buf->fd != -1)
|
abort();
|
||||||
|
if (buf->fd >= 0)
|
||||||
close(buf->fd);
|
close(buf->fd);
|
||||||
buf->fd = fd;
|
buf->fd = -1;
|
||||||
|
if (fd >= 0)
|
||||||
|
buf->fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct msgbuf *
|
||||||
|
msgbuf_new(void)
|
||||||
|
{
|
||||||
|
struct msgbuf *msgbuf;
|
||||||
|
|
||||||
|
if ((msgbuf = calloc(1, sizeof(*msgbuf))) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
ibufq_init(&msgbuf->bufs);
|
||||||
|
ibufq_init(&msgbuf->rbufs);
|
||||||
|
|
||||||
|
return msgbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct msgbuf *
|
||||||
|
msgbuf_new_reader(size_t hdrsz,
|
||||||
|
struct ibuf *(*readhdr)(struct ibuf *, void *, int *), void *arg)
|
||||||
|
{
|
||||||
|
struct msgbuf *msgbuf;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
if (hdrsz == 0 || hdrsz > IBUF_READ_SIZE / 2) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buf = malloc(IBUF_READ_SIZE)) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
msgbuf = msgbuf_new();
|
||||||
|
if (msgbuf == NULL) {
|
||||||
|
free(buf);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
msgbuf->rbuf = buf;
|
||||||
|
msgbuf->hdrsize = hdrsz;
|
||||||
|
msgbuf->readhdr = readhdr;
|
||||||
|
msgbuf->rarg = arg;
|
||||||
|
|
||||||
|
return (msgbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
msgbuf_free(struct msgbuf *msgbuf)
|
||||||
|
{
|
||||||
|
if (msgbuf == NULL)
|
||||||
|
return;
|
||||||
|
msgbuf_clear(msgbuf);
|
||||||
|
free(msgbuf->rbuf);
|
||||||
|
free(msgbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
msgbuf_queuelen(struct msgbuf *msgbuf)
|
||||||
|
{
|
||||||
|
return ibufq_queuelen(&msgbuf->bufs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
msgbuf_clear(struct msgbuf *msgbuf)
|
||||||
|
{
|
||||||
|
/* write side */
|
||||||
|
ibufq_flush(&msgbuf->bufs);
|
||||||
|
|
||||||
|
/* read side */
|
||||||
|
ibufq_flush(&msgbuf->rbufs);
|
||||||
|
msgbuf->roff = 0;
|
||||||
|
ibuf_free(msgbuf->rpmsg);
|
||||||
|
msgbuf->rpmsg = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ibuf *
|
||||||
|
msgbuf_get(struct msgbuf *msgbuf)
|
||||||
|
{
|
||||||
|
return ibufq_pop(&msgbuf->rbufs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
msgbuf_concat(struct msgbuf *msgbuf, struct ibufqueue *from)
|
||||||
|
{
|
||||||
|
ibufq_concat(&msgbuf->bufs, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ibuf_write(struct msgbuf *msgbuf)
|
ibuf_write(int fd, struct msgbuf *msgbuf)
|
||||||
{
|
{
|
||||||
struct iovec iov[IOV_MAX];
|
struct iovec iov[IOV_MAX];
|
||||||
struct ibuf *buf;
|
struct ibuf *buf;
|
||||||
@@ -554,70 +730,32 @@ ibuf_write(struct msgbuf *msgbuf)
|
|||||||
ssize_t n;
|
ssize_t n;
|
||||||
|
|
||||||
memset(&iov, 0, sizeof(iov));
|
memset(&iov, 0, sizeof(iov));
|
||||||
TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
|
TAILQ_FOREACH(buf, &msgbuf->bufs.bufs, entry) {
|
||||||
if (i >= IOV_MAX)
|
if (i >= IOV_MAX)
|
||||||
break;
|
break;
|
||||||
iov[i].iov_base = ibuf_data(buf);
|
iov[i].iov_base = ibuf_data(buf);
|
||||||
iov[i].iov_len = ibuf_size(buf);
|
iov[i].iov_len = ibuf_size(buf);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
if (i == 0)
|
||||||
|
return (0); /* nothing queued */
|
||||||
|
|
||||||
again:
|
again:
|
||||||
if ((n = writev(msgbuf->fd, iov, i)) == -1) {
|
if ((n = writev(fd, iov, i)) == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
goto again;
|
goto again;
|
||||||
if (errno == ENOBUFS)
|
if (errno == EAGAIN || errno == ENOBUFS)
|
||||||
errno = EAGAIN;
|
/* lets retry later again */
|
||||||
|
return (0);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n == 0) { /* connection closed */
|
|
||||||
errno = 0;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
msgbuf_drain(msgbuf, n);
|
msgbuf_drain(msgbuf, n);
|
||||||
|
return (0);
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
msgbuf_init(struct msgbuf *msgbuf)
|
|
||||||
{
|
|
||||||
msgbuf->queued = 0;
|
|
||||||
msgbuf->fd = -1;
|
|
||||||
TAILQ_INIT(&msgbuf->bufs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
msgbuf_drain(struct msgbuf *msgbuf, size_t n)
|
|
||||||
{
|
|
||||||
struct ibuf *buf, *next;
|
|
||||||
|
|
||||||
for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
|
|
||||||
buf = next) {
|
|
||||||
next = TAILQ_NEXT(buf, entry);
|
|
||||||
if (n >= ibuf_size(buf)) {
|
|
||||||
n -= ibuf_size(buf);
|
|
||||||
ibuf_dequeue(msgbuf, buf);
|
|
||||||
} else {
|
|
||||||
buf->rpos += n;
|
|
||||||
n = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
msgbuf_clear(struct msgbuf *msgbuf)
|
|
||||||
{
|
|
||||||
struct ibuf *buf;
|
|
||||||
|
|
||||||
while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
|
|
||||||
ibuf_dequeue(msgbuf, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
msgbuf_write(struct msgbuf *msgbuf)
|
msgbuf_write(int fd, struct msgbuf *msgbuf)
|
||||||
{
|
{
|
||||||
struct iovec iov[IOV_MAX];
|
struct iovec iov[IOV_MAX];
|
||||||
struct ibuf *buf, *buf0 = NULL;
|
struct ibuf *buf, *buf0 = NULL;
|
||||||
@@ -633,7 +771,7 @@ msgbuf_write(struct msgbuf *msgbuf)
|
|||||||
memset(&iov, 0, sizeof(iov));
|
memset(&iov, 0, sizeof(iov));
|
||||||
memset(&msg, 0, sizeof(msg));
|
memset(&msg, 0, sizeof(msg));
|
||||||
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
|
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
|
||||||
TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
|
TAILQ_FOREACH(buf, &msgbuf->bufs.bufs, entry) {
|
||||||
if (i >= IOV_MAX)
|
if (i >= IOV_MAX)
|
||||||
break;
|
break;
|
||||||
if (i > 0 && buf->fd != -1)
|
if (i > 0 && buf->fd != -1)
|
||||||
@@ -645,6 +783,9 @@ msgbuf_write(struct msgbuf *msgbuf)
|
|||||||
buf0 = buf;
|
buf0 = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
return (0); /* nothing queued */
|
||||||
|
|
||||||
msg.msg_iov = iov;
|
msg.msg_iov = iov;
|
||||||
msg.msg_iovlen = i;
|
msg.msg_iovlen = i;
|
||||||
|
|
||||||
@@ -658,20 +799,16 @@ msgbuf_write(struct msgbuf *msgbuf)
|
|||||||
*(int *)CMSG_DATA(cmsg) = buf0->fd;
|
*(int *)CMSG_DATA(cmsg) = buf0->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
again:
|
again:
|
||||||
if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
|
if ((n = sendmsg(fd, &msg, 0)) == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
goto again;
|
goto again;
|
||||||
if (errno == ENOBUFS)
|
if (errno == EAGAIN || errno == ENOBUFS)
|
||||||
errno = EAGAIN;
|
/* lets retry later again */
|
||||||
|
return (0);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n == 0) { /* connection closed */
|
|
||||||
errno = 0;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assumption: fd got sent if sendmsg sent anything
|
* assumption: fd got sent if sendmsg sent anything
|
||||||
* this works because fds are passed one at a time
|
* this works because fds are passed one at a time
|
||||||
@@ -683,28 +820,257 @@ again:
|
|||||||
|
|
||||||
msgbuf_drain(msgbuf, n);
|
msgbuf_drain(msgbuf, n);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ibuf_read_process(struct msgbuf *msgbuf, int fd)
|
||||||
|
{
|
||||||
|
struct ibuf rbuf, msg;
|
||||||
|
ssize_t sz;
|
||||||
|
|
||||||
|
ibuf_from_buffer(&rbuf, msgbuf->rbuf, msgbuf->roff);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (msgbuf->rpmsg == NULL) {
|
||||||
|
if (ibuf_size(&rbuf) < msgbuf->hdrsize)
|
||||||
|
break;
|
||||||
|
/* get size from header */
|
||||||
|
ibuf_from_buffer(&msg, ibuf_data(&rbuf),
|
||||||
|
msgbuf->hdrsize);
|
||||||
|
if ((msgbuf->rpmsg = msgbuf->readhdr(&msg,
|
||||||
|
msgbuf->rarg, &fd)) == NULL)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ibuf_left(msgbuf->rpmsg) <= ibuf_size(&rbuf))
|
||||||
|
sz = ibuf_left(msgbuf->rpmsg);
|
||||||
|
else
|
||||||
|
sz = ibuf_size(&rbuf);
|
||||||
|
|
||||||
|
/* neither call below can fail */
|
||||||
|
if (ibuf_get_ibuf(&rbuf, sz, &msg) == -1 ||
|
||||||
|
ibuf_add_ibuf(msgbuf->rpmsg, &msg) == -1)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (ibuf_left(msgbuf->rpmsg) == 0) {
|
||||||
|
ibufq_push(&msgbuf->rbufs, msgbuf->rpmsg);
|
||||||
|
msgbuf->rpmsg = NULL;
|
||||||
|
}
|
||||||
|
} while (ibuf_size(&rbuf) > 0);
|
||||||
|
|
||||||
|
if (ibuf_size(&rbuf) > 0)
|
||||||
|
memmove(msgbuf->rbuf, ibuf_data(&rbuf), ibuf_size(&rbuf));
|
||||||
|
msgbuf->roff = ibuf_size(&rbuf);
|
||||||
|
|
||||||
|
if (fd != -1)
|
||||||
|
close(fd);
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
/* XXX how to properly clean up is unclear */
|
||||||
|
if (fd != -1)
|
||||||
|
close(fd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ibuf_read(int fd, struct msgbuf *msgbuf)
|
||||||
|
{
|
||||||
|
struct iovec iov;
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
if (msgbuf->rbuf == NULL) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
iov.iov_base = msgbuf->rbuf + msgbuf->roff;
|
||||||
|
iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
|
||||||
|
|
||||||
|
again:
|
||||||
|
if ((n = readv(fd, &iov, 1)) == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
goto again;
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
/* lets retry later again */
|
||||||
|
return (1);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (n == 0) /* connection closed */
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
msgbuf->roff += n;
|
||||||
|
/* new data arrived, try to process it */
|
||||||
|
return (ibuf_read_process(msgbuf, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
msgbuf_read(int fd, struct msgbuf *msgbuf)
|
||||||
|
{
|
||||||
|
struct msghdr msg;
|
||||||
|
struct cmsghdr *cmsg;
|
||||||
|
union {
|
||||||
|
struct cmsghdr hdr;
|
||||||
|
char buf[CMSG_SPACE(sizeof(int) * 1)];
|
||||||
|
} cmsgbuf;
|
||||||
|
struct iovec iov;
|
||||||
|
ssize_t n;
|
||||||
|
int fdpass = -1;
|
||||||
|
|
||||||
|
if (msgbuf->rbuf == NULL) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
|
||||||
|
|
||||||
|
iov.iov_base = msgbuf->rbuf + msgbuf->roff;
|
||||||
|
iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
|
||||||
|
msg.msg_iov = &iov;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
msg.msg_control = &cmsgbuf.buf;
|
||||||
|
msg.msg_controllen = sizeof(cmsgbuf.buf);
|
||||||
|
|
||||||
|
again:
|
||||||
|
if ((n = recvmsg(fd, &msg, 0)) == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
goto again;
|
||||||
|
if (errno == EMSGSIZE)
|
||||||
|
/*
|
||||||
|
* Not enough fd slots: fd passing failed, retry
|
||||||
|
* to receive the message without fd.
|
||||||
|
* imsg_get_fd() will return -1 in that case.
|
||||||
|
*/
|
||||||
|
goto again;
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
/* lets retry later again */
|
||||||
|
return (1);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (n == 0) /* connection closed */
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
msgbuf->roff += n;
|
||||||
|
|
||||||
|
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||||
|
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||||
|
if (cmsg->cmsg_level == SOL_SOCKET &&
|
||||||
|
cmsg->cmsg_type == SCM_RIGHTS) {
|
||||||
|
int i, j, f;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only accept one file descriptor. Due to C
|
||||||
|
* padding rules, our control buffer might contain
|
||||||
|
* more than one fd, and we must close them.
|
||||||
|
*/
|
||||||
|
j = ((char *)cmsg + cmsg->cmsg_len -
|
||||||
|
(char *)CMSG_DATA(cmsg)) / sizeof(int);
|
||||||
|
for (i = 0; i < j; i++) {
|
||||||
|
f = ((int *)CMSG_DATA(cmsg))[i];
|
||||||
|
if (i == 0)
|
||||||
|
fdpass = f;
|
||||||
|
else
|
||||||
|
close(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* we do not handle other ctl data level */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* new data arrived, try to process it */
|
||||||
|
return (ibuf_read_process(msgbuf, fdpass));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
msgbuf_drain(struct msgbuf *msgbuf, size_t n)
|
||||||
|
{
|
||||||
|
struct ibuf *buf;
|
||||||
|
|
||||||
|
while ((buf = TAILQ_FIRST(&msgbuf->bufs.bufs)) != NULL) {
|
||||||
|
if (n >= ibuf_size(buf)) {
|
||||||
|
n -= ibuf_size(buf);
|
||||||
|
TAILQ_REMOVE(&msgbuf->bufs.bufs, buf, entry);
|
||||||
|
msgbuf->bufs.queued--;
|
||||||
|
ibuf_free(buf);
|
||||||
|
} else {
|
||||||
|
buf->rpos += n;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ibufq_init(struct ibufqueue *bufq)
|
||||||
|
{
|
||||||
|
TAILQ_INIT(&bufq->bufs);
|
||||||
|
bufq->queued = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ibufqueue *
|
||||||
|
ibufq_new(void)
|
||||||
|
{
|
||||||
|
struct ibufqueue *bufq;
|
||||||
|
|
||||||
|
if ((bufq = calloc(1, sizeof(*bufq))) == NULL)
|
||||||
|
return NULL;
|
||||||
|
ibufq_init(bufq);
|
||||||
|
return bufq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ibufq_free(struct ibufqueue *bufq)
|
||||||
|
{
|
||||||
|
if (bufq == NULL)
|
||||||
|
return;
|
||||||
|
ibufq_flush(bufq);
|
||||||
|
free(bufq);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ibuf *
|
||||||
|
ibufq_pop(struct ibufqueue *bufq)
|
||||||
|
{
|
||||||
|
struct ibuf *buf;
|
||||||
|
|
||||||
|
if ((buf = TAILQ_FIRST(&bufq->bufs)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
TAILQ_REMOVE(&bufq->bufs, buf, entry);
|
||||||
|
bufq->queued--;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ibufq_push(struct ibufqueue *bufq, struct ibuf *buf)
|
||||||
|
{
|
||||||
|
/* if buf lives on the stack abort before causing more harm */
|
||||||
|
if (buf->fd == IBUF_FD_MARK_ON_STACK)
|
||||||
|
abort();
|
||||||
|
TAILQ_INSERT_TAIL(&bufq->bufs, buf, entry);
|
||||||
|
bufq->queued++;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
msgbuf_queuelen(struct msgbuf *msgbuf)
|
ibufq_queuelen(struct ibufqueue *bufq)
|
||||||
{
|
{
|
||||||
return (msgbuf->queued);
|
return (bufq->queued);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
|
ibufq_concat(struct ibufqueue *to, struct ibufqueue *from)
|
||||||
{
|
{
|
||||||
if (buf->max == 0) /* if buf lives on the stack */
|
to->queued += from->queued;
|
||||||
abort(); /* abort before causing more harm */
|
TAILQ_CONCAT(&to->bufs, &from->bufs, entry);
|
||||||
TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
|
from->queued = 0;
|
||||||
msgbuf->queued++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
|
ibufq_flush(struct ibufqueue *bufq)
|
||||||
{
|
{
|
||||||
TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
|
struct ibuf *buf;
|
||||||
msgbuf->queued--;
|
|
||||||
ibuf_free(buf);
|
while ((buf = TAILQ_FIRST(&bufq->bufs)) != NULL) {
|
||||||
|
TAILQ_REMOVE(&bufq->bufs, buf, entry);
|
||||||
|
ibuf_free(buf);
|
||||||
|
}
|
||||||
|
bufq->queued = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
394
compat/imsg.c
394
compat/imsg.c
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: imsg.c,v 1.23 2023/12/12 15:47:41 claudio Exp $ */
|
/* $OpenBSD: imsg.c,v 1.42 2025/06/16 13:56:11 claudio Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -29,158 +30,156 @@
|
|||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "imsg.h"
|
#include "imsg.h"
|
||||||
|
|
||||||
struct imsg_fd {
|
#define IMSG_ALLOW_FDPASS 0x01
|
||||||
TAILQ_ENTRY(imsg_fd) entry;
|
#define IMSG_FD_MARK 0x80000000U
|
||||||
int fd;
|
|
||||||
};
|
|
||||||
|
|
||||||
int imsg_fd_overhead = 0;
|
static struct ibuf *imsg_parse_hdr(struct ibuf *, void *, int *);
|
||||||
|
|
||||||
static int imsg_dequeue_fd(struct imsgbuf *);
|
int
|
||||||
|
imsgbuf_init(struct imsgbuf *imsgbuf, int fd)
|
||||||
void
|
|
||||||
imsg_init(struct imsgbuf *imsgbuf, int fd)
|
|
||||||
{
|
{
|
||||||
msgbuf_init(&imsgbuf->w);
|
imsgbuf->w = msgbuf_new_reader(IMSG_HEADER_SIZE, imsg_parse_hdr,
|
||||||
memset(&imsgbuf->r, 0, sizeof(imsgbuf->r));
|
imsgbuf);
|
||||||
imsgbuf->fd = fd;
|
if (imsgbuf->w == NULL)
|
||||||
imsgbuf->w.fd = fd;
|
return (-1);
|
||||||
imsgbuf->pid = getpid();
|
imsgbuf->pid = getpid();
|
||||||
TAILQ_INIT(&imsgbuf->fds);
|
imsgbuf->maxsize = MAX_IMSGSIZE;
|
||||||
|
imsgbuf->fd = fd;
|
||||||
|
imsgbuf->flags = 0;
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
void
|
||||||
imsg_read(struct imsgbuf *imsgbuf)
|
imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf)
|
||||||
{
|
{
|
||||||
struct msghdr msg;
|
imsgbuf->flags |= IMSG_ALLOW_FDPASS;
|
||||||
struct cmsghdr *cmsg;
|
}
|
||||||
union {
|
|
||||||
struct cmsghdr hdr;
|
|
||||||
char buf[CMSG_SPACE(sizeof(int) * 1)];
|
|
||||||
} cmsgbuf;
|
|
||||||
struct iovec iov;
|
|
||||||
ssize_t n = -1;
|
|
||||||
int fd;
|
|
||||||
struct imsg_fd *ifd;
|
|
||||||
|
|
||||||
memset(&msg, 0, sizeof(msg));
|
int
|
||||||
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
|
imsgbuf_set_maxsize(struct imsgbuf *imsgbuf, uint32_t max)
|
||||||
|
{
|
||||||
iov.iov_base = imsgbuf->r.buf + imsgbuf->r.wpos;
|
if (max > UINT32_MAX - IMSG_HEADER_SIZE) {
|
||||||
iov.iov_len = sizeof(imsgbuf->r.buf) - imsgbuf->r.wpos;
|
errno = ERANGE;
|
||||||
msg.msg_iov = &iov;
|
|
||||||
msg.msg_iovlen = 1;
|
|
||||||
msg.msg_control = &cmsgbuf.buf;
|
|
||||||
msg.msg_controllen = sizeof(cmsgbuf.buf);
|
|
||||||
|
|
||||||
if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
again:
|
|
||||||
if (getdtablecount() + imsg_fd_overhead +
|
|
||||||
(int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
|
|
||||||
>= getdtablesize()) {
|
|
||||||
errno = EAGAIN;
|
|
||||||
free(ifd);
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
max += IMSG_HEADER_SIZE;
|
||||||
if ((n = recvmsg(imsgbuf->fd, &msg, 0)) == -1) {
|
if (max & IMSG_FD_MARK) {
|
||||||
if (errno == EINTR)
|
errno = EINVAL;
|
||||||
goto again;
|
return (-1);
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
imsgbuf->maxsize = max;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
imsgbuf->r.wpos += n;
|
int
|
||||||
|
imsgbuf_read(struct imsgbuf *imsgbuf)
|
||||||
|
{
|
||||||
|
if (imsgbuf->flags & IMSG_ALLOW_FDPASS)
|
||||||
|
return msgbuf_read(imsgbuf->fd, imsgbuf->w);
|
||||||
|
else
|
||||||
|
return ibuf_read(imsgbuf->fd, imsgbuf->w);
|
||||||
|
}
|
||||||
|
|
||||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
int
|
||||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
imsgbuf_write(struct imsgbuf *imsgbuf)
|
||||||
if (cmsg->cmsg_level == SOL_SOCKET &&
|
{
|
||||||
cmsg->cmsg_type == SCM_RIGHTS) {
|
if (imsgbuf->flags & IMSG_ALLOW_FDPASS)
|
||||||
int i;
|
return msgbuf_write(imsgbuf->fd, imsgbuf->w);
|
||||||
int j;
|
else
|
||||||
|
return ibuf_write(imsgbuf->fd, imsgbuf->w);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
int
|
||||||
* We only accept one file descriptor. Due to C
|
imsgbuf_flush(struct imsgbuf *imsgbuf)
|
||||||
* padding rules, our control buffer might contain
|
{
|
||||||
* more than one fd, and we must close them.
|
while (imsgbuf_queuelen(imsgbuf) > 0) {
|
||||||
*/
|
if (imsgbuf_write(imsgbuf) == -1)
|
||||||
j = ((char *)cmsg + cmsg->cmsg_len -
|
return (-1);
|
||||||
(char *)CMSG_DATA(cmsg)) / sizeof(int);
|
|
||||||
for (i = 0; i < j; i++) {
|
|
||||||
fd = ((int *)CMSG_DATA(cmsg))[i];
|
|
||||||
if (ifd != NULL) {
|
|
||||||
ifd->fd = fd;
|
|
||||||
TAILQ_INSERT_TAIL(&imsgbuf->fds, ifd,
|
|
||||||
entry);
|
|
||||||
ifd = NULL;
|
|
||||||
} else
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* we do not handle other ctl data level */
|
|
||||||
}
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
fail:
|
void
|
||||||
free(ifd);
|
imsgbuf_clear(struct imsgbuf *imsgbuf)
|
||||||
return (n);
|
{
|
||||||
|
msgbuf_free(imsgbuf->w);
|
||||||
|
imsgbuf->w = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
imsgbuf_queuelen(struct imsgbuf *imsgbuf)
|
||||||
|
{
|
||||||
|
return msgbuf_queuelen(imsgbuf->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
imsgbuf_get(struct imsgbuf *imsgbuf, struct imsg *imsg)
|
||||||
|
{
|
||||||
|
struct imsg m;
|
||||||
|
struct ibuf *buf;
|
||||||
|
|
||||||
|
if ((buf = msgbuf_get(imsgbuf->w)) == NULL)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
if (ibuf_get(buf, &m.hdr, sizeof(m.hdr)) == -1)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
if (ibuf_size(buf))
|
||||||
|
m.data = ibuf_data(buf);
|
||||||
|
else
|
||||||
|
m.data = NULL;
|
||||||
|
m.buf = buf;
|
||||||
|
m.hdr.len &= ~IMSG_FD_MARK;
|
||||||
|
|
||||||
|
*imsg = m;
|
||||||
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg)
|
imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg)
|
||||||
{
|
{
|
||||||
struct imsg m;
|
int rv;
|
||||||
size_t av, left, datalen;
|
|
||||||
|
|
||||||
av = imsgbuf->r.wpos;
|
if ((rv = imsgbuf_get(imsgbuf, imsg)) != 1)
|
||||||
|
return rv;
|
||||||
|
return (imsg_get_len(imsg) + IMSG_HEADER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
if (IMSG_HEADER_SIZE > av)
|
int
|
||||||
|
imsg_ibufq_pop(struct ibufqueue *bufq, struct imsg *imsg)
|
||||||
|
{
|
||||||
|
struct imsg m;
|
||||||
|
struct ibuf *buf;
|
||||||
|
|
||||||
|
if ((buf = ibufq_pop(bufq)) == NULL)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
memcpy(&m.hdr, imsgbuf->r.buf, sizeof(m.hdr));
|
if (ibuf_get(buf, &m.hdr, sizeof(m.hdr)) == -1)
|
||||||
if (m.hdr.len < IMSG_HEADER_SIZE ||
|
|
||||||
m.hdr.len > MAX_IMSGSIZE) {
|
|
||||||
errno = ERANGE;
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
|
||||||
if (m.hdr.len > av)
|
|
||||||
return (0);
|
|
||||||
|
|
||||||
m.fd = -1;
|
if (ibuf_size(buf))
|
||||||
m.buf = NULL;
|
m.data = ibuf_data(buf);
|
||||||
m.data = NULL;
|
else
|
||||||
|
m.data = NULL;
|
||||||
datalen = m.hdr.len - IMSG_HEADER_SIZE;
|
m.buf = buf;
|
||||||
imsgbuf->r.rptr = imsgbuf->r.buf + IMSG_HEADER_SIZE;
|
m.hdr.len &= ~IMSG_FD_MARK;
|
||||||
if (datalen != 0) {
|
|
||||||
if ((m.buf = ibuf_open(datalen)) == NULL)
|
|
||||||
return (-1);
|
|
||||||
if (ibuf_add(m.buf, imsgbuf->r.rptr, datalen) == -1) {
|
|
||||||
/* this should never fail */
|
|
||||||
ibuf_free(m.buf);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
m.data = ibuf_data(m.buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m.hdr.flags & IMSGF_HASFD)
|
|
||||||
m.fd = imsg_dequeue_fd(imsgbuf);
|
|
||||||
|
|
||||||
if (m.hdr.len < av) {
|
|
||||||
left = av - m.hdr.len;
|
|
||||||
memmove(&imsgbuf->r.buf, imsgbuf->r.buf + m.hdr.len, left);
|
|
||||||
imsgbuf->r.wpos = left;
|
|
||||||
} else
|
|
||||||
imsgbuf->r.wpos = 0;
|
|
||||||
|
|
||||||
*imsg = m;
|
*imsg = m;
|
||||||
return (datalen + IMSG_HEADER_SIZE);
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
imsg_ibufq_push(struct ibufqueue *bufq, struct imsg *imsg)
|
||||||
|
{
|
||||||
|
ibuf_rewind(imsg->buf);
|
||||||
|
ibufq_push(bufq, imsg->buf);
|
||||||
|
memset(imsg, 0, sizeof(*imsg));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf)
|
imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf)
|
||||||
{
|
{
|
||||||
if (imsg->buf == NULL) {
|
if (ibuf_size(imsg->buf) == 0) {
|
||||||
errno = EBADMSG;
|
errno = EBADMSG;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@@ -194,20 +193,29 @@ imsg_get_data(struct imsg *imsg, void *data, size_t len)
|
|||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
if (imsg->buf == NULL || ibuf_size(imsg->buf) != len) {
|
if (ibuf_size(imsg->buf) != len) {
|
||||||
errno = EBADMSG;
|
errno = EBADMSG;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
return ibuf_get(imsg->buf, data, len);
|
return ibuf_get(imsg->buf, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
imsg_get_buf(struct imsg *imsg, void *data, size_t len)
|
||||||
|
{
|
||||||
|
return ibuf_get(imsg->buf, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
imsg_get_strbuf(struct imsg *imsg, char *str, size_t len)
|
||||||
|
{
|
||||||
|
return ibuf_get_strbuf(imsg->buf, str, len);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
imsg_get_fd(struct imsg *imsg)
|
imsg_get_fd(struct imsg *imsg)
|
||||||
{
|
{
|
||||||
int fd = imsg->fd;
|
return ibuf_fd_get(imsg->buf);
|
||||||
|
|
||||||
imsg->fd = -1;
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
@@ -219,8 +227,6 @@ imsg_get_id(struct imsg *imsg)
|
|||||||
size_t
|
size_t
|
||||||
imsg_get_len(struct imsg *imsg)
|
imsg_get_len(struct imsg *imsg)
|
||||||
{
|
{
|
||||||
if (imsg->buf == NULL)
|
|
||||||
return 0;
|
|
||||||
return ibuf_size(imsg->buf);
|
return ibuf_size(imsg->buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,15 +249,19 @@ imsg_compose(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
|
|||||||
struct ibuf *wbuf;
|
struct ibuf *wbuf;
|
||||||
|
|
||||||
if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL)
|
if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL)
|
||||||
return (-1);
|
goto fail;
|
||||||
|
|
||||||
if (imsg_add(wbuf, data, datalen) == -1)
|
if (ibuf_add(wbuf, data, datalen) == -1)
|
||||||
return (-1);
|
goto fail;
|
||||||
|
|
||||||
ibuf_fd_set(wbuf, fd);
|
ibuf_fd_set(wbuf, fd);
|
||||||
imsg_close(imsgbuf, wbuf);
|
imsg_close(imsgbuf, wbuf);
|
||||||
|
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
ibuf_free(wbuf);
|
||||||
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -266,16 +276,20 @@ imsg_composev(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
|
|||||||
datalen += iov[i].iov_len;
|
datalen += iov[i].iov_len;
|
||||||
|
|
||||||
if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL)
|
if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL)
|
||||||
return (-1);
|
goto fail;
|
||||||
|
|
||||||
for (i = 0; i < iovcnt; i++)
|
for (i = 0; i < iovcnt; i++)
|
||||||
if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
|
if (ibuf_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
|
||||||
return (-1);
|
goto fail;
|
||||||
|
|
||||||
ibuf_fd_set(wbuf, fd);
|
ibuf_fd_set(wbuf, fd);
|
||||||
imsg_close(imsgbuf, wbuf);
|
imsg_close(imsgbuf, wbuf);
|
||||||
|
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
ibuf_free(wbuf);
|
||||||
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -288,34 +302,30 @@ imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id,
|
|||||||
{
|
{
|
||||||
struct ibuf *hdrbuf = NULL;
|
struct ibuf *hdrbuf = NULL;
|
||||||
struct imsg_hdr hdr;
|
struct imsg_hdr hdr;
|
||||||
int save_errno;
|
|
||||||
|
|
||||||
if (ibuf_size(buf) + IMSG_HEADER_SIZE > MAX_IMSGSIZE) {
|
if (ibuf_size(buf) + IMSG_HEADER_SIZE > imsgbuf->maxsize) {
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
hdr.type = type;
|
hdr.type = type;
|
||||||
hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE;
|
hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE;
|
||||||
hdr.flags = 0;
|
|
||||||
hdr.peerid = id;
|
hdr.peerid = id;
|
||||||
if ((hdr.pid = pid) == 0)
|
if ((hdr.pid = pid) == 0)
|
||||||
hdr.pid = imsgbuf->pid;
|
hdr.pid = imsgbuf->pid;
|
||||||
|
|
||||||
if ((hdrbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL)
|
if ((hdrbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (imsg_add(hdrbuf, &hdr, sizeof(hdr)) == -1)
|
if (ibuf_add(hdrbuf, &hdr, sizeof(hdr)) == -1)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
ibuf_close(&imsgbuf->w, hdrbuf);
|
ibuf_close(imsgbuf->w, hdrbuf);
|
||||||
ibuf_close(&imsgbuf->w, buf);
|
ibuf_close(imsgbuf->w, buf);
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
save_errno = errno;
|
|
||||||
ibuf_free(buf);
|
ibuf_free(buf);
|
||||||
ibuf_free(hdrbuf);
|
ibuf_free(hdrbuf);
|
||||||
errno = save_errno;
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,24 +336,18 @@ int
|
|||||||
imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg)
|
imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg)
|
||||||
{
|
{
|
||||||
struct ibuf *wbuf;
|
struct ibuf *wbuf;
|
||||||
size_t len = 0;
|
size_t len;
|
||||||
|
|
||||||
if (msg->fd != -1) {
|
ibuf_rewind(msg->buf);
|
||||||
close(msg->fd);
|
ibuf_skip(msg->buf, sizeof(msg->hdr));
|
||||||
msg->fd = -1;
|
len = ibuf_size(msg->buf);
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->buf != NULL) {
|
|
||||||
ibuf_rewind(msg->buf);
|
|
||||||
len = ibuf_size(msg->buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((wbuf = imsg_create(imsgbuf, msg->hdr.type, msg->hdr.peerid,
|
if ((wbuf = imsg_create(imsgbuf, msg->hdr.type, msg->hdr.peerid,
|
||||||
msg->hdr.pid, len)) == NULL)
|
msg->hdr.pid, len)) == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
if (msg->buf != NULL) {
|
if (len != 0) {
|
||||||
if (ibuf_add_buf(wbuf, msg->buf) == -1) {
|
if (ibuf_add_ibuf(wbuf, msg->buf) == -1) {
|
||||||
ibuf_free(wbuf);
|
ibuf_free(wbuf);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@@ -361,23 +365,26 @@ imsg_create(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
|
|||||||
struct imsg_hdr hdr;
|
struct imsg_hdr hdr;
|
||||||
|
|
||||||
datalen += IMSG_HEADER_SIZE;
|
datalen += IMSG_HEADER_SIZE;
|
||||||
if (datalen > MAX_IMSGSIZE) {
|
if (datalen > imsgbuf->maxsize) {
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hdr.len = 0;
|
||||||
hdr.type = type;
|
hdr.type = type;
|
||||||
hdr.flags = 0;
|
|
||||||
hdr.peerid = id;
|
hdr.peerid = id;
|
||||||
if ((hdr.pid = pid) == 0)
|
if ((hdr.pid = pid) == 0)
|
||||||
hdr.pid = imsgbuf->pid;
|
hdr.pid = imsgbuf->pid;
|
||||||
if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
|
if ((wbuf = ibuf_dynamic(datalen, imsgbuf->maxsize)) == NULL)
|
||||||
return (NULL);
|
goto fail;
|
||||||
}
|
if (ibuf_add(wbuf, &hdr, sizeof(hdr)) == -1)
|
||||||
if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
|
goto fail;
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
return (wbuf);
|
return (wbuf);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
ibuf_free(wbuf);
|
||||||
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -394,16 +401,13 @@ imsg_add(struct ibuf *msg, const void *data, size_t datalen)
|
|||||||
void
|
void
|
||||||
imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg)
|
imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg)
|
||||||
{
|
{
|
||||||
struct imsg_hdr *hdr;
|
uint32_t len;
|
||||||
|
|
||||||
hdr = (struct imsg_hdr *)msg->buf;
|
len = ibuf_size(msg);
|
||||||
|
|
||||||
hdr->flags &= ~IMSGF_HASFD;
|
|
||||||
if (ibuf_fd_avail(msg))
|
if (ibuf_fd_avail(msg))
|
||||||
hdr->flags |= IMSGF_HASFD;
|
len |= IMSG_FD_MARK;
|
||||||
hdr->len = ibuf_size(msg);
|
(void)ibuf_set_h32(msg, offsetof(struct imsg_hdr, len), len);
|
||||||
|
ibuf_close(imsgbuf->w, msg);
|
||||||
ibuf_close(&imsgbuf->w, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -412,37 +416,39 @@ imsg_free(struct imsg *imsg)
|
|||||||
ibuf_free(imsg->buf);
|
ibuf_free(imsg->buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
imsg_dequeue_fd(struct imsgbuf *imsgbuf)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
struct imsg_fd *ifd;
|
|
||||||
|
|
||||||
if ((ifd = TAILQ_FIRST(&imsgbuf->fds)) == NULL)
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
fd = ifd->fd;
|
|
||||||
TAILQ_REMOVE(&imsgbuf->fds, ifd, entry);
|
|
||||||
free(ifd);
|
|
||||||
|
|
||||||
return (fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
imsg_flush(struct imsgbuf *imsgbuf)
|
imsg_set_maxsize(struct ibuf *msg, size_t max)
|
||||||
{
|
{
|
||||||
while (imsgbuf->w.queued)
|
if (max > UINT32_MAX - IMSG_HEADER_SIZE) {
|
||||||
if (msgbuf_write(&imsgbuf->w) <= 0)
|
errno = ERANGE;
|
||||||
return (-1);
|
return (-1);
|
||||||
return (0);
|
}
|
||||||
|
return ibuf_set_maxsize(msg, max + IMSG_HEADER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static struct ibuf *
|
||||||
imsg_clear(struct imsgbuf *imsgbuf)
|
imsg_parse_hdr(struct ibuf *buf, void *arg, int *fd)
|
||||||
{
|
{
|
||||||
int fd;
|
struct imsgbuf *imsgbuf = arg;
|
||||||
|
struct imsg_hdr hdr;
|
||||||
|
struct ibuf *b;
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
msgbuf_clear(&imsgbuf->w);
|
if (ibuf_get(buf, &hdr, sizeof(hdr)) == -1)
|
||||||
while ((fd = imsg_dequeue_fd(imsgbuf)) != -1)
|
return (NULL);
|
||||||
close(fd);
|
|
||||||
|
len = hdr.len & ~IMSG_FD_MARK;
|
||||||
|
|
||||||
|
if (len < IMSG_HEADER_SIZE || len > imsgbuf->maxsize) {
|
||||||
|
errno = ERANGE;
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
if ((b = ibuf_open(len)) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
if (hdr.len & IMSG_FD_MARK) {
|
||||||
|
ibuf_fd_set(b, *fd);
|
||||||
|
*fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return b;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: imsg.h,v 1.8 2023/12/12 15:47:41 claudio Exp $ */
|
/* $OpenBSD: imsg.h,v 1.24 2025/06/05 08:55:07 tb Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#define _IMSG_H_
|
#define _IMSG_H_
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#define IBUF_READ_SIZE 65535
|
#define IBUF_READ_SIZE 65535
|
||||||
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
|
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
|
||||||
@@ -38,40 +39,26 @@ struct ibuf {
|
|||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct msgbuf {
|
struct ibufqueue;
|
||||||
TAILQ_HEAD(, ibuf) bufs;
|
struct msgbuf;
|
||||||
uint32_t queued;
|
|
||||||
int fd;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ibuf_read {
|
|
||||||
unsigned char buf[IBUF_READ_SIZE];
|
|
||||||
unsigned char *rptr;
|
|
||||||
size_t wpos;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct imsg_fd;
|
|
||||||
struct imsgbuf {
|
struct imsgbuf {
|
||||||
TAILQ_HEAD(, imsg_fd) fds;
|
struct msgbuf *w;
|
||||||
struct ibuf_read r;
|
|
||||||
struct msgbuf w;
|
|
||||||
int fd;
|
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
uint32_t maxsize;
|
||||||
|
int fd;
|
||||||
|
int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IMSGF_HASFD 1
|
|
||||||
|
|
||||||
struct imsg_hdr {
|
struct imsg_hdr {
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
uint16_t len;
|
uint32_t len;
|
||||||
uint16_t flags;
|
|
||||||
uint32_t peerid;
|
uint32_t peerid;
|
||||||
uint32_t pid;
|
uint32_t pid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct imsg {
|
struct imsg {
|
||||||
struct imsg_hdr hdr;
|
struct imsg_hdr hdr;
|
||||||
int fd;
|
|
||||||
void *data;
|
void *data;
|
||||||
struct ibuf *buf;
|
struct ibuf *buf;
|
||||||
};
|
};
|
||||||
@@ -82,7 +69,6 @@ struct iovec;
|
|||||||
struct ibuf *ibuf_open(size_t);
|
struct ibuf *ibuf_open(size_t);
|
||||||
struct ibuf *ibuf_dynamic(size_t, size_t);
|
struct ibuf *ibuf_dynamic(size_t, size_t);
|
||||||
int ibuf_add(struct ibuf *, const void *, size_t);
|
int ibuf_add(struct ibuf *, const void *, size_t);
|
||||||
int ibuf_add_buf(struct ibuf *, const struct ibuf *);
|
|
||||||
int ibuf_add_ibuf(struct ibuf *, const struct ibuf *);
|
int ibuf_add_ibuf(struct ibuf *, const struct ibuf *);
|
||||||
int ibuf_add_zero(struct ibuf *, size_t);
|
int ibuf_add_zero(struct ibuf *, size_t);
|
||||||
int ibuf_add_n8(struct ibuf *, uint64_t);
|
int ibuf_add_n8(struct ibuf *, uint64_t);
|
||||||
@@ -92,6 +78,7 @@ int ibuf_add_n64(struct ibuf *, uint64_t);
|
|||||||
int ibuf_add_h16(struct ibuf *, uint64_t);
|
int ibuf_add_h16(struct ibuf *, uint64_t);
|
||||||
int ibuf_add_h32(struct ibuf *, uint64_t);
|
int ibuf_add_h32(struct ibuf *, uint64_t);
|
||||||
int ibuf_add_h64(struct ibuf *, uint64_t);
|
int ibuf_add_h64(struct ibuf *, uint64_t);
|
||||||
|
int ibuf_add_strbuf(struct ibuf *, const char *, size_t);
|
||||||
void *ibuf_reserve(struct ibuf *, size_t);
|
void *ibuf_reserve(struct ibuf *, size_t);
|
||||||
void *ibuf_seek(struct ibuf *, size_t, size_t);
|
void *ibuf_seek(struct ibuf *, size_t, size_t);
|
||||||
int ibuf_set(struct ibuf *, size_t, const void *, size_t);
|
int ibuf_set(struct ibuf *, size_t, const void *, size_t);
|
||||||
@@ -102,6 +89,7 @@ int ibuf_set_n64(struct ibuf *, size_t, uint64_t);
|
|||||||
int ibuf_set_h16(struct ibuf *, size_t, uint64_t);
|
int ibuf_set_h16(struct ibuf *, size_t, uint64_t);
|
||||||
int ibuf_set_h32(struct ibuf *, size_t, uint64_t);
|
int ibuf_set_h32(struct ibuf *, size_t, uint64_t);
|
||||||
int ibuf_set_h64(struct ibuf *, size_t, uint64_t);
|
int ibuf_set_h64(struct ibuf *, size_t, uint64_t);
|
||||||
|
int ibuf_set_maxsize(struct ibuf *, size_t);
|
||||||
void *ibuf_data(const struct ibuf *);
|
void *ibuf_data(const struct ibuf *);
|
||||||
size_t ibuf_size(const struct ibuf *);
|
size_t ibuf_size(const struct ibuf *);
|
||||||
size_t ibuf_left(const struct ibuf *);
|
size_t ibuf_left(const struct ibuf *);
|
||||||
@@ -119,23 +107,51 @@ int ibuf_get_n64(struct ibuf *, uint64_t *);
|
|||||||
int ibuf_get_h16(struct ibuf *, uint16_t *);
|
int ibuf_get_h16(struct ibuf *, uint16_t *);
|
||||||
int ibuf_get_h32(struct ibuf *, uint32_t *);
|
int ibuf_get_h32(struct ibuf *, uint32_t *);
|
||||||
int ibuf_get_h64(struct ibuf *, uint64_t *);
|
int ibuf_get_h64(struct ibuf *, uint64_t *);
|
||||||
|
char *ibuf_get_string(struct ibuf *, size_t);
|
||||||
|
int ibuf_get_strbuf(struct ibuf *, char *, size_t);
|
||||||
int ibuf_skip(struct ibuf *, size_t);
|
int ibuf_skip(struct ibuf *, size_t);
|
||||||
void ibuf_free(struct ibuf *);
|
void ibuf_free(struct ibuf *);
|
||||||
int ibuf_fd_avail(struct ibuf *);
|
int ibuf_fd_avail(struct ibuf *);
|
||||||
int ibuf_fd_get(struct ibuf *);
|
int ibuf_fd_get(struct ibuf *);
|
||||||
void ibuf_fd_set(struct ibuf *, int);
|
void ibuf_fd_set(struct ibuf *, int);
|
||||||
int ibuf_write(struct msgbuf *);
|
struct msgbuf *msgbuf_new(void);
|
||||||
void msgbuf_init(struct msgbuf *);
|
struct msgbuf *msgbuf_new_reader(size_t,
|
||||||
|
struct ibuf *(*)(struct ibuf *, void *, int *), void *);
|
||||||
|
void msgbuf_free(struct msgbuf *);
|
||||||
void msgbuf_clear(struct msgbuf *);
|
void msgbuf_clear(struct msgbuf *);
|
||||||
|
void msgbuf_concat(struct msgbuf *, struct ibufqueue *);
|
||||||
uint32_t msgbuf_queuelen(struct msgbuf *);
|
uint32_t msgbuf_queuelen(struct msgbuf *);
|
||||||
int msgbuf_write(struct msgbuf *);
|
int ibuf_write(int, struct msgbuf *);
|
||||||
|
int msgbuf_write(int, struct msgbuf *);
|
||||||
|
int ibuf_read(int, struct msgbuf *);
|
||||||
|
int msgbuf_read(int, struct msgbuf *);
|
||||||
|
struct ibuf *msgbuf_get(struct msgbuf *);
|
||||||
|
|
||||||
|
struct ibufqueue *ibufq_new(void);
|
||||||
|
void ibufq_free(struct ibufqueue *);
|
||||||
|
struct ibuf *ibufq_pop(struct ibufqueue *bufq);
|
||||||
|
void ibufq_push(struct ibufqueue *, struct ibuf *);
|
||||||
|
uint32_t ibufq_queuelen(struct ibufqueue *);
|
||||||
|
void ibufq_concat(struct ibufqueue *, struct ibufqueue *);
|
||||||
|
void ibufq_flush(struct ibufqueue *);
|
||||||
|
|
||||||
/* imsg.c */
|
/* imsg.c */
|
||||||
void imsg_init(struct imsgbuf *, int);
|
int imsgbuf_init(struct imsgbuf *, int);
|
||||||
ssize_t imsg_read(struct imsgbuf *);
|
void imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf);
|
||||||
|
int imsgbuf_set_maxsize(struct imsgbuf *, uint32_t);
|
||||||
|
int imsgbuf_read(struct imsgbuf *);
|
||||||
|
int imsgbuf_write(struct imsgbuf *);
|
||||||
|
int imsgbuf_flush(struct imsgbuf *);
|
||||||
|
void imsgbuf_clear(struct imsgbuf *);
|
||||||
|
uint32_t imsgbuf_queuelen(struct imsgbuf *);
|
||||||
|
int imsgbuf_get(struct imsgbuf *, struct imsg *);
|
||||||
ssize_t imsg_get(struct imsgbuf *, struct imsg *);
|
ssize_t imsg_get(struct imsgbuf *, struct imsg *);
|
||||||
|
int imsg_ibufq_pop(struct ibufqueue *, struct imsg *);
|
||||||
|
void imsg_ibufq_push(struct ibufqueue *, struct imsg *);
|
||||||
int imsg_get_ibuf(struct imsg *, struct ibuf *);
|
int imsg_get_ibuf(struct imsg *, struct ibuf *);
|
||||||
int imsg_get_data(struct imsg *, void *, size_t);
|
int imsg_get_data(struct imsg *, void *, size_t);
|
||||||
|
int imsg_get_buf(struct imsg *, void *, size_t);
|
||||||
|
int imsg_get_strbuf(struct imsg *, char *, size_t);
|
||||||
int imsg_get_fd(struct imsg *);
|
int imsg_get_fd(struct imsg *);
|
||||||
uint32_t imsg_get_id(struct imsg *);
|
uint32_t imsg_get_id(struct imsg *);
|
||||||
size_t imsg_get_len(struct imsg *);
|
size_t imsg_get_len(struct imsg *);
|
||||||
@@ -152,7 +168,6 @@ struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, size_t);
|
|||||||
int imsg_add(struct ibuf *, const void *, size_t);
|
int imsg_add(struct ibuf *, const void *, size_t);
|
||||||
void imsg_close(struct imsgbuf *, struct ibuf *);
|
void imsg_close(struct imsgbuf *, struct ibuf *);
|
||||||
void imsg_free(struct imsg *);
|
void imsg_free(struct imsg *);
|
||||||
int imsg_flush(struct imsgbuf *);
|
int imsg_set_maxsize(struct ibuf *, size_t);
|
||||||
void imsg_clear(struct imsgbuf *);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
139
compat/systemd.c
139
compat/systemd.c
@@ -30,6 +30,11 @@
|
|||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
|
#ifndef SD_ID128_UUID_FORMAT_STR
|
||||||
|
#define SD_ID128_UUID_FORMAT_STR \
|
||||||
|
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
systemd_activated(void)
|
systemd_activated(void)
|
||||||
{
|
{
|
||||||
@@ -70,16 +75,50 @@ fail:
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
struct systemd_job_watch {
|
||||||
systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
|
const char *path;
|
||||||
|
int done;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
job_removed_handler(sd_bus_message *m, void *userdata,
|
||||||
|
__unused sd_bus_error *ret_error)
|
||||||
{
|
{
|
||||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
struct systemd_job_watch *watch = userdata;
|
||||||
sd_bus_message *m = NULL, *reply = NULL;
|
const char *path = NULL;
|
||||||
sd_bus *bus = NULL;
|
uint32_t id;
|
||||||
char *name, *desc, *slice;
|
int r;
|
||||||
sd_id128_t uuid;
|
|
||||||
int r;
|
/* This handler could be called during the sd_bus_call. */
|
||||||
pid_t parent_pid;
|
if (watch->path == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = sd_bus_message_read(m, "uo", &id, &path);
|
||||||
|
if (r < 0)
|
||||||
|
return (r);
|
||||||
|
|
||||||
|
if (strcmp(path, watch->path) == 0)
|
||||||
|
watch->done = 1;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
systemd_move_to_new_cgroup(char **cause)
|
||||||
|
{
|
||||||
|
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
|
sd_bus_message *m = NULL, *reply = NULL;
|
||||||
|
sd_bus *bus = NULL;
|
||||||
|
sd_bus_slot *slot = NULL;
|
||||||
|
char *name, *desc, *slice, *unit;
|
||||||
|
sd_id128_t uuid;
|
||||||
|
int r;
|
||||||
|
uint64_t elapsed_usec;
|
||||||
|
pid_t pid, parent_pid;
|
||||||
|
struct timeval start, now;
|
||||||
|
struct systemd_job_watch watch = {};
|
||||||
|
|
||||||
|
gettimeofday(&start, NULL);
|
||||||
|
|
||||||
/* Connect to the session bus. */
|
/* Connect to the session bus. */
|
||||||
r = sd_bus_default_user(&bus);
|
r = sd_bus_default_user(&bus);
|
||||||
@@ -89,6 +128,20 @@ systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Start watching for JobRemoved events */
|
||||||
|
r = sd_bus_match_signal(bus, &slot,
|
||||||
|
"org.freedesktop.systemd1",
|
||||||
|
"/org/freedesktop/systemd1",
|
||||||
|
"org.freedesktop.systemd1.Manager",
|
||||||
|
"JobRemoved",
|
||||||
|
job_removed_handler,
|
||||||
|
&watch);
|
||||||
|
if (r < 0) {
|
||||||
|
xasprintf(cause, "failed to create match signal: %s",
|
||||||
|
strerror(-r));
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
/* Start building the method call. */
|
/* Start building the method call. */
|
||||||
r = sd_bus_message_new_method_call(bus, &m,
|
r = sd_bus_message_new_method_call(bus, &m,
|
||||||
"org.freedesktop.systemd1",
|
"org.freedesktop.systemd1",
|
||||||
@@ -133,7 +186,8 @@ systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent_pid = getpid();
|
pid = getpid();
|
||||||
|
parent_pid = getppid();
|
||||||
xasprintf(&desc, "tmux child pane %ld launched by process %ld",
|
xasprintf(&desc, "tmux child pane %ld launched by process %ld",
|
||||||
(long)pid, (long)parent_pid);
|
(long)pid, (long)parent_pid);
|
||||||
r = sd_bus_message_append(m, "(sv)", "Description", "s", desc);
|
r = sd_bus_message_append(m, "(sv)", "Description", "s", desc);
|
||||||
@@ -188,6 +242,26 @@ systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try locating systemd unit that started the server, and mark pane units
|
||||||
|
* as dependent on it. Use "Before" to make sure systemd will not try to
|
||||||
|
* kill them first.
|
||||||
|
*/
|
||||||
|
if (sd_pid_get_user_unit(parent_pid, &unit) == 0 ||
|
||||||
|
sd_pid_get_unit(parent_pid, &unit) == 0) {
|
||||||
|
r = sd_bus_message_append(m, "(sv)", "Before", "as", 1, unit);
|
||||||
|
if (r >= 0) {
|
||||||
|
r = sd_bus_message_append(m, "(sv)", "PartOf", "as", 1,
|
||||||
|
unit);
|
||||||
|
}
|
||||||
|
free(unit);
|
||||||
|
if (r < 0) {
|
||||||
|
xasprintf(cause, "failed to append to properties: %s",
|
||||||
|
strerror(-r));
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* End properties array. */
|
/* End properties array. */
|
||||||
r = sd_bus_message_close_container(m);
|
r = sd_bus_message_close_container(m);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@@ -218,10 +292,55 @@ systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the job (object path) from the reply */
|
||||||
|
r = sd_bus_message_read(reply, "o", &watch.path);
|
||||||
|
if (r < 0) {
|
||||||
|
xasprintf(cause, "failed to parse method reply: %s",
|
||||||
|
strerror(-r));
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!watch.done) {
|
||||||
|
/* Process events including callbacks. */
|
||||||
|
r = sd_bus_process(bus, NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
xasprintf(cause,
|
||||||
|
"failed waiting for cgroup allocation: %s",
|
||||||
|
strerror(-r));
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A positive return means we handled an event and should keep
|
||||||
|
* processing; zero indicates no events available, so wait.
|
||||||
|
*/
|
||||||
|
if (r > 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
elapsed_usec = (now.tv_sec - start.tv_sec) * 1000000 +
|
||||||
|
now.tv_usec - start.tv_usec;
|
||||||
|
|
||||||
|
if (elapsed_usec >= 1000000) {
|
||||||
|
xasprintf(cause,
|
||||||
|
"timeout waiting for cgroup allocation");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_bus_wait(bus, 1000000 - elapsed_usec);
|
||||||
|
if (r < 0) {
|
||||||
|
xasprintf(cause,
|
||||||
|
"failed waiting for cgroup allocation: %s",
|
||||||
|
strerror(-r));
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
sd_bus_error_free(&error);
|
sd_bus_error_free(&error);
|
||||||
sd_bus_message_unref(m);
|
sd_bus_message_unref(m);
|
||||||
sd_bus_message_unref(reply);
|
sd_bus_message_unref(reply);
|
||||||
|
sd_bus_slot_unref(slot);
|
||||||
sd_bus_unref(bus);
|
sd_bus_unref(bus);
|
||||||
|
|
||||||
return (r);
|
return (r);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ utf8proc_mbtowc(wchar_t *pwc, const char *s, size_t n)
|
|||||||
* *pwc == -1 indicates invalid codepoint
|
* *pwc == -1 indicates invalid codepoint
|
||||||
* slen < 0 indicates an error
|
* slen < 0 indicates an error
|
||||||
*/
|
*/
|
||||||
slen = utf8proc_iterate(s, n, pwc);
|
slen = utf8proc_iterate(s, n, (utf8proc_int32_t*)pwc);
|
||||||
if (*pwc == (wchar_t)-1 || slen < 0)
|
if (*pwc == (wchar_t)-1 || slen < 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
return (slen);
|
return (slen);
|
||||||
|
|||||||
67
configure.ac
67
configure.ac
@@ -1,6 +1,6 @@
|
|||||||
# configure.ac
|
# configure.ac
|
||||||
|
|
||||||
AC_INIT([tmux], 3.5a)
|
AC_INIT([tmux], 3.7a)
|
||||||
AC_PREREQ([2.60])
|
AC_PREREQ([2.60])
|
||||||
|
|
||||||
AC_CONFIG_AUX_DIR(etc)
|
AC_CONFIG_AUX_DIR(etc)
|
||||||
@@ -64,6 +64,24 @@ AC_ARG_ENABLE(
|
|||||||
)
|
)
|
||||||
AM_CONDITIONAL(IS_DEBUG, test "x$enable_debug" = xyes)
|
AM_CONDITIONAL(IS_DEBUG, test "x$enable_debug" = xyes)
|
||||||
|
|
||||||
|
# Is this --enable-optimizations?
|
||||||
|
AC_ARG_ENABLE(
|
||||||
|
optimizations,
|
||||||
|
AS_HELP_STRING(--enable-optimizations, enable optimization build flags),
|
||||||
|
,
|
||||||
|
enable_optimizations=yes
|
||||||
|
)
|
||||||
|
AM_CONDITIONAL(IS_OPTIMIZED, test "x$enable_optimizations" = xyes)
|
||||||
|
|
||||||
|
# Is this --enable-asan?
|
||||||
|
AC_ARG_ENABLE(
|
||||||
|
asan,
|
||||||
|
AS_HELP_STRING(--enable-asan, enable ASAN build flags),
|
||||||
|
,
|
||||||
|
enable_asan=no
|
||||||
|
)
|
||||||
|
AM_CONDITIONAL(IS_ASAN, test "x$enable_asan" = xyes)
|
||||||
|
|
||||||
# Is this a static build?
|
# Is this a static build?
|
||||||
AC_ARG_ENABLE(
|
AC_ARG_ENABLE(
|
||||||
static,
|
static,
|
||||||
@@ -219,7 +237,7 @@ AC_SEARCH_LIBS(clock_gettime, rt)
|
|||||||
# musl does not set optarg to NULL for flags without arguments (although it is
|
# musl does not set optarg to NULL for flags without arguments (although it is
|
||||||
# not required to, but it is helpful) 3) there are probably other weird
|
# not required to, but it is helpful) 3) there are probably other weird
|
||||||
# implementations.
|
# implementations.
|
||||||
AC_LIBOBJ(getopt)
|
AC_LIBOBJ(getopt_long)
|
||||||
|
|
||||||
# Look for libevent. Try libevent_core or libevent with pkg-config first then
|
# Look for libevent. Try libevent_core or libevent with pkg-config first then
|
||||||
# look for the library.
|
# look for the library.
|
||||||
@@ -279,24 +297,24 @@ fi
|
|||||||
# Look for ncurses or curses. Try pkg-config first then directly for the
|
# Look for ncurses or curses. Try pkg-config first then directly for the
|
||||||
# library.
|
# library.
|
||||||
PKG_CHECK_MODULES(
|
PKG_CHECK_MODULES(
|
||||||
LIBTINFO,
|
LIBTINFOW,
|
||||||
tinfo,
|
tinfow,
|
||||||
[
|
[
|
||||||
AM_CPPFLAGS="$LIBTINFO_CFLAGS $AM_CPPFLAGS"
|
AM_CPPFLAGS="$LIBTINFOW_CFLAGS $AM_CPPFLAGS"
|
||||||
CPPFLAGS="$LIBTINFO_CFLAGS $SAVED_CPPFLAGS"
|
CPPFLAGS="$LIBTINFOW_CFLAGS $SAVED_CPPFLAGS"
|
||||||
LIBS="$LIBTINFO_LIBS $LIBS"
|
LIBS="$LIBTINFOW_LIBS $LIBS"
|
||||||
found_ncurses=yes
|
found_ncurses=yes
|
||||||
],
|
],
|
||||||
found_ncurses=no
|
found_ncurses=no
|
||||||
)
|
)
|
||||||
if test "x$found_ncurses" = xno; then
|
if test "x$found_ncurses" = xno; then
|
||||||
PKG_CHECK_MODULES(
|
PKG_CHECK_MODULES(
|
||||||
LIBNCURSES,
|
LIBTINFO,
|
||||||
ncurses,
|
tinfo,
|
||||||
[
|
[
|
||||||
AM_CPPFLAGS="$LIBNCURSES_CFLAGS $AM_CPPFLAGS"
|
AM_CPPFLAGS="$LIBTINFO_CFLAGS $AM_CPPFLAGS"
|
||||||
CPPFLAGS="$LIBNCURSES_CFLAGS $SAVED_CPPFLAGS"
|
CPPFLAGS="$LIBTINFO_CFLAGS $SAVED_CPPFLAGS"
|
||||||
LIBS="$LIBNCURSES_LIBS $LIBS"
|
LIBS="$LIBTINFO_LIBS $LIBS"
|
||||||
found_ncurses=yes
|
found_ncurses=yes
|
||||||
],
|
],
|
||||||
found_ncurses=no
|
found_ncurses=no
|
||||||
@@ -315,10 +333,23 @@ if test "x$found_ncurses" = xno; then
|
|||||||
found_ncurses=no
|
found_ncurses=no
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
if test "x$found_ncurses" = xno; then
|
||||||
|
PKG_CHECK_MODULES(
|
||||||
|
LIBNCURSES,
|
||||||
|
ncurses,
|
||||||
|
[
|
||||||
|
AM_CPPFLAGS="$LIBNCURSES_CFLAGS $AM_CPPFLAGS"
|
||||||
|
CPPFLAGS="$LIBNCURSES_CFLAGS $SAVED_CPPFLAGS"
|
||||||
|
LIBS="$LIBNCURSES_LIBS $LIBS"
|
||||||
|
found_ncurses=yes
|
||||||
|
],
|
||||||
|
found_ncurses=no
|
||||||
|
)
|
||||||
|
fi
|
||||||
if test "x$found_ncurses" = xno; then
|
if test "x$found_ncurses" = xno; then
|
||||||
AC_SEARCH_LIBS(
|
AC_SEARCH_LIBS(
|
||||||
setupterm,
|
setupterm,
|
||||||
[tinfo terminfo ncurses ncursesw],
|
[tinfow tinfo terminfo ncursesw ncurses],
|
||||||
found_ncurses=yes,
|
found_ncurses=yes,
|
||||||
found_ncurses=no
|
found_ncurses=no
|
||||||
)
|
)
|
||||||
@@ -638,9 +669,9 @@ else
|
|||||||
AC_LIBOBJ(err)
|
AC_LIBOBJ(err)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Look for imsg_init in libutil.
|
# Look for imsg_add in libutil.
|
||||||
AC_SEARCH_LIBS(imsg_init, util, found_imsg_init=yes, found_imsg_init=no)
|
AC_SEARCH_LIBS(imsg_add, util, found_imsg_add=yes, found_imsg_add=no)
|
||||||
if test "x$found_imsg_init" = xyes; then
|
if test "x$found_imsg_add" = xyes; then
|
||||||
AC_DEFINE(HAVE_IMSG)
|
AC_DEFINE(HAVE_IMSG)
|
||||||
else
|
else
|
||||||
AC_LIBOBJ(imsg)
|
AC_LIBOBJ(imsg)
|
||||||
@@ -982,22 +1013,22 @@ AM_CONDITIONAL(IS_NETBSD, test "x$PLATFORM" = xnetbsd)
|
|||||||
AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd)
|
AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd)
|
||||||
AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos)
|
AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos)
|
||||||
AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux)
|
AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux)
|
||||||
|
AM_CONDITIONAL(IS_CYGWIN, test "x$PLATFORM" = xcygwin)
|
||||||
AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku)
|
AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku)
|
||||||
AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown)
|
AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown)
|
||||||
|
|
||||||
# Set the default lock command
|
# Set the default lock command
|
||||||
DEFAULT_LOCK_CMD="lock -np"
|
DEFAULT_LOCK_CMD="lock -np"
|
||||||
AC_MSG_CHECKING(lock-command)
|
|
||||||
if test "x$PLATFORM" = xlinux; then
|
if test "x$PLATFORM" = xlinux; then
|
||||||
AC_CHECK_PROG(found_vlock, vlock, yes, no)
|
AC_CHECK_PROG(found_vlock, vlock, yes, no)
|
||||||
if test "x$found_vlock" = xyes; then
|
if test "x$found_vlock" = xyes; then
|
||||||
DEFAULT_LOCK_CMD="vlock"
|
DEFAULT_LOCK_CMD="vlock"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
AC_MSG_CHECKING(lock-command)
|
||||||
AC_MSG_RESULT($DEFAULT_LOCK_CMD)
|
AC_MSG_RESULT($DEFAULT_LOCK_CMD)
|
||||||
AC_SUBST(DEFAULT_LOCK_CMD)
|
AC_SUBST(DEFAULT_LOCK_CMD)
|
||||||
|
|
||||||
|
|
||||||
# Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user
|
# Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user
|
||||||
# variables.
|
# variables.
|
||||||
AC_SUBST(AM_CPPFLAGS)
|
AC_SUBST(AM_CPPFLAGS)
|
||||||
|
|||||||
@@ -24,7 +24,8 @@
|
|||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
#define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
|
#define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
|
||||||
((c) != NULL && ((c)->flags & CLIENT_CONTROL))
|
((c) != NULL && ((c)->flags & CLIENT_CONTROL) && \
|
||||||
|
(c)->control_state != NULL)
|
||||||
|
|
||||||
void
|
void
|
||||||
control_notify_pane_mode_changed(int pane)
|
control_notify_pane_mode_changed(int pane)
|
||||||
@@ -51,29 +52,24 @@ control_notify_window_layout_changed(struct window *w)
|
|||||||
template = "%layout-change #{window_id} #{window_layout} "
|
template = "%layout-change #{window_id} #{window_layout} "
|
||||||
"#{window_visible_layout} #{window_raw_flags}";
|
"#{window_visible_layout} #{window_raw_flags}";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When the last pane in a window is closed it won't have a layout root
|
||||||
|
* and we don't need to inform the client about the layout change
|
||||||
|
* because the whole window will go away soon.
|
||||||
|
*/
|
||||||
|
wl = TAILQ_FIRST(&w->winlinks);
|
||||||
|
if (wl == NULL || w->layout_root == NULL)
|
||||||
|
return;
|
||||||
|
cp = format_single(NULL, template, NULL, NULL, wl, NULL);
|
||||||
|
|
||||||
TAILQ_FOREACH(c, &clients, entry) {
|
TAILQ_FOREACH(c, &clients, entry) {
|
||||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
||||||
continue;
|
continue;
|
||||||
s = c->session;
|
s = c->session;
|
||||||
|
if (winlink_find_by_window_id(&s->windows, w->id) != NULL)
|
||||||
if (winlink_find_by_window_id(&s->windows, w->id) == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When the last pane in a window is closed it won't have a
|
|
||||||
* layout root and we don't need to inform the client about the
|
|
||||||
* layout change because the whole window will go away soon.
|
|
||||||
*/
|
|
||||||
if (w->layout_root == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
wl = winlink_find_by_window(&s->windows, w);
|
|
||||||
if (wl != NULL) {
|
|
||||||
cp = format_single(NULL, template, c, NULL, wl, NULL);
|
|
||||||
control_write(c, "%s", cp);
|
control_write(c, "%s", cp);
|
||||||
free(cp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
free(cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -81,6 +77,8 @@ control_notify_window_pane_changed(struct window *w)
|
|||||||
{
|
{
|
||||||
struct client *c;
|
struct client *c;
|
||||||
|
|
||||||
|
if (w->active == NULL)
|
||||||
|
return;
|
||||||
TAILQ_FOREACH(c, &clients, entry) {
|
TAILQ_FOREACH(c, &clients, entry) {
|
||||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
219
control.c
219
control.c
@@ -207,10 +207,12 @@ control_free_sub(struct control_state *cs, struct control_sub *csub)
|
|||||||
|
|
||||||
RB_FOREACH_SAFE(csp, control_sub_panes, &csub->panes, csp1) {
|
RB_FOREACH_SAFE(csp, control_sub_panes, &csub->panes, csp1) {
|
||||||
RB_REMOVE(control_sub_panes, &csub->panes, csp);
|
RB_REMOVE(control_sub_panes, &csub->panes, csp);
|
||||||
|
free(csp->last);
|
||||||
free(csp);
|
free(csp);
|
||||||
}
|
}
|
||||||
RB_FOREACH_SAFE(csw, control_sub_windows, &csub->windows, csw1) {
|
RB_FOREACH_SAFE(csw, control_sub_windows, &csub->windows, csw1) {
|
||||||
RB_REMOVE(control_sub_windows, &csub->windows, csw);
|
RB_REMOVE(control_sub_windows, &csub->windows, csw);
|
||||||
|
free(csw->last);
|
||||||
free(csw);
|
free(csw);
|
||||||
}
|
}
|
||||||
free(csub->last);
|
free(csub->last);
|
||||||
@@ -298,6 +300,7 @@ control_reset_offsets(struct client *c)
|
|||||||
struct control_pane *cp, *cp1;
|
struct control_pane *cp, *cp1;
|
||||||
|
|
||||||
RB_FOREACH_SAFE(cp, control_panes, &cs->panes, cp1) {
|
RB_FOREACH_SAFE(cp, control_panes, &cs->panes, cp1) {
|
||||||
|
control_discard_pane(c, cp);
|
||||||
RB_REMOVE(control_panes, &cs->panes, cp);
|
RB_REMOVE(control_panes, &cs->panes, cp);
|
||||||
free(cp);
|
free(cp);
|
||||||
}
|
}
|
||||||
@@ -352,6 +355,9 @@ control_set_pane_off(struct client *c, struct window_pane *wp)
|
|||||||
struct control_pane *cp;
|
struct control_pane *cp;
|
||||||
|
|
||||||
cp = control_add_pane(c, wp);
|
cp = control_add_pane(c, wp);
|
||||||
|
control_discard_pane(c, cp);
|
||||||
|
memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
|
||||||
|
memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
|
||||||
cp->flags |= CONTROL_PANE_OFF;
|
cp->flags |= CONTROL_PANE_OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,7 +616,7 @@ control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
|
|||||||
struct evbuffer *message, struct window_pane *wp, size_t size)
|
struct evbuffer *message, struct window_pane *wp, size_t size)
|
||||||
{
|
{
|
||||||
u_char *new_data;
|
u_char *new_data;
|
||||||
size_t new_size;
|
size_t new_size, start;
|
||||||
u_int i;
|
u_int i;
|
||||||
|
|
||||||
if (message == NULL) {
|
if (message == NULL) {
|
||||||
@@ -629,10 +635,16 @@ control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
|
|||||||
if (new_size < size)
|
if (new_size < size)
|
||||||
fatalx("not enough data: %zu < %zu", new_size, size);
|
fatalx("not enough data: %zu < %zu", new_size, size);
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
if (new_data[i] < ' ' || new_data[i] == '\\')
|
if (new_data[i] < ' ' || new_data[i] == '\\') {
|
||||||
evbuffer_add_printf(message, "\\%03o", new_data[i]);
|
evbuffer_add_printf(message, "\\%03o", new_data[i]);
|
||||||
else
|
} else {
|
||||||
evbuffer_add_printf(message, "%c", new_data[i]);
|
start = i;
|
||||||
|
while (i + 1 < size &&
|
||||||
|
new_data[i + 1] >= ' ' &&
|
||||||
|
new_data[i + 1] != '\\')
|
||||||
|
i++;
|
||||||
|
evbuffer_add(message, new_data + start, i - start + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
window_pane_update_used_data(wp, &cp->offset, size);
|
window_pane_update_used_data(wp, &cp->offset, size);
|
||||||
return (message);
|
return (message);
|
||||||
@@ -822,6 +834,9 @@ control_stop(struct client *c)
|
|||||||
struct control_block *cb, *cb1;
|
struct control_block *cb, *cb1;
|
||||||
struct control_sub *csub, *csub1;
|
struct control_sub *csub, *csub1;
|
||||||
|
|
||||||
|
if (cs == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
if (~c->flags & CLIENT_CONTROLCONTROL)
|
if (~c->flags & CLIENT_CONTROLCONTROL)
|
||||||
bufferevent_free(cs->write_event);
|
bufferevent_free(cs->write_event);
|
||||||
bufferevent_free(cs->read_event);
|
bufferevent_free(cs->read_event);
|
||||||
@@ -831,24 +846,23 @@ control_stop(struct client *c)
|
|||||||
if (evtimer_initialized(&cs->subs_timer))
|
if (evtimer_initialized(&cs->subs_timer))
|
||||||
evtimer_del(&cs->subs_timer);
|
evtimer_del(&cs->subs_timer);
|
||||||
|
|
||||||
|
control_reset_offsets(c);
|
||||||
TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1)
|
TAILQ_FOREACH_SAFE(cb, &cs->all_blocks, all_entry, cb1)
|
||||||
control_free_block(cs, cb);
|
control_free_block(cs, cb);
|
||||||
control_reset_offsets(c);
|
|
||||||
|
|
||||||
|
c->control_state = NULL;
|
||||||
free(cs);
|
free(cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check session subscription. */
|
/* Check session subscription. */
|
||||||
static void
|
static void
|
||||||
control_check_subs_session(struct client *c, struct control_sub *csub)
|
control_check_subs_session(struct client *c, struct control_sub *csub,
|
||||||
|
struct format_tree *ft)
|
||||||
{
|
{
|
||||||
struct session *s = c->session;
|
struct session *s = c->session;
|
||||||
struct format_tree *ft;
|
|
||||||
char *value;
|
char *value;
|
||||||
|
|
||||||
ft = format_create_defaults(NULL, c, s, NULL, NULL);
|
|
||||||
value = format_expand(ft, csub->format);
|
value = format_expand(ft, csub->format);
|
||||||
format_free(ft);
|
|
||||||
|
|
||||||
if (csub->last != NULL && strcmp(value, csub->last) == 0) {
|
if (csub->last != NULL && strcmp(value, csub->last) == 0) {
|
||||||
free(value);
|
free(value);
|
||||||
@@ -909,48 +923,38 @@ control_check_subs_pane(struct client *c, struct control_sub *csub)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check all panes subscription. */
|
/* Check all-panes subscription for a pane. */
|
||||||
static void
|
static void
|
||||||
control_check_subs_all_panes(struct client *c, struct control_sub *csub)
|
control_check_subs_all_panes_one(struct client *c, struct control_sub *csub,
|
||||||
|
struct format_tree *ft, struct winlink *wl, struct window_pane *wp)
|
||||||
{
|
{
|
||||||
struct session *s = c->session;
|
struct session *s = c->session;
|
||||||
struct window_pane *wp;
|
struct window *w = wl->window;
|
||||||
struct window *w;
|
|
||||||
struct winlink *wl;
|
|
||||||
struct format_tree *ft;
|
|
||||||
char *value;
|
char *value;
|
||||||
struct control_sub_pane *csp, find;
|
struct control_sub_pane *csp, find;
|
||||||
|
|
||||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
value = format_expand(ft, csub->format);
|
||||||
w = wl->window;
|
|
||||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
|
||||||
ft = format_create_defaults(NULL, c, s, wl, wp);
|
|
||||||
value = format_expand(ft, csub->format);
|
|
||||||
format_free(ft);
|
|
||||||
|
|
||||||
find.pane = wp->id;
|
find.pane = wp->id;
|
||||||
find.idx = wl->idx;
|
find.idx = wl->idx;
|
||||||
|
|
||||||
csp = RB_FIND(control_sub_panes, &csub->panes, &find);
|
csp = RB_FIND(control_sub_panes, &csub->panes, &find);
|
||||||
if (csp == NULL) {
|
if (csp == NULL) {
|
||||||
csp = xcalloc(1, sizeof *csp);
|
csp = xcalloc(1, sizeof *csp);
|
||||||
csp->pane = wp->id;
|
csp->pane = wp->id;
|
||||||
csp->idx = wl->idx;
|
csp->idx = wl->idx;
|
||||||
RB_INSERT(control_sub_panes, &csub->panes, csp);
|
RB_INSERT(control_sub_panes, &csub->panes, csp);
|
||||||
}
|
|
||||||
|
|
||||||
if (csp->last != NULL &&
|
|
||||||
strcmp(value, csp->last) == 0) {
|
|
||||||
free(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
control_write(c,
|
|
||||||
"%%subscription-changed %s $%u @%u %u %%%u : %s",
|
|
||||||
csub->name, s->id, w->id, wl->idx, wp->id, value);
|
|
||||||
free(csp->last);
|
|
||||||
csp->last = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (csp->last != NULL && strcmp(value, csp->last) == 0) {
|
||||||
|
free(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
control_write(c,
|
||||||
|
"%%subscription-changed %s $%u @%u %u %%%u : %s",
|
||||||
|
csub->name, s->id, w->id, wl->idx, wp->id, value);
|
||||||
|
free(csp->last);
|
||||||
|
csp->last = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check window subscription. */
|
/* Check window subscription. */
|
||||||
@@ -999,45 +1003,38 @@ control_check_subs_window(struct client *c, struct control_sub *csub)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check all windows subscription. */
|
/* Check all-windows subscription for a window. */
|
||||||
static void
|
static void
|
||||||
control_check_subs_all_windows(struct client *c, struct control_sub *csub)
|
control_check_subs_all_windows_one(struct client *c, struct control_sub *csub,
|
||||||
|
struct format_tree *ft, struct winlink *wl)
|
||||||
{
|
{
|
||||||
struct session *s = c->session;
|
struct session *s = c->session;
|
||||||
struct window *w;
|
struct window *w = wl->window;
|
||||||
struct winlink *wl;
|
|
||||||
struct format_tree *ft;
|
|
||||||
char *value;
|
char *value;
|
||||||
struct control_sub_window *csw, find;
|
struct control_sub_window *csw, find;
|
||||||
|
|
||||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
value = format_expand(ft, csub->format);
|
||||||
w = wl->window;
|
|
||||||
|
|
||||||
ft = format_create_defaults(NULL, c, s, wl, NULL);
|
find.window = w->id;
|
||||||
value = format_expand(ft, csub->format);
|
find.idx = wl->idx;
|
||||||
format_free(ft);
|
|
||||||
|
|
||||||
find.window = w->id;
|
csw = RB_FIND(control_sub_windows, &csub->windows, &find);
|
||||||
find.idx = wl->idx;
|
if (csw == NULL) {
|
||||||
|
csw = xcalloc(1, sizeof *csw);
|
||||||
csw = RB_FIND(control_sub_windows, &csub->windows, &find);
|
csw->window = w->id;
|
||||||
if (csw == NULL) {
|
csw->idx = wl->idx;
|
||||||
csw = xcalloc(1, sizeof *csw);
|
RB_INSERT(control_sub_windows, &csub->windows, csw);
|
||||||
csw->window = w->id;
|
|
||||||
csw->idx = wl->idx;
|
|
||||||
RB_INSERT(control_sub_windows, &csub->windows, csw);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (csw->last != NULL && strcmp(value, csw->last) == 0) {
|
|
||||||
free(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
control_write(c,
|
|
||||||
"%%subscription-changed %s $%u @%u %u - : %s",
|
|
||||||
csub->name, s->id, w->id, wl->idx, value);
|
|
||||||
free(csw->last);
|
|
||||||
csw->last = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (csw->last != NULL && strcmp(value, csw->last) == 0) {
|
||||||
|
free(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
control_write(c,
|
||||||
|
"%%subscription-changed %s $%u @%u %u - : %s",
|
||||||
|
csub->name, s->id, w->id, wl->idx, value);
|
||||||
|
free(csw->last);
|
||||||
|
csw->last = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check subscriptions timer. */
|
/* Check subscriptions timer. */
|
||||||
@@ -1047,30 +1044,94 @@ control_check_subs_timer(__unused int fd, __unused short events, void *data)
|
|||||||
struct client *c = data;
|
struct client *c = data;
|
||||||
struct control_state *cs = c->control_state;
|
struct control_state *cs = c->control_state;
|
||||||
struct control_sub *csub, *csub1;
|
struct control_sub *csub, *csub1;
|
||||||
|
struct session *s = c->session;
|
||||||
|
struct format_tree *ft;
|
||||||
|
struct winlink *wl;
|
||||||
|
struct window_pane *wp;
|
||||||
struct timeval tv = { .tv_sec = 1 };
|
struct timeval tv = { .tv_sec = 1 };
|
||||||
|
int have_session = 0, have_all_panes = 0;
|
||||||
|
int have_all_windows = 0;
|
||||||
|
|
||||||
log_debug("%s: timer fired", __func__);
|
log_debug("%s: timer fired", __func__);
|
||||||
evtimer_add(&cs->subs_timer, &tv);
|
evtimer_add(&cs->subs_timer, &tv);
|
||||||
|
|
||||||
RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) {
|
if (s == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Find which subscription types are present. */
|
||||||
|
RB_FOREACH(csub, control_subs, &cs->subs) {
|
||||||
switch (csub->type) {
|
switch (csub->type) {
|
||||||
case CONTROL_SUB_SESSION:
|
case CONTROL_SUB_SESSION:
|
||||||
control_check_subs_session(c, csub);
|
have_session = 1;
|
||||||
break;
|
|
||||||
case CONTROL_SUB_PANE:
|
|
||||||
control_check_subs_pane(c, csub);
|
|
||||||
break;
|
break;
|
||||||
case CONTROL_SUB_ALL_PANES:
|
case CONTROL_SUB_ALL_PANES:
|
||||||
control_check_subs_all_panes(c, csub);
|
have_all_panes = 1;
|
||||||
|
break;
|
||||||
|
case CONTROL_SUB_ALL_WINDOWS:
|
||||||
|
have_all_windows = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check session subscriptions. */
|
||||||
|
if (have_session) {
|
||||||
|
ft = format_create_defaults(NULL, c, s, NULL, NULL);
|
||||||
|
RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) {
|
||||||
|
if (csub->type == CONTROL_SUB_SESSION)
|
||||||
|
control_check_subs_session(c, csub, ft);
|
||||||
|
}
|
||||||
|
format_free(ft);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check pane and window subscriptions. */
|
||||||
|
RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) {
|
||||||
|
switch (csub->type) {
|
||||||
|
case CONTROL_SUB_PANE:
|
||||||
|
control_check_subs_pane(c, csub);
|
||||||
break;
|
break;
|
||||||
case CONTROL_SUB_WINDOW:
|
case CONTROL_SUB_WINDOW:
|
||||||
control_check_subs_window(c, csub);
|
control_check_subs_window(c, csub);
|
||||||
break;
|
break;
|
||||||
|
case CONTROL_SUB_SESSION:
|
||||||
|
case CONTROL_SUB_ALL_PANES:
|
||||||
case CONTROL_SUB_ALL_WINDOWS:
|
case CONTROL_SUB_ALL_WINDOWS:
|
||||||
control_check_subs_all_windows(c, csub);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check all-panes subscriptions. */
|
||||||
|
if (have_all_panes) {
|
||||||
|
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||||
|
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
|
||||||
|
ft = format_create_defaults(NULL, c, s, wl, wp);
|
||||||
|
RB_FOREACH_SAFE(csub, control_subs, &cs->subs,
|
||||||
|
csub1) {
|
||||||
|
if (csub->type != CONTROL_SUB_ALL_PANES)
|
||||||
|
continue;
|
||||||
|
control_check_subs_all_panes_one(c,
|
||||||
|
csub, ft, wl, wp);
|
||||||
|
}
|
||||||
|
format_free(ft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check all-windows subscriptions. */
|
||||||
|
if (have_all_windows) {
|
||||||
|
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||||
|
ft = format_create_defaults(NULL, c, s, wl, NULL);
|
||||||
|
RB_FOREACH_SAFE(csub, control_subs, &cs->subs,
|
||||||
|
csub1) {
|
||||||
|
if (csub->type != CONTROL_SUB_ALL_WINDOWS)
|
||||||
|
continue;
|
||||||
|
control_check_subs_all_windows_one(c, csub, ft,
|
||||||
|
wl);
|
||||||
|
}
|
||||||
|
format_free(ft);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a subscription. */
|
/* Add a subscription. */
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ environ_free(struct environ *env)
|
|||||||
{
|
{
|
||||||
struct environ_entry *envent, *envent1;
|
struct environ_entry *envent, *envent1;
|
||||||
|
|
||||||
|
if (env == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
RB_FOREACH_SAFE(envent, environ, env, envent1) {
|
RB_FOREACH_SAFE(envent, environ, env, envent1) {
|
||||||
RB_REMOVE(environ, env, envent);
|
RB_REMOVE(environ, env, envent);
|
||||||
free(envent->name);
|
free(envent->name);
|
||||||
@@ -262,6 +265,7 @@ environ_for_session(struct session *s, int no_TERM)
|
|||||||
environ_set(env, "TERM", 0, "%s", value);
|
environ_set(env, "TERM", 0, "%s", value);
|
||||||
environ_set(env, "TERM_PROGRAM", 0, "%s", "tmux");
|
environ_set(env, "TERM_PROGRAM", 0, "%s", "tmux");
|
||||||
environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion());
|
environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion());
|
||||||
|
environ_set(env, "COLORTERM", 0, "truecolor");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SYSTEMD
|
#ifdef HAVE_SYSTEMD
|
||||||
|
|||||||
53
file.c
53
file.c
@@ -41,13 +41,22 @@ RB_GENERATE(client_files, client_file, entry, file_cmp);
|
|||||||
static char *
|
static char *
|
||||||
file_get_path(struct client *c, const char *file)
|
file_get_path(struct client *c, const char *file)
|
||||||
{
|
{
|
||||||
char *path;
|
const char *home;
|
||||||
|
char *path, *full_path;
|
||||||
|
|
||||||
if (*file == '/')
|
if (strncmp(file, "~/", 2) != 0)
|
||||||
path = xstrdup(file);
|
path = xstrdup(file);
|
||||||
else
|
else {
|
||||||
xasprintf(&path, "%s/%s", server_client_get_cwd(c, NULL), file);
|
home = find_home();
|
||||||
return (path);
|
if (home == NULL)
|
||||||
|
home = "";
|
||||||
|
xasprintf(&path, "%s%s", home, file + 1);
|
||||||
|
}
|
||||||
|
if (*path == '/')
|
||||||
|
return (path);
|
||||||
|
xasprintf(&full_path, "%s/%s", server_client_get_cwd(c, NULL), path);
|
||||||
|
free(path);
|
||||||
|
return (full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tree comparison function. */
|
/* Tree comparison function. */
|
||||||
@@ -361,7 +370,7 @@ file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
|
|||||||
size_t msglen;
|
size_t msglen;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
u_int stream = file_next_stream++;
|
u_int stream = file_next_stream++;
|
||||||
FILE *f;
|
FILE *f = NULL;
|
||||||
size_t size;
|
size_t size;
|
||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
|
|
||||||
@@ -390,6 +399,10 @@ file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
|
|||||||
}
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
size = fread(buffer, 1, sizeof buffer, f);
|
size = fread(buffer, 1, sizeof buffer, f);
|
||||||
|
if (ferror(f)) {
|
||||||
|
cf->error = errno;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if (evbuffer_add(cf->buffer, buffer, size) != 0) {
|
if (evbuffer_add(cf->buffer, buffer, size) != 0) {
|
||||||
cf->error = ENOMEM;
|
cf->error = ENOMEM;
|
||||||
goto done;
|
goto done;
|
||||||
@@ -401,7 +414,6 @@ file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
|
|||||||
cf->error = EIO;
|
cf->error = EIO;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
fclose(f);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,6 +436,8 @@ skip:
|
|||||||
return cf;
|
return cf;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
if (f != NULL)
|
||||||
|
fclose(f);
|
||||||
file_fire_done(cf);
|
file_fire_done(cf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -661,7 +675,7 @@ file_write_close(struct client_files *files, struct imsg *imsg)
|
|||||||
|
|
||||||
/* Client file read error callback. */
|
/* Client file read error callback. */
|
||||||
static void
|
static void
|
||||||
file_read_error_callback(__unused struct bufferevent *bev, __unused short what,
|
file_read_error_callback(__unused struct bufferevent *bev, short what,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
struct client_file *cf = arg;
|
struct client_file *cf = arg;
|
||||||
@@ -670,7 +684,7 @@ file_read_error_callback(__unused struct bufferevent *bev, __unused short what,
|
|||||||
log_debug("read error file %d", cf->stream);
|
log_debug("read error file %d", cf->stream);
|
||||||
|
|
||||||
msg.stream = cf->stream;
|
msg.stream = cf->stream;
|
||||||
msg.error = 0;
|
msg.error = (what & EVBUFFER_ERROR) ? EIO : 0;
|
||||||
proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg);
|
proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg);
|
||||||
|
|
||||||
bufferevent_free(cf->event);
|
bufferevent_free(cf->event);
|
||||||
@@ -794,7 +808,7 @@ file_read_cancel(struct client_files *files, struct imsg *imsg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Handle a write ready message (server). */
|
/* Handle a write ready message (server). */
|
||||||
void
|
int
|
||||||
file_write_ready(struct client_files *files, struct imsg *imsg)
|
file_write_ready(struct client_files *files, struct imsg *imsg)
|
||||||
{
|
{
|
||||||
struct msg_write_ready *msg = imsg->data;
|
struct msg_write_ready *msg = imsg->data;
|
||||||
@@ -802,19 +816,20 @@ file_write_ready(struct client_files *files, struct imsg *imsg)
|
|||||||
struct client_file find, *cf;
|
struct client_file find, *cf;
|
||||||
|
|
||||||
if (msglen != sizeof *msg)
|
if (msglen != sizeof *msg)
|
||||||
fatalx("bad MSG_WRITE_READY size");
|
return (-1);
|
||||||
find.stream = msg->stream;
|
find.stream = msg->stream;
|
||||||
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
|
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
|
||||||
return;
|
return (0);
|
||||||
if (msg->error != 0) {
|
if (msg->error != 0) {
|
||||||
cf->error = msg->error;
|
cf->error = msg->error;
|
||||||
file_fire_done(cf);
|
file_fire_done(cf);
|
||||||
} else
|
} else
|
||||||
file_push(cf);
|
file_push(cf);
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle read data message (server). */
|
/* Handle read data message (server). */
|
||||||
void
|
int
|
||||||
file_read_data(struct client_files *files, struct imsg *imsg)
|
file_read_data(struct client_files *files, struct imsg *imsg)
|
||||||
{
|
{
|
||||||
struct msg_read_data *msg = imsg->data;
|
struct msg_read_data *msg = imsg->data;
|
||||||
@@ -824,10 +839,10 @@ file_read_data(struct client_files *files, struct imsg *imsg)
|
|||||||
size_t bsize = msglen - sizeof *msg;
|
size_t bsize = msglen - sizeof *msg;
|
||||||
|
|
||||||
if (msglen < sizeof *msg)
|
if (msglen < sizeof *msg)
|
||||||
fatalx("bad MSG_READ_DATA size");
|
return (-1);
|
||||||
find.stream = msg->stream;
|
find.stream = msg->stream;
|
||||||
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
|
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
|
||||||
return;
|
return (0);
|
||||||
|
|
||||||
log_debug("file %d read %zu bytes", cf->stream, bsize);
|
log_debug("file %d read %zu bytes", cf->stream, bsize);
|
||||||
if (cf->error == 0 && !cf->closed) {
|
if (cf->error == 0 && !cf->closed) {
|
||||||
@@ -837,10 +852,11 @@ file_read_data(struct client_files *files, struct imsg *imsg)
|
|||||||
} else
|
} else
|
||||||
file_fire_read(cf);
|
file_fire_read(cf);
|
||||||
}
|
}
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle a read done message (server). */
|
/* Handle a read done message (server). */
|
||||||
void
|
int
|
||||||
file_read_done(struct client_files *files, struct imsg *imsg)
|
file_read_done(struct client_files *files, struct imsg *imsg)
|
||||||
{
|
{
|
||||||
struct msg_read_done *msg = imsg->data;
|
struct msg_read_done *msg = imsg->data;
|
||||||
@@ -848,12 +864,13 @@ file_read_done(struct client_files *files, struct imsg *imsg)
|
|||||||
struct client_file find, *cf;
|
struct client_file find, *cf;
|
||||||
|
|
||||||
if (msglen != sizeof *msg)
|
if (msglen != sizeof *msg)
|
||||||
fatalx("bad MSG_READ_DONE size");
|
return (-1);
|
||||||
find.stream = msg->stream;
|
find.stream = msg->stream;
|
||||||
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
|
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
|
||||||
return;
|
return (0);
|
||||||
|
|
||||||
log_debug("file %d read done", cf->stream);
|
log_debug("file %d read done", cf->stream);
|
||||||
cf->error = msg->error;
|
cf->error = msg->error;
|
||||||
file_fire_done(cf);
|
file_fire_done(cf);
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ format_is_type(struct format_range *fr, struct style *sy)
|
|||||||
case STYLE_RANGE_NONE:
|
case STYLE_RANGE_NONE:
|
||||||
case STYLE_RANGE_LEFT:
|
case STYLE_RANGE_LEFT:
|
||||||
case STYLE_RANGE_RIGHT:
|
case STYLE_RANGE_RIGHT:
|
||||||
|
case STYLE_RANGE_CONTROL:
|
||||||
return (1);
|
return (1);
|
||||||
case STYLE_RANGE_PANE:
|
case STYLE_RANGE_PANE:
|
||||||
case STYLE_RANGE_WINDOW:
|
case STYLE_RANGE_WINDOW:
|
||||||
@@ -719,7 +720,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
|||||||
int focus_start = -1, focus_end = -1;
|
int focus_start = -1, focus_end = -1;
|
||||||
int list_state = -1, fill = -1, even;
|
int list_state = -1, fill = -1, even;
|
||||||
enum style_align list_align = STYLE_ALIGN_DEFAULT;
|
enum style_align list_align = STYLE_ALIGN_DEFAULT;
|
||||||
struct grid_cell gc, current_default;
|
struct grid_cell gc, current_default, base_default;
|
||||||
struct style sy, saved_sy;
|
struct style sy, saved_sy;
|
||||||
struct utf8_data *ud = &sy.gc.data;
|
struct utf8_data *ud = &sy.gc.data;
|
||||||
const char *cp, *end;
|
const char *cp, *end;
|
||||||
@@ -729,7 +730,9 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
|||||||
struct format_ranges frs;
|
struct format_ranges frs;
|
||||||
struct style_range *sr;
|
struct style_range *sr;
|
||||||
|
|
||||||
|
memcpy(&base_default, base, sizeof base_default);
|
||||||
memcpy(¤t_default, base, sizeof current_default);
|
memcpy(¤t_default, base, sizeof current_default);
|
||||||
|
base = &base_default;
|
||||||
style_set(&sy, ¤t_default);
|
style_set(&sy, ¤t_default);
|
||||||
TAILQ_INIT(&frs);
|
TAILQ_INIT(&frs);
|
||||||
log_debug("%s: %s", __func__, expanded);
|
log_debug("%s: %s", __func__, expanded);
|
||||||
@@ -847,6 +850,12 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
|||||||
} else if (sy.default_type == STYLE_DEFAULT_POP) {
|
} else if (sy.default_type == STYLE_DEFAULT_POP) {
|
||||||
memcpy(¤t_default, base, sizeof current_default);
|
memcpy(¤t_default, base, sizeof current_default);
|
||||||
sy.default_type = STYLE_DEFAULT_BASE;
|
sy.default_type = STYLE_DEFAULT_BASE;
|
||||||
|
} else if (sy.default_type == STYLE_DEFAULT_SET) {
|
||||||
|
memcpy(&base_default, &saved_sy.gc,
|
||||||
|
sizeof base_default);
|
||||||
|
memcpy(¤t_default, &saved_sy.gc,
|
||||||
|
sizeof current_default);
|
||||||
|
sy.default_type = STYLE_DEFAULT_BASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the list state. */
|
/* Check the list state. */
|
||||||
@@ -1057,6 +1066,10 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
|||||||
log_debug("%s: range user|%u at %u-%u", __func__,
|
log_debug("%s: range user|%u at %u-%u", __func__,
|
||||||
sr->argument, sr->start, sr->end);
|
sr->argument, sr->start, sr->end);
|
||||||
break;
|
break;
|
||||||
|
case STYLE_RANGE_CONTROL:
|
||||||
|
log_debug("%s: range control|%u at %u-%u", __func__,
|
||||||
|
sr->argument, sr->start, sr->end);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
format_free_range(&frs, fr);
|
format_free_range(&frs, fr);
|
||||||
}
|
}
|
||||||
@@ -1096,8 +1109,6 @@ format_width(const char *expanded)
|
|||||||
more = utf8_append(&ud, *cp);
|
more = utf8_append(&ud, *cp);
|
||||||
if (more == UTF8_DONE)
|
if (more == UTF8_DONE)
|
||||||
width += ud.width;
|
width += ud.width;
|
||||||
else
|
|
||||||
cp -= ud.have;
|
|
||||||
} else if (*cp > 0x1f && *cp < 0x7f) {
|
} else if (*cp > 0x1f && *cp < 0x7f) {
|
||||||
width++;
|
width++;
|
||||||
cp++;
|
cp++;
|
||||||
@@ -1110,7 +1121,7 @@ format_width(const char *expanded)
|
|||||||
/*
|
/*
|
||||||
* Trim on the left, taking #[] into account. Note, we copy the whole set of
|
* Trim on the left, taking #[] into account. Note, we copy the whole set of
|
||||||
* unescaped #s, but only add their escaped size to width. This is because the
|
* unescaped #s, but only add their escaped size to width. This is because the
|
||||||
* format_draw function will actually do the escaping when it runs
|
* format_draw function will actually do the escaping.
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
format_trim_left(const char *expanded, u_int limit)
|
format_trim_left(const char *expanded, u_int limit)
|
||||||
|
|||||||
83
fuzz/cmd-parse-fuzzer.c
Normal file
83
fuzz/cmd-parse-fuzzer.c
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026 David Korczynski <david@adalogics.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fuzz the tmux command parser (cmd_parse_from_buffer).
|
||||||
|
*
|
||||||
|
* This exercises:
|
||||||
|
* - cmd-parse.y (yacc grammar, lexer, command building)
|
||||||
|
* - cmd.c (command lookup and validation)
|
||||||
|
* - arguments.c (argument parsing and flag handling)
|
||||||
|
* - cmd-find.c (target resolution)
|
||||||
|
* - options.c (option name lookups during parsing)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tmux.h"
|
||||||
|
|
||||||
|
struct event_base *libevent;
|
||||||
|
|
||||||
|
int
|
||||||
|
LLVMFuzzerTestOneInput(const u_char *data, size_t size)
|
||||||
|
{
|
||||||
|
struct cmd_parse_input pi;
|
||||||
|
struct cmd_parse_result *pr;
|
||||||
|
|
||||||
|
if (size > 2048 || size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memset(&pi, 0, sizeof pi);
|
||||||
|
pi.flags = CMD_PARSE_QUIET;
|
||||||
|
|
||||||
|
pr = cmd_parse_from_buffer(data, size, &pi);
|
||||||
|
switch (pr->status) {
|
||||||
|
case CMD_PARSE_SUCCESS:
|
||||||
|
cmd_list_free(pr->cmdlist);
|
||||||
|
break;
|
||||||
|
case CMD_PARSE_ERROR:
|
||||||
|
free(pr->error);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv)
|
||||||
|
{
|
||||||
|
const struct options_table_entry *oe;
|
||||||
|
|
||||||
|
global_environ = environ_create();
|
||||||
|
global_options = options_create(NULL);
|
||||||
|
global_s_options = options_create(NULL);
|
||||||
|
global_w_options = options_create(NULL);
|
||||||
|
for (oe = options_table; oe->name != NULL; oe++) {
|
||||||
|
if (oe->scope & OPTIONS_TABLE_SERVER)
|
||||||
|
options_default(global_options, oe);
|
||||||
|
if (oe->scope & OPTIONS_TABLE_SESSION)
|
||||||
|
options_default(global_s_options, oe);
|
||||||
|
if (oe->scope & OPTIONS_TABLE_WINDOW)
|
||||||
|
options_default(global_w_options, oe);
|
||||||
|
}
|
||||||
|
libevent = osdep_event_init();
|
||||||
|
socket_path = xstrdup("dummy");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
133
fuzz/cmd-parse-fuzzer.dict
Normal file
133
fuzz/cmd-parse-fuzzer.dict
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
# tmux command names
|
||||||
|
"set-option"
|
||||||
|
"bind-key"
|
||||||
|
"unbind-key"
|
||||||
|
"send-keys"
|
||||||
|
"new-session"
|
||||||
|
"new-window"
|
||||||
|
"split-window"
|
||||||
|
"select-window"
|
||||||
|
"select-pane"
|
||||||
|
"kill-pane"
|
||||||
|
"kill-window"
|
||||||
|
"kill-session"
|
||||||
|
"kill-server"
|
||||||
|
"list-sessions"
|
||||||
|
"list-windows"
|
||||||
|
"list-panes"
|
||||||
|
"list-keys"
|
||||||
|
"list-buffers"
|
||||||
|
"list-clients"
|
||||||
|
"list-commands"
|
||||||
|
"attach-session"
|
||||||
|
"detach-client"
|
||||||
|
"switch-client"
|
||||||
|
"rename-session"
|
||||||
|
"rename-window"
|
||||||
|
"resize-pane"
|
||||||
|
"resize-window"
|
||||||
|
"display-message"
|
||||||
|
"display-menu"
|
||||||
|
"display-popup"
|
||||||
|
"display-panes"
|
||||||
|
"copy-mode"
|
||||||
|
"paste-buffer"
|
||||||
|
"capture-pane"
|
||||||
|
"save-buffer"
|
||||||
|
"load-buffer"
|
||||||
|
"set-buffer"
|
||||||
|
"delete-buffer"
|
||||||
|
"show-buffer"
|
||||||
|
"choose-buffer"
|
||||||
|
"choose-tree"
|
||||||
|
"choose-client"
|
||||||
|
"if-shell"
|
||||||
|
"run-shell"
|
||||||
|
"source-file"
|
||||||
|
"command-prompt"
|
||||||
|
"confirm-before"
|
||||||
|
"pipe-pane"
|
||||||
|
"wait-for"
|
||||||
|
"set-environment"
|
||||||
|
"show-environment"
|
||||||
|
"set-hook"
|
||||||
|
"show-hooks"
|
||||||
|
"show-messages"
|
||||||
|
"show-options"
|
||||||
|
"set-window-option"
|
||||||
|
"show-window-options"
|
||||||
|
"clear-history"
|
||||||
|
"clock-mode"
|
||||||
|
"find-window"
|
||||||
|
"join-pane"
|
||||||
|
"move-pane"
|
||||||
|
"break-pane"
|
||||||
|
"swap-pane"
|
||||||
|
"swap-window"
|
||||||
|
"move-window"
|
||||||
|
"link-window"
|
||||||
|
"unlink-window"
|
||||||
|
"rotate-window"
|
||||||
|
"next-window"
|
||||||
|
"previous-window"
|
||||||
|
"last-window"
|
||||||
|
"last-pane"
|
||||||
|
"next-layout"
|
||||||
|
"previous-layout"
|
||||||
|
"select-layout"
|
||||||
|
"customize-mode"
|
||||||
|
"refresh-client"
|
||||||
|
"suspend-client"
|
||||||
|
"lock-client"
|
||||||
|
"lock-server"
|
||||||
|
"lock-session"
|
||||||
|
"respawn-pane"
|
||||||
|
"respawn-window"
|
||||||
|
"start-server"
|
||||||
|
"server-access"
|
||||||
|
"send-prefix"
|
||||||
|
"clear-prompt-history"
|
||||||
|
"show-prompt-history"
|
||||||
|
|
||||||
|
# Common flags and syntax
|
||||||
|
"-t"
|
||||||
|
"-s"
|
||||||
|
"-g"
|
||||||
|
"-w"
|
||||||
|
"-p"
|
||||||
|
"-a"
|
||||||
|
"-o"
|
||||||
|
"-q"
|
||||||
|
"-u"
|
||||||
|
"-F"
|
||||||
|
"-f"
|
||||||
|
"-b"
|
||||||
|
"-d"
|
||||||
|
"-e"
|
||||||
|
"-n"
|
||||||
|
"-r"
|
||||||
|
|
||||||
|
# Targets and option names
|
||||||
|
"status"
|
||||||
|
"default"
|
||||||
|
"mouse"
|
||||||
|
"on"
|
||||||
|
"off"
|
||||||
|
"vi"
|
||||||
|
"emacs"
|
||||||
|
"set -g"
|
||||||
|
"set -s"
|
||||||
|
"setw"
|
||||||
|
"bind"
|
||||||
|
"unbind"
|
||||||
|
|
||||||
|
# Syntax elements
|
||||||
|
"{"
|
||||||
|
"}"
|
||||||
|
";"
|
||||||
|
"#{"
|
||||||
|
"%if"
|
||||||
|
"%elif"
|
||||||
|
"%else"
|
||||||
|
"%endif"
|
||||||
|
"%hidden"
|
||||||
2
fuzz/cmd-parse-fuzzer.options
Normal file
2
fuzz/cmd-parse-fuzzer.options
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[libfuzzer]
|
||||||
|
max_len = 2048
|
||||||
88
fuzz/format-fuzzer.c
Normal file
88
fuzz/format-fuzzer.c
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026 David Korczynski <david@adalogics.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fuzz the tmux format string expander (format_expand).
|
||||||
|
*
|
||||||
|
* This exercises:
|
||||||
|
* - format.c (format parsing, modifier chains, conditionals, math, regex)
|
||||||
|
* - colour.c (colour name and RGB parsing within formats)
|
||||||
|
* - utf8.c (UTF-8 width calculations in format padding)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tmux.h"
|
||||||
|
|
||||||
|
struct event_base *libevent;
|
||||||
|
|
||||||
|
int
|
||||||
|
LLVMFuzzerTestOneInput(const u_char *data, size_t size)
|
||||||
|
{
|
||||||
|
struct format_tree *ft;
|
||||||
|
char *buf, *expanded;
|
||||||
|
|
||||||
|
if (size > 2048 || size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Null-terminate the input for format_expand. */
|
||||||
|
buf = malloc(size + 1);
|
||||||
|
if (buf == NULL)
|
||||||
|
return 0;
|
||||||
|
memcpy(buf, data, size);
|
||||||
|
buf[size] = '\0';
|
||||||
|
|
||||||
|
ft = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
|
||||||
|
format_add(ft, "session_name", "%s", "fuzz-session");
|
||||||
|
format_add(ft, "window_index", "%d", 0);
|
||||||
|
format_add(ft, "window_name", "%s", "fuzz-window");
|
||||||
|
format_add(ft, "pane_index", "%d", 0);
|
||||||
|
format_add(ft, "pane_id", "%s", "%%0");
|
||||||
|
format_add(ft, "host", "%s", "fuzzhost");
|
||||||
|
format_add(ft, "pane_width", "%d", 80);
|
||||||
|
format_add(ft, "pane_height", "%d", 25);
|
||||||
|
|
||||||
|
expanded = format_expand(ft, buf);
|
||||||
|
free(expanded);
|
||||||
|
format_free(ft);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv)
|
||||||
|
{
|
||||||
|
const struct options_table_entry *oe;
|
||||||
|
|
||||||
|
global_environ = environ_create();
|
||||||
|
global_options = options_create(NULL);
|
||||||
|
global_s_options = options_create(NULL);
|
||||||
|
global_w_options = options_create(NULL);
|
||||||
|
for (oe = options_table; oe->name != NULL; oe++) {
|
||||||
|
if (oe->scope & OPTIONS_TABLE_SERVER)
|
||||||
|
options_default(global_options, oe);
|
||||||
|
if (oe->scope & OPTIONS_TABLE_SESSION)
|
||||||
|
options_default(global_s_options, oe);
|
||||||
|
if (oe->scope & OPTIONS_TABLE_WINDOW)
|
||||||
|
options_default(global_w_options, oe);
|
||||||
|
}
|
||||||
|
libevent = osdep_event_init();
|
||||||
|
socket_path = xstrdup("dummy");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
71
fuzz/format-fuzzer.dict
Normal file
71
fuzz/format-fuzzer.dict
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# Format expansion syntax
|
||||||
|
"#{"
|
||||||
|
"}"
|
||||||
|
"#{?"
|
||||||
|
"#{=="
|
||||||
|
"#{!="
|
||||||
|
"#{<"
|
||||||
|
"#{>"
|
||||||
|
"#{m:"
|
||||||
|
"#{C:"
|
||||||
|
"#{s/"
|
||||||
|
"#{t:"
|
||||||
|
"#{T:"
|
||||||
|
"#{E:"
|
||||||
|
"#{S:"
|
||||||
|
"#{W:"
|
||||||
|
"#{P:"
|
||||||
|
"##"
|
||||||
|
|
||||||
|
# Common format modifiers
|
||||||
|
"b:"
|
||||||
|
"d:"
|
||||||
|
"q:"
|
||||||
|
"l:"
|
||||||
|
"e:"
|
||||||
|
"t:"
|
||||||
|
"p:"
|
||||||
|
"w:"
|
||||||
|
"n:"
|
||||||
|
"a:"
|
||||||
|
"=:"
|
||||||
|
"||"
|
||||||
|
"&&"
|
||||||
|
","
|
||||||
|
"#{e|"
|
||||||
|
"#{p-1:"
|
||||||
|
"#{=/10/...:"
|
||||||
|
|
||||||
|
# Format variables
|
||||||
|
"session_name"
|
||||||
|
"window_index"
|
||||||
|
"window_name"
|
||||||
|
"pane_index"
|
||||||
|
"pane_id"
|
||||||
|
"host"
|
||||||
|
"pane_width"
|
||||||
|
"pane_height"
|
||||||
|
"pane_current_command"
|
||||||
|
"pane_pid"
|
||||||
|
"session_id"
|
||||||
|
"window_id"
|
||||||
|
"client_name"
|
||||||
|
"version"
|
||||||
|
"line"
|
||||||
|
|
||||||
|
# Conditionals
|
||||||
|
"#{?pane_active,"
|
||||||
|
",}"
|
||||||
|
"#{?#{==:"
|
||||||
|
|
||||||
|
# Math and comparison
|
||||||
|
"#{e|+:"
|
||||||
|
"#{e|-:"
|
||||||
|
"#{e|*:"
|
||||||
|
"#{e|/:"
|
||||||
|
"#{e|%:"
|
||||||
|
|
||||||
|
# Nested
|
||||||
|
"#{="
|
||||||
|
"#{"
|
||||||
|
"#{l:"
|
||||||
2
fuzz/format-fuzzer.options
Normal file
2
fuzz/format-fuzzer.options
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[libfuzzer]
|
||||||
|
max_len = 2048
|
||||||
@@ -44,7 +44,7 @@ LLVMFuzzerTestOneInput(const u_char *data, size_t size)
|
|||||||
w = window_create(PANE_WIDTH, PANE_HEIGHT, 0, 0);
|
w = window_create(PANE_WIDTH, PANE_HEIGHT, 0, 0);
|
||||||
wp = window_add_pane(w, NULL, 0, 0);
|
wp = window_add_pane(w, NULL, 0, 0);
|
||||||
bufferevent_pair_new(libevent, BEV_OPT_CLOSE_ON_FREE, vpty);
|
bufferevent_pair_new(libevent, BEV_OPT_CLOSE_ON_FREE, vpty);
|
||||||
wp->ictx = input_init(wp, vpty[0], NULL);
|
wp->ictx = input_init(wp, vpty[0], NULL, NULL);
|
||||||
window_add_ref(w, __func__);
|
window_add_ref(w, __func__);
|
||||||
|
|
||||||
wp->fd = open("/dev/null", O_WRONLY);
|
wp->fd = open("/dev/null", O_WRONLY);
|
||||||
|
|||||||
79
fuzz/style-fuzzer.c
Normal file
79
fuzz/style-fuzzer.c
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026 David Korczynski <david@adalogics.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fuzz the tmux style parser (style_parse).
|
||||||
|
*
|
||||||
|
* This exercises:
|
||||||
|
* - style.c (style string parsing, alignment, ranges)
|
||||||
|
* - colour.c (colour name, RGB, and indexed colour parsing)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tmux.h"
|
||||||
|
|
||||||
|
struct event_base *libevent;
|
||||||
|
|
||||||
|
int
|
||||||
|
LLVMFuzzerTestOneInput(const u_char *data, size_t size)
|
||||||
|
{
|
||||||
|
struct style sy;
|
||||||
|
struct grid_cell gc;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
if (size > 512 || size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Null-terminate the input for style_parse. */
|
||||||
|
buf = malloc(size + 1);
|
||||||
|
if (buf == NULL)
|
||||||
|
return 0;
|
||||||
|
memcpy(buf, data, size);
|
||||||
|
buf[size] = '\0';
|
||||||
|
|
||||||
|
memset(&gc, 0, sizeof gc);
|
||||||
|
style_set(&sy, &gc);
|
||||||
|
|
||||||
|
style_parse(&sy, &gc, buf);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv)
|
||||||
|
{
|
||||||
|
const struct options_table_entry *oe;
|
||||||
|
|
||||||
|
global_environ = environ_create();
|
||||||
|
global_options = options_create(NULL);
|
||||||
|
global_s_options = options_create(NULL);
|
||||||
|
global_w_options = options_create(NULL);
|
||||||
|
for (oe = options_table; oe->name != NULL; oe++) {
|
||||||
|
if (oe->scope & OPTIONS_TABLE_SERVER)
|
||||||
|
options_default(global_options, oe);
|
||||||
|
if (oe->scope & OPTIONS_TABLE_SESSION)
|
||||||
|
options_default(global_s_options, oe);
|
||||||
|
if (oe->scope & OPTIONS_TABLE_WINDOW)
|
||||||
|
options_default(global_w_options, oe);
|
||||||
|
}
|
||||||
|
libevent = osdep_event_init();
|
||||||
|
socket_path = xstrdup("dummy");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user