mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-04-19 14:51:13 -03:00
Compare commits
1528 Commits
Integratio
...
Integratio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54360d8cfe | ||
|
|
0b0d0e7799 | ||
|
|
c9c311fbdb | ||
|
|
e4ce5ca24f | ||
|
|
01fb830bf5 | ||
|
|
c18614552d | ||
|
|
9701d5cc7b | ||
|
|
a5f6382d77 | ||
|
|
b2f047421d | ||
|
|
dfe7813c02 | ||
|
|
ddbf63c46f | ||
|
|
c8fe0e53dd | ||
|
|
7bcae09674 | ||
|
|
9f23f619c9 | ||
|
|
070ef6fd5b | ||
|
|
5a8be61954 | ||
|
|
7fdbbe0711 | ||
|
|
8af6bb4436 | ||
|
|
31432c3535 | ||
|
|
e9543617f6 | ||
|
|
9c85dce863 | ||
|
|
bf3466d82c | ||
|
|
3eb7a8fa09 | ||
|
|
dcb39af8c0 | ||
|
|
8a2d6a9752 | ||
|
|
cc31cda835 | ||
|
|
b560daac21 | ||
|
|
8a7b30d3f0 | ||
|
|
d474368ea5 | ||
|
|
7e962d6f22 | ||
|
|
a26f68d63f | ||
|
|
bff6a6e66a | ||
|
|
f490b56378 | ||
|
|
dc6b538f56 | ||
|
|
4f397e86d7 | ||
|
|
d5ca88d42d | ||
|
|
f48fec31d6 | ||
|
|
0f65d9306b | ||
|
|
bb47dfcabc | ||
|
|
170a5ea31c | ||
|
|
4f95c4b8ac | ||
|
|
36352c0370 | ||
|
|
6d322dff73 | ||
|
|
fe8727fb71 | ||
|
|
44baf0f9bd | ||
|
|
4acfdcb0a0 | ||
|
|
e8ed45ecd3 | ||
|
|
3c0de01c07 | ||
|
|
1d418365b5 | ||
|
|
a3d0ea5c7f | ||
|
|
d35cbb6594 | ||
|
|
3663726689 | ||
|
|
cda415cb5d | ||
|
|
36f320598e | ||
|
|
d8497f0f1e | ||
|
|
f464704884 | ||
|
|
ea3e144f2d | ||
|
|
14efcb7cc5 | ||
|
|
4ffc6e02b7 | ||
|
|
f33ece11ac | ||
|
|
92e14d7e4a | ||
|
|
a5034874ab | ||
|
|
37c4247cb7 | ||
|
|
c07c98ac05 | ||
|
|
851e449347 | ||
|
|
213ef3ee56 | ||
|
|
30e56c0237 | ||
|
|
5d4fffcae4 | ||
|
|
8d40bf325d | ||
|
|
488a09fffb | ||
|
|
22558f9e7b | ||
|
|
b71aa8f9e8 | ||
|
|
8b9102d9fe | ||
|
|
4e1226a313 | ||
|
|
91a311c156 | ||
|
|
7fd3079bb6 | ||
|
|
f7f39b8c90 | ||
|
|
d389b22afc | ||
|
|
17f5727e7e | ||
|
|
61388cff02 | ||
|
|
d2739f10e1 | ||
|
|
a863f74fc4 | ||
|
|
41bf002049 | ||
|
|
632a209685 | ||
|
|
ce6e9b52ce | ||
|
|
0c23b5652a | ||
|
|
40a83e4018 | ||
|
|
53f1ebaf6b | ||
|
|
386f2bdcf4 | ||
|
|
c5b17b5310 | ||
|
|
36fe172932 | ||
|
|
94aeb47f63 | ||
|
|
ce1c9f3a65 | ||
|
|
45ae726d4f | ||
|
|
cd84587c3a | ||
|
|
c0c2e1d4fa | ||
|
|
d17f2585fa | ||
|
|
b05c09429d | ||
|
|
7ec205d59c | ||
|
|
b485d95808 | ||
|
|
eeea3f3b3c | ||
|
|
ca929e088e | ||
|
|
92dd6de73c | ||
|
|
01fa31f313 | ||
|
|
662ba60d63 | ||
|
|
f843eb3d31 | ||
|
|
e9b5505169 | ||
|
|
c2a8de4873 | ||
|
|
503edf2d49 | ||
|
|
4c34ba9959 | ||
|
|
204e79105a | ||
|
|
98470ab608 | ||
|
|
93bea5b321 | ||
|
|
2c8bc05826 | ||
|
|
8b1625be2b | ||
|
|
d71b97c2cf | ||
|
|
76c73aa8ce | ||
|
|
02ba7933e0 | ||
|
|
be0bd999ad | ||
|
|
92e3a3c8ef | ||
|
|
96ebfaaf87 | ||
|
|
30b71fbb78 | ||
|
|
fc3cd77c2f | ||
|
|
22c20f36cb | ||
|
|
46ab1a155c | ||
|
|
29b9e6705a | ||
|
|
ed7bf83b56 | ||
|
|
0a6dc2addb | ||
|
|
05b52eaa0b | ||
|
|
e14ae90cc8 | ||
|
|
06c658dd5e | ||
|
|
85cd372a4e | ||
|
|
f9115b5ef1 | ||
|
|
9d69f44550 | ||
|
|
c57b30cba1 | ||
|
|
bb754c2085 | ||
|
|
f7c6426b21 | ||
|
|
90e535f66f | ||
|
|
af95813514 | ||
|
|
82b298dcc5 | ||
|
|
ae32d0288b | ||
|
|
b17ebb4551 | ||
|
|
6faa2f9866 | ||
|
|
0335921c3c | ||
|
|
af0a2add10 | ||
|
|
87a532f533 | ||
|
|
fa837a2e4a | ||
|
|
f0125734d0 | ||
|
|
c0c8fffd50 | ||
|
|
2822dfc92d | ||
|
|
87fd9bca02 | ||
|
|
3d6cb59b31 | ||
|
|
6936e64b34 | ||
|
|
f78f51e2a7 | ||
|
|
578e4e8207 | ||
|
|
f7daa5884a | ||
|
|
f0e884075c | ||
|
|
363fa0a598 | ||
|
|
9f6ba5db7a | ||
|
|
cac3b239e3 | ||
|
|
b0716885bc | ||
|
|
a0623e870b | ||
|
|
7ce042ccff | ||
|
|
30f26b62e6 | ||
|
|
e89057b70c | ||
|
|
1bc887cd9f | ||
|
|
6b1801063b | ||
|
|
b895a50bb2 | ||
|
|
4b740d1fb6 | ||
|
|
e54b30d138 | ||
|
|
4b2d1c9acf | ||
|
|
8ca3adaa91 | ||
|
|
2345bea5c1 | ||
|
|
443fc66048 | ||
|
|
eeb42f5e54 | ||
|
|
35bee00802 | ||
|
|
3702616b60 | ||
|
|
3e30857e99 | ||
|
|
f37995c676 | ||
|
|
5328d6b83c | ||
|
|
172541c689 | ||
|
|
cfefaaf4ee | ||
|
|
0893134543 | ||
|
|
4f596536f5 | ||
|
|
2047351723 | ||
|
|
476ffe12f6 | ||
|
|
a872d9c299 | ||
|
|
b0184f1476 | ||
|
|
cb22354f83 | ||
|
|
4d04125fa1 | ||
|
|
ecaba64056 | ||
|
|
4906a5f390 | ||
|
|
f76e620be8 | ||
|
|
bfee664af3 | ||
|
|
4e2d2c125c | ||
|
|
f25d5a0f52 | ||
|
|
6d81e2b8a4 | ||
|
|
df0d0ae80a | ||
|
|
044efef577 | ||
|
|
8f0ea07eab | ||
|
|
b93ac10dda | ||
|
|
c99386a375 | ||
|
|
5dd959070c | ||
|
|
df10ffab9c | ||
|
|
9b5625a66b | ||
|
|
6f53709b65 | ||
|
|
9daffc7080 | ||
|
|
790968120d | ||
|
|
386c698d45 | ||
|
|
f3e93f0666 | ||
|
|
2a119ff082 | ||
|
|
2dbc7ddcb8 | ||
|
|
710addde16 | ||
|
|
ef5d3232e4 | ||
|
|
dc02587ac4 | ||
|
|
077a0e1b47 | ||
|
|
816857ead2 | ||
|
|
1248642996 | ||
|
|
a5e31cb0f1 | ||
|
|
27c88c870b | ||
|
|
67a594c12c | ||
|
|
e46978fedb | ||
|
|
7e0e745958 | ||
|
|
43515e1298 | ||
|
|
ccd62ff44b | ||
|
|
744da2cab2 | ||
|
|
b36414152b | ||
|
|
93b9e7443e | ||
|
|
b1f576deae | ||
|
|
01f09cf4c1 | ||
|
|
d68320a3c6 | ||
|
|
00cb9ce80a | ||
|
|
afa266a7ea | ||
|
|
3f9bd72bca | ||
|
|
fb845cdb72 | ||
|
|
8277f6a1ba | ||
|
|
d7604dcc99 | ||
|
|
71e1e38426 | ||
|
|
b77e2a67f8 | ||
|
|
e75fc8452f | ||
|
|
6c8ecab44b | ||
|
|
5da3d2f27b | ||
|
|
d51a1e4fe2 | ||
|
|
ee26eafc25 | ||
|
|
acfd380176 | ||
|
|
3a08a24259 | ||
|
|
0a51b17716 | ||
|
|
b12c413c28 | ||
|
|
375de96016 | ||
|
|
49008d7a1c | ||
|
|
e1ab6494cd | ||
|
|
5afd939f3e | ||
|
|
644ea82c2f | ||
|
|
450d4be88f | ||
|
|
3669805627 | ||
|
|
46fba342db | ||
|
|
5eedb0ee9c | ||
|
|
325f047803 | ||
|
|
c76f896f69 | ||
|
|
88688d02b2 | ||
|
|
ec292ec51b | ||
|
|
3a7a6f16ef | ||
|
|
3d0ea5fe79 | ||
|
|
d252704fdb | ||
|
|
dfe363c945 | ||
|
|
799d8ddfc4 | ||
|
|
99351fcb44 | ||
|
|
9bd5257dda | ||
|
|
10ae6d8b26 | ||
|
|
2fa4bd8fd7 | ||
|
|
3468fbc605 | ||
|
|
34ca8fd213 | ||
|
|
8140f74d75 | ||
|
|
1d2fff9686 | ||
|
|
b53f42970c | ||
|
|
4fbc476b19 | ||
|
|
9aad3781fb | ||
|
|
23ea77be76 | ||
|
|
51e25e5a8d | ||
|
|
113145e52a | ||
|
|
f9355a0b86 | ||
|
|
eb0d04d7ff | ||
|
|
b2be50f081 | ||
|
|
190fb4a665 | ||
|
|
20f28c2ef3 | ||
|
|
e00c70c5fe | ||
|
|
6b99af05a5 | ||
|
|
2df263fa26 | ||
|
|
06003f82ae | ||
|
|
f08ac969e9 | ||
|
|
fb3c839a15 | ||
|
|
e3187b2361 | ||
|
|
1e27910b60 | ||
|
|
09291735e6 | ||
|
|
512506f0f9 | ||
|
|
8cb560dc7e | ||
|
|
b2b327fec4 | ||
|
|
013506dfd5 | ||
|
|
bd2b7764c7 | ||
|
|
ba12bcad33 | ||
|
|
8b06d2ad66 | ||
|
|
a6cd12a7f1 | ||
|
|
6e0521e23f | ||
|
|
d895f876b4 | ||
|
|
bb6ce9d142 | ||
|
|
0ef811f8b8 | ||
|
|
7c6a3e7026 | ||
|
|
34a2ce2646 | ||
|
|
9abbc5f06c | ||
|
|
3ca5ca77fa | ||
|
|
733e960c11 | ||
|
|
14c7cfa84b | ||
|
|
2f0cb2a32b | ||
|
|
bd33e11599 | ||
|
|
3c4e322ec1 | ||
|
|
755d0089f3 | ||
|
|
ee599bdd5c | ||
|
|
a8d911bd39 | ||
|
|
85c346d6ad | ||
|
|
7a343a8665 | ||
|
|
40b4732f94 | ||
|
|
3cd1ef23ab | ||
|
|
efbbe5129f | ||
|
|
8326bdc9af | ||
|
|
ceedc6f345 | ||
|
|
f839282ac0 | ||
|
|
e99c6104fe | ||
|
|
d68c37b726 | ||
|
|
e3ac6d3fe2 | ||
|
|
b7c96417d1 | ||
|
|
9a442673e6 | ||
|
|
0fb434d372 | ||
|
|
163e16f546 | ||
|
|
9b4938e2c2 | ||
|
|
67f6a48a78 | ||
|
|
89c96c2114 | ||
|
|
52d8fdccff | ||
|
|
de076f00f8 | ||
|
|
30065d101b | ||
|
|
5a1a25bfbe | ||
|
|
cf393a264d | ||
|
|
70d798f6ed | ||
|
|
ca15a22cd1 | ||
|
|
86d9e5251a | ||
|
|
417d53a58f | ||
|
|
497b3f51c8 | ||
|
|
080e3efd1b | ||
|
|
71cf516f58 | ||
|
|
08fc19484f | ||
|
|
f966248f16 | ||
|
|
e597df70d7 | ||
|
|
c79e9c7d4e | ||
|
|
75e7784f18 | ||
|
|
8e7f0e781d | ||
|
|
528b9fdcf2 | ||
|
|
edee3e5eb2 | ||
|
|
c9caee37b4 | ||
|
|
bc693bd4e0 | ||
|
|
dff384e42d | ||
|
|
cd422e5d78 | ||
|
|
ca6cda20a3 | ||
|
|
3d8e8a8715 | ||
|
|
af0f9e5308 | ||
|
|
88cb616c1b | ||
|
|
63120a9962 | ||
|
|
807dc82a75 | ||
|
|
1fb4cc0e76 | ||
|
|
6a36144587 | ||
|
|
0045b46af8 | ||
|
|
47fbfdca3e | ||
|
|
772e35562a | ||
|
|
e42f593553 | ||
|
|
9642fcb589 | ||
|
|
7e58a3982a | ||
|
|
431589a16a | ||
|
|
cbee315b1b | ||
|
|
84b08a4fe3 | ||
|
|
c429a585e4 | ||
|
|
68e167d576 | ||
|
|
262452d0b1 | ||
|
|
7e08679f1b | ||
|
|
dda890cf88 | ||
|
|
44cde9e0e9 | ||
|
|
d7bc20c933 | ||
|
|
d69a68e265 | ||
|
|
534c1287ca | ||
|
|
81dee16d69 | ||
|
|
e5011fbcdf | ||
|
|
0f5bfeead2 | ||
|
|
a47b4b0e95 | ||
|
|
02f578a82d | ||
|
|
dfb4998778 | ||
|
|
ea71f0b610 | ||
|
|
a3e9e179eb | ||
|
|
0f3b4d2bd8 | ||
|
|
ceee1ebfd9 | ||
|
|
046174397b | ||
|
|
a6ec2dc3ed | ||
|
|
6ec83568b5 | ||
|
|
b2a2705df4 | ||
|
|
0d6bdb38e6 | ||
|
|
02cef2da23 | ||
|
|
9c53019d95 | ||
|
|
7a4065eb9f | ||
|
|
13eb302f3c | ||
|
|
6122ae83a6 | ||
|
|
fa78a7101c | ||
|
|
5d680f6dbc | ||
|
|
290e936322 | ||
|
|
ecf4517ffe | ||
|
|
eb834f47ef | ||
|
|
db2c128b24 | ||
|
|
e0a627f99d | ||
|
|
8070cd81d6 | ||
|
|
00291c1c5a | ||
|
|
10661bb024 | ||
|
|
f9edcbbbe2 | ||
|
|
7365b6bd0c | ||
|
|
d66d51f101 | ||
|
|
bc8ec46ef9 | ||
|
|
3a0d417b9e | ||
|
|
7e56d6385e | ||
|
|
db0176b884 | ||
|
|
f63f6e54fa | ||
|
|
7cf6ef675a | ||
|
|
29664c42a0 | ||
|
|
8dc4b0d4b2 | ||
|
|
cb74f0f60e | ||
|
|
d8dd718695 | ||
|
|
4424909801 | ||
|
|
a243580cfa | ||
|
|
693d6879d3 | ||
|
|
ad7e9a8d56 | ||
|
|
d0fdc82fdf | ||
|
|
82c56bc64b | ||
|
|
098f6d01c4 | ||
|
|
4b0f1cf85b | ||
|
|
7ac32e45cb | ||
|
|
8e21d5de92 | ||
|
|
f04644f749 | ||
|
|
7ab65595cb | ||
|
|
2cabcf4ad4 | ||
|
|
20d36f16d3 | ||
|
|
dc58edd521 | ||
|
|
e6d4ac5ee2 | ||
|
|
0ca103686f | ||
|
|
cfe3fc301c | ||
|
|
cbe97ac1a1 | ||
|
|
3cecc1f475 | ||
|
|
9f0c31611c | ||
|
|
d70be18c42 | ||
|
|
1be3fe6633 | ||
|
|
7b17d20099 | ||
|
|
ab1db7ebee | ||
|
|
723d689679 | ||
|
|
cd6a9ee522 | ||
|
|
a5e0555e83 | ||
|
|
1499ade89c | ||
|
|
0310d3bd8c | ||
|
|
02375982df | ||
|
|
5435f60f31 | ||
|
|
b72ed1fa8c | ||
|
|
3a7719015d | ||
|
|
0ee03cbf98 | ||
|
|
67339caa33 | ||
|
|
d77c20b09a | ||
|
|
d910aa15fe | ||
|
|
5d20750aaa | ||
|
|
c4e322d3ad | ||
|
|
222a07e907 | ||
|
|
9d2092bf9f | ||
|
|
4d49c902ac | ||
|
|
65ed22d5a6 | ||
|
|
09f9d71bb2 | ||
|
|
059e11078c | ||
|
|
8829bb1364 | ||
|
|
e30db95baa | ||
|
|
970d895aca | ||
|
|
c9b3220160 | ||
|
|
10575d895d | ||
|
|
67f3c01396 | ||
|
|
536d6cebd9 | ||
|
|
7a97095583 | ||
|
|
f37dafdf52 | ||
|
|
c84137aec8 | ||
|
|
f1dc1cd92b | ||
|
|
41f2344cea | ||
|
|
a965a71079 | ||
|
|
913624cbfa | ||
|
|
220fd418a7 | ||
|
|
5dda908c1f | ||
|
|
b7f45c3783 | ||
|
|
3a6e239437 | ||
|
|
fcbeddc3eb | ||
|
|
7ef40f4e53 | ||
|
|
2fafb13eaa | ||
|
|
90ee810c73 | ||
|
|
1357f5a364 | ||
|
|
9f21e3792a | ||
|
|
0b385f145c | ||
|
|
32a585a52b | ||
|
|
410d92ed61 | ||
|
|
53e865b654 | ||
|
|
57f289850c | ||
|
|
63a851cfd6 | ||
|
|
24d6f6d066 | ||
|
|
db1ec847f9 | ||
|
|
aee9d2c9d7 | ||
|
|
22e0702e8d | ||
|
|
29c38d73a2 | ||
|
|
8d11bb9f86 | ||
|
|
8d6735cb41 | ||
|
|
3d74b160b3 | ||
|
|
2768d2ea06 | ||
|
|
bb11999bf7 | ||
|
|
5bf1b0e5f5 | ||
|
|
3d19b549c8 | ||
|
|
bfb5fec330 | ||
|
|
0d257fd651 | ||
|
|
ebde55f704 | ||
|
|
f23464001f | ||
|
|
0882e0cb95 | ||
|
|
763c620d0b | ||
|
|
2871096f9c | ||
|
|
a918397da2 | ||
|
|
8e88b29eeb | ||
|
|
aaaea44714 | ||
|
|
ffe5736abb | ||
|
|
d79a5a3152 | ||
|
|
ffcfe73299 | ||
|
|
2885c085d8 | ||
|
|
7af9e1f5c5 | ||
|
|
980fb59232 | ||
|
|
9ad3488b5d | ||
|
|
8f420b9272 | ||
|
|
d55b226f19 | ||
|
|
95635a5982 | ||
|
|
91962d8aa2 | ||
|
|
d1208386d2 | ||
|
|
d7a4838a54 | ||
|
|
6d6f67ee67 | ||
|
|
987f7cafd3 | ||
|
|
b883e59ee9 | ||
|
|
79fa4d5c4a | ||
|
|
23de5908cf | ||
|
|
0d5ef3f43e | ||
|
|
2a8309458d | ||
|
|
2418daebf3 | ||
|
|
53c506f109 | ||
|
|
7d1f45e25f | ||
|
|
1bad956633 | ||
|
|
2f51088bfb | ||
|
|
0a40dcdb44 | ||
|
|
6b92fdd18d | ||
|
|
b9848538e3 | ||
|
|
475439fa0b | ||
|
|
8fba36b242 | ||
|
|
8b44358c53 | ||
|
|
dac8483f7e | ||
|
|
46f4819ffa | ||
|
|
c238ad35bd | ||
|
|
309e10e7a2 | ||
|
|
dc470bcad3 | ||
|
|
49d9883b3e | ||
|
|
2606cfe72d | ||
|
|
85e701f422 | ||
|
|
5accc7c6c5 | ||
|
|
60317190bd | ||
|
|
6594c061be | ||
|
|
216a45edee | ||
|
|
7828f2303a | ||
|
|
245be2c2e4 | ||
|
|
14b953e414 | ||
|
|
432c0058a9 | ||
|
|
7c24369454 | ||
|
|
46be5ac468 | ||
|
|
ade6ebf522 | ||
|
|
30ea7cc3f8 | ||
|
|
573b3797a5 | ||
|
|
a0b3b8ac4c | ||
|
|
4d63ebde15 | ||
|
|
9cee3f13a1 | ||
|
|
8dc74de92e | ||
|
|
21fc2decd7 | ||
|
|
9192bf1db5 | ||
|
|
7c2c516353 | ||
|
|
db18449f4c | ||
|
|
44757c81af | ||
|
|
d0aa461587 | ||
|
|
504b32f61b | ||
|
|
6a5d89669e | ||
|
|
e39628bbe9 | ||
|
|
f5dcb6a0cb | ||
|
|
14187f9e3f | ||
|
|
9225b16d12 | ||
|
|
00e32a0909 | ||
|
|
73f2992a2e | ||
|
|
d55113b5b5 | ||
|
|
51468b7646 | ||
|
|
ff1d651415 | ||
|
|
768277a312 | ||
|
|
149e601743 | ||
|
|
a998921f39 | ||
|
|
3daccf3c22 | ||
|
|
c63c88262b | ||
|
|
fbe2cdc3c7 | ||
|
|
b60ef72c3d | ||
|
|
d2e79cf6f6 | ||
|
|
a38d5504ac | ||
|
|
76d24aa1bc | ||
|
|
a7605d584b | ||
|
|
4244a6e6fe | ||
|
|
b055b8440c | ||
|
|
14d7b1a0fa | ||
|
|
3626c39398 | ||
|
|
0d1d324e9f | ||
|
|
c53951b9b3 | ||
|
|
46b819a265 | ||
|
|
4d1e77fcae | ||
|
|
4efd0dfd65 | ||
|
|
100eef4e42 | ||
|
|
59c8800c4d | ||
|
|
1d101ef3d0 | ||
|
|
ac47100a7d | ||
|
|
c1e15ef084 | ||
|
|
01e5ca5c96 | ||
|
|
28228627fc | ||
|
|
8ec81393a3 | ||
|
|
1c6f6df2b3 | ||
|
|
bc6cc4c105 | ||
|
|
4481692037 | ||
|
|
1cdf386822 | ||
|
|
d4b5620bb3 | ||
|
|
4246cfa95c | ||
|
|
22cc0515c9 | ||
|
|
79f342b954 | ||
|
|
49838c768d | ||
|
|
862e0127f6 | ||
|
|
527e5f52ba | ||
|
|
42068931c7 | ||
|
|
e1a706bd77 | ||
|
|
d97c22df2d | ||
|
|
3ad5c7c289 | ||
|
|
fc44cffac5 | ||
|
|
5c8763be0e | ||
|
|
ee44879d4d | ||
|
|
c14bac4284 | ||
|
|
0aa7fd95b8 | ||
|
|
fa53563733 | ||
|
|
835176ef32 | ||
|
|
ed086fb1c8 | ||
|
|
c76d866317 | ||
|
|
9d742a4fa1 | ||
|
|
dc8d31a12a | ||
|
|
8d6b88eb5d | ||
|
|
80250c0729 | ||
|
|
ca912f157e | ||
|
|
716706bd9f | ||
|
|
61a614b612 | ||
|
|
3d6f995a9c | ||
|
|
ea945cc437 | ||
|
|
13d7432368 | ||
|
|
ed8d1040ba | ||
|
|
4f619c966b | ||
|
|
483b798863 | ||
|
|
b19bfc0dd3 | ||
|
|
8b2cf81f17 | ||
|
|
da17420cdf | ||
|
|
08c29727e0 | ||
|
|
45c6ac0208 | ||
|
|
7378871768 | ||
|
|
d3f155d895 | ||
|
|
075811e588 | ||
|
|
aa8840b423 | ||
|
|
58d7c4b388 | ||
|
|
1cd4731c2d | ||
|
|
a897ef0025 | ||
|
|
fb1443a885 | ||
|
|
05a432da32 | ||
|
|
404ab5e9ab | ||
|
|
901652d5c3 | ||
|
|
fde26d4049 | ||
|
|
b32bf22616 | ||
|
|
4bb805b5fe | ||
|
|
52731c480c | ||
|
|
f44ef3ad3f | ||
|
|
54319435f4 | ||
|
|
b064da8d38 | ||
|
|
ba5a55b754 | ||
|
|
bd2b107d37 | ||
|
|
4c84224d06 | ||
|
|
8e19c82e09 | ||
|
|
74d3aa582b | ||
|
|
85b136314b | ||
|
|
09bb713989 | ||
|
|
6466ffe82d | ||
|
|
8fc6011741 | ||
|
|
5092904ea3 | ||
|
|
3e24ae80b3 | ||
|
|
ffad7b0b29 | ||
|
|
d93bbfd486 | ||
|
|
32c241f51b | ||
|
|
690ceeeaa7 | ||
|
|
ea02da35d4 | ||
|
|
cea65599e6 | ||
|
|
6c329e8a83 | ||
|
|
5fa8370c13 | ||
|
|
96a28df018 | ||
|
|
ce41e3468e | ||
|
|
75064ed786 | ||
|
|
e08039a2bd | ||
|
|
108d66211f | ||
|
|
87d5fa054d | ||
|
|
5f4a77a324 | ||
|
|
8a940a2ee7 | ||
|
|
ac68c0c878 | ||
|
|
d5797c5439 | ||
|
|
bc35ca6366 | ||
|
|
d0fdc80725 | ||
|
|
df10b53c0c | ||
|
|
c2f9d60eb1 | ||
|
|
c4c7983497 | ||
|
|
1f06e5f0b9 | ||
|
|
daa217f533 | ||
|
|
e67505bead | ||
|
|
7ebafa53f6 | ||
|
|
e6ad48ea1b | ||
|
|
ba5a22e2ce | ||
|
|
f5241da836 | ||
|
|
8ab980b793 | ||
|
|
dcef1a5593 | ||
|
|
5df8fab463 | ||
|
|
b8817215dc | ||
|
|
375bef4443 | ||
|
|
0e7ab7a7d0 | ||
|
|
413ac86da2 | ||
|
|
f28a1c58f3 | ||
|
|
2f8d0e9aba | ||
|
|
bd4622a0d0 | ||
|
|
0f888ad4e6 | ||
|
|
9aeed0dc06 | ||
|
|
43535cf5a5 | ||
|
|
bf0e91cc97 | ||
|
|
fc78e70d08 | ||
|
|
aefcf544ca | ||
|
|
c93e38380a | ||
|
|
a10a79c6d0 | ||
|
|
0fd3f5c0dd | ||
|
|
61c0ca9dd9 | ||
|
|
e7599fd18c | ||
|
|
8d3eae0d76 | ||
|
|
ba1008b750 | ||
|
|
8558561650 | ||
|
|
f034d8ba3a | ||
|
|
8eb342ad3c | ||
|
|
d7fd0427f3 | ||
|
|
baee807837 | ||
|
|
c2e9cda7b3 | ||
|
|
4aa8fc753f | ||
|
|
635a1e9dd2 | ||
|
|
21e927d24e | ||
|
|
5f849d0264 | ||
|
|
671c0515d4 | ||
|
|
b5b8d9010e | ||
|
|
ea3d9c36a5 | ||
|
|
706bfa70c1 | ||
|
|
8e103c231e | ||
|
|
9569f51e83 | ||
|
|
6431c0de16 | ||
|
|
85799ee86e | ||
|
|
0993141334 | ||
|
|
46840ae375 | ||
|
|
59f0261dba | ||
|
|
7ad6a90ea2 | ||
|
|
574851f092 | ||
|
|
2d5eaed745 | ||
|
|
6adc35c636 | ||
|
|
6c5f923a47 | ||
|
|
d7c690b416 | ||
|
|
8eb9dac4bc | ||
|
|
2ff3a36675 | ||
|
|
e395a0eb69 | ||
|
|
36691df6fe | ||
|
|
790c7f80c7 | ||
|
|
155befe90e | ||
|
|
9347630d1e | ||
|
|
784b438d4a | ||
|
|
d2ae00ca44 | ||
|
|
8477126ae4 | ||
|
|
9c75546724 | ||
|
|
e1e1e558ce | ||
|
|
c37c93fcf6 | ||
|
|
35e282928a | ||
|
|
02f18cae0a | ||
|
|
4ff8e6e781 | ||
|
|
8e8b5a6481 | ||
|
|
200a10e78d | ||
|
|
9e93ddc097 | ||
|
|
3435e94994 | ||
|
|
fd1b7ba529 | ||
|
|
a4642f141f | ||
|
|
8f33b55ccc | ||
|
|
484c1484c9 | ||
|
|
cb6d5d76c8 | ||
|
|
47f1a92cc4 | ||
|
|
0953590cca | ||
|
|
411d573ba9 | ||
|
|
9dd6873e58 | ||
|
|
3f1fc332e7 | ||
|
|
bbf0007c46 | ||
|
|
6fa09e6a70 | ||
|
|
4f5d42858c | ||
|
|
83233ccc5a | ||
|
|
6888c3d604 | ||
|
|
35cee1e39c | ||
|
|
7e014174b8 | ||
|
|
aacdaee6a9 | ||
|
|
0e18e2ba78 | ||
|
|
a148b755a6 | ||
|
|
dfb23c4fce | ||
|
|
d30f8fffc8 | ||
|
|
19dd28e400 | ||
|
|
daf94e14d4 | ||
|
|
2eb518f59c | ||
|
|
0eb3fd6b3f | ||
|
|
6663c73eb0 | ||
|
|
bb5608e920 | ||
|
|
6495bd470d | ||
|
|
7accadc33f | ||
|
|
ad97a122c9 | ||
|
|
516695ff21 | ||
|
|
9d2b53450a | ||
|
|
de1258e09b | ||
|
|
2a4a539d86 | ||
|
|
a81bd697a8 | ||
|
|
2e0205a746 | ||
|
|
168a156e58 | ||
|
|
879ee61a30 | ||
|
|
c2f1df1d4a | ||
|
|
fb0921249f | ||
|
|
1828def866 | ||
|
|
dedc7f6f03 | ||
|
|
de0349399c | ||
|
|
b1b2698a84 | ||
|
|
9f0417b587 | ||
|
|
03460a3928 | ||
|
|
19c13c72f6 | ||
|
|
f20e8420a8 | ||
|
|
a7012648fe | ||
|
|
46b9f263ac | ||
|
|
540bdfcb02 | ||
|
|
6288f89bf9 | ||
|
|
6a16bdb808 | ||
|
|
5e09411340 | ||
|
|
f4c14b69a2 | ||
|
|
b4b52b8234 | ||
|
|
ed4b78918a | ||
|
|
6bee85fefa | ||
|
|
a37d4d809e | ||
|
|
3044697baa | ||
|
|
1e7c3fe709 | ||
|
|
333415f42a | ||
|
|
e3968ba872 | ||
|
|
58d56f91f3 | ||
|
|
0e8a8a7c80 | ||
|
|
fbd53f2da1 | ||
|
|
65aeaab054 | ||
|
|
94c12d84e2 | ||
|
|
a5f5e6c1ef | ||
|
|
61fd8b9861 | ||
|
|
f2246dfb34 | ||
|
|
b41b962336 | ||
|
|
5446841069 | ||
|
|
60bd3c809a | ||
|
|
fb5a8a089e | ||
|
|
9151ec7092 | ||
|
|
3633c51ad8 | ||
|
|
e3970f9cbb | ||
|
|
077757a30b | ||
|
|
211d626152 | ||
|
|
e8aab9183e | ||
|
|
10f3ea0008 | ||
|
|
88a785e321 | ||
|
|
d628fe0dea | ||
|
|
cbd3fa6b01 | ||
|
|
584cca59bf | ||
|
|
6cb48c6380 | ||
|
|
99be3ee96f | ||
|
|
c1c35e0f21 | ||
|
|
d8a497434f | ||
|
|
211829c586 | ||
|
|
2bb7c587f4 | ||
|
|
2187c0a84b | ||
|
|
c359d28b21 | ||
|
|
c1b384e5d3 | ||
|
|
8b67a1b26f | ||
|
|
c79ade9627 | ||
|
|
d61e95e4f9 | ||
|
|
68807f274e | ||
|
|
a805d401b8 | ||
|
|
2f52f073da | ||
|
|
c4cc9f9b8d | ||
|
|
6c401bc587 | ||
|
|
35160db268 | ||
|
|
5b0996fd80 | ||
|
|
585c03db72 | ||
|
|
613739ba07 | ||
|
|
947f659f96 | ||
|
|
8703c5bc00 | ||
|
|
43e1c0a2bf | ||
|
|
99e18d9cef | ||
|
|
718d9baead | ||
|
|
e2f4584220 | ||
|
|
4138073a2f | ||
|
|
1907323afc | ||
|
|
c39b94949b | ||
|
|
31bc88d16f | ||
|
|
5dbf40ca75 | ||
|
|
2d68b25025 | ||
|
|
1767681f9a | ||
|
|
0395c33982 | ||
|
|
83d3c9fc04 | ||
|
|
c184c1a81a | ||
|
|
31a617408f | ||
|
|
a6565bbea8 | ||
|
|
81cdceddd3 | ||
|
|
5b506499c1 | ||
|
|
62b76b26b4 | ||
|
|
b72837a0f4 | ||
|
|
c4f702b7c4 | ||
|
|
00cd01c89e | ||
|
|
eb0d18add4 | ||
|
|
585bdf45c8 | ||
|
|
89206d8654 | ||
|
|
a00e26b109 | ||
|
|
de17bdb130 | ||
|
|
3345f5d0d0 | ||
|
|
28837a8b30 | ||
|
|
96e688ea91 | ||
|
|
52f8707c3e | ||
|
|
b6e058985b | ||
|
|
bc9e3c7546 | ||
|
|
57fcbecb41 | ||
|
|
c4d0612e5c | ||
|
|
992dfcc4ce | ||
|
|
1e6492ef93 | ||
|
|
4c5aa8860a | ||
|
|
adc3b0e122 | ||
|
|
29d06760bc | ||
|
|
218843b9e4 | ||
|
|
25ad8866c9 | ||
|
|
2646d51a0b | ||
|
|
e88bfbc440 | ||
|
|
4e465ee04c | ||
|
|
1d446b74ff | ||
|
|
dae0f63e5b | ||
|
|
0779c89a65 | ||
|
|
b908d0b89b | ||
|
|
cadb5d51ea | ||
|
|
fcdc6a48c0 | ||
|
|
16aa0b93e9 | ||
|
|
158ea98189 | ||
|
|
962f9914c6 | ||
|
|
df8c4ce835 | ||
|
|
1b8face1a3 | ||
|
|
b4a44deb7b | ||
|
|
60a477a303 | ||
|
|
f8da754884 | ||
|
|
1688b2384f | ||
|
|
0c94c2b9e8 | ||
|
|
d3f6c8a694 | ||
|
|
e086e27f98 | ||
|
|
2f5d750393 | ||
|
|
b88e31b3f1 | ||
|
|
7c4f553acc | ||
|
|
4eb6aaf36f | ||
|
|
08edfaeae8 | ||
|
|
8081e9f189 | ||
|
|
0dac245b58 | ||
|
|
c7ba446c23 | ||
|
|
4b2495f28f | ||
|
|
11785c2bf4 | ||
|
|
4b9fece9f4 | ||
|
|
766176443d | ||
|
|
3552d073f6 | ||
|
|
49d3042bd3 | ||
|
|
701d141109 | ||
|
|
870593e345 | ||
|
|
5cf0e918b0 | ||
|
|
d7f38a0802 | ||
|
|
a77ce393ba | ||
|
|
f8ed1d182e | ||
|
|
68fcb790b0 | ||
|
|
8db1a5fae7 | ||
|
|
6bf70c86d2 | ||
|
|
b7d98fa873 | ||
|
|
daafe4ef37 | ||
|
|
ed1919b266 | ||
|
|
fdb2559425 | ||
|
|
ac545940de | ||
|
|
7a8cbcda06 | ||
|
|
8e79da3b2d | ||
|
|
1dac0041d5 | ||
|
|
43728fe7a0 | ||
|
|
e1f988b987 | ||
|
|
03fe30a774 | ||
|
|
c56df11128 | ||
|
|
6027eae1a1 | ||
|
|
bd482898d4 | ||
|
|
4417a6ee34 | ||
|
|
2a4f21cc92 | ||
|
|
8cc213ed4f | ||
|
|
4f519297dd | ||
|
|
4c4020babe | ||
|
|
ef31aa94f8 | ||
|
|
bc3260402a | ||
|
|
c5ed4e5cdf | ||
|
|
92d0d98a24 | ||
|
|
23fabf81d7 | ||
|
|
19112980ee | ||
|
|
8eca775977 | ||
|
|
c3971957ac | ||
|
|
9a7b2b190b | ||
|
|
6f2f0cfce2 | ||
|
|
3a249bb549 | ||
|
|
1a12071a48 | ||
|
|
b7fb11cb7f | ||
|
|
95c30f7a23 | ||
|
|
d5fe5c02a8 | ||
|
|
759b45ad79 | ||
|
|
1363c7468d | ||
|
|
834ebef53c | ||
|
|
bb932a0a0a | ||
|
|
f23c2beb61 | ||
|
|
994aba075d | ||
|
|
979b94e274 | ||
|
|
076ebf8cee | ||
|
|
6eea3992b3 | ||
|
|
6969cfab3d | ||
|
|
1a3bcf63bc | ||
|
|
814cb51eb5 | ||
|
|
d6d3977f3d | ||
|
|
c9ddad94a9 | ||
|
|
172f1e1b5f | ||
|
|
b257e79a07 | ||
|
|
f029e04047 | ||
|
|
6aa2cbe807 | ||
|
|
ad72421b2c | ||
|
|
594b460ba2 | ||
|
|
0a6f62358b | ||
|
|
8c707a4e2f | ||
|
|
7188d94c1b | ||
|
|
836b6bea73 | ||
|
|
8a6f26ff9b | ||
|
|
7143512198 | ||
|
|
5306fce16e | ||
|
|
fb1a7d9d73 | ||
|
|
482cfca84f | ||
|
|
e29d200ba5 | ||
|
|
43c7ababf9 | ||
|
|
baa6971a46 | ||
|
|
aefe084124 | ||
|
|
c68f8f3418 | ||
|
|
aa5291c6bd | ||
|
|
f045d9b143 | ||
|
|
666dcd78ba | ||
|
|
70ee7650f3 | ||
|
|
aa974b58bc | ||
|
|
6c8518dd10 | ||
|
|
346d918555 | ||
|
|
8104854d5d | ||
|
|
b4b5c2188f | ||
|
|
a0eef2663a | ||
|
|
f5dfebb6a3 | ||
|
|
2b7ffca414 | ||
|
|
96b3e1ce1b | ||
|
|
ce719a700c | ||
|
|
4280df3aa2 | ||
|
|
b73bf53bd3 | ||
|
|
d90169e79b | ||
|
|
fea798011b | ||
|
|
f17a71de74 | ||
|
|
0212314479 | ||
|
|
16c34b387f | ||
|
|
d65c63322e | ||
|
|
6943536ef3 | ||
|
|
7322c9c591 | ||
|
|
dfaefb97ff | ||
|
|
0a0acc8a2e | ||
|
|
a8837f537f | ||
|
|
ef67fc7ba0 | ||
|
|
83c0f43b33 | ||
|
|
17672b08c6 | ||
|
|
dc1f2fbb4c | ||
|
|
2d90859cab | ||
|
|
d325b4bf39 | ||
|
|
1d64c480c4 | ||
|
|
9f7334deef | ||
|
|
3dbefd08ad | ||
|
|
1a5d0fc47f | ||
|
|
17b6936f53 | ||
|
|
c5bcc4567e | ||
|
|
ce360bcfe3 | ||
|
|
789657456a | ||
|
|
7b3d93f4a1 | ||
|
|
3868203c76 | ||
|
|
e5bfdcd9a4 | ||
|
|
b7f13b4685 | ||
|
|
c2c4fbf206 | ||
|
|
bf86a92596 | ||
|
|
53fc9a4002 | ||
|
|
a8a9ac0dae | ||
|
|
3b53abecd0 | ||
|
|
3f12f75853 | ||
|
|
917c727619 | ||
|
|
6336288da1 | ||
|
|
3e0ff6db2a | ||
|
|
5db811253e | ||
|
|
e31a93040e | ||
|
|
8e55f7154b | ||
|
|
71d3357b71 | ||
|
|
3eafb3520f | ||
|
|
e50d104399 | ||
|
|
45dfa2d864 | ||
|
|
c2024a6a94 | ||
|
|
32d54e37f7 | ||
|
|
2bbad22248 | ||
|
|
22493c9df8 | ||
|
|
8d97a85834 | ||
|
|
e7d18b96f9 | ||
|
|
1854ef9823 | ||
|
|
c9577394eb | ||
|
|
0918ad6cee | ||
|
|
d3bcee9e2e | ||
|
|
1055864438 | ||
|
|
be0d9d093c | ||
|
|
bb491742ea | ||
|
|
46fbfaaa83 | ||
|
|
09bd938e25 | ||
|
|
d5f3a09ce9 | ||
|
|
036a29acf5 | ||
|
|
3e7dfd7f5e | ||
|
|
f21d826850 | ||
|
|
8e3e286577 | ||
|
|
f4b4e5b41f | ||
|
|
4a05d56337 | ||
|
|
73708061fc | ||
|
|
55abe105ea | ||
|
|
0006d23df8 | ||
|
|
df3da55602 | ||
|
|
13479fbc2a | ||
|
|
226cdc6a28 | ||
|
|
b13f0701a4 | ||
|
|
4c2cc384d2 | ||
|
|
2971887bbd | ||
|
|
b776327b9d | ||
|
|
b7e991c4b7 | ||
|
|
9788566ba4 | ||
|
|
233c443694 | ||
|
|
35bbc1d7b7 | ||
|
|
4e5e04bfda | ||
|
|
c0e8ad6f1f | ||
|
|
3472a39d07 | ||
|
|
9865a8c807 | ||
|
|
35e769d494 | ||
|
|
6e3ea5b2ea | ||
|
|
54f215294f | ||
|
|
f6f982226a | ||
|
|
98b33d7b6b | ||
|
|
86471ac21f | ||
|
|
57e22e87c2 | ||
|
|
0b3406bdc0 | ||
|
|
74cd977566 | ||
|
|
d9d2f61ba6 | ||
|
|
434eabb787 | ||
|
|
e8605cb3ef | ||
|
|
1bdf06836a | ||
|
|
0a99772572 | ||
|
|
2ffb47eba2 | ||
|
|
b208d752e2 | ||
|
|
ec74479d44 | ||
|
|
e75108fc4c | ||
|
|
176e34cf73 | ||
|
|
65415cb761 | ||
|
|
45bf843b03 | ||
|
|
610a5926a8 | ||
|
|
3b0f9911e2 | ||
|
|
55a2945449 | ||
|
|
16061d06a9 | ||
|
|
aeaacedf75 | ||
|
|
bec6d5c174 | ||
|
|
d98b6f2434 | ||
|
|
3ffbf9a7ea | ||
|
|
c481137b40 | ||
|
|
9f0b077295 | ||
|
|
5f2feee680 | ||
|
|
9ecd73d956 | ||
|
|
b9b39f7c31 | ||
|
|
37f4cbe3d7 | ||
|
|
126c8c14b8 | ||
|
|
3992315505 | ||
|
|
eb4e4fa7ad | ||
|
|
71e38dec11 | ||
|
|
11376ae25b | ||
|
|
dd245f62f0 | ||
|
|
aa37b40d93 | ||
|
|
8eccf8a6f7 | ||
|
|
7376639789 | ||
|
|
2334374fd6 | ||
|
|
f086bc9564 | ||
|
|
c30de8add4 | ||
|
|
de3cb6b374 | ||
|
|
4c8fdf6e90 | ||
|
|
1a41f908d3 | ||
|
|
95908aa2bc | ||
|
|
a19f4dd4c8 | ||
|
|
eadd4d9b71 | ||
|
|
4f3ff3d77f | ||
|
|
5bb81461f6 | ||
|
|
871a2088db | ||
|
|
abeaac6632 | ||
|
|
d591cebf44 | ||
|
|
8abb19aaca | ||
|
|
bcc937e4e0 | ||
|
|
915d92019c | ||
|
|
f24d5cb5f0 | ||
|
|
79c22c76bf | ||
|
|
20e96df85d | ||
|
|
be51fe944d | ||
|
|
54d1d98e39 | ||
|
|
6f92781992 | ||
|
|
c1bd3b5824 | ||
|
|
fb615843b3 | ||
|
|
c6d808a0d8 | ||
|
|
4f12821ca8 | ||
|
|
4fcda28d9b | ||
|
|
1883e051ba | ||
|
|
4825afbf58 | ||
|
|
ad8c7b9d0b | ||
|
|
7eb88ed7dc | ||
|
|
6afd0d8add | ||
|
|
bfe142fef0 | ||
|
|
54e626f665 | ||
|
|
f296471726 | ||
|
|
b2e8967e94 | ||
|
|
d83ef07ca7 | ||
|
|
e70ed961ea | ||
|
|
7216e36cb1 | ||
|
|
10a60b6ec2 | ||
|
|
054fb22854 | ||
|
|
b34127e346 | ||
|
|
be70ea7d49 | ||
|
|
1ef178c5e6 | ||
|
|
56399b9aa3 | ||
|
|
a79c7495c8 | ||
|
|
b13ee9da2a | ||
|
|
f86ee20579 | ||
|
|
f7e8f8031d | ||
|
|
18a116394d | ||
|
|
094948db51 | ||
|
|
18c7e97ecc | ||
|
|
c8ac48ff9a | ||
|
|
fa4ec55c96 | ||
|
|
a02d4dc27c | ||
|
|
31c75e747c | ||
|
|
8a1a446f45 | ||
|
|
7fe8a63f53 | ||
|
|
48874294d6 | ||
|
|
f5093f1625 | ||
|
|
4bc8cf1a1a | ||
|
|
527c932e93 | ||
|
|
cba3db6205 | ||
|
|
3b798b1733 | ||
|
|
f898d82536 | ||
|
|
3b5aab6edb | ||
|
|
11c8a47d22 | ||
|
|
b2323ca203 | ||
|
|
2c648c80c8 | ||
|
|
b8d9ba993d | ||
|
|
3810ef47f7 | ||
|
|
bbbadbcb78 | ||
|
|
c0acc98faa | ||
|
|
9828d787fa | ||
|
|
53456b5fc3 | ||
|
|
73a5e2bc6b | ||
|
|
9a2ac5fcb6 | ||
|
|
025b45b91e | ||
|
|
31d1e04301 | ||
|
|
a828f90d38 | ||
|
|
00556734bc | ||
|
|
b231ab7238 | ||
|
|
2587bbc4a7 | ||
|
|
40df11b162 | ||
|
|
a66d44054c | ||
|
|
e9fcbb334e | ||
|
|
babc6f0f9c | ||
|
|
bffeb664cc | ||
|
|
b85a8bbbfe | ||
|
|
925f451773 | ||
|
|
8bf1e694fe | ||
|
|
c5bc221b27 | ||
|
|
7f28acc5ed | ||
|
|
f36d2ff55f | ||
|
|
396e01a0e0 | ||
|
|
787c1304c6 | ||
|
|
d92c08c9bb | ||
|
|
bd3b4e03e9 | ||
|
|
cb5511c8db | ||
|
|
54b6a1c08e | ||
|
|
8cc154bc48 | ||
|
|
ab6d9ad521 | ||
|
|
5e1c71b059 | ||
|
|
f3695b95fc | ||
|
|
32a3e15309 | ||
|
|
0661553484 | ||
|
|
5f080fcfc9 | ||
|
|
a21e44c155 | ||
|
|
60089f9750 | ||
|
|
5043b9d06e | ||
|
|
a17b9fdaba | ||
|
|
2f3123e175 | ||
|
|
17c756971a | ||
|
|
f71e877f18 | ||
|
|
d6c97a6a13 | ||
|
|
e0e732523e | ||
|
|
47b9993469 | ||
|
|
7bfad18ec7 | ||
|
|
b0504f7739 | ||
|
|
67ed58b0ba | ||
|
|
a815e6ca14 | ||
|
|
b59904632d | ||
|
|
c1b9b27f86 | ||
|
|
2b87705a46 | ||
|
|
34faf7638e | ||
|
|
5e555fc1cf | ||
|
|
cb5d36d89f | ||
|
|
e2f16ec20e | ||
|
|
b615534d8d | ||
|
|
93d57bd73a | ||
|
|
60798798ef | ||
|
|
81696c16d2 | ||
|
|
89c504daf6 | ||
|
|
5a2287c52f | ||
|
|
a65a288eca | ||
|
|
cf80baa2d8 | ||
|
|
871a822379 | ||
|
|
b9b6b6108e | ||
|
|
3a2ba60b70 | ||
|
|
aa76f64a94 | ||
|
|
e34a8da5d7 | ||
|
|
6157a9a858 | ||
|
|
6b92c4867d | ||
|
|
3bd6eab88f | ||
|
|
3a3a9f5cc1 | ||
|
|
f87268e2ac | ||
|
|
5238ed309f | ||
|
|
6347988e0a | ||
|
|
b92acd3cf2 | ||
|
|
fd96bafbc8 | ||
|
|
b7e16cb0dd | ||
|
|
459df23931 | ||
|
|
e7b22a7ed2 | ||
|
|
bcbe91461e | ||
|
|
b68410d619 | ||
|
|
602e9cebd9 | ||
|
|
d2049edcab | ||
|
|
83322f63c6 | ||
|
|
f0a2f24701 | ||
|
|
97f1a8fe91 | ||
|
|
0ac9f159d6 | ||
|
|
a3f8e27bf8 | ||
|
|
b55c13f275 | ||
|
|
761651d410 | ||
|
|
70548f7cc7 | ||
|
|
f6ab0b4d07 | ||
|
|
bc8a34f8df | ||
|
|
8f0cd5508d | ||
|
|
a151c3f892 | ||
|
|
5b9135a698 | ||
|
|
db5c02fbfc | ||
|
|
938da3039d | ||
|
|
cfeae48b83 | ||
|
|
50f18ddaad | ||
|
|
2874650802 | ||
|
|
1271de321e | ||
|
|
a265ee6f6f | ||
|
|
e196203320 | ||
|
|
33d062cb60 | ||
|
|
53bcd4b1ab | ||
|
|
385f961b29 | ||
|
|
eada714a0a | ||
|
|
66f11e9bd3 | ||
|
|
158d3cc743 | ||
|
|
07c109fad8 | ||
|
|
618a4b42ad | ||
|
|
e2c81e54e2 | ||
|
|
e56f0628d5 | ||
|
|
546ba888ae | ||
|
|
9b2a17eb1e | ||
|
|
a7ecc0db1f | ||
|
|
bc7eb39781 | ||
|
|
299a383d98 | ||
|
|
75515af537 | ||
|
|
b1ed15a07a | ||
|
|
9dc6ef6771 | ||
|
|
a6a16808e3 | ||
|
|
aee71b594b | ||
|
|
6e3231a9d7 | ||
|
|
85dad6913e | ||
|
|
deacec07bf | ||
|
|
958880d972 | ||
|
|
78af59f40c | ||
|
|
c59f5e9f01 | ||
|
|
c9349f2ef6 | ||
|
|
4ebaa7b6bd | ||
|
|
618896c043 | ||
|
|
0dbd83ffaf | ||
|
|
3929e9de0e | ||
|
|
f4d1657c22 | ||
|
|
caab298f72 | ||
|
|
0d0b2ce9b3 | ||
|
|
16ad5d3a2e | ||
|
|
92e9297a15 | ||
|
|
ac72db8ef0 | ||
|
|
9b4e365517 | ||
|
|
c0cefde5d1 | ||
|
|
1786a7cdc4 | ||
|
|
a91e8887cd | ||
|
|
d3a0372e89 | ||
|
|
793e1afa08 | ||
|
|
78162a2a13 | ||
|
|
30ea4fc416 | ||
|
|
d1d36cc9af | ||
|
|
b2a97e4245 | ||
|
|
b32f770a69 | ||
|
|
78d4f22ce4 | ||
|
|
3925929979 | ||
|
|
60fdd71f74 | ||
|
|
b4f53143b0 | ||
|
|
9c2fdc6da5 | ||
|
|
821e8ec59a | ||
|
|
4401abb166 | ||
|
|
27be004c64 | ||
|
|
6c668868e9 | ||
|
|
6add8a7df9 | ||
|
|
7fa69ef8be | ||
|
|
f77f71c17e | ||
|
|
749b9182ab | ||
|
|
3b0805f4d7 | ||
|
|
0c1485c325 | ||
|
|
86554d66d0 | ||
|
|
6475d763d0 | ||
|
|
7add4d5782 | ||
|
|
f70b1ffbbf | ||
|
|
8a9b7dc63a | ||
|
|
3f30096727 | ||
|
|
52ff997bf0 | ||
|
|
08911e2dcc | ||
|
|
dd4639e5db | ||
|
|
2109af0987 | ||
|
|
68bbe13d23 | ||
|
|
b1a0498ff9 | ||
|
|
882f4714ac | ||
|
|
e7273e1d81 | ||
|
|
f359ded336 | ||
|
|
ff4b1104a2 | ||
|
|
a550695cba | ||
|
|
9438d33358 | ||
|
|
e35a2450d9 | ||
|
|
616d848fac | ||
|
|
a4b17b162c | ||
|
|
9fd6b5e1e2 | ||
|
|
466806fb11 | ||
|
|
97edc96afd | ||
|
|
8b14f1050d | ||
|
|
9cf2bb18c2 | ||
|
|
4b8febd44e | ||
|
|
d49f6e1b29 | ||
|
|
1e32f9431d | ||
|
|
4a3cda1495 | ||
|
|
05daedf7c6 | ||
|
|
f07d59c55d | ||
|
|
b057efdb37 | ||
|
|
7954b95f5d | ||
|
|
ebf91d59c7 | ||
|
|
0effcf6df1 | ||
|
|
a5fabc6875 | ||
|
|
506720003d | ||
|
|
0f3306870b | ||
|
|
a1b86749cf | ||
|
|
25d19f7d63 | ||
|
|
ae58809c9f | ||
|
|
976ce1e8fd | ||
|
|
6ec58a20c0 | ||
|
|
ad237136e7 | ||
|
|
a4d6a104a6 | ||
|
|
a150ae76ac | ||
|
|
4621e763b6 | ||
|
|
8db162e048 | ||
|
|
7d94b7fd1b | ||
|
|
d018ef39e1 | ||
|
|
4115a2f2d1 | ||
|
|
767742c7e7 | ||
|
|
0ddd0ed4fb | ||
|
|
2d1331e104 | ||
|
|
9223b643b6 | ||
|
|
f3560b8e62 | ||
|
|
18d7465592 | ||
|
|
ec7dd1ece8 | ||
|
|
cdfb425ac4 | ||
|
|
cb984cf761 | ||
|
|
7efbcc039d | ||
|
|
d31eceddaf | ||
|
|
3a190bbe49 | ||
|
|
5c4acc8ee1 | ||
|
|
92a9ba478b | ||
|
|
71a5db6961 | ||
|
|
013d91d4ee | ||
|
|
8e0c1c70ce | ||
|
|
bfbeca8b6c | ||
|
|
412a42246f | ||
|
|
781b61d074 | ||
|
|
2008415106 | ||
|
|
386d6a77f2 | ||
|
|
29d22e4e8b | ||
|
|
286c60bc9d | ||
|
|
c26d317da5 | ||
|
|
534fd1a59e |
10
.clang-format
Normal file
10
.clang-format
Normal file
@@ -0,0 +1,10 @@
|
||||
# Use the Google style with these modifications:
|
||||
#
|
||||
# 1) lines can be up to 100 chars long rather than 80, and
|
||||
# 2) use a four space indent rather than two spaces.
|
||||
#
|
||||
BasedOnStyle: Google
|
||||
ColumnLimit: 100
|
||||
IndentWidth: 4
|
||||
# We don't want OCLint pragmas to be reformatted.
|
||||
CommentPragmas: '^!OCLINT'
|
||||
18
.cppcheck.rule
Normal file
18
.cppcheck.rule
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
<rule version="1">
|
||||
<pattern> wcwidth \(</pattern>
|
||||
<message>
|
||||
<id>wcwidthForbidden</id>
|
||||
<severity>warning</severity>
|
||||
<summary>Always use fish_wcwidth rather than wcwidth.</summary>
|
||||
</message>
|
||||
</rule>
|
||||
|
||||
<rule version="1">
|
||||
<pattern> wcswidth \(</pattern>
|
||||
<message>
|
||||
<id>wcswidthForbidden</id>
|
||||
<severity>warning</severity>
|
||||
<summary>Always use fish_wcswidth rather than wcswidth.</summary>
|
||||
</message>
|
||||
</rule>
|
||||
21
.editorconfig
Normal file
21
.editorconfig
Normal file
@@ -0,0 +1,21 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[{Makefile,*.in}]
|
||||
indent_style = tab
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{sh,ac}]
|
||||
indent_size = 2
|
||||
|
||||
[Dockerfile]
|
||||
indent_size = 2
|
||||
33
.gitattributes
vendored
33
.gitattributes
vendored
@@ -1,21 +1,42 @@
|
||||
# normalize newlines
|
||||
* text=auto
|
||||
*.fish text
|
||||
*.bat eol=crlf
|
||||
|
||||
# let git show off diff hunk headers, help git diff -L:
|
||||
# https://git-scm.com/docs/gitattributes
|
||||
*.cpp diff=cpp
|
||||
*.py diff=py
|
||||
# add a [diff "fish"] to git config with pattern
|
||||
*.fish diff=fish
|
||||
|
||||
# omit from git archive
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
.travis.yml export-ignore
|
||||
fish.spec.in export-ignore
|
||||
/build_tools/make_svn_completions.fish export-ignore
|
||||
/build_tools/description-pak export-ignore
|
||||
/build_tools/make_hg_completions.fish export-ignore
|
||||
/build_tools/make_vcs_completions.fish export-ignore
|
||||
/build_tools/make_vcs_completions_generic.fish export-ignore
|
||||
/build_tools/osx_package_resources export-ignore
|
||||
/build_tools/osx_package_resources/terminal_logo.png export-ignore
|
||||
/build_tools/osx_package_resources/welcome.rtf export-ignore
|
||||
/build_tools/osx_package_resources/* export-ignore
|
||||
/build_tools/make_csv_completions.fish export-ignore
|
||||
/build_tools/osx_distribution.xml export-ignore
|
||||
/build_tools/make_tarball.sh export-ignore
|
||||
/build_tools/make_deb.sh export-ignore
|
||||
/build_tools/osx_package_scripts export-ignore
|
||||
/build_tools/osx_package_scripts/add-shell export-ignore
|
||||
/build_tools/osx_package_scripts/postinstall export-ignore
|
||||
/build_tools/osx_package_scripts/* export-ignore
|
||||
/build_tools/make_pkg.sh export-ignore
|
||||
/build_tools/make_darcs_completions.fish export-ignore
|
||||
/debian export-ignore
|
||||
/debian/* export-ignore
|
||||
/.github export-ignore
|
||||
/.github/* export-ignore
|
||||
|
||||
# for linguist; let github identify our project as C++ instead of C due to pcre2
|
||||
/pcre2-10.21/ linguist-vendored
|
||||
/pcre2-10.21/* linguist-vendored
|
||||
angular.js linguist-vendored
|
||||
/doc_src/* linguist-documentation
|
||||
*.fish linguist-language=fish
|
||||
tests/*.in linguist-language=fish
|
||||
21
.github/ISSUE_TEMPLATE.md
vendored
Normal file
21
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<!-- check if this problem is already solved! github.com/issues?q=is:issue+user:fish-shell -->
|
||||
- [ ] Have you checked if problem occurs with [fish 2.3.1](/fish-shell/fish-shell/releases/tag/2.3.1)?
|
||||
- [ ] Tried fish without third-party customizations *(check `sh -c 'env HOME=$(mktemp -d) fish'`)*?
|
||||
|
||||
**fish version installed** *(`fish --version`)*:
|
||||
|
||||
**OS/terminal used**:
|
||||
|
||||
Talk about the the issue here.
|
||||
|
||||
## Reproduction steps
|
||||
1. step one
|
||||
2. …
|
||||
|
||||
<!-- Hard to explain? Post a screen recording on asciinema.org then link it here -->
|
||||
|
||||
## Results
|
||||
```console
|
||||
~ $ math 2 + 2
|
||||
5
|
||||
```
|
||||
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
## Description
|
||||
|
||||
Talk about your changes here.
|
||||
|
||||
Fixes issue #
|
||||
|
||||
## TODOs:
|
||||
<!-- Just check off what what we know been done so far. We can help you with this stuff. -->
|
||||
- [ ] Changes to fish usage are reflected in user documenation/manpages.
|
||||
- [ ] Tests have been added for regressions fixed
|
||||
125
.gitignore
vendored
125
.gitignore
vendored
@@ -1,43 +1,98 @@
|
||||
*.o
|
||||
*~
|
||||
*.exe
|
||||
*.xccheckout
|
||||
# Note that some of the patterns below should be in an individual's
|
||||
# ~/.config/git/ignore file. For example, ".DS_Store" from people working on
|
||||
# MacOS.
|
||||
|
||||
.DS_Store
|
||||
# File extensions that should never be checked in regardless of which project
|
||||
# directory they reside in.
|
||||
*.exe
|
||||
*.app
|
||||
*.out
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
*.o
|
||||
*.obj
|
||||
*.lo
|
||||
*.slo
|
||||
*.d
|
||||
*.gch
|
||||
*.pch
|
||||
*.xccheckout
|
||||
*~
|
||||
*~HEAD
|
||||
*bak
|
||||
*.new
|
||||
*.orig
|
||||
*.log
|
||||
.Trash-*
|
||||
*.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
._*
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
|
||||
|
||||
# These file names can appear anywhere in the hierarchy. They tend to be OS
|
||||
# or build system artifacts.
|
||||
autom4te.cache
|
||||
Makefile
|
||||
autom4te.cache/
|
||||
build/
|
||||
command_list.txt
|
||||
command_list_toc.txt
|
||||
confdefs.h
|
||||
config.h
|
||||
config.cache
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
configure
|
||||
doc/
|
||||
doc.h
|
||||
doc_src/commands.hdr
|
||||
doc_src/index.hdr
|
||||
po/*.gmo
|
||||
fish
|
||||
fish_indent
|
||||
fish_tests
|
||||
fish.pc
|
||||
mimedb
|
||||
seq
|
||||
set_color
|
||||
share/config.fish
|
||||
share/man/
|
||||
toc.txt
|
||||
user_doc/
|
||||
xcuserdata
|
||||
tests/*tmp.*
|
||||
tests/foo.txt
|
||||
FISH-BUILD-VERSION-FILE
|
||||
version
|
||||
messages.pot
|
||||
lexicon.txt
|
||||
lexicon_filter
|
||||
lexicon.log
|
||||
.directory
|
||||
.fuse_hidden*
|
||||
|
||||
|
||||
# Directories that only contain transitory files from building and testing.
|
||||
/doc/
|
||||
/obj/
|
||||
/share/man/
|
||||
/share/doc/
|
||||
/test/
|
||||
/user_doc/
|
||||
|
||||
# File names that can appear in the project root that represent artifacts from
|
||||
# building and testing.
|
||||
/FISH-BUILD-VERSION-FILE
|
||||
/command_list.txt
|
||||
/command_list_toc.txt
|
||||
/compile_commands.json
|
||||
/confdefs.h
|
||||
/doc.h
|
||||
/fish
|
||||
/fish.pc
|
||||
/fish_indent
|
||||
/fish_key_reader
|
||||
/fish_tests
|
||||
/lexicon.txt
|
||||
/lexicon_filter
|
||||
/toc.txt
|
||||
/version
|
||||
|
||||
# File names that can appear below the project root that represent artifacts
|
||||
# from building and testing.
|
||||
/doc_src/commands.hdr
|
||||
/doc_src/index.hdr
|
||||
/po/*.gmo
|
||||
/share/__fish_build_paths.fish
|
||||
/tests/*.tmp.*
|
||||
/share/pkgconfig
|
||||
|
||||
# xcode
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData/
|
||||
xcuserdata/
|
||||
*.moved-aside
|
||||
*.xccheckout
|
||||
*.xcscmblueprin
|
||||
|
||||
|
||||
53
.oclint
Normal file
53
.oclint
Normal file
@@ -0,0 +1,53 @@
|
||||
rules:
|
||||
rule-configurations:
|
||||
#
|
||||
# This is the default value (as of the time I wrote this) but I'm making
|
||||
# it explicit since it needs to agree with the value used by clang-format.
|
||||
# Thus, if we ever change the fish style to allow longer or shorter lines
|
||||
# this should be changed (as well as the corresponding .clang-format file).
|
||||
#
|
||||
- key: LONG_LINE
|
||||
value: 100
|
||||
#
|
||||
# The default limit for the length of variable names is 20. Long names are
|
||||
# problematic but twenty chars results in way too many errors. So increase
|
||||
# the limit to something more reasonable.
|
||||
#
|
||||
- key: LONG_VARIABLE_NAME
|
||||
value: 30
|
||||
#
|
||||
# This allows us to avoid peppering our code with inline comments such as
|
||||
#
|
||||
# scoped_lock locker(m_lock); //!OCLINT(side-effect)
|
||||
#
|
||||
# Specifically, this config key tells oclint that the named classes have
|
||||
# RAII behavior so the local vars are actually used.
|
||||
#
|
||||
- key: RAII_CUSTOM_CLASSES
|
||||
value: scoped_lock scoped_buffer_t builtin_commandline_scoped_transient_t scoped_push
|
||||
|
||||
disable-rules:
|
||||
#
|
||||
# A few instances of "useless parentheses" errors are meaningful. Mostly
|
||||
# in the context of the `return` statement. Unfortunately the vast
|
||||
# majority would result in removing parentheses that decreases
|
||||
# readability. So we're going to ignore this warning and rely on humans to
|
||||
# notice when the parentheses are truly not needed.
|
||||
#
|
||||
# Also, some macro expansions, such as FD_SET(), trigger this warning and
|
||||
# we don't want to suppress each of those individually.
|
||||
#
|
||||
- UselessParentheses
|
||||
#
|
||||
# OCLint wants variable names to be at least three characters in length.
|
||||
# Which would be fine if it supported a reasonable set of exceptions
|
||||
# (e.g., "i", "j", "k") and allowed adding additional exceptions to match
|
||||
# conventions employed by a project. Since it doesn't, and thus generates
|
||||
# a lot of really annoying warnings, we're going to disable this rule.
|
||||
#
|
||||
- ShortVariableName
|
||||
#
|
||||
# This rule flags perfectly reasonable conditions like `if (!some_condition)`
|
||||
# and is therefore just noise. Disable this rule.
|
||||
#
|
||||
- InvertedLogic
|
||||
77
.travis.yml
77
.travis.yml
@@ -1,27 +1,76 @@
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
before_install:
|
||||
- sudo apt-get update
|
||||
install:
|
||||
- sudo apt-get install --no-install-recommends bc doxygen expect gettext libncurses5-dev
|
||||
dist: trusty
|
||||
sudo: required
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- bc
|
||||
- expect
|
||||
- gettext
|
||||
- libncurses5-dev
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- bc
|
||||
- expect
|
||||
- gettext
|
||||
- lib32ncurses5-dev
|
||||
- g++-multilib
|
||||
env:
|
||||
- CXXFLAGS="-g -m32" CFLAGS="-g -m32"
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env:
|
||||
- CXXFLAGS="-g -fno-omit-frame-pointer -fsanitize=address" ASAN_OPTIONS=check_initialization_order=1:detect_stack_use_after_return=1:detect_leaks=1
|
||||
before_install: export CXX=clang++-3.8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- llvm-toolchain-precise-3.8
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- clang-3.8
|
||||
- llvm-3.8 # for llvm-symbolizer
|
||||
- bc
|
||||
- expect
|
||||
- gettext
|
||||
- libncurses5-dev
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
before_install:
|
||||
- brew update
|
||||
- brew install pcre2 # use system PCRE2
|
||||
- brew outdated xctool || brew upgrade xctool # for xcode... soon.
|
||||
env:
|
||||
- CXXFLAGS="-g -lstdc++"
|
||||
fast_finish: true
|
||||
|
||||
script:
|
||||
- autoreconf
|
||||
- ./configure
|
||||
- ./configure --prefix=$HOME/prefix || cat config.log
|
||||
- make -j2
|
||||
- sudo make install
|
||||
- make test SHOW_INTERACTIVE_LOG=1
|
||||
- make install
|
||||
- make test DESTDIR=$HOME/prefix/ SHOW_INTERACTIVE_LOG=1
|
||||
|
||||
notifications:
|
||||
# Some items are encrypted so that notifications from other repositories
|
||||
# don't flood the official repositories.
|
||||
irc:
|
||||
channels:
|
||||
- "irc.oftc.net#fish"
|
||||
#- "irc.oftc.net#fish"
|
||||
secure: "eRk9KGZ5+mrlD2SoI8yg2Sp8OYrh7YPyGe3WCDQUwTnNgNDII34rbM9a6UOA/l7AeWSNY8joLq5xVLCU4wpFgUcJ11SYIpMnLosZK29OW4ubDOHmdBDvJ971rLgAVG9cXngZtIxEVVxN/jnS1Qr8GKZx4DjkaTMgz1pemb4WxCc="
|
||||
template:
|
||||
- "%{repository}#%{build_number} (%{commit} on %{branch} by %{author}): %{message} Details at %{build_url}"
|
||||
use_notice: true
|
||||
skip_join: true
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/61821cec3015bf0f8bb1
|
||||
matrix:
|
||||
fast_finish: true
|
||||
#- https://webhooks.gitter.im/e/61821cec3015bf0f8bb1
|
||||
secure: fPfOmxnC3MCsfR1oocVFeWLawGcRZkn+8fNHlSOeZ+SqqoZfcCHgQTvQ22TqmVl1yvkXbNlaXjo6dbVzTOAh7r7H0bRMEKBVh3dQS7wqjB1sKivpXd8PAS3BTj5MQpGeJzdHnDuwVlwDktGtfHfhGeq1Go/4IosOq8u+6RTe28g=
|
||||
|
||||
478
CHANGELOG.md
Normal file
478
CHANGELOG.md
Normal file
@@ -0,0 +1,478 @@
|
||||
# fish 2.4.0 (released November 8, 2016)
|
||||
|
||||
There are no major changes between 2.4b1 and 2.4.0.
|
||||
|
||||
## Notable fixes and improvements
|
||||
- The documentation is now generated properly and with the correct version identifier.
|
||||
- Automatic cursor changes are now only enabled on the subset of XTerm versions known to support them, resolving a problem where older versions printed garbage to the terminal before and after every prompt (#3499).
|
||||
- Improved the title set in Apple Terminal.app.
|
||||
- Added completions for `defaults` and improved completions for `diskutil` (#3478).
|
||||
|
||||
# fish 2.4b1 (released October 18, 2016)
|
||||
|
||||
## Significant changes
|
||||
- The clipboard integration has been revamped with explicit bindings. The killring commands no longer copy from, or paste to, the X11 clipboard - use the new copy (`C-x`) and paste (`C-v`) bindings instead. The clipboard is now available on OS X as well as systems using X11 (e.g. Linux). (#3061)
|
||||
- `history` uses subcommands (`history delete`) rather than options (`history --delete`) for its actions (#3367). You can no longer specify multiple actions via flags (e.g., `history --delete --save something`).
|
||||
- New `history` options have been added, including `--max=n` to limit the number of history entries, `--show-time` option to show timestamps (#3175, #3244), and `--null` to null terminate history entries in the search output.
|
||||
- `history search` is now case-insensitive by default (which also affects `history delete`) (#3236).
|
||||
- `history delete` now correctly handles multiline commands (#31).
|
||||
- Vi-style bindings no longer include all of the default emacs-style bindings; instead, they share some definitions (#3068).
|
||||
- If there is no locale set in the environment, various known system configuration files will be checked for a default. If no locale can be found, `en_US-UTF.8` will be used (#277).
|
||||
- A number followed by a caret (e.g. `5^`) is no longer treated as a redirection (#1873).
|
||||
- The `$version` special variable can be overwritten, so that it can be used for other purposes if required.
|
||||
|
||||
## Notable fixes and improvements
|
||||
- The `fish_realpath` builtin has been renamed to `realpath` and made compatible with GNU `realpath` when run without arguments (#3400). It is used only for systems without a `realpath` or `grealpath` utility (#3374).
|
||||
- Improved color handling on terminals/consoles with 8-16 colors, particularly the use of bright named color (#3176, #3260).
|
||||
- `fish_indent` can now read from files given as arguments, rather than just standard input (#3037).
|
||||
- Fuzzy tab completions behave in a less surprising manner (#3090, #3211).
|
||||
- `jobs` should only print its header line once (#3127).
|
||||
- Wildcards in redirections are highlighted appropriately (#2789).
|
||||
- Suggestions will be offered more often, like after removing characters (#3069).
|
||||
- `history --merge` now correctly interleaves items in chronological order (#2312).
|
||||
- Options for `fish_indent` have been aligned with the other binaries - in particular, `-d` now means `--debug`. The `--dump` option has been renamed to `--dump-parse-tree` (#3191).
|
||||
- The display of bindings in the Web-based configuration has been greatly improved (#3325), as has the rendering of prompts (#2924).
|
||||
- fish should no longer hang using 100% CPU in the C locale (#3214).
|
||||
- A bug in FreeBSD 11 & 12, Dragonfly BSD & illumos prevented fish from working correctly on these platforms under UTF-8 locales; fish now avoids the buggy behaviour (#3050).
|
||||
- Prompts which show git repository information (via `__fish_git_prompt`) are faster in large repositories (#3294) and slow filesystems (#3083).
|
||||
- fish 2.3.0 reintroduced a problem where the greeting was printed even when using `read`; this has been corrected again (#3261).
|
||||
- Vi mode changes the cursor depending on the current mode (#3215).
|
||||
- Command lines with escaped space characters at the end tab-complete correctly (#2447).
|
||||
- Added completions for:
|
||||
- `arcanist` (#3256)
|
||||
- `connmanctl` (#3419)
|
||||
- `figlet` (#3378)
|
||||
- `mdbook` (#3378)
|
||||
- `ninja` (#3415)
|
||||
- `p4`, the Perforce client (#3314)
|
||||
- `pygmentize` (#3378)
|
||||
- `ranger` (#3378)
|
||||
- Improved completions for `aura` (#3297), `abbr` (#3267), `brew` (#3309), `chown` (#3380, #3383),`cygport` (#3392), `git` (#3274, #3226, #3225, #3094, #3087, #3035, #3021, #2982, #3230), `kill & `pkill` (#3200), `screen` (#3271), `wget` (#3470), and `xz` (#3378).
|
||||
- Distributors, packagers and developers will notice that the build process produces more succinct output by default; use `make V=1` to get verbose output (#3248).
|
||||
- Improved compatibility with minor platforms including musl (#2988), Cygwin (#2993), Android (#3441, #3442), Haiku (#3322) and Solaris .
|
||||
|
||||
---
|
||||
|
||||
# fish 2.3.1 (released July 3, 2016)
|
||||
|
||||
This is a functionality and bugfix release. This release does not contain all the changes to fish since the last release, but fixes a number of issues directly affecting users at present and includes a small number of new features.
|
||||
|
||||
## Significant changes
|
||||
- A new `fish_key_reader` binary for decoding interactive keypresses (#2991).
|
||||
- `fish_mode_prompt` has been updated to reflect the changes in the way the Vi input mode is set up (#3067), making this more reliable.
|
||||
- `fish_config` can now properly be launched from the OS X app bundle (#3140).
|
||||
|
||||
## Notable fixes and improvements
|
||||
|
||||
- Extra lines were sometimes inserted into the output under Windows (Cygwin and Microsoft Windows Subsystem for Linux) due to TTY timestamps not being updated (#2859).
|
||||
- The `string` builtin's `match` mode now handles the combination of `-rnv` (match, invert and count) correctly (#3098).
|
||||
- Improvements to TTY special character handling (#3064), locale handling (#3124) and terminal environment variable handling (#3060).
|
||||
- Work towards handling the terminal modes for external commands launched from initialisation files (#2980).
|
||||
- Ease the upgrade path from fish 2.2.0 and before by warning users to restart fish if the `string` builtin is not available (#3057).
|
||||
- `type -a` now syntax-colorizes function source output.
|
||||
- Added completions for `alsamixer`, `godoc`, `gofmt`, `goimports`, `gorename`, `lscpu`, `mkdir`, `modinfo`, `netctl-auto`, `poweroff`, `termite`, `udisksctl` and `xz` (#3123).
|
||||
- Improved completions for `apt` (#3097), `aura` (#3102),`git` (#3114), `npm` (#3158), `string` and `suspend` (#3154).
|
||||
|
||||
---
|
||||
|
||||
# fish 2.3.0 (released May 20, 2016)
|
||||
|
||||
There are no significant changes between 2.3.0 and 2.3b2.
|
||||
|
||||
## Other notable fixes and improvements
|
||||
|
||||
- `abbr` now allows non-letter keys (#2996).
|
||||
- Define a few extra colours on first start (#2987).
|
||||
- Multiple documentation updates.
|
||||
- Added completions for rmmod (#3007).
|
||||
- Improved completions for git (#2998).
|
||||
|
||||
## Known issues
|
||||
|
||||
- Interactive commands started from fish configuration files or from the `-c` option may, under certain circumstances, be started with incorrect terminal modes and fail to behave as expected. A fix is planned but requires further testing (#2619).
|
||||
|
||||
---
|
||||
|
||||
# fish 2.3b2 (released May 5, 2016)
|
||||
|
||||
## Significant changes
|
||||
|
||||
- A new `fish_realpath` builtin and associated function to allow the use of `realpath` even on those platforms that don't ship an appropriate command (#2932).
|
||||
- Alt-# toggles the current command line between commented and uncommented states, making it easy to save a command in history without executing it.
|
||||
- The `fish_vi_mode` function is now deprecated in favour of `fish_vi_key_bindings`.
|
||||
|
||||
## Other notable fixes and improvements
|
||||
|
||||
- Fix the build on Cygwin (#2952) and RedHat Enterprise Linux/CentOS 5 (#2955).
|
||||
- Avoid confusing the terminal line driver with non-printing characters in `fish_title` (#2453).
|
||||
- Improved completions for busctl, git (#2585, #2879, #2984), and netctl.
|
||||
|
||||
---
|
||||
|
||||
# fish 2.3b1 (released April 19, 2016)
|
||||
|
||||
## Significant Changes
|
||||
|
||||
- A new `string` builtin to handle... strings! This builtin will measure, split, search and replace text strings, including using regular expressions. It can also be used to turn lists into plain strings using `join`. `string` can be used in place of `sed`, `grep`, `tr`, `cut`, and `awk` in many situations. (#2296)
|
||||
- Allow using escape as the Meta modifier key, by waiting after seeing an escape character wait up to 300ms for an additional character. This is consistent with readline (e.g. bash) and can be configured via the `fish_escape_delay_ms variable`. This allows using escape as the Meta modifier. (#1356)
|
||||
- Add new directories for vendor functions and configuration snippets (#2500)
|
||||
- A new `fish_realpath` builtin and associated `realpath` function should allow scripts to resolve path names via `realpath` regardless of whether there is an external command of that name; albeit with some limitations. See the associated documentation.
|
||||
|
||||
## Backward-incompatible changes
|
||||
|
||||
- Unmatched globs will now cause an error, except when used with `for`, `set` or `count` (#2719)
|
||||
- `and` and `or` will now bind to the closest `if` or `while`, allowing compound conditions without `begin` and `end` (#1428)
|
||||
- `set -ql` now searches up to function scope for variables (#2502)
|
||||
- `status -f` will now behave the same when run as the main script or using `source` (#2643)
|
||||
- `source` no longer puts the file name in `$argv` if no arguments are given (#139)
|
||||
- History files are stored under the `XDG_DATA_HOME` hierarchy (by default, in `~/.local/share`), and existing history will be moved on first use (#744)
|
||||
|
||||
## Other notable fixes and improvements
|
||||
|
||||
- Fish no longer silences errors in config.fish (#2702)
|
||||
- Directory autosuggestions will now descend as far as possible if there is only one child directory (#2531)
|
||||
- Add support for bright colors (#1464)
|
||||
- Allow Ctrl-J (\cj) to be bound separately from Ctrl-M (\cm) (#217)
|
||||
- psub now has a "-s"/"–suffix" option to name the temporary file with that suffix
|
||||
- Enable 24-bit colors on select terminals (#2495)
|
||||
- Support for SVN status in the prompt (#2582)
|
||||
- Mercurial and SVN support have been added to the Classic + Git (now Classic + VCS) prompt (via the new \__fish_vcs_prompt function) (#2592)
|
||||
- export now handles variables with a "=" in the value (#2403)
|
||||
- New completions for:
|
||||
- alsactl
|
||||
- Archlinux's asp, makepkg
|
||||
- Atom's apm (#2390)
|
||||
- entr - the "Event Notify Test Runner" (#2265)
|
||||
- Fedora's dnf (#2638)
|
||||
- OSX diskutil (#2738)
|
||||
- pkgng (#2395)
|
||||
- pulseaudio's pacmd and pactl
|
||||
- rust's rustc and cargo (#2409)
|
||||
- sysctl (#2214)
|
||||
- systemd's machinectl (#2158), busctl (#2144), systemd-nspawn, systemd-analyze, localectl, timedatectl
|
||||
- and more
|
||||
- Fish no longer has a function called sgrep, freeing it for user customization (#2245)
|
||||
- A rewrite of the completions for cd, fixing a few bugs (#2299, #2300, #562)
|
||||
- Linux VTs now run in a simplified mode to avoid issues (#2311)
|
||||
- The vi-bindings now inherit from the emacs bindings
|
||||
- Fish will also execute `fish_user_key_bindings` when in vi-mode
|
||||
- `funced` will now also check $VISUAL (#2268)
|
||||
- A new `suspend` function (#2269)
|
||||
- Subcommand completion now works better with split /usr (#2141)
|
||||
- The command-not-found-handler can now be overridden by defining a function called `__fish_command_not_found_handler` in config.fish (#2332)
|
||||
- A few fixes to the Sorin theme
|
||||
- PWD shortening in the prompt can now be configured via the `fish_prompt_pwd_dir_length` variable, set to the length per path component (#2473)
|
||||
- fish no longer requires `/etc/fish/config.fish` to correctly start, and now ships a skeleton file that only contains some documentation (#2799)
|
||||
|
||||
---
|
||||
|
||||
# fish 2.2.0 (released July 12, 2015)
|
||||
|
||||
### Significant changes ###
|
||||
|
||||
* Abbreviations: the new `abbr` command allows for interactively-expanded abbreviations, allowing quick access to frequently-used commands (#731).
|
||||
* Vi mode: run `fish_vi_mode` to switch fish into the key bindings and prompt familiar to users of the Vi editor (#65).
|
||||
* New inline and interactive pager, which will be familiar to users of zsh (#291).
|
||||
* Underlying architectural changes: the `fishd` universal variable server has been removed as it was a source of many bugs and security problems. Notably, old fish sessions will not be able to communicate universal variable changes with new fish sessions. For best results, restart all running instances of `fish`.
|
||||
* The web-based configuration tool has been redesigned, featuring a prompt theme chooser and other improvements.
|
||||
* New German, Brazilian Portuguese, and Chinese translations.
|
||||
|
||||
### Backward-incompatible changes ###
|
||||
|
||||
These are kept to a minimum, but either change undocumented features or are too hard to use in their existing forms. These changes may break existing scripts.
|
||||
|
||||
* `commandline` no longer interprets functions "in reverse", instead behaving as expected (#1567).
|
||||
* The previously-undocumented `CMD_DURATION` variable is now set for all commands and contains the execution time of the last command in milliseconds (#1585). It is no longer exported to other commands (#1896).
|
||||
* `if` / `else` conditional statements now return values consistent with the Single Unix Specification, like other shells (#1443).
|
||||
* A new "top-level" local scope has been added, allowing local variables declared on the commandline to be visible to subsequent commands. (#1908)
|
||||
|
||||
### Other notable fixes and improvements ###
|
||||
|
||||
* New documentation design (#1662), which requires a Doxygen version 1.8.7 or newer to build.
|
||||
* Fish now defines a default directory for other packages to provide completions. By default this is `/usr/share/fish/vendor-completions.d`; on systems with `pkgconfig` installed this path is discoverable with `pkg-config --variable completionsdir fish`.
|
||||
* A new parser removes many bugs; all existing syntax should keep working.
|
||||
* New `fish_preexec` and `fish_postexec` events are fired before and after job execution respectively (#1549).
|
||||
* Unmatched wildcards no longer prevent a job from running. Wildcards used interactively will still print an error, but the job will proceed and the wildcard will expand to zero arguments (#1482).
|
||||
* The `.` command is deprecated and the `source` command is preferred (#310).
|
||||
* `bind` supports "bind modes", which allows bindings to be set for a particular named mode, to support the implementation of Vi mode.
|
||||
* A new `export` alias, which behaves like other shells (#1833).
|
||||
* `command` has a new `--search` option to print the name of the disk file that would be executed, like other shells' `command -v` (#1540).
|
||||
* `commandline` has a new `--paging-mode` option to support the new pager.
|
||||
* `complete` has a new `--wraps` option, which allows a command to (recursively) inherit the completions of a wrapped command (#393), and `complete -e` now correctly erases completions (#380).
|
||||
* Completions are now generated from manual pages by default on the first run of fish (#997).
|
||||
* `fish_indent` can now produce colorized (`--ansi`) and HTML (`--html`) output (#1827).
|
||||
* `functions --erase` now prevents autoloaded functions from being reloaded in the current session.
|
||||
* `history` has a new `--merge` option, to incorporate history from other sessions into the current session (#825).
|
||||
* `jobs` returns 1 if there are no active jobs (#1484).
|
||||
* `read` has several new options:
|
||||
* `--array` to break input into an array (#1540)
|
||||
* `--null` to break lines on NUL characters rather than newlines (#1694)
|
||||
* `--nchars` to read a specific number of characters (#1616)
|
||||
* `--right-prompt` to display a right-hand-side prompt during interactive read (#1698).
|
||||
* `type` has a new `-q` option to suppress output (#1540 and, like other shells, `type -a` now prints all matches for a command (#261).
|
||||
* Pressing F1 now shows the manual page for the current command (#1063).
|
||||
* `fish_title` functions have access to the arguments of the currently running argument as `$argv[1]` (#1542).
|
||||
* The OS command-not-found handler is used on Arch Linux (#1925), nixOS (#1852), openSUSE and Fedora (#1280).
|
||||
* `Alt`+`.` searches backwards in the token history, mapping to the same behavior as inserting the last argument of the previous command, like other shells (#89).
|
||||
* The `SHLVL` environment variable is incremented correctly (#1634 & #1693).
|
||||
* Added completions for `adb` (#1165 & #1211), `apt` (#2018), `aura` (#1292), `composer` (#1607), `cygport` (#1841), `dropbox` (#1533), `elixir` (#1167), `fossil`, `heroku` (#1790), `iex` (#1167), `kitchen` (#2000), `nix` (#1167), `node`/`npm` (#1566), `opam` (#1615), `setfacl` (#1752), `tmuxinator` (#1863), and `yast2` (#1739).
|
||||
* Improved completions for `brew` (#1090 & #1810), `bundler` (#1779), `cd` (#1135), `emerge` (#1840),`git` (#1680, #1834 & #1951), `man` (#960), `modprobe` (#1124), `pacman` (#1292), `rpm` (#1236), `rsync` (#1872), `scp` (#1145), `ssh` (#1234), `sshfs` (#1268), `systemctl` (#1462, #1950 & #1972), `tmux` (#1853), `vagrant` (#1748), `yum` (#1269), and `zypper` (#1787).
|
||||
|
||||
---
|
||||
|
||||
# fish 2.1.2 (released Feb 24, 2015)
|
||||
|
||||
fish 2.1.2 contains a workaround for a filesystem bug in Mac OS X Yosemite. #1859
|
||||
|
||||
Specifically, after installing fish 2.1.1 and then rebooting, "Verify Disk" in Disk Utility will report "Invalid number of hard links." We don't have any reports of data loss or other adverse consequences. fish 2.1.2 avoids triggering the bug, but does not repair an already affected filesystem. To repair the filesystem, you can boot into Recovery Mode and use Repair Disk from Disk Utility. Linux and versions of OS X prior to Yosemite are believed to be unaffected.
|
||||
|
||||
There are no other changes in this release.
|
||||
|
||||
---
|
||||
|
||||
# fish 2.1.1 (released September 26, 2014)
|
||||
|
||||
__Important:__ if you are upgrading, stop all running instances of `fishd` as soon as possible after installing this release; it will be restarted automatically. On most systems, there will be no further action required. Note that some environments (where `XDG_RUNTIME_DIR` is set), such as Fedora 20, will require a restart of all running fish processes before universal variables work as intended.
|
||||
|
||||
Distributors are highly encouraged to call `killall fishd`, `pkill fishd` or similar in installation scripts, or to warn their users to do so.
|
||||
|
||||
### Security fixes
|
||||
* The fish_config web interface now uses an authentication token to protect requests and only responds to requests from the local machine with this token, preventing a remote code execution attack. (closing CVE-2014-2914). #1438
|
||||
* `psub` and `funced` are no longer vulnerable to attacks which allow local privilege escalation and data tampering (closing CVE-2014-2906 and CVE-2014-3856). #1437
|
||||
* `fishd` uses a secure path for its socket, preventing a local privilege escalation attack (closing CVE-2014-2905). #1436
|
||||
* `__fish_print_packages` is no longer vulnerable to attacks which would allow local privilege escalation and data tampering (closing CVE-2014-3219). #1440
|
||||
|
||||
### Other fixes
|
||||
* `fishd` now ignores SIGPIPE, fixing crashes using tools like GNU Parallel and which occurred more often as a result of the other `fishd` changes. #1084 & #1690
|
||||
|
||||
---
|
||||
|
||||
# fish 2.1.0
|
||||
|
||||
Significant Changes
|
||||
-------------------
|
||||
|
||||
* **Tab completions will fuzzy-match files.** #568
|
||||
|
||||
When tab-completing a file, fish will first attempt prefix matches (`foo` matches `foobar`), then substring matches (`ooba` matches `foobar`), and lastly subsequence matches (`fbr` matches `foobar`). For example, in a directory with files foo1.txt, foo2.txt, foo3.txt…, you can type only the numeric part and hit tab to fill in the rest.
|
||||
|
||||
This feature is implemented for files and executables. It is not yet implemented for options (like `--foobar`), and not yet implemented across path components (like `/u/l/b` to match `/usr/local/bin`).
|
||||
|
||||
* **Redirections now work better across pipelines.** #110, #877
|
||||
|
||||
In particular, you can pipe stderr and stdout together, for example, with `cmd ^&1 | tee log.txt`, or the more familiar `cmd 2>&1 | tee log.txt`.
|
||||
|
||||
* **A single `%` now expands to the last job backgrounded.** #1008
|
||||
|
||||
Previously, a single `%` would pid-expand to either all backgrounded jobs, or all jobs owned by your user. Now it expands to the last job backgrounded. If no job is in the background, it will fail to expand. In particular, `fg %` can be used to put the most recent background job in the foreground.
|
||||
|
||||
Other Notable Fixes
|
||||
-------------------
|
||||
|
||||
* alt-U and alt+C now uppercase and capitalize words, respectively. #995
|
||||
|
||||
* VTE based terminals should now know the working directory. #906
|
||||
|
||||
* The autotools build now works on Mavericks. #968
|
||||
|
||||
* The end-of-line binding (ctrl+E) now accepts autosuggestions. #932
|
||||
|
||||
* Directories in `/etc/paths` (used on OS X) are now prepended instead of appended, similar to other shells. #927
|
||||
|
||||
* Option-right-arrow (used for partial autosuggestion completion) now works on iTerm2. #920
|
||||
|
||||
* Tab completions now work properly within nested subcommands. #913
|
||||
|
||||
* `printf` supports \e, the escape character. #910
|
||||
|
||||
* `fish_config history` no longer shows duplicate items. #900
|
||||
|
||||
* `$fish_user_paths` is now prepended to $PATH instead of appended. #888
|
||||
|
||||
* Jobs complete when all processes complete. #876
|
||||
|
||||
|
||||
For example, in previous versions of fish, `sleep 10 | echo Done` returns control immediately, because echo does not read from stdin. Now it does not complete until sleep exits (presumably after 10 seconds).
|
||||
|
||||
* Better error reporting for square brackets. #875
|
||||
|
||||
* fish no longer tries to add `/bin` to `$PATH` unless PATH is totally empty. #852
|
||||
|
||||
* History token substitution (alt-up) now works correctly inside subshells. #833
|
||||
|
||||
* Flow control is now disabled, freeing up ctrl-S and ctrl-Q for other uses. #814
|
||||
|
||||
* sh-style variable setting like `foo=bar` now produces better error messages. #809
|
||||
|
||||
* Commands with wildcards no longer produce autosuggestions. #785
|
||||
|
||||
* funced no longer freaks out when supplied with no arguments. #780
|
||||
|
||||
* fish.app now works correctly in a directory containing spaces. #774
|
||||
|
||||
* Tab completion cycling no longer occasionally fails to repaint. #765
|
||||
|
||||
* Comments now work in eval'd strings. #684
|
||||
|
||||
* History search (up-arrow) now shows the item matching the autosuggestion, if that autosuggestion was truncated. #650
|
||||
|
||||
* Ctrl-T now transposes characters, as in other shells. #128
|
||||
|
||||
---
|
||||
|
||||
# fish 2.0.0
|
||||
|
||||
Significant Changes
|
||||
-------------------
|
||||
|
||||
* **Command substitutions now modify `$status` #547.**
|
||||
Previously the exit status of command substitutions (like `(pwd)`) was ignored; however now it modifies $status. Furthermore, the `set` command now only sets $status on failure; it is untouched on success. This allows for the following pattern:
|
||||
|
||||
```sh
|
||||
if set python_path (which python)
|
||||
...
|
||||
end
|
||||
```
|
||||
Because set does not modify $status on success, the if branch effectively tests whether `which` succeeded, and if so, whether the `set` also succeeded.
|
||||
* **Improvements to $PATH handling.**
|
||||
* There is a new variable, `$fish_user_paths`, which can be set universally, and whose contents are appended to $PATH #527
|
||||
* /etc/paths and /etc/paths.d are now respected on OS X
|
||||
* fish no longer modifies $PATH to find its own binaries
|
||||
* **Long lines no longer use ellipsis for line breaks**, and copy and paste
|
||||
should no longer include a newline even if the line was broken #300
|
||||
* **New syntax for index ranges** (sometimes known as "slices") #212
|
||||
* **fish now supports an `else if` statement** #134
|
||||
* **Process and pid completion now works on OS X** #129
|
||||
* **fish is now relocatable**, and no longer depends on compiled-in paths #125
|
||||
* **fish now supports a right prompt (RPROMPT)** through the fish_right_prompt function #80
|
||||
* **fish now uses posix_spawn instead of fork when possible**, which is much faster on BSD and OS X #11
|
||||
|
||||
Other Notable Fixes
|
||||
-------------------
|
||||
|
||||
* Updated VCS completions (darcs, cvs, svn, etc.)
|
||||
* Avoid calling getcwd on the main thread, as it can hang #696
|
||||
* Control-D (forward delete) no longer stops at a period #667
|
||||
* Completions for many new commands
|
||||
* fish now respects rxvt's unique keybindings #657
|
||||
* xsel is no longer built as part of fish. It will still be invoked if installed separately #633
|
||||
* __fish_filter_mime no longer spews #628
|
||||
* The --no-execute option to fish no longer falls over when reaching the end of a block #624
|
||||
* fish_config knows how to find fish even if it's not in the $PATH #621
|
||||
* A leading space now prevents writing to history, as is done in bash and zsh #615
|
||||
* Hitting enter after a backslash only goes to a new line if it is followed by whitespace or the end of the line #613
|
||||
* printf is now a builtin #611
|
||||
* Event handlers should no longer fire if signals are blocked #608
|
||||
* set_color is now a builtin #578
|
||||
* man page completions are now located in a new generated_completions directory, instead of your completions directory #576
|
||||
* tab now clears autosuggestions #561
|
||||
* tab completion from within a pair of quotes now attempts to "appropriate" the closing quote #552
|
||||
* $EDITOR can now be a list: for example, `set EDITOR gvim -f`) #541
|
||||
* `case` bodies are now indented #530
|
||||
* The profile switch `-p` no longer crashes #517
|
||||
* You can now control-C out of `read` #516
|
||||
* `umask` is now functional on OS X #515
|
||||
* Avoid calling getpwnam on the main thread, as it can hang #512
|
||||
* Alt-F or Alt-right-arrow (Option-F or option-right-arrow) now accepts one word of an autosuggestion #435
|
||||
* Setting fish as your login shell no longer kills OpenSUSE #367
|
||||
* Backslashes now join lines, instead of creating multiple commands #347
|
||||
* echo now implements the -e flag to interpret escapes #337
|
||||
* When the last token in the user's input contains capital letters, use its case in preference to that of the autosuggestion #335
|
||||
* Descriptions now have their own muted color #279
|
||||
* Wildcards beginning with a . (for example, `ls .*`) no longer match . and .. #270
|
||||
* Recursive wildcards now handle symlink loops #268
|
||||
* You can now delete history items from the fish_config web interface #250
|
||||
* The OS X build now weak links `wcsdup` and `wcscasecmp` #240
|
||||
* fish now saves and restores the process group, which prevents certain processes from being erroneously reported as stopped #197
|
||||
* funced now takes an editor option #187
|
||||
* Alternating row colors are available in fish pager through `fish_pager_color_secondary` #186
|
||||
* Universal variable values are now stored based on your MAC address, not your hostname #183
|
||||
* The caret ^ now only does a stderr redirection if it is the first character of a token, making git users happy #168
|
||||
* Autosuggestions will no longer cause line wrapping #167
|
||||
* Better handling of Unicode combining characters #155
|
||||
* fish SIGHUPs processes more often #138
|
||||
* fish no longer causes `sudo` to ask for a password every time
|
||||
* fish behaves better under Midnight Commander #121
|
||||
* `set -e` no longer crashes #100
|
||||
* fish now will automatically import history from bash, if there is no fish history #66
|
||||
* Backslashed-newlines inside quoted strings now behave more intuitively #52
|
||||
* Tab titles should be shown correctly in iTerm2 #47
|
||||
* scp remote path completion now sometimes works #42
|
||||
* The `read` builtin no longer shows autosuggestions #29
|
||||
* Custom key bindings can now be set via the `fish_user_key_bindings` function #21
|
||||
* All Python scripts now run correctly under both Python 2 and Python 3 #14
|
||||
* The "accept autosuggestion" key can now be configured #19
|
||||
* Autosuggestions will no longer suggest invalid commands #6
|
||||
|
||||
---
|
||||
|
||||
# fishfish Beta r2
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
* **Implicit cd** is back, for paths that start with one or two dots, a slash, or a tilde.
|
||||
* **Overrides of default functions should be fixed.** The "internalized scripts" feature is disabled for now.
|
||||
* **Disabled delayed suspend.** This is a strange job-control feature of BSD systems, including OS X. Disabling it frees up Control Y for other purposes; in particular, for yank, which now works on OS X.
|
||||
* **fish_indent is fixed.** In particular, the `funced` and `funcsave` functions work again.
|
||||
* A SIGTERM now ends the whole execution stack again (resolving #13).
|
||||
* Bumped the __fish_config_interactive version number so the default fish_color_autosuggestion kicks in.
|
||||
* fish_config better handles combined term256 and classic colors like "555 yellow".
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
* **A history builtin**, and associated interactive function that enables deleting history items. Example usage:
|
||||
* Print all history items beginning with echo: `history --prefix echo`
|
||||
* Print all history items containing foo: `history --contains foo`
|
||||
* Interactively delete some items containing foo: `history --delete --contains foo`
|
||||
|
||||
Credit to @siteshwar for implementation. Thanks @siteshwar!
|
||||
|
||||
---
|
||||
|
||||
# fishfish Beta r1
|
||||
|
||||
## Scripting
|
||||
* No changes! All existing fish scripts, config files, completions, etc. from trunk should continue to work.
|
||||
|
||||
## New Features
|
||||
* **Autosuggestions**. Think URL fields in browsers. When you type a command, fish will suggest the rest of the command after the cursor, in a muted gray when possible. You can accept the suggestion with the right arrow key or Ctrl-F. Suggestions come from command history, completions, and some custom code for cd; there's a lot of potential for improvement here. The suggestions are computed on a background pthread, so they never slow down your typing. The autosuggestion feature is incredible. I miss it dearly every time I use anything else.
|
||||
|
||||
* **term256 support** where available, specifically modern xterms and OS X Lion. You can specify colors the old way ('set_color cyan') or by specifying RGB hex values ('set_color FF3333'); fish will pick the closest supported color. Some xterms do not advertise term256 support either in the $TERM or terminfo max_colors field, but nevertheless support it. For that reason, fish will default into using it on any xterm (but it can be disabled with an environment variable).
|
||||
|
||||
* **Web-based configuration** page. There is a new function 'fish_config'. This spins up a simple Python web server and opens a browser window to it. From this web page, you can set your shell colors and view your functions, variables, and history; all changes apply immediately to all running shells. Eventually all configuration ought to be supported via this mechanism (but in addition to, not instead of, command line mechanisms).
|
||||
|
||||
* **Man page completions**. There is a new function 'fish_update_completions'. This function reads all the man1 files from your manpath, removes the roff formatting, parses them to find the commands and options, and outputs fish completions into ~/.config/fish/completions. It won't overwrite existing completion files (except ones that it generated itself).
|
||||
|
||||
## Programmatic Changes
|
||||
* fish is now entirely in C++. I have no particular love for C++, but it provides a ready memory-model to replace halloc. We've made an effort to keep it to a sane and portable subset (no C++11, no boost, no going crazy with templates or smart pointers), but we do use the STL and a little tr1.
|
||||
* halloc is entirely gone, replaced by normal C++ ownership semantics. If you don't know what halloc is, well, now you have two reasons to be happy.
|
||||
* All the crufty C data structures are entirely gone. array_list_t, priority_queue_t, hash_table_t, string_buffer_t have been removed and replaced by STL equivalents like std::vector, std::map, and std::wstring. A lot of the string handling now uses std::wstring instead of wchar_t *
|
||||
* fish now spawns pthreads for tasks like syntax highlighting that require blocking I/O.
|
||||
* History has been completely rewritten. History files now use an extensible YAML-style syntax. History "merging" (multiple shells writing to the same history file) now works better. There is now a maximum history length of about 250k items (256 * 1024).
|
||||
* The parser has been "instanced," so you can now create more than one.
|
||||
* Total #LoC has shrunk slightly even with the new features.
|
||||
|
||||
## Performance
|
||||
* fish now runs syntax highlighting in a background thread, so typing commands is always responsive even on slow filesystems.
|
||||
* echo, test, and pwd are now builtins, which eliminates many forks.
|
||||
* The files in share/functions and share/completions now get 'internalized' into C strings that get compiled in with fish. This substantially reduces the number of files touched at startup. A consequence is that you cannot change these functions without recompiling, but often other functions depend on these "standard" functions, so changing them is perhaps not a good idea anyways.
|
||||
|
||||
Here are some system call counts for launching and then exiting fish with the default configuration, on OS X. The first column is fish trunk, the next column is with our changes, and the last column is bash for comparison. This data was collected via dtrace.
|
||||
|
||||
<table>
|
||||
<tr> <th> <th> before <th> after <th> bash
|
||||
<tr> <th> open <td> 9 <td> 4 <td> 5
|
||||
<tr> <th> fork <td> 28 <td> 14 <td> 0
|
||||
<tr> <th> stat <td> 131 <td> 85 <td> 11
|
||||
<tr> <th> lstat <td> 670 <td> 0 <td> 0
|
||||
<tr> <th> read <td> 332 <td> 80 <td> 4
|
||||
<tr> <th> write <td> 172 <td> 149 <td> 0
|
||||
</table>
|
||||
|
||||
The large number of forks relative to bash are due to fish's insanely expensive default prompt, which is unchanged in my version. If we switch to a prompt comparable to bash's (lame) default, the forks drop to 16 with trunk, 4 after our changes.
|
||||
|
||||
The large reduction in lstat() numbers is due to fish no longer needing to call ttyname() on OS X.
|
||||
|
||||
We've got some work to do to be as lean as bash, but we're on the right track.
|
||||
296
CONTRIBUTING.md
296
CONTRIBUTING.md
@@ -1,105 +1,255 @@
|
||||
# Style guide
|
||||
|
||||
This is style guide for fish contributors. You should use it for any new code
|
||||
that you would add to this project and try to format existing code to use this
|
||||
style.
|
||||
# Guidelines For Developers
|
||||
|
||||
## Formatting
|
||||
This document provides guidelines for making changes to the fish-shell project. This includes rules for how to format the code, naming conventions, etc. It also includes recommended best practices such as creating a Travis-CI account so you can verify your changes pass all the tests before making a pull-request.
|
||||
|
||||
1. fish uses the Allman/BSD style of indentation.
|
||||
2. Indent with spaces, not tabs.
|
||||
3. Use 4 spaces per indent (unless needed like `Makefile`).
|
||||
4. Opening curly bracket is on the following line:
|
||||
See the bottom of this document for help on installing the linting and style reformatting tools discussed in the following sections.
|
||||
|
||||
// ✔:
|
||||
struct name
|
||||
{
|
||||
// code
|
||||
};
|
||||
Fish source should limit the C++ features it uses to those available in C++03. That allows fish to use a few components from [C++TR1](https://en.wikipedia.org/wiki/C%2B%2B_Technical_Report_1) such as `shared_ptr`. It also allows fish to be built and run on OS X Snow Leopard (released in 2009); the oldest OS X release we still support.
|
||||
|
||||
void func()
|
||||
{
|
||||
// code
|
||||
}
|
||||
## Include What You Use
|
||||
|
||||
if (...)
|
||||
{
|
||||
// code
|
||||
}
|
||||
You should not depend on symbols being visible to a `*.cpp` module from `#include` statements inside another header file. In other words if your module does `#include "common.h"` and that header does `#include "signal.h"` your module should pretend that sub-include is not present. It should instead directly `#include "signal.h"` if it needs any symbol from that header. That makes the actual dependencies much clearer. It also makes it easy to modify the headers included by a specific header file without having to worry that will break any module (or header) that includes a particular header.
|
||||
|
||||
// ✗:
|
||||
void func() {
|
||||
// code
|
||||
}
|
||||
To help enforce this rule the `make lint` (and `make lint-all`) command will run the [include-what-you-use](http://include-what-you-use.org/) tool. The IWYU you project is on [github](https://github.com/include-what-you-use/include-what-you-use).
|
||||
|
||||
5. Put space after `if`, `while` and `for` before conditions.
|
||||
To install the tool on OS X you'll need to add a [formula](https://github.com/jasonmp85/homebrew-iwyu) then install it:
|
||||
|
||||
// ✔:
|
||||
if () {}
|
||||
```
|
||||
brew tap jasonmp85/iwyu
|
||||
brew install iwyu
|
||||
```
|
||||
|
||||
// ✗:
|
||||
if() {}
|
||||
On Ubuntu you can install it via `sudo apt-get install iwyu`.
|
||||
|
||||
6. Put spaces before and after operators excluding increment and decrement;
|
||||
## Lint Free Code
|
||||
|
||||
// ✔:
|
||||
int a = 1 + 2 * 3;
|
||||
a++;
|
||||
Automated analysis tools like cppcheck and oclint can point out potential bugs. They also help ensure the code has a consistent style and that it avoids patterns that tend to confuse people.
|
||||
|
||||
// ✗:
|
||||
int a=1+2*3;
|
||||
a ++;
|
||||
Ultimately we want lint free code. However, at the moment a lot of cleanup is required to reach that goal. For now simply try to avoid introducing new lint.
|
||||
|
||||
7. Never put spaces between function name and parameters list.
|
||||
To make linting the code easy there are two make targets: `lint` and `lint-all`. The latter does just what the name implies. The former will lint any modified but not committed `*.cpp` files. If there is no uncommitted work it will lint the files in the most recent commit.
|
||||
|
||||
// ✔:
|
||||
func(args);
|
||||
Fish has custom cppcheck rules in the file `.cppcheck.rule`. These help catch mistakes such as using `wcwidth()` rather than `fish_wcwidth()`. Please add a new rule if you find similar mistakes being made.
|
||||
|
||||
// ✗:
|
||||
func (args);
|
||||
### Dealing With Lint Warnings
|
||||
|
||||
8. Never put spaces after `(` and before `)`.
|
||||
9. Always put space after comma and semicolon.
|
||||
You are strongly encouraged to address a lint warning by refactoring the code, changing variable names, or whatever action is implied by the warning.
|
||||
|
||||
// ✔:
|
||||
func(arg1, arg2);
|
||||
### Suppressing Lint Warnings
|
||||
|
||||
for (int i = 0; i < LENGTH; i++) {}
|
||||
Once in a while the lint tools emit a false positive warning. For example, cppcheck might suggest a memory leak is present when that is not the case. To suppress that cppcheck warning you should insert a line like the following immediately prior to the line cppcheck warned about:
|
||||
|
||||
// ✗:
|
||||
func(arg1,arg2);
|
||||
```
|
||||
// cppcheck-suppress memleak // addr not really leaked
|
||||
```
|
||||
|
||||
for (int i = 0;i<LENGTH;i++) {}
|
||||
The explanatory portion of the suppression comment is optional. For other types of warnings replace "memleak" with the value inside the parenthesis (e.g., "nullPointerRedundantCheck") from a warning like the following:
|
||||
|
||||
## Documentation
|
||||
```
|
||||
[src/complete.cpp:1727]: warning (nullPointerRedundantCheck): Either the condition 'cmd_node' is redundant or there is possible null pointer dereference: cmd_node.
|
||||
```
|
||||
|
||||
Document your code using [Doxygen][dox].
|
||||
Suppressing oclint warnings is more complicated to describe so I'll refer you to the [OCLint HowTo](http://docs.oclint.org/en/latest/howto/suppress.html#annotations) on the topic.
|
||||
|
||||
1. Documentation comment should use double star notation or tripple slash:
|
||||
## Ensuring Your Changes Conform to the Style Guides
|
||||
|
||||
// ✔:
|
||||
/// Some var
|
||||
int var;
|
||||
The following sections discuss the specific rules for the style that should be used when writing fish code. To ensure your changes conform to the style rules you simply need to run
|
||||
|
||||
/**
|
||||
* Some func
|
||||
*/
|
||||
void func();
|
||||
```
|
||||
make style
|
||||
```
|
||||
|
||||
2. Use slash as tag mark:
|
||||
before commiting your change. That will run `git-clang-format` to rewrite just the lines you're modifying.
|
||||
|
||||
// ✔:
|
||||
If you've already committed your changes that's okay since it will then check the files in the most recent commit. This can be useful after you've merged someone elses change and want to check that it's style is acceptable. However, in that case it will run `clang-format` to ensure the entire file, not just the lines modified by the commit, conform to the style.
|
||||
|
||||
/**
|
||||
* \param a an integer argument.
|
||||
* \param s a constant character pointer.
|
||||
* \return The results
|
||||
*/
|
||||
int foo(int a, const char *s);
|
||||
If you want to check the style of the entire code base run
|
||||
|
||||
## Naming
|
||||
```
|
||||
make style-all
|
||||
```
|
||||
|
||||
All names in code should be `small_snake_case`. No Hungarian notation is used.
|
||||
Classes and structs names should be followed by `_t`.
|
||||
That command will refuse to restyle any files if you have uncommitted changes.
|
||||
|
||||
[dox]: http://www.stack.nl/~dimitri/doxygen/ "Doxygen homepage"
|
||||
### Configuring Your Editor for Fish C++ Code
|
||||
|
||||
#### ViM
|
||||
|
||||
As of ViM 7.4 it does not recognize triple-slash comments as used by Doxygen and the OS X Xcode IDE to flag comments that explain the following C symbol. This means the `gq` key binding to reformat such comments doesn't behave as expected. You can fix that by adding the following to your vimrc:
|
||||
|
||||
```
|
||||
autocmd Filetype c,cpp setlocal comments^=:///
|
||||
```
|
||||
|
||||
If you use ViM I recommend the [vim-clang-format plugin](https://github.com/rhysd/vim-clang-format) by [@rhysd](https://github.com/rhysd).
|
||||
|
||||
You can also get ViM to provide reasonably correct behavior by installing
|
||||
|
||||
http://www.vim.org/scripts/script.php?script_id=2636
|
||||
|
||||
#### Emacs
|
||||
|
||||
If you use Emacs: TBD
|
||||
|
||||
### Configuring Your Editor for Fish Scripts
|
||||
|
||||
If you use ViM: TBD
|
||||
|
||||
If you use Emacs: Install [fish-mode](https://github.com/wwwjfy/emacs-fish) (also available in melpa and melpa-stable) and `(setq-default indent-tabs-mode nil)` for it (via a hook or in `use-package`s ":init" block). It can also be made to run fish_indent via e.g.
|
||||
|
||||
```elisp
|
||||
(add-hook 'fish-mode-hook (lambda ()
|
||||
(add-hook 'before-save-hook 'fish_indent-before-save)))
|
||||
```
|
||||
|
||||
### Suppressing Reformatting of C++ Code
|
||||
|
||||
If you have a good reason for doing so you can tell `clang-format` to not reformat a block of code by enclosing it in comments like this:
|
||||
|
||||
```
|
||||
// clang-format off
|
||||
code to ignore
|
||||
// clang-format on
|
||||
```
|
||||
|
||||
## Fish Script Style Guide
|
||||
|
||||
1. Fish scripts such as those in the *share/functions* and *tests* directories should be formatted using the `fish_indent` command.
|
||||
|
||||
1. Function names should be all lowercase with undescores separating words. Private functions should begin with an underscore. The first word should be `fish` if the function is unique to fish.
|
||||
|
||||
1. The first word of global variable names should generally be `fish` for public vars or `_fish` for private vars to minimize the possibility of name clashes with user defined vars.
|
||||
|
||||
## C++ Style Guide
|
||||
|
||||
1. The [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) forms the basis of the fish C++ style guide. There are two major deviations for the fish project. First, a four, rather than two, space indent. Second, line lengths up to 100, rather than 80, characters.
|
||||
|
||||
1. The `clang-format` command is authoritative with respect to indentation, whitespace around operators, etc. **Note**: this rule should be ignored at this time. After the code is cleaned up this rule will become mandatory.
|
||||
|
||||
1. All names in code should be `small_snake_case`. No Hungarian notation is used. Classes and structs names should be followed by `_t`.
|
||||
|
||||
1. Always attach braces to the surrounding context.
|
||||
|
||||
1. Indent with spaces, not tabs and use four spaces per indent.
|
||||
|
||||
1. Comments should always use the C++ style; i.e., each line of the comment should begin with a `//` and should be limited to 100 characters. Comments that do not begin a line should be separated from the previous text by two spaces.
|
||||
|
||||
1. Comments that document the purpose of a function or class should begin with three slashes, `///`, so that OS X Xcode (and possibly other ideas) will extract the comment and show it in the "Quick Help" window when the cursor is on the symbol.
|
||||
|
||||
## Testing
|
||||
|
||||
The source code for fish includes a large collection of tests. If you are making any changes to fish, running these tests is highly recommended to make sure the behaviour remains consistent.
|
||||
|
||||
You are also strongly encouraged to add tests when changing the functionality of fish. Especially if you are fixing a bug to help ensure there are no regressions in the future (i.e., we don't reintroduce the bug).
|
||||
|
||||
### Local testing
|
||||
|
||||
The tests can be run on your local computer on all operating systems.
|
||||
|
||||
Running the tests is only supported from the autotools build and not xcodebuild. On OS X, you will need to install autoconf — we suggest using [Homebrew](http://brew.sh/) to install these tools.
|
||||
|
||||
autoconf
|
||||
./configure
|
||||
make test [gmake on BSD]
|
||||
|
||||
### Travis CI Build and Test
|
||||
|
||||
The Travis Continuous Integration services can be used to test your changes using multiple configurations. This is the same service that the fish shell project uses to ensure new changes haven't broken anything. Thus it is a really good idea that you leverage Travis CI before making a pull-request to avoid embarrasment at breaking the build.
|
||||
|
||||
You will need to [fork the fish-shell repository on GitHub](https://help.github.com/articles/fork-a-repo/). Then setup Travis to test your changes before you make a pull-request:
|
||||
|
||||
1. [Sign in to Travis CI](https://travis-ci.org/auth) with your GitHub account, accepting the GitHub access permissions confirmation.
|
||||
1. Once you're signed in, and your repositories are synchronised, go to your [profile page](https://travis-ci.org/profile) and enable the fish-shell repository.
|
||||
1. Push your changes to GitHub.
|
||||
|
||||
You'll receive an email when the tests are complete telling you whether or not any tests failed.
|
||||
|
||||
You'll find the configuration used to control Travis in the `.travis.yml` file.
|
||||
|
||||
### Git hooks
|
||||
|
||||
Since developers sometimes forget to run the tests, it can be helpful to use git hooks (see githooks(5)) to automate it.
|
||||
|
||||
One possibility is a pre-push hook script like this one:
|
||||
|
||||
```sh
|
||||
#!/bin/sh
|
||||
#### A pre-push hook for the fish-shell project
|
||||
# This will run the tests when a push to master is detected, and will stop that if the tests fail
|
||||
# Save this as .git/hooks/pre-push and make it executable
|
||||
|
||||
protected_branch='master'
|
||||
|
||||
# Git gives us lines like "refs/heads/frombranch SOMESHA1 refs/heads/tobranch SOMESHA1"
|
||||
# We're only interested in the branches
|
||||
while read from _ to _; do
|
||||
if [ "x$to" = "xrefs/heads/$protected_branch" ]; then
|
||||
isprotected=1
|
||||
fi
|
||||
done
|
||||
if [ "x$isprotected" = x1 ]; then
|
||||
echo "Running tests before push to master"
|
||||
make test
|
||||
RESULT=$?
|
||||
if [ $RESULT -ne 0 ]; then
|
||||
echo "Tests failed for a push to master, we can't let you do that" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
```
|
||||
|
||||
This will check if the push is to the master branch and, if it is, will run `make test` and only allow the push if that succeeds. In some circumstances it might be advisable to circumvent it with `git push --no-verify`, but usually that should not be necessary.
|
||||
|
||||
To install the hook, put it in .git/hooks/pre-push and make it executable.
|
||||
|
||||
### Coverity Scan
|
||||
|
||||
We use Coverity's static analysis tool which offers free access to open source projects. While access to the tool itself is
|
||||
restricted, fish-shell organization members should know that they can login
|
||||
[here with their GitHub account](https://scan.coverity.com/projects/fish-shell-fish-shell?tab=overview).
|
||||
Currently, tests are triggered upon merging the `master` branch into `coverity_scan_master`.
|
||||
Even if you are not a fish developer, you can keep an eye on our statistics there.
|
||||
|
||||
## Installing the Required Tools
|
||||
|
||||
### Installing the Linting Tools
|
||||
|
||||
To install the lint checkers on Mac OS X using HomeBrew:
|
||||
|
||||
```
|
||||
brew tap oclint/formulae
|
||||
brew install oclint
|
||||
brew install cppcheck
|
||||
```
|
||||
|
||||
To install the lint checkers on Linux distros that use Apt:
|
||||
|
||||
```
|
||||
sudo apt-get install clang
|
||||
sudo apt-get install oclint
|
||||
sudo apt-get install cppcheck
|
||||
```
|
||||
|
||||
### Installing the Reformatting Tools
|
||||
|
||||
To install the reformatting tool on Mac OS X using HomeBrew:
|
||||
|
||||
```
|
||||
brew install clang-format
|
||||
```
|
||||
|
||||
To install the reformatting tool on Linux distros that use Apt:
|
||||
|
||||
```
|
||||
apt-cache search clang-format
|
||||
```
|
||||
|
||||
That will list the versions available. Pick the newest one available (3.6 for Ubuntu 14.04 as I write this) and install it:
|
||||
|
||||
```
|
||||
sudo apt-get install clang-format-3.6
|
||||
sudo ln -s /usr/bin/clang-format-3.6 /usr/bin/clang-format
|
||||
|
||||
```
|
||||
|
||||
20
Doxyfile
20
Doxyfile
@@ -274,6 +274,8 @@ ALIASES += "span{2}=\2"
|
||||
ALIASES += "spcl{2}=\2"
|
||||
|
||||
ALIASES += "bksl{1}=\\\1"
|
||||
ALIASES += "pcnt{1}=\%\1"
|
||||
ALIASES += "atat{1}=\@"
|
||||
|
||||
# This tag can be used to specify a number of word-keyword mappings (TCL only).
|
||||
# A mapping has the form "name=value". For example adding "class=itcl::class"
|
||||
@@ -287,7 +289,7 @@ TCL_SUBST =
|
||||
# members will be omitted, etc.
|
||||
# The default value is: NO.
|
||||
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
|
||||
# Python sources only. Doxygen will then generate output that is more tailored
|
||||
@@ -820,7 +822,7 @@ INPUT_ENCODING = UTF-8
|
||||
# *.qsf, *.as and *.js.
|
||||
|
||||
FILE_PATTERNS = *.h \
|
||||
*.c
|
||||
*.cpp
|
||||
|
||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||
# be searched for input files as well.
|
||||
@@ -835,19 +837,7 @@ RECURSIVE = NO
|
||||
# Note that relative paths are relative to the directory from which doxygen is
|
||||
# run.
|
||||
|
||||
EXCLUDE = print_help.c \
|
||||
xdgmimealias.c \
|
||||
xdgmimealias.h \
|
||||
xdgmime.c \
|
||||
xdgmimeglob.c \
|
||||
xdgmimeglob.h \
|
||||
xdgmime.h \
|
||||
xdgmimeint.c \
|
||||
xdgmimeint.h \
|
||||
xdgmimemagic.c \
|
||||
xdgmimemagic.h \
|
||||
xdgmimeparent.c \
|
||||
xdgmimeparent.h
|
||||
EXCLUDE =
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||
|
||||
@@ -274,6 +274,8 @@ ALIASES += "span{2}=\2"
|
||||
ALIASES += "spcl{2}=\2"
|
||||
|
||||
ALIASES += "bksl{1}=\\\1"
|
||||
ALIASES += "pcnt{1}=\%\1"
|
||||
ALIASES += "atat{1}=\@"
|
||||
|
||||
# This tag can be used to specify a number of word-keyword mappings (TCL only).
|
||||
# A mapping has the form "name=value". For example adding "class=itcl::class"
|
||||
@@ -739,7 +741,7 @@ CITE_BIB_FILES =
|
||||
# messages are off.
|
||||
# The default value is: NO.
|
||||
|
||||
QUIET = NO
|
||||
QUIET = YES
|
||||
|
||||
# The WARNINGS tag can be used to turn on/off the warning messages that are
|
||||
# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
|
||||
|
||||
@@ -274,6 +274,8 @@ ALIASES += "span{2}=<span style=\"\1\">\2</span>"
|
||||
ALIASES += "spcl{2}=<span class=\"\1\">\2</span>"
|
||||
|
||||
ALIASES += "bksl{1}=<span>\</span>\1"
|
||||
ALIASES += "pcnt{1}=<span>%</span>\1"
|
||||
ALIASES += "atat{1}=<span>@</span>"
|
||||
|
||||
# This tag can be used to specify a number of word-keyword mappings (TCL only).
|
||||
# A mapping has the form "name=value". For example adding "class=itcl::class"
|
||||
@@ -739,7 +741,7 @@ CITE_BIB_FILES =
|
||||
# messages are off.
|
||||
# The default value is: NO.
|
||||
|
||||
QUIET = NO
|
||||
QUIET = YES
|
||||
|
||||
# The WARNINGS tag can be used to turn on/off the warning messages that are
|
||||
# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
|
||||
|
||||
1334
Makefile.in
1334
Makefile.in
File diff suppressed because it is too large
Load Diff
32
README.md
32
README.md
@@ -7,25 +7,27 @@ For more on fish's design philosophy, see the [design document](http://fishshell
|
||||
|
||||
## Quick Start
|
||||
|
||||
fish generally works like other shells, like bash or zsh. A few important differences can be found at <http://fishshell.com/docs/current/tutorial.html> by searching for the magic phrase 'unlike other shells'.
|
||||
fish generally works like other shells, like bash or zsh. A few important differences can be found at <http://fishshell.com/docs/current/tutorial.html> by searching for the magic phrase "unlike other shells".
|
||||
|
||||
Detailed user documentation is available by running `help` within fish, and also at <http://fishshell.com/docs/current/index.html>
|
||||
|
||||
## Building
|
||||
|
||||
fish is written in a sane subset of C++98, with a few components from C++TR1. It builds successfully with g++ 4.2 or later, and with clang. It also will build as C++11.
|
||||
Fish can be built using a C++11 environment but only requires C++03. It builds successfully with g++ 4.2 or later, and with clang. This allows fish to run on older systems such as OS X Snow Leopard (released in 2009).
|
||||
|
||||
fish can be built using autotools or Xcode. autoconf 2.60 or later is required.
|
||||
Fish can be built using autotools or Xcode. autoconf 2.60 or later is required to build from git versions, but is not required for releases.
|
||||
|
||||
fish depends on a curses implementation, such as ncurses. The headers and libraries are required for building.
|
||||
|
||||
fish requires PCRE2 due to the regular expression support contained in the `string` builtin. A copy is included with the source code, and will be used automatically if it does not already exist on your system.
|
||||
|
||||
fish requires gettext for translation support.
|
||||
|
||||
Building the documentation requires Doxygen 1.8.7 or newer.
|
||||
|
||||
### Autotools Build
|
||||
|
||||
autoconf
|
||||
autoconf [if building from Git]
|
||||
./configure
|
||||
make [gmake on BSD]
|
||||
sudo make install
|
||||
@@ -46,7 +48,7 @@ If fish reports that it could not find curses, try installing a curses developme
|
||||
|
||||
On Debian or Ubuntu you want:
|
||||
|
||||
sudo apt-get install build-essential ncurses-dev libncurses5-dev gettext
|
||||
sudo apt-get install build-essential ncurses-dev libncurses5-dev gettext autoconf
|
||||
|
||||
On RedHat, CentOS, or Amazon EC2:
|
||||
|
||||
@@ -56,13 +58,17 @@ On RedHat, CentOS, or Amazon EC2:
|
||||
|
||||
fish requires a curses implementation, such as ncurses, to run.
|
||||
|
||||
fish requires PCRE2 due to the regular expression support contained in the `string` builtin. A bundled version will be compiled in automatically at build time if required.
|
||||
|
||||
fish requires a number of utilities to operate, which should be present on any Unix, GNU/Linux or OS X system. These include (but are not limited to) hostname, grep, awk, sed, which, and getopt. fish also requires the bc program.
|
||||
|
||||
Translation support requires the gettext program.
|
||||
|
||||
Usage output for builtin functions is generated on-demand from the installed manpages using `nroff` and `ul`.
|
||||
|
||||
Some optional features of fish, such as the manual page completion parser and the web configuration tool, require Python.
|
||||
|
||||
In order to generate completions from man pages compressed with either lzma or xz, you may need to install an extra Python package. Python versions prior to 2.6 are not supported. For Python versions 2.6 to 3.2 you need to install the module `backports.lzma`. How to install it depends on your system and how you installed Python. Most Linux distributions should include it as a package named `backports-lzma` (or similar). From version 3.3 onwards, Python already includes the required module.
|
||||
In order to generate completions from man pages compressed with either lzma or xz, you may need to install an extra Python package. Python versions prior to 2.6 are not supported. To process lzma-compresed manpages, backports.lzma is needed for Python 3.2 or older. From version 3.3 onwards, Python already includes the required module.
|
||||
|
||||
## Packages for Linux
|
||||
|
||||
@@ -74,7 +80,11 @@ If you wish to use fish as your default shell, use the following command:
|
||||
|
||||
chsh -s /usr/local/bin/fish
|
||||
|
||||
chsh will prompt you for your password, and change your default shell.
|
||||
chsh will prompt you for your password, and change your default shell. Substitute "/usr/local/bin/fish" with whatever path to fish is in your /etc/shells file.
|
||||
|
||||
Use the following command if you didn't already add your fish path to /etc/shells.
|
||||
|
||||
echo /usr/local/bin/fish | sudo tee -a /etc/shells
|
||||
|
||||
To switch your default shell back, you can run:
|
||||
|
||||
@@ -82,8 +92,14 @@ To switch your default shell back, you can run:
|
||||
|
||||
Substitute /bin/bash with /bin/tcsh or /bin/zsh as appropriate.
|
||||
|
||||
You may need to logout/login for the change (chsh) to take effect.
|
||||
|
||||
## Contributing Changes to the Code
|
||||
|
||||
See the [Guide for Developers](CONTRIBUTING.md).
|
||||
|
||||
## Contact Us
|
||||
|
||||
Questions, comments, rants and raves can be posted to the official fish mailing list at <https://lists.sourceforge.net/lists/listinfo/fish-users> or join us on our IRC channel [#fish at irc.oftc.net](https://webchat.oftc.net/?channels=fish).
|
||||
Questions, comments, rants and raves can be posted to the official fish mailing list at <https://lists.sourceforge.net/lists/listinfo/fish-users> or join us on our [gitter.im channel](https://gitter.im/fish-shell/fish-shell) or IRC channel [#fish at irc.oftc.net](https://webchat.oftc.net/?channels=fish). Or use the [fish tag on Stackoverflow](https://stackoverflow.com/questions/tagged/fish).
|
||||
|
||||
Found a bug? Have an awesome idea? Please open an issue on this github page.
|
||||
|
||||
375
autoload.cpp
375
autoload.cpp
@@ -1,375 +0,0 @@
|
||||
/** \file autoload.cpp
|
||||
|
||||
The classes responsible for autoloading functions and completions.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "autoload.h"
|
||||
#include "wutil.h"
|
||||
#include "common.h"
|
||||
#include "signal.h"
|
||||
#include "env.h"
|
||||
#include "exec.h"
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
|
||||
/* The time before we'll recheck an autoloaded file */
|
||||
static const int kAutoloadStalenessInterval = 15;
|
||||
|
||||
file_access_attempt_t access_file(const wcstring &path, int mode)
|
||||
{
|
||||
//printf("Touch %ls\n", path.c_str());
|
||||
file_access_attempt_t result = {};
|
||||
struct stat statbuf;
|
||||
if (wstat(path, &statbuf))
|
||||
{
|
||||
result.error = errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.mod_time = statbuf.st_mtime;
|
||||
if (waccess(path, mode))
|
||||
{
|
||||
result.error = errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.accessible = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Note that we record the last checked time after the call, on the assumption that in a slow filesystem, the lag comes before the kernel check, not after.
|
||||
result.stale = false;
|
||||
result.last_checked = time(NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
autoload_t::autoload_t(const wcstring &env_var_name_var, const builtin_script_t * const scripts, size_t script_count) :
|
||||
lock(),
|
||||
env_var_name(env_var_name_var),
|
||||
builtin_scripts(scripts),
|
||||
builtin_script_count(script_count)
|
||||
{
|
||||
pthread_mutex_init(&lock, NULL);
|
||||
}
|
||||
|
||||
autoload_t::~autoload_t()
|
||||
{
|
||||
pthread_mutex_destroy(&lock);
|
||||
}
|
||||
|
||||
void autoload_t::node_was_evicted(autoload_function_t *node)
|
||||
{
|
||||
// This should only ever happen on the main thread
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
|
||||
// Tell ourselves that the command was removed if it was loaded
|
||||
if (node->is_loaded)
|
||||
this->command_removed(node->key);
|
||||
delete node;
|
||||
}
|
||||
|
||||
int autoload_t::unload(const wcstring &cmd)
|
||||
{
|
||||
return this->evict_node(cmd);
|
||||
}
|
||||
|
||||
int autoload_t::load(const wcstring &cmd, bool reload)
|
||||
{
|
||||
int res;
|
||||
CHECK_BLOCK(0);
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
|
||||
env_var_t path_var = env_get_string(env_var_name);
|
||||
|
||||
/*
|
||||
Do we know where to look?
|
||||
*/
|
||||
if (path_var.empty())
|
||||
return 0;
|
||||
|
||||
/* Check if the lookup path has changed. If so, drop all loaded files. path_var may only be inspected on the main thread. */
|
||||
if (path_var != this->last_path)
|
||||
{
|
||||
this->last_path = path_var;
|
||||
this->last_path_tokenized.clear();
|
||||
tokenize_variable_array(this->last_path, this->last_path_tokenized);
|
||||
|
||||
scoped_lock locker(lock);
|
||||
this->evict_all_nodes();
|
||||
}
|
||||
|
||||
/* Mark that we're loading this. Hang onto the iterator for fast erasing later. Note that std::set has guarantees about not invalidating iterators, so this is safe to do across the callouts below. */
|
||||
typedef std::set<wcstring>::iterator set_iterator_t;
|
||||
std::pair<set_iterator_t, bool> insert_result = is_loading_set.insert(cmd);
|
||||
set_iterator_t where = insert_result.first;
|
||||
bool inserted = insert_result.second;
|
||||
|
||||
/** Warn and fail on infinite recursion. It's OK to do this because this function is only called on the main thread. */
|
||||
if (! inserted)
|
||||
{
|
||||
/* We failed to insert */
|
||||
debug(0,
|
||||
_(L"Could not autoload item '%ls', it is already being autoloaded. "
|
||||
L"This is a circular dependency in the autoloading scripts, please remove it."),
|
||||
cmd.c_str());
|
||||
return 1;
|
||||
}
|
||||
/* Try loading it */
|
||||
res = this->locate_file_and_maybe_load_it(cmd, true, reload, this->last_path_tokenized);
|
||||
|
||||
/* Clean up */
|
||||
is_loading_set.erase(where);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool autoload_t::can_load(const wcstring &cmd, const env_vars_snapshot_t &vars)
|
||||
{
|
||||
const env_var_t path_var = vars.get(env_var_name);
|
||||
if (path_var.missing_or_empty())
|
||||
return false;
|
||||
|
||||
std::vector<wcstring> path_list;
|
||||
tokenize_variable_array(path_var, path_list);
|
||||
return this->locate_file_and_maybe_load_it(cmd, false, false, path_list);
|
||||
}
|
||||
|
||||
static bool script_name_precedes_script_name(const builtin_script_t &script1, const builtin_script_t &script2)
|
||||
{
|
||||
return wcscmp(script1.name, script2.name) < 0;
|
||||
}
|
||||
|
||||
void autoload_t::unload_all(void)
|
||||
{
|
||||
scoped_lock locker(lock);
|
||||
this->evict_all_nodes();
|
||||
}
|
||||
|
||||
/** Check whether the given command is loaded. */
|
||||
bool autoload_t::has_tried_loading(const wcstring &cmd)
|
||||
{
|
||||
scoped_lock locker(lock);
|
||||
autoload_function_t * func = this->get_node(cmd);
|
||||
return func != NULL;
|
||||
}
|
||||
|
||||
static bool is_stale(const autoload_function_t *func)
|
||||
{
|
||||
/** Return whether this function is stale. Internalized functions can never be stale. */
|
||||
return ! func->is_internalized && time(NULL) - func->access.last_checked > kAutoloadStalenessInterval;
|
||||
}
|
||||
|
||||
autoload_function_t *autoload_t::get_autoloaded_function_with_creation(const wcstring &cmd, bool allow_eviction)
|
||||
{
|
||||
ASSERT_IS_LOCKED(lock);
|
||||
autoload_function_t *func = this->get_node(cmd);
|
||||
if (! func)
|
||||
{
|
||||
func = new autoload_function_t(cmd);
|
||||
if (allow_eviction)
|
||||
{
|
||||
this->add_node(func);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->add_node_without_eviction(func);
|
||||
}
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
This internal helper function does all the real work. By using two
|
||||
functions, the internal function can return on various places in
|
||||
the code, and the caller can take care of various cleanup work.
|
||||
|
||||
cmd: the command name ('grep')
|
||||
really_load: whether to actually parse it as a function, or just check it it exists
|
||||
reload: whether to reload it if it's already loaded
|
||||
path_list: the set of paths to check
|
||||
|
||||
Result: if really_load is true, returns whether the function was loaded. Otherwise returns whether the function existed.
|
||||
*/
|
||||
bool autoload_t::locate_file_and_maybe_load_it(const wcstring &cmd, bool really_load, bool reload, const wcstring_list_t &path_list)
|
||||
{
|
||||
/* Note that we are NOT locked in this function! */
|
||||
bool reloaded = 0;
|
||||
|
||||
/* Try using a cached function. If we really want the function to be loaded, require that it be really loaded. If we're not reloading, allow stale functions. */
|
||||
{
|
||||
bool allow_stale_functions = ! reload;
|
||||
|
||||
/* Take a lock */
|
||||
scoped_lock locker(lock);
|
||||
|
||||
/* Get the function */
|
||||
autoload_function_t * func = this->get_node(cmd);
|
||||
|
||||
/* Determine if we can use this cached function */
|
||||
bool use_cached;
|
||||
if (! func)
|
||||
{
|
||||
/* Can't use a function that doesn't exist */
|
||||
use_cached = false;
|
||||
}
|
||||
else if (really_load && ! func->is_placeholder && ! func->is_loaded)
|
||||
{
|
||||
/* Can't use an unloaded function */
|
||||
use_cached = false;
|
||||
}
|
||||
else if (! allow_stale_functions && is_stale(func))
|
||||
{
|
||||
/* Can't use a stale function */
|
||||
use_cached = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* I guess we can use it */
|
||||
use_cached = true;
|
||||
}
|
||||
|
||||
/* If we can use this function, return whether we were able to access it */
|
||||
if (use_cached)
|
||||
{
|
||||
assert(func != NULL);
|
||||
return func->is_internalized || func->access.accessible;
|
||||
}
|
||||
}
|
||||
/* The source of the script will end up here */
|
||||
wcstring script_source;
|
||||
bool has_script_source = false;
|
||||
|
||||
/* Whether we found an accessible file */
|
||||
bool found_file = false;
|
||||
|
||||
/* Look for built-in scripts via a binary search */
|
||||
const builtin_script_t *matching_builtin_script = NULL;
|
||||
if (builtin_script_count > 0)
|
||||
{
|
||||
const builtin_script_t test_script = {cmd.c_str(), NULL};
|
||||
const builtin_script_t *array_end = builtin_scripts + builtin_script_count;
|
||||
const builtin_script_t *found = std::lower_bound(builtin_scripts, array_end, test_script, script_name_precedes_script_name);
|
||||
if (found != array_end && ! wcscmp(found->name, test_script.name))
|
||||
{
|
||||
/* We found it */
|
||||
matching_builtin_script = found;
|
||||
}
|
||||
}
|
||||
if (matching_builtin_script)
|
||||
{
|
||||
has_script_source = true;
|
||||
script_source = str2wcstring(matching_builtin_script->def);
|
||||
|
||||
/* Make a node representing this function */
|
||||
scoped_lock locker(lock);
|
||||
autoload_function_t *func = this->get_autoloaded_function_with_creation(cmd, really_load);
|
||||
|
||||
/* This function is internalized */
|
||||
func->is_internalized = true;
|
||||
|
||||
/* It's a fiction to say the script is loaded at this point, but we're definitely going to load it down below. */
|
||||
if (really_load) func->is_loaded = true;
|
||||
}
|
||||
|
||||
if (! has_script_source)
|
||||
{
|
||||
/* Iterate over path searching for suitable completion files */
|
||||
for (size_t i=0; i<path_list.size(); i++)
|
||||
{
|
||||
wcstring next = path_list.at(i);
|
||||
wcstring path = next + L"/" + cmd + L".fish";
|
||||
|
||||
const file_access_attempt_t access = access_file(path, R_OK);
|
||||
if (access.accessible)
|
||||
{
|
||||
/* Found it! */
|
||||
found_file = true;
|
||||
|
||||
/* Now we're actually going to take the lock. */
|
||||
scoped_lock locker(lock);
|
||||
autoload_function_t *func = this->get_node(cmd);
|
||||
|
||||
/* Generate the source if we need to load it */
|
||||
bool need_to_load_function = really_load && (func == NULL || func->access.mod_time != access.mod_time || ! func->is_loaded);
|
||||
if (need_to_load_function)
|
||||
{
|
||||
|
||||
/* Generate the script source */
|
||||
wcstring esc = escape_string(path, 1);
|
||||
script_source = L"source " + esc;
|
||||
has_script_source = true;
|
||||
|
||||
/* Remove any loaded command because we are going to reload it. Note that this will deadlock if command_removed calls back into us. */
|
||||
if (func && func->is_loaded)
|
||||
{
|
||||
command_removed(cmd);
|
||||
func->is_placeholder = false;
|
||||
}
|
||||
|
||||
/* Mark that we're reloading it */
|
||||
reloaded = true;
|
||||
}
|
||||
|
||||
/* Create the function if we haven't yet. This does not load it. Do not trigger eviction unless we are actually loading, because we don't want to evict off of the main thread. */
|
||||
if (! func)
|
||||
{
|
||||
func = get_autoloaded_function_with_creation(cmd, really_load);
|
||||
}
|
||||
|
||||
/* It's a fiction to say the script is loaded at this point, but we're definitely going to load it down below. */
|
||||
if (need_to_load_function) func->is_loaded = true;
|
||||
|
||||
/* Unconditionally record our access time */
|
||||
func->access = access;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
If no file or builtin script was found we insert a placeholder function.
|
||||
Later we only research if the current time is at least five seconds later.
|
||||
This way, the files won't be searched over and over again.
|
||||
*/
|
||||
if (! found_file && ! has_script_source)
|
||||
{
|
||||
scoped_lock locker(lock);
|
||||
/* Generate a placeholder */
|
||||
autoload_function_t *func = this->get_node(cmd);
|
||||
if (! func)
|
||||
{
|
||||
func = new autoload_function_t(cmd);
|
||||
func->is_placeholder = true;
|
||||
if (really_load)
|
||||
{
|
||||
this->add_node(func);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->add_node_without_eviction(func);
|
||||
}
|
||||
}
|
||||
func->access.last_checked = time(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a script, either built-in or a file source, then run it */
|
||||
if (really_load && has_script_source)
|
||||
{
|
||||
if (exec_subshell(script_source, false /* do not apply exit status */) == -1)
|
||||
{
|
||||
/* Do nothing on failure */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (really_load)
|
||||
{
|
||||
return reloaded;
|
||||
}
|
||||
else
|
||||
{
|
||||
return found_file || has_script_source;
|
||||
}
|
||||
}
|
||||
136
autoload.h
136
autoload.h
@@ -1,136 +0,0 @@
|
||||
/** \file autoload.h
|
||||
|
||||
The classes responsible for autoloading functions and completions.
|
||||
*/
|
||||
|
||||
#ifndef FISH_AUTOLOAD_H
|
||||
#define FISH_AUTOLOAD_H
|
||||
|
||||
#include <wchar.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include "common.h"
|
||||
#include "lru.h"
|
||||
|
||||
/** A struct responsible for recording an attempt to access a file. */
|
||||
struct file_access_attempt_t
|
||||
{
|
||||
time_t mod_time; /** The modification time of the file */
|
||||
time_t last_checked; /** When we last checked the file */
|
||||
bool accessible; /** Whether we believe we could access this file */
|
||||
bool stale; /** Whether the access attempt is stale */
|
||||
int error; /** If we could not access the file, the error code */
|
||||
};
|
||||
|
||||
file_access_attempt_t access_file(const wcstring &path, int mode);
|
||||
|
||||
struct autoload_function_t : public lru_node_t
|
||||
{
|
||||
autoload_function_t(const wcstring &key) : lru_node_t(key), access(), is_loaded(false), is_placeholder(false), is_internalized(false) { }
|
||||
file_access_attempt_t access; /** The last access attempt */
|
||||
bool is_loaded; /** Whether we have actually loaded this function */
|
||||
bool is_placeholder; /** Whether we are a placeholder that stands in for "no such function". If this is true, then is_loaded must be false. */
|
||||
bool is_internalized; /** Whether this function came from a builtin "internalized" script */
|
||||
};
|
||||
|
||||
struct builtin_script_t
|
||||
{
|
||||
const wchar_t *name;
|
||||
const char *def;
|
||||
};
|
||||
|
||||
struct builtin_script_t;
|
||||
class env_vars_snapshot_t;
|
||||
|
||||
/**
|
||||
A class that represents a path from which we can autoload, and the autoloaded contents.
|
||||
*/
|
||||
class autoload_t : private lru_cache_t<autoload_function_t>
|
||||
{
|
||||
private:
|
||||
|
||||
/** Lock for thread safety */
|
||||
pthread_mutex_t lock;
|
||||
|
||||
/** The environment variable name */
|
||||
const wcstring env_var_name;
|
||||
|
||||
/** Builtin script array */
|
||||
const struct builtin_script_t *const builtin_scripts;
|
||||
|
||||
/** Builtin script count */
|
||||
const size_t builtin_script_count;
|
||||
|
||||
/** The path from which we most recently autoloaded */
|
||||
wcstring last_path;
|
||||
|
||||
/** That path, tokenized (split on separators) */
|
||||
wcstring_list_t last_path_tokenized;
|
||||
|
||||
/**
|
||||
A table containing all the files that are currently being
|
||||
loaded. This is here to help prevent recursion.
|
||||
*/
|
||||
std::set<wcstring> is_loading_set;
|
||||
|
||||
void remove_all_functions(void)
|
||||
{
|
||||
this->evict_all_nodes();
|
||||
}
|
||||
|
||||
bool locate_file_and_maybe_load_it(const wcstring &cmd, bool really_load, bool reload, const wcstring_list_t &path_list);
|
||||
|
||||
virtual void node_was_evicted(autoload_function_t *node);
|
||||
|
||||
autoload_function_t *get_autoloaded_function_with_creation(const wcstring &cmd, bool allow_eviction);
|
||||
|
||||
protected:
|
||||
/** Overridable callback for when a command is removed */
|
||||
virtual void command_removed(const wcstring &cmd) { }
|
||||
|
||||
public:
|
||||
|
||||
/** Create an autoload_t for the given environment variable name */
|
||||
autoload_t(const wcstring &env_var_name_var, const builtin_script_t *scripts, size_t script_count);
|
||||
|
||||
/** Destructor */
|
||||
virtual ~autoload_t();
|
||||
|
||||
/**
|
||||
Autoload the specified file, if it exists in the specified path. Do
|
||||
not load it multiple times unless its timestamp changes or
|
||||
parse_util_unload is called.
|
||||
|
||||
Autoloading one file may unload another.
|
||||
|
||||
\param cmd the filename to search for. The suffix '.fish' is always added to this name
|
||||
\param on_unload a callback function to run if a suitable file is found, which has not already been run. unload will also be called for old files which are unloaded.
|
||||
\param reload wheter to recheck file timestamps on already loaded files
|
||||
*/
|
||||
int load(const wcstring &cmd, bool reload);
|
||||
|
||||
/** Check whether we have tried loading the given command. Does not do any I/O. */
|
||||
bool has_tried_loading(const wcstring &cmd);
|
||||
|
||||
/**
|
||||
Tell the autoloader that the specified file, in the specified path,
|
||||
is no longer loaded.
|
||||
|
||||
\param cmd the filename to search for. The suffix '.fish' is always added to this name
|
||||
\param on_unload a callback function which will be called before (re)loading a file, may be used to unload the previous file.
|
||||
\return non-zero if the file was removed, zero if the file had not yet been loaded
|
||||
*/
|
||||
int unload(const wcstring &cmd);
|
||||
|
||||
/**
|
||||
Unloads all files.
|
||||
*/
|
||||
void unload_all();
|
||||
|
||||
/** Check whether the given command could be loaded, but do not load it. */
|
||||
bool can_load(const wcstring &cmd, const env_vars_snapshot_t &vars);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -46,6 +46,9 @@ echo " input filter: $INPUTFILTER"
|
||||
echo " output directory: $OUTPUTDIR"
|
||||
echo " skipping: $CONDEMNED_PAGES"
|
||||
|
||||
#Until now the makefile likely has been affecting our output, reset for upcoming warnings
|
||||
tput sgr0
|
||||
|
||||
# Make sure INPUTDIR is found
|
||||
if test ! -d "$INPUTDIR"; then
|
||||
echo >&2 "Could not find input directory '${INPUTDIR}'"
|
||||
@@ -132,13 +135,18 @@ if test "$RESULT" = 0 ; then
|
||||
fi
|
||||
|
||||
# Destroy TMPLOC
|
||||
echo "Cleaning up '$TMPLOC'"
|
||||
if test "$RESULT" -ne 0; then
|
||||
echo "Cleaning up '$TMPLOC'"
|
||||
fi
|
||||
rm -Rf "$TMPLOC"
|
||||
|
||||
if test "$RESULT" = 0; then
|
||||
# Tell the user what we did
|
||||
echo "Output man pages into '${OUTPUTDIR}'"
|
||||
if test "$RESULT" -ne 0; then
|
||||
tput smso 2> /dev/null || true
|
||||
echo "Doxygen failed creating manpages. See the output log for details."
|
||||
tput sgr0 2> /dev/null || true
|
||||
else
|
||||
echo "Doxygen failed. See the output log for details."
|
||||
tput bold 2> /dev/null || true
|
||||
echo Built manpages
|
||||
tput sgr0 2> /dev/null || true
|
||||
fi
|
||||
exit $RESULT
|
||||
|
||||
3
build_tools/cppcheck.sh
Executable file
3
build_tools/cppcheck.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/local/bin/fish
|
||||
|
||||
cppcheck --enable=all --std=posix --quiet ./src/
|
||||
@@ -1,3 +0,0 @@
|
||||
This is the_ridiculous'fish s delightful fork of, fish friendly interactive shell. For more information, visit http://ridiculousfish.com/shell/ .
|
||||
|
||||
This installer will install fish, but will not modify your /etc/shells file or your default shell. I trust you know how to do that yourself if you care to!
|
||||
28
build_tools/iwyu.linux.imp
Normal file
28
build_tools/iwyu.linux.imp
Normal file
@@ -0,0 +1,28 @@
|
||||
# Map file for the include-what-you-use tool on Linux.
|
||||
[
|
||||
{ include: ["<bits/fcntl-linux.h>", "private", "<fcntl.h>", "public"] },
|
||||
{ include: ["<bits/mman-linux.h>", "private", "<sys/mman.h>", "public"] },
|
||||
{ include: ["<bits/socket-linux.h>", "private", "<sys/socket.h>", "public"] },
|
||||
{ include: ["<bits/socket_type.h>", "private", "<sys/socket.h>", "public"] },
|
||||
{ include: ["<bits/local_lim.h>", "private", "<limits.h>", "public"] },
|
||||
{ include: ["<tr1/memory>", "public", "<memory>", "public"] },
|
||||
{ include: ["<features.h>", "public", "<stdio.h>", "public"] },
|
||||
{ include: ["<features.h>", "public", "<stddef.h>", "public"] },
|
||||
{ include: ["<features.h>", "public", "<unistd.h>", "public"] },
|
||||
|
||||
{ symbol: ["size_t", "private", "<unistd.h>", "public"] },
|
||||
{ symbol: ["size_t", "private", "<stddef.h>", "public"] },
|
||||
{ symbol: ["size_t", "private", "<stdlib.h>", "public"] },
|
||||
{ symbol: ["intmax_t", "private", "<sys/stdint.h>", "public"] },
|
||||
{ symbol: ["intmax_t", "private", "<sys/types.h>", "public"] },
|
||||
{ symbol: ["uint32_t", "private", "<sys/stdint.h>", "public"] },
|
||||
{ symbol: ["uint32_t", "private", "<sys/types.h>", "public"] },
|
||||
{ symbol: ["uint64_t", "private", "<sys/stdint.h>", "public"] },
|
||||
{ symbol: ["uint64_t", "private", "<sys/types.h>", "public"] },
|
||||
{ symbol: ["uintmax_t", "private", "<sys/stdint.h>", "public"] },
|
||||
{ symbol: ["uintmax_t", "private", "<sys/types.h>", "public"] },
|
||||
{ symbol: ["clock_gettime", "private", "<sys/time.h>", "public"] },
|
||||
{ symbol: ["timespec", "private", "<sys/time.h>", "public"] },
|
||||
{ symbol: ["memset", "private", "<string.h>", "public"] },
|
||||
{ symbol: ["strerror", "private", "<string.h>", "public"] },
|
||||
]
|
||||
98
build_tools/iwyu.osx.imp
Normal file
98
build_tools/iwyu.osx.imp
Normal file
@@ -0,0 +1,98 @@
|
||||
# Map file for the include-what-you-use tool on OS X. For some reason
|
||||
# the version installed by HomeBrew doesn't have useful mappings for the
|
||||
# system provided private headers.
|
||||
[
|
||||
{ include: ["<sys/_pthread/_pthread_once_t.h>", "private", "<pthread.h>", "public"] },
|
||||
{ include: ["<sys/_pthread/_pthread_mutex_t.h>", "private", "<pthread.h>", "public"] },
|
||||
{ include: ["<sys/_pthread/_pthread_rwlock_t.h>", "private", "<pthread.h>", "public"] },
|
||||
{ include: ["<sys/_pthread/_pthread_mutexattr_t.h>", "private", "<pthread.h>", "public"] },
|
||||
{ include: ["<sys/_pthread/_pthread_cond_t.h>", "private", "<pthread.h>", "public"] },
|
||||
{ include: ["<sys/_pthread/_pthread_t.h>", "private", "<pthread.h>", "public"] },
|
||||
{ include: ["<sys/_pthread/_pthread_key_t.h>", "private", "<pthread.h>", "public"] },
|
||||
{ include: ["<sys/_types/_posix_vdisable.h>", "private", "<pthread.h>", "public"] },
|
||||
{ include: ["<sys/_types/_time_t.h>", "private", "<time.h>", "public"] },
|
||||
{ include: ["<sys/_types/_suseconds_t.h>", "private", "<time.h>", "public"] },
|
||||
{ include: ["<sys/_types/_suseconds_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/errno.h>", "private", "<errno.h>", "public"] },
|
||||
{ include: ["<sys/unistd.h>", "private", "<unistd.h>", "public"] },
|
||||
{ include: ["<_wctype.h>", "private", "<wctype.h>", "public"] },
|
||||
{ include: ["<sys/fcntl.h>", "private", "<fcntl.h>", "public"] },
|
||||
{ include: ["<sys/_types/_seek_set.h>", "private", "<fcntl.h>", "public"] },
|
||||
{ include: ["<sys/_types/_mbstate_t.h>", "private", "<wchar.h>", "public"] },
|
||||
{ include: ["<iosfwd>", "private", "<string>", "public"] },
|
||||
{ include: ["<sys/_types/_s_ifmt.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_size_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_size_t.h>", "private", "<stdlib.h>", "public"] },
|
||||
{ include: ["<sys/_types/_mode_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_pid_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_fd_def.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_fd_isset.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_fd_set.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_fd_zero.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_timeval.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_uid_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<_types/_intmax_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<_types/_uintmax_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<_types/_uint8_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_int32_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<_types/_uint64_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_uintptr_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_dev_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_ino_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_va_list.h>", "private", "<stdio.h>", "public"] },
|
||||
{ include: ["<__functional_base>", "private", "<memory>", "public"] },
|
||||
{ include: ["<__functional_base>", "private", "<vector>", "public"] },
|
||||
{ include: ["<__functional_base>", "private", "<string>", "public"] },
|
||||
{ include: ["<__tree>", "private", "<map>", "public"] },
|
||||
{ include: ["<__tree>", "private", "<set>", "public"] },
|
||||
{ include: ["<_types/_uint32_t.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_va_list.h>", "private", "<sys/types.h>", "public"] },
|
||||
{ include: ["<sys/_types/_sigset_t.h>", "private", "<signal.h>", "public"] },
|
||||
{ include: ["<sys/signal.h>", "private", "<signal.h>", "public"] },
|
||||
{ include: ["<strings.h>", "private", "<string.h>", "public"] },
|
||||
{ include: ["<sys/termios.h>", "private", "<termios.h>", "public"] },
|
||||
{ include: ["<sys/ttycom.h>", "private", "<termios.h>", "public"] },
|
||||
{ include: ["<sys/syslimits.h>", "private", "<limits.h>", "public"] },
|
||||
{ include: ["<i386/limits.h>", "private", "<limits.h>", "public"] },
|
||||
{ include: ["<sys/_types/_wint_t.h>", "private", "<stddef.h>", "public"] },
|
||||
{ include: ["<sys/_select.h>", "private", "<select.h>", "public"] },
|
||||
{ include: ["<sys/cdefs.h>", "private", "<unistd.h>", "public"] },
|
||||
{ include: ["<istream>", "private", "<iostream>", "public"] },
|
||||
{ include: ["<sys/_endian.h>", "private", "<netinet/in.h>", "public"] },
|
||||
{ include: ["<sys/_types/_timespec.h>", "private", "<time.h>", "public"] },
|
||||
{ include: ["<sys/spawn.h>", "private", "<spawn.h>", "public"] },
|
||||
{ include: ["<sys/dirent.h>", "private", "<dirent.h>", "public"] },
|
||||
# { include: ["<>", "private", "<>", "public"] },
|
||||
|
||||
{ symbol: ["NULL", "private", "<stddef.h>", "public"] },
|
||||
{ symbol: ["NULL", "private", "<stdlib.h>", "public"] },
|
||||
{ symbol: ["NULL", "private", "<stdio.h>", "public"] },
|
||||
{ symbol: ["NULL", "private", "<unistd.h>", "public"] },
|
||||
{ symbol: ["off_t", "private", "<unistd.h>", "public"] },
|
||||
{ symbol: ["size_t", "private", "<unistd.h>", "public"] },
|
||||
{ symbol: ["size_t", "private", "<stddef.h>", "public"] },
|
||||
{ symbol: ["size_t", "private", "<stdlib.h>", "public"] },
|
||||
{ symbol: ["off_t", "private", "<sys/types.h>", "public"] },
|
||||
{ symbol: ["size_t", "private", "<sys/types.h>", "public"] },
|
||||
{ symbol: ["ssize_t", "private", "<sys/types.h>", "public"] },
|
||||
{ symbol: ["intptr_t", "private", "<unistd.h>", "public"] },
|
||||
{ symbol: ["ssize_t", "private", "<unistd.h>", "public"] },
|
||||
{ symbol: ["gid_t", "private", "<unistd.h>", "public"] },
|
||||
{ symbol: ["uid_t", "private", "<unistd.h>", "public"] },
|
||||
{ symbol: ["pid_t", "private", "<unistd.h>", "public"] },
|
||||
{ symbol: ["pid_t", "private", "<sys/types.h>", "public"] },
|
||||
{ symbol: ["uid_t", "private", "<sys/types.h>", "public"] },
|
||||
{ symbol: ["gid_t", "private", "<sys/types.h>", "public"] },
|
||||
{ symbol: ["timeval", "private", "<sys/time.h>", "public"] },
|
||||
{ symbol: ["uint32_t", "private", "<sys/types.h>", "public"] },
|
||||
{ symbol: ["uint32_t", "private", "<stdint.h>", "public"] },
|
||||
{ symbol: ["intptr_t", "private", "<stdint.h>", "public"] },
|
||||
{ symbol: ["size_t", "private", "<stdint.h>", "public"] },
|
||||
{ symbol: ["tparm", "private", "<ncurses.h>", "public"] },
|
||||
{ symbol: ["ERR", "private", "<ncurses.h>", "public"] },
|
||||
{ symbol: ["select", "private", "<sys/select.h>", "public"] },
|
||||
{ symbol: ["_LIBCPP_VERSION", "private", "<stddef.h>", "public"] },
|
||||
{ symbol: ["_LIBCPP_VERSION", "private", "<unistd.h>", "public"] },
|
||||
{ symbol: ["MB_CUR_MAX", "private", "<xlocale.h>", "public"] },
|
||||
{ symbol: ["MB_CUR_MAX", "private", "<stdlib.h>", "public"] },
|
||||
]
|
||||
4
build_tools/iwyu.sh
Executable file
4
build_tools/iwyu.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
# Reminder of how to run Include What You Use
|
||||
|
||||
make iwyu
|
||||
131
build_tools/lint.fish
Executable file
131
build_tools/lint.fish
Executable file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env fish
|
||||
#
|
||||
# This is meant to be run by "make lint" or "make lint-all". It is not meant to
|
||||
# be run directly from a shell prompt.
|
||||
#
|
||||
set cppchecks warning,performance,portability,information,missingInclude
|
||||
set cppcheck_args
|
||||
set c_files
|
||||
set all no
|
||||
set kernel_name (uname -s)
|
||||
set machine_type (uname -m)
|
||||
|
||||
set -gx CXX $argv[1]
|
||||
set -e argv[1]
|
||||
|
||||
if test "$argv[1]" = "--all"
|
||||
set all yes
|
||||
set cppchecks "$cppchecks,unusedFunction"
|
||||
set -e argv[1]
|
||||
end
|
||||
|
||||
if test $kernel_name = Linux
|
||||
# This is an awful hack. However, the include-what-you-use program spews lots of errors like
|
||||
# /usr/include/unistd.h:226:10: fatal error: 'stddef.h' file not found
|
||||
# if we don't explicitly tell it where to find the system headers on Linux. See
|
||||
# http://stackoverflow.com/questions/19642590/libtooling-cant-find-stddef-h-nor-other-headers/
|
||||
set -l sys_includes (eval $CXX -v -c src/builtin.cpp 2>&1 | \
|
||||
sed -n -e '/^#include <...> search/,/^End of search list/s/^ *//p')[2..-2]
|
||||
set -x CPLUS_INCLUDE_PATH (string join ':' $sys_includes)
|
||||
end
|
||||
|
||||
# We only want -D and -I options to be passed thru to cppcheck.
|
||||
for arg in $argv
|
||||
if string match -q -- '-D*' $arg
|
||||
set cppcheck_args $cppcheck_args $arg
|
||||
else if string match -q -- '-I*' $arg
|
||||
set cppcheck_args $cppcheck_args $arg
|
||||
else if string match -q -- '-iquote*' $arg
|
||||
set cppcheck_args $cppcheck_args $arg
|
||||
end
|
||||
end
|
||||
if test "$machine_type" = "x86_64"
|
||||
set cppcheck_args -D__x86_64__ -D__LP64__ $cppcheck_args
|
||||
end
|
||||
|
||||
if test $all = yes
|
||||
set c_files src/*.cpp
|
||||
else
|
||||
# We haven't been asked to lint all the source. If there are uncommitted
|
||||
# changes lint those, else lint the files in the most recent commit.
|
||||
# Select (cached files) (modified but not cached, and untracked files)
|
||||
set files (git diff-index --cached HEAD --name-only) (git ls-files --exclude-standard --others --modified)
|
||||
if not set -q files[1]
|
||||
# No pending changes so lint the files in the most recent commit.
|
||||
set files (git diff-tree --no-commit-id --name-only -r HEAD)
|
||||
end
|
||||
|
||||
# Extract just the C/C++ files that exist.
|
||||
set c_files
|
||||
for file in (string match -r '.*\.c(?:pp)?$' -- $files)
|
||||
test -f $file; and set c_files $c_files $file
|
||||
end
|
||||
end
|
||||
|
||||
# We now have a list of files to check so run the linters.
|
||||
if set -q c_files[1]
|
||||
if type -q iwyu
|
||||
echo
|
||||
echo ========================================
|
||||
echo Running IWYU
|
||||
echo ========================================
|
||||
# The stderr to stdout redirection is because cppcheck, incorrectly IMHO, writes its
|
||||
# diagnostic messages to stderr. Anyone running this who wants to capture its output will
|
||||
# expect those messages to be written to stdout.
|
||||
for c_file in $c_files
|
||||
switch $kernel_name
|
||||
case Darwin
|
||||
include-what-you-use -Xiwyu --no_default_mappings -Xiwyu --mapping_file=build_tools/iwyu.osx.imp $cppcheck_args --std=c++11 $c_file 2>&1
|
||||
case Linux
|
||||
include-what-you-use -Xiwyu --mapping_file=build_tools/iwyu.linux.imp $cppcheck_args $c_file 2>&1
|
||||
case '*' # hope for the best
|
||||
include-what-you-use $cppcheck_args $c_file 2>&1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if type -q cppcheck
|
||||
echo
|
||||
echo ========================================
|
||||
echo Running cppcheck
|
||||
echo ========================================
|
||||
# The stderr to stdout redirection is because cppcheck, incorrectly IMHO, writes its
|
||||
# diagnostic messages to stderr. Anyone running this who wants to capture its output will
|
||||
# expect those messages to be written to stdout.
|
||||
cppcheck -q --verbose --std=posix --language=c++ --template "[{file}:{line}]: {severity} ({id}): {message}" --suppress=missingIncludeSystem --inline-suppr --enable=$cppchecks --rule-file=.cppcheck.rule $cppcheck_args $c_files 2>&1
|
||||
end
|
||||
|
||||
if type -q oclint
|
||||
echo
|
||||
echo ========================================
|
||||
echo Running oclint
|
||||
echo ========================================
|
||||
# The stderr to stdout redirection is because oclint, incorrectly writes its final summary
|
||||
# counts of the errors detected to stderr. Anyone running this who wants to capture its
|
||||
# output will expect those messages to be written to stdout.
|
||||
if test "$kernel_name" = "Darwin"
|
||||
if not test -f compile_commands.json
|
||||
xcodebuild >xcodebuild.log
|
||||
oclint-xcodebuild xcodebuild.log >/dev/null
|
||||
end
|
||||
if test $all = yes
|
||||
oclint-json-compilation-database -e '/pcre2-10.21/' -- -enable-global-analysis 2>&1
|
||||
else
|
||||
set i_files
|
||||
for f in $c_files
|
||||
set i_files $i_files -i $f
|
||||
end
|
||||
echo oclint-json-compilation-database -e '/pcre2-10.21/' $i_files
|
||||
oclint-json-compilation-database -e '/pcre2-10.21/' $i_files 2>&1
|
||||
end
|
||||
else
|
||||
# Presumably we're on Linux or other platform not requiring special
|
||||
# handling for oclint to work.
|
||||
oclint $c_files -- $argv 2>&1
|
||||
end
|
||||
end
|
||||
else
|
||||
echo
|
||||
echo 'WARNING: No C/C++ files to check'
|
||||
echo
|
||||
end
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Terminate on error
|
||||
set -e
|
||||
|
||||
sudo rm -Rf /tmp/fishfish
|
||||
mkdir /tmp/fishfish
|
||||
git archive --format=tar fish_fish | tar -x -C /tmp/fishfish
|
||||
mkdir /tmp/fishfish/doc-pak
|
||||
cp README INSTALL CHANGELOG release_notes.html /tmp/fishfish/doc-pak/
|
||||
cp build_tools/description-pak /tmp/fishfish/
|
||||
cd /tmp/fishfish
|
||||
autoconf
|
||||
./configure
|
||||
make -j 3
|
||||
sudo checkinstall --default --pakdir ~/fish_built/ --pkgversion 0.9 make install
|
||||
mv ~/fish_built/fishfish_0.9-1_i386.deb ~/fish_built/fishfish_0.9_i386.deb
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
VERSION=`sed -E -n 's/^.*PACKAGE_VERSION "([0-9.]+)"/\1/p' osx/config.h`
|
||||
# Script to produce an OS X installer .pkg and .app(.zip)
|
||||
|
||||
VERSION=`git describe --always --dirty 2>/dev/null`
|
||||
if test -z "$VERSION" ; then
|
||||
echo "Could not get version from osx/config.h"
|
||||
exit 1
|
||||
echo "Could not get version from git"
|
||||
VERSION=`sed -E -n 's/^.*PACKAGE_VERSION "([0-9a-z.\-]+)"/\1/p' osx/config.h`
|
||||
if test -z "$VERSION"; then
|
||||
echo "Could not get version from osx/config.h"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Version is $VERSION"
|
||||
@@ -11,20 +17,25 @@ echo "Version is $VERSION"
|
||||
set -x
|
||||
|
||||
make distclean
|
||||
rm -Rf /tmp/fish_pkg
|
||||
|
||||
#Exit on error
|
||||
set -e
|
||||
|
||||
mkdir -p /tmp/fish_pkg/root /tmp/fish_pkg/intermediates /tmp/fish_pkg/dst
|
||||
xcodebuild install -scheme install_tree -configuration Release DSTROOT=/tmp/fish_pkg/root/
|
||||
pkgbuild --scripts build_tools/osx_package_scripts --root /tmp/fish_pkg/root/ --identifier 'com.ridiculousfish.fish-shell-pkg' --version "$VERSION" /tmp/fish_pkg/intermediates/fish.pkg
|
||||
PKGDIR=`mktemp -d`
|
||||
|
||||
productbuild --package-path /tmp/fish_pkg/intermediates --distribution build_tools/osx_distribution.xml --resources build_tools/osx_package_resources/ ~/fish_built/fish.pkg
|
||||
OUTPUT_PATH=${FISH_ARTEFACT_PATH:-~/fish_built}
|
||||
|
||||
mkdir -p $PKGDIR/root $PKGDIR/intermediates $PKGDIR/dst
|
||||
xcodebuild install -scheme install_tree -configuration Release DSTROOT=$PKGDIR/root/
|
||||
pkgbuild --scripts build_tools/osx_package_scripts --root $PKGDIR/root/ --identifier 'com.ridiculousfish.fish-shell-pkg' --version "$VERSION" $PKGDIR/intermediates/fish.pkg
|
||||
|
||||
productbuild --package-path $PKGDIR/intermediates --distribution build_tools/osx_distribution.xml --resources build_tools/osx_package_resources/ $OUTPUT_PATH/fish-$VERSION.pkg
|
||||
|
||||
|
||||
# Make the app
|
||||
xcodebuild -scheme fish.app -configuration Release DSTROOT=/tmp/fish_app/
|
||||
rm -f ~/fish_built/fish.app.zip
|
||||
xcodebuild -scheme fish.app -configuration Release DSTROOT=/tmp/fish_app/ SYMROOT=DerivedData/fish/Build/Products
|
||||
|
||||
cd DerivedData/fish/Build/Products/Release/
|
||||
zip -r ~/fish_built/fish.app.zip fish.app
|
||||
zip -r $OUTPUT_PATH/fish-$VERSION.app.zip fish.app
|
||||
|
||||
rm -r $PKGDIR
|
||||
|
||||
@@ -4,27 +4,43 @@
|
||||
# We use git to output a tree. But we also want to build the user documentation
|
||||
# and put that in the tarball, so that nobody needs to have doxygen installed
|
||||
# to build it.
|
||||
# Outputs to $FISH_ARTEFACT_PATH or ~/fish_built by default
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
|
||||
# We wil generate a tarball with a prefix "fish"
|
||||
# We wil generate a tarball with a prefix "fish-VERSION"
|
||||
# git can do that automatically for us via git-archive
|
||||
# but to get the documentation in, we need to make a symlink called "fish"
|
||||
# but to get the documentation in, we need to make a symlink called "fish-VERSION"
|
||||
# and tar from that, so that the documentation gets the right prefix
|
||||
|
||||
# We need GNU tar as that supports the --mtime option
|
||||
# BSD tar supports --mtree but keeping them in sync sounds too hard
|
||||
TAR=notfound
|
||||
for try in tar gtar gnutar; do
|
||||
if $try -Pcf /dev/null --mtime now /dev/null >/dev/null 2>&1; then
|
||||
TAR=$try
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$TAR" = "notfound" ]; then
|
||||
echo 'No suitable tar (supporting --mtime) found as tar/gtar/gnutar in PATH'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the current directory, which we'll use for symlinks
|
||||
wd="$PWD"
|
||||
|
||||
# The name of the prefix, which is the directory that you get when you untar
|
||||
prefix="fish"
|
||||
|
||||
# Get the version from git-describe
|
||||
VERSION=`git describe --dirty 2>/dev/null`
|
||||
prefix="$prefix-$VERSION"
|
||||
|
||||
# The name of the prefix, which is the directory that you get when you untar
|
||||
prefix="fish-$VERSION"
|
||||
|
||||
# The path where we will output the tar file
|
||||
path=~/fish_built/$prefix.tar
|
||||
# Defaults to ~/fish_built
|
||||
path=${FISH_ARTEFACT_PATH:-~/fish_built}/$prefix.tar
|
||||
|
||||
# Clean up stuff we've written before
|
||||
rm -f "$path" "$path".gz
|
||||
@@ -37,22 +53,27 @@ git archive --format=tar --prefix="$prefix"/ HEAD > "$path"
|
||||
# Don't run autoheader since configure.ac runs it. autoconf is enough.
|
||||
autoconf
|
||||
./configure --with-doxygen
|
||||
make user_doc share/man
|
||||
make doc share/man
|
||||
echo $VERSION > version
|
||||
cd /tmp
|
||||
rm -f "$prefix"
|
||||
|
||||
PREFIX_TMPDIR=`mktemp -d`
|
||||
cd $PREFIX_TMPDIR
|
||||
|
||||
ln -s "$wd" "$prefix"
|
||||
TAR_APPEND="gnutar --append --file=$path --mtime=now --owner=0 --group=0 --mode=g+w,a+rX"
|
||||
TAR_APPEND="$TAR --append --file=$path --mtime=now --owner=0 --group=0 --mode=g+w,a+rX"
|
||||
$TAR_APPEND --no-recursion "$prefix"/user_doc
|
||||
$TAR_APPEND "$prefix"/user_doc/html "$prefix"/share/man
|
||||
$TAR_APPEND "$prefix"/version
|
||||
$TAR_APPEND "$prefix"/configure "$prefix"/config.h.in
|
||||
rm -f "$prefix"/version
|
||||
rm -f "$prefix"
|
||||
rm "$prefix"/version
|
||||
unlink "$prefix"
|
||||
|
||||
cd -
|
||||
rmdir $PREFIX_TMPDIR
|
||||
|
||||
# gzip it
|
||||
gzip "$path"
|
||||
|
||||
# Output what we did, and the sha1 hash
|
||||
echo "Tarball written to $path".gz
|
||||
openssl sha1 "$path".gz
|
||||
openssl dgst -sha256 "$path".gz
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 35 KiB |
@@ -1,15 +1,16 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370
|
||||
{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset0 Monaco;}
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf1485\cocoasubrtf410
|
||||
{\fonttbl\f0\fnil\fcharset0 HelveticaNeue;\f1\fnil\fcharset0 Menlo-Regular;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
{\*\expandedcolortbl;\csgenericrgb\c100000\c100000\c100000;}
|
||||
{\info
|
||||
{\author dlkfjslfjsfdlkfk}}\margl1440\margr1440\vieww10800\viewh8400\viewkind0
|
||||
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural
|
||||
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
|
||||
|
||||
\f0\fs30 \cf0 The fish shell is a smart and user friendly command line shell. For more information, visit {\field{\*\fldinst{HYPERLINK "http://fishshell.com"}}{\fldrslt http://fishshell.com}}.\
|
||||
\f0\fs30 \cf0 Fish is a smart and user friendly command line shell. For more information, visit {\field{\*\fldinst{HYPERLINK "https://fishshell.com"}}{\fldrslt https://fishshell.com}}\
|
||||
\
|
||||
fish will be installed into
|
||||
fish will be installed into
|
||||
\f1\fs26 /usr/local/
|
||||
\f0\fs30 , and fish will be added to
|
||||
\f0\fs30 , and fish will be added to
|
||||
\f1\fs26 /etc/shells
|
||||
\f0\fs30 if necessary.\
|
||||
\
|
||||
|
||||
119
build_tools/style.fish
Executable file
119
build_tools/style.fish
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env fish
|
||||
#
|
||||
# This is meant to be run by "make style" or "make style-all". It is not meant to
|
||||
# be run directly from a shell prompt although it can be.
|
||||
#
|
||||
# This runs C++ files and fish scripts (*.fish) through their respective code
|
||||
# formatting programs.
|
||||
#
|
||||
set git_clang_format no
|
||||
set c_files
|
||||
set f_files
|
||||
set all no
|
||||
|
||||
if test "$argv[1]" = "--all"
|
||||
set all yes
|
||||
set -e argv[1]
|
||||
end
|
||||
|
||||
if set -q argv[1]
|
||||
echo "Unexpected arguments: '$argv'"
|
||||
exit 1
|
||||
end
|
||||
|
||||
if test $all = yes
|
||||
set files (git status --porcelain --short --untracked-files=all | sed -e 's/^ *[^ ]* *//')
|
||||
if set -q files[1]
|
||||
echo
|
||||
echo You have uncommited changes. Cowardly refusing to restyle the entire code base.
|
||||
echo
|
||||
exit 1
|
||||
end
|
||||
set c_files src/*.h src/*.cpp
|
||||
# For now we don't restyle all the fish scripts. That's because `fish_indent` still has some
|
||||
# problems with its output that require manual intervention. Not to mention that very few of the
|
||||
# fish scripts even conform to `fish_indent` output at this time. When `fish_indent` output is
|
||||
# deemed acceptable as a default and all the fish scripts have been restyled this comment should
|
||||
# be removed and the following statement uncommented.
|
||||
# set f_files share/***.fish
|
||||
else
|
||||
# We haven't been asked to reformat all the source. If there are uncommitted changes reformat
|
||||
# those using `git clang-format`. Else reformat the files in the most recent commit.
|
||||
# Select (cached files) (modified but not cached, and untracked files)
|
||||
set files (git diff-index --cached HEAD --name-only) (git ls-files --exclude-standard --others --modified)
|
||||
if set -q files[1]
|
||||
set git_clang_format yes
|
||||
else
|
||||
# No pending changes so lint the files in the most recent commit.
|
||||
set files (git diff-tree --no-commit-id --name-only -r HEAD)
|
||||
end
|
||||
|
||||
# Extract just the C/C++ files that exist.
|
||||
set c_files
|
||||
for file in (string match -r '^.*\.(?:c|cpp|h)$' -- $files)
|
||||
test -f $file; and set c_files $c_files $file
|
||||
end
|
||||
# Extract just the fish files.
|
||||
set f_files (string match -r '^.*\.fish$' -- $files)
|
||||
end
|
||||
|
||||
# Run the C++ reformatter if we have any C++ files.
|
||||
if set -q c_files[1]
|
||||
if test $git_clang_format = yes
|
||||
if type -q git-clang-format
|
||||
echo
|
||||
echo ========================================
|
||||
echo Running git-clang-format
|
||||
echo ========================================
|
||||
git add $c_files
|
||||
git-clang-format
|
||||
else
|
||||
echo
|
||||
echo 'WARNING: Cannot find git-clang-format command'
|
||||
echo
|
||||
end
|
||||
else if type -q clang-format
|
||||
echo
|
||||
echo ========================================
|
||||
echo Running clang-format
|
||||
echo ========================================
|
||||
for file in $c_files
|
||||
cp $file $file.new # preserves mode bits
|
||||
clang-format $file >$file.new
|
||||
if cmp --quiet $file $file.new
|
||||
echo $file was correctly formatted
|
||||
rm $file.new
|
||||
else
|
||||
echo $file was NOT correctly formatted
|
||||
mv $file.new $file
|
||||
end
|
||||
end
|
||||
else
|
||||
echo
|
||||
echo 'WARNING: Cannot find clang-format command'
|
||||
echo
|
||||
end
|
||||
end
|
||||
|
||||
# Run the fish reformatter if we have any fish files.
|
||||
if set -q f_files[1]
|
||||
if not type -q fish_indent
|
||||
make fish_indent
|
||||
set PATH . $PATH
|
||||
end
|
||||
echo
|
||||
echo ========================================
|
||||
echo Running fish_indent
|
||||
echo ========================================
|
||||
for file in $f_files
|
||||
cp $file $file.new # preserves mode bits
|
||||
fish_indent <$file >$file.new
|
||||
if cmp --quiet $file $file.new
|
||||
echo $file was correctly formatted
|
||||
rm $file.new
|
||||
else
|
||||
echo $file was NOT correctly formatted
|
||||
mv $file.new $file
|
||||
end
|
||||
end
|
||||
end
|
||||
17
build_tools/xcode_version_gen.sh
Executable file
17
build_tools/xcode_version_gen.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# Expects to be called from Xcode (Run Script build phase),
|
||||
# write version number C preprocessor macro to header file.
|
||||
|
||||
tmp="$SCRIPT_OUTPUT_FILE_1"
|
||||
ver="$SCRIPT_OUTPUT_FILE_0"
|
||||
|
||||
./build_tools/git_version_gen.sh
|
||||
|
||||
cat FISH-BUILD-VERSION-FILE | awk '{printf("#define %s \"%s\"\n",$1,$3)}' > "$tmp"
|
||||
|
||||
cmp --quiet "$tmp" "$ver"
|
||||
if [ $? -ne 0 ]; then
|
||||
/bin/mv "$tmp" "$ver"
|
||||
else
|
||||
/bin/rm "$tmp"
|
||||
fi
|
||||
4266
builtin.cpp
4266
builtin.cpp
File diff suppressed because it is too large
Load Diff
198
builtin.h
198
builtin.h
@@ -1,198 +0,0 @@
|
||||
/** \file builtin.h
|
||||
Prototypes for functions for executing builtin functions.
|
||||
*/
|
||||
|
||||
#ifndef FISH_BUILTIN_H
|
||||
#define FISH_BUILTIN_H
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "io.h"
|
||||
#include "common.h"
|
||||
|
||||
class parser_t;
|
||||
|
||||
enum
|
||||
{
|
||||
COMMAND_NOT_BUILTIN,
|
||||
BUILTIN_REGULAR,
|
||||
BUILTIN_FUNCTION
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
Error message on missing argument
|
||||
*/
|
||||
#define BUILTIN_ERR_MISSING _( L"%ls: Expected argument\n" )
|
||||
|
||||
/**
|
||||
Error message on invalid combination of options
|
||||
*/
|
||||
#define BUILTIN_ERR_COMBO _( L"%ls: Invalid combination of options\n" )
|
||||
|
||||
/**
|
||||
Error message on invalid combination of options
|
||||
*/
|
||||
#define BUILTIN_ERR_COMBO2 _( L"%ls: Invalid combination of options,\n%ls\n" )
|
||||
|
||||
/**
|
||||
Error message on multiple scope levels for variables
|
||||
*/
|
||||
#define BUILTIN_ERR_GLOCAL _( L"%ls: Variable scope can only be one of universal, global and local\n" )
|
||||
|
||||
/**
|
||||
Error message for specifying both export and unexport to set/read
|
||||
*/
|
||||
#define BUILTIN_ERR_EXPUNEXP _( L"%ls: Variable can't be both exported and unexported\n" )
|
||||
|
||||
/**
|
||||
Error message for unknown switch
|
||||
*/
|
||||
#define BUILTIN_ERR_UNKNOWN _( L"%ls: Unknown option '%ls'\n" )
|
||||
|
||||
/**
|
||||
Error message for invalid character in variable name
|
||||
*/
|
||||
#define BUILTIN_ERR_VARCHAR _( L"%ls: Invalid character '%lc' in variable name. Only alphanumerical characters and underscores are valid in a variable name.\n" )
|
||||
|
||||
/**
|
||||
Error message for invalid (empty) variable name
|
||||
*/
|
||||
#define BUILTIN_ERR_VARNAME_ZERO _( L"%ls: Variable name can not be the empty string\n" )
|
||||
|
||||
/**
|
||||
Error message when second argument to for isn't 'in'
|
||||
*/
|
||||
#define BUILTIN_FOR_ERR_IN _( L"%ls: Second argument must be 'in'\n" )
|
||||
|
||||
/**
|
||||
Error message for insufficient number of arguments
|
||||
*/
|
||||
#define BUILTIN_FOR_ERR_COUNT _( L"%ls: Expected at least two arguments, got %d\n")
|
||||
|
||||
#define BUILTIN_FOR_ERR_NAME _( L"%ls: '%ls' is not a valid variable name\n" )
|
||||
|
||||
/** Error messages for 'else if' */
|
||||
#define BUILTIN_ELSEIF_ERR_COUNT _( L"%ls: can only take 'if' and then another command as an argument\n")
|
||||
#define BUILTIN_ELSEIF_ERR_ARGUMENT _( L"%ls: any second argument must be 'if'\n")
|
||||
|
||||
/**
|
||||
Error message when too many arguments are supplied to a builtin
|
||||
*/
|
||||
#define BUILTIN_ERR_TOO_MANY_ARGUMENTS _( L"%ls: Too many arguments\n" )
|
||||
|
||||
/**
|
||||
Error message when block types mismatch in the end builtin, e.g. 'begin; end for'
|
||||
*/
|
||||
#define BUILTIN_END_BLOCK_MISMATCH _( L"%ls: Block mismatch: '%ls' vs. '%ls'\n" )
|
||||
|
||||
/**
|
||||
Error message for unknown block type in the end builtin, e.g. 'begin; end beggin'
|
||||
*/
|
||||
#define BUILTIN_END_BLOCK_UNKNOWN _( L"%ls: Unknown block type '%ls'\n" )
|
||||
|
||||
#define BUILTIN_ERR_NOT_NUMBER _( L"%ls: Argument '%ls' is not a number\n" )
|
||||
|
||||
/** Get the string used to represent stdout and stderr */
|
||||
const wcstring &get_stdout_buffer();
|
||||
const wcstring &get_stderr_buffer();
|
||||
|
||||
/** Output an error */
|
||||
void builtin_show_error(const wcstring &err);
|
||||
|
||||
/**
|
||||
Kludge. Tells builtins if output is to screen
|
||||
*/
|
||||
extern int builtin_out_redirect;
|
||||
|
||||
/**
|
||||
Kludge. Tells builtins if error is to screen
|
||||
*/
|
||||
extern int builtin_err_redirect;
|
||||
|
||||
|
||||
/**
|
||||
Initialize builtin data.
|
||||
*/
|
||||
void builtin_init();
|
||||
|
||||
/**
|
||||
Destroy builtin data.
|
||||
*/
|
||||
void builtin_destroy();
|
||||
|
||||
/**
|
||||
Is there a builtin command with the given name?
|
||||
*/
|
||||
int builtin_exists(const wcstring &cmd);
|
||||
|
||||
/**
|
||||
Execute a builtin command
|
||||
|
||||
\param parser The parser being used
|
||||
\param argv Array containing the command and parameters
|
||||
of the builtin. The list is terminated by a
|
||||
null pointer. This syntax resembles the syntax
|
||||
for exec.
|
||||
\param io the io redirections to perform on this builtin.
|
||||
|
||||
\return the exit status of the builtin command
|
||||
*/
|
||||
int builtin_run(parser_t &parser, const wchar_t * const *argv, const io_chain_t &io);
|
||||
|
||||
/** Returns a list of all builtin names */
|
||||
wcstring_list_t builtin_get_names(void);
|
||||
|
||||
/** Insert all builtin names into list. */
|
||||
void builtin_get_names(std::vector<completion_t> &list);
|
||||
|
||||
/**
|
||||
Pushes a new set of input/output to the stack. The new stdin is supplied, a new set of output strings is created.
|
||||
*/
|
||||
void builtin_push_io(parser_t &parser, int stdin_fd);
|
||||
|
||||
/**
|
||||
Pops a set of input/output from the stack. The output strings are destroued, but the input file is not closed.
|
||||
*/
|
||||
void builtin_pop_io(parser_t &parser);
|
||||
|
||||
|
||||
/**
|
||||
Return a one-line description of the specified builtin.
|
||||
*/
|
||||
wcstring builtin_get_desc(const wcstring &b);
|
||||
|
||||
|
||||
|
||||
/** Support for setting and removing transient command lines.
|
||||
This is used by 'complete -C' in order to make
|
||||
the commandline builtin operate on the string to complete instead
|
||||
of operating on whatever is to be completed. It's also used by
|
||||
completion wrappers, to allow a command to appear as the command
|
||||
being wrapped for the purposes of completion.
|
||||
|
||||
Instantiating an instance of builtin_commandline_scoped_transient_t
|
||||
pushes the command as the new transient commandline. The destructor removes it.
|
||||
It will assert if construction/destruction does not happen in a stack-like (LIFO) order.
|
||||
*/
|
||||
class builtin_commandline_scoped_transient_t
|
||||
{
|
||||
size_t token;
|
||||
public:
|
||||
builtin_commandline_scoped_transient_t(const wcstring &cmd);
|
||||
~builtin_commandline_scoped_transient_t();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Run the __fish_print_help function to obtain the help information
|
||||
for the specified command.
|
||||
*/
|
||||
wcstring builtin_help_get(parser_t &parser, const wchar_t *cmd);
|
||||
|
||||
/** Defines a function, like builtin_function. Returns 0 on success. args should NOT contain 'function' as the first argument. */
|
||||
int define_function(parser_t &parser, const wcstring_list_t &args, const wcstring &contents, int definition_line_offset, wcstring *out_err);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,674 +0,0 @@
|
||||
/** \file builtin_commandline.c Functions defining the commandline builtin
|
||||
|
||||
Functions used for implementing the commandline builtin.
|
||||
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "fallback.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "wutil.h"
|
||||
#include "builtin.h"
|
||||
#include "common.h"
|
||||
#include "wgetopt.h"
|
||||
#include "reader.h"
|
||||
#include "proc.h"
|
||||
#include "parser.h"
|
||||
#include "tokenizer.h"
|
||||
#include "input_common.h"
|
||||
#include "input.h"
|
||||
|
||||
#include "parse_util.h"
|
||||
|
||||
/**
|
||||
Which part of the comandbuffer are we operating on
|
||||
*/
|
||||
enum
|
||||
{
|
||||
STRING_MODE=1, /**< Operate on entire buffer */
|
||||
JOB_MODE, /**< Operate on job under cursor */
|
||||
PROCESS_MODE, /**< Operate on process under cursor */
|
||||
TOKEN_MODE /**< Operate on token under cursor */
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
For text insertion, how should it be done
|
||||
*/
|
||||
enum
|
||||
{
|
||||
REPLACE_MODE=1, /**< Replace current text */
|
||||
INSERT_MODE, /**< Insert at cursor position */
|
||||
APPEND_MODE /**< Insert at end of current token/command/buffer */
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
Pointer to what the commandline builtin considers to be the current
|
||||
contents of the command line buffer.
|
||||
*/
|
||||
static const wchar_t *current_buffer=0;
|
||||
/**
|
||||
What the commandline builtin considers to be the current cursor
|
||||
position.
|
||||
*/
|
||||
static size_t current_cursor_pos = (size_t)(-1);
|
||||
|
||||
/**
|
||||
Returns the current commandline buffer.
|
||||
*/
|
||||
static const wchar_t *get_buffer()
|
||||
{
|
||||
return current_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the position of the cursor
|
||||
*/
|
||||
static size_t get_cursor_pos()
|
||||
{
|
||||
return current_cursor_pos;
|
||||
}
|
||||
|
||||
static pthread_mutex_t transient_commandline_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static wcstring_list_t *get_transient_stack()
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
ASSERT_IS_LOCKED(transient_commandline_lock);
|
||||
// A pointer is a little more efficient than an object as a static because we can elide the thread-safe initialization
|
||||
static wcstring_list_t *result = NULL;
|
||||
if (! result)
|
||||
{
|
||||
result = new wcstring_list_t();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool get_top_transient(wcstring *out_result)
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
bool result = false;
|
||||
scoped_lock locker(transient_commandline_lock);
|
||||
const wcstring_list_t *stack = get_transient_stack();
|
||||
if (! stack->empty())
|
||||
{
|
||||
out_result->assign(stack->back());
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
builtin_commandline_scoped_transient_t::builtin_commandline_scoped_transient_t(const wcstring &cmd)
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
scoped_lock locker(transient_commandline_lock);
|
||||
wcstring_list_t *stack = get_transient_stack();
|
||||
stack->push_back(cmd);
|
||||
this->token = stack->size();
|
||||
}
|
||||
|
||||
builtin_commandline_scoped_transient_t::~builtin_commandline_scoped_transient_t()
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
scoped_lock locker(transient_commandline_lock);
|
||||
wcstring_list_t *stack = get_transient_stack();
|
||||
assert(this->token == stack->size());
|
||||
stack->pop_back();
|
||||
}
|
||||
|
||||
/**
|
||||
Replace/append/insert the selection with/at/after the specified string.
|
||||
|
||||
\param begin beginning of selection
|
||||
\param end end of selection
|
||||
\param insert the string to insert
|
||||
\param append_mode can be one of REPLACE_MODE, INSERT_MODE or APPEND_MODE, affects the way the test update is performed
|
||||
*/
|
||||
static void replace_part(const wchar_t *begin,
|
||||
const wchar_t *end,
|
||||
const wchar_t *insert,
|
||||
int append_mode)
|
||||
{
|
||||
const wchar_t *buff = get_buffer();
|
||||
size_t out_pos = get_cursor_pos();
|
||||
|
||||
wcstring out;
|
||||
|
||||
out.append(buff, begin - buff);
|
||||
|
||||
switch (append_mode)
|
||||
{
|
||||
case REPLACE_MODE:
|
||||
{
|
||||
|
||||
out.append(insert);
|
||||
out_pos = wcslen(insert) + (begin-buff);
|
||||
break;
|
||||
|
||||
}
|
||||
case APPEND_MODE:
|
||||
{
|
||||
out.append(begin, end-begin);
|
||||
out.append(insert);
|
||||
break;
|
||||
}
|
||||
case INSERT_MODE:
|
||||
{
|
||||
long cursor = get_cursor_pos() -(begin-buff);
|
||||
out.append(begin, cursor);
|
||||
out.append(insert);
|
||||
out.append(begin+cursor, end-begin-cursor);
|
||||
out_pos += wcslen(insert);
|
||||
break;
|
||||
}
|
||||
}
|
||||
out.append(end);
|
||||
reader_set_buffer(out, out_pos);
|
||||
}
|
||||
|
||||
/**
|
||||
Output the specified selection.
|
||||
|
||||
\param begin start of selection
|
||||
\param end end of selection
|
||||
\param cut_at_cursor whether printing should stop at the surrent cursor position
|
||||
\param tokenize whether the string should be tokenized, printing one string token on every line and skipping non-string tokens
|
||||
*/
|
||||
static void write_part(const wchar_t *begin,
|
||||
const wchar_t *end,
|
||||
int cut_at_cursor,
|
||||
int tokenize)
|
||||
{
|
||||
size_t pos = get_cursor_pos()-(begin-get_buffer());
|
||||
|
||||
if (tokenize)
|
||||
{
|
||||
wchar_t *buff = wcsndup(begin, end-begin);
|
||||
// fwprintf( stderr, L"Subshell: %ls, end char %lc\n", buff, *end );
|
||||
wcstring out;
|
||||
tokenizer_t tok(buff, TOK_ACCEPT_UNFINISHED);
|
||||
for (; tok_has_next(&tok); tok_next(&tok))
|
||||
{
|
||||
if ((cut_at_cursor) &&
|
||||
(tok_get_pos(&tok)+wcslen(tok_last(&tok)) >= pos))
|
||||
break;
|
||||
|
||||
switch (tok_last_type(&tok))
|
||||
{
|
||||
case TOK_STRING:
|
||||
{
|
||||
wcstring tmp = tok_last(&tok);
|
||||
unescape_string_in_place(&tmp, UNESCAPE_INCOMPLETE);
|
||||
out.append(tmp);
|
||||
out.push_back(L'\n');
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stdout_buffer.append(out);
|
||||
|
||||
free(buff);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cut_at_cursor)
|
||||
{
|
||||
end = begin+pos;
|
||||
}
|
||||
|
||||
// debug( 0, L"woot2 %ls -> %ls", buff, esc );
|
||||
wcstring tmp = wcstring(begin, end - begin);
|
||||
unescape_string_in_place(&tmp, UNESCAPE_INCOMPLETE);
|
||||
stdout_buffer.append(tmp);
|
||||
stdout_buffer.append(L"\n");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The commandline builtin. It is used for specifying a new value for
|
||||
the commandline.
|
||||
*/
|
||||
static int builtin_commandline(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
|
||||
int buffer_part=0;
|
||||
int cut_at_cursor=0;
|
||||
|
||||
int argc = builtin_count_args(argv);
|
||||
int append_mode=0;
|
||||
|
||||
int function_mode = 0;
|
||||
int selection_mode = 0;
|
||||
|
||||
int tokenize = 0;
|
||||
|
||||
int cursor_mode = 0;
|
||||
int line_mode = 0;
|
||||
int search_mode = 0;
|
||||
int paging_mode = 0;
|
||||
const wchar_t *begin = NULL, *end = NULL;
|
||||
|
||||
scoped_push<const wchar_t *> saved_current_buffer(¤t_buffer);
|
||||
scoped_push<size_t> saved_current_cursor_pos(¤t_cursor_pos);
|
||||
|
||||
wcstring transient_commandline;
|
||||
if (get_top_transient(&transient_commandline))
|
||||
{
|
||||
current_buffer = transient_commandline.c_str();
|
||||
current_cursor_pos = transient_commandline.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
current_buffer = reader_get_buffer();
|
||||
current_cursor_pos = reader_get_cursor_pos();
|
||||
}
|
||||
|
||||
if (!get_buffer())
|
||||
{
|
||||
if (is_interactive_session)
|
||||
{
|
||||
/*
|
||||
Prompt change requested while we don't have
|
||||
a prompt, most probably while reading the
|
||||
init files. Just ignore it.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
stderr_buffer.append(argv[0]);
|
||||
stderr_buffer.append(L": Can not set commandline in non-interactive mode\n");
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
woptind=0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
static const struct woption
|
||||
long_options[] =
|
||||
{
|
||||
{ L"append", no_argument, 0, 'a' },
|
||||
{ L"insert", no_argument, 0, 'i' },
|
||||
{ L"replace", no_argument, 0, 'r' },
|
||||
{ L"current-job", no_argument, 0, 'j' },
|
||||
{ L"current-process", no_argument, 0, 'p' },
|
||||
{ L"current-token", no_argument, 0, 't' },
|
||||
{ L"current-buffer", no_argument, 0, 'b' },
|
||||
{ L"cut-at-cursor", no_argument, 0, 'c' },
|
||||
{ L"function", no_argument, 0, 'f' },
|
||||
{ L"tokenize", no_argument, 0, 'o' },
|
||||
{ L"help", no_argument, 0, 'h' },
|
||||
{ L"input", required_argument, 0, 'I' },
|
||||
{ L"cursor", no_argument, 0, 'C' },
|
||||
{ L"line", no_argument, 0, 'L' },
|
||||
{ L"search-mode", no_argument, 0, 'S' },
|
||||
{ L"selection", no_argument, 0, 's' },
|
||||
{ L"paging-mode", no_argument, 0, 'P' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int opt_index = 0;
|
||||
|
||||
int opt = wgetopt_long(argc,
|
||||
argv,
|
||||
L"abijpctwforhI:CLSsP",
|
||||
long_options,
|
||||
&opt_index);
|
||||
if (opt == -1)
|
||||
break;
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case 0:
|
||||
if (long_options[opt_index].flag != 0)
|
||||
break;
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_UNKNOWN,
|
||||
argv[0],
|
||||
long_options[opt_index].name);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
|
||||
return 1;
|
||||
|
||||
case L'a':
|
||||
append_mode = APPEND_MODE;
|
||||
break;
|
||||
|
||||
case L'b':
|
||||
buffer_part = STRING_MODE;
|
||||
break;
|
||||
|
||||
|
||||
case L'i':
|
||||
append_mode = INSERT_MODE;
|
||||
break;
|
||||
|
||||
case L'r':
|
||||
append_mode = REPLACE_MODE;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
cut_at_cursor=1;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
buffer_part = TOKEN_MODE;
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
buffer_part = JOB_MODE;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
buffer_part = PROCESS_MODE;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
function_mode=1;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
tokenize=1;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
current_buffer = woptarg;
|
||||
current_cursor_pos = wcslen(woptarg);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
cursor_mode = 1;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
line_mode = 1;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
search_mode = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
selection_mode = 1;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
paging_mode = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help(parser, argv[0], stdout_buffer);
|
||||
return 0;
|
||||
|
||||
case L'?':
|
||||
builtin_unknown_option(parser, argv[0], argv[woptind-1]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (function_mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
Check for invalid switch combinations
|
||||
*/
|
||||
if (buffer_part || cut_at_cursor || append_mode || tokenize || cursor_mode || line_mode || search_mode || paging_mode)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_COMBO,
|
||||
argv[0]);
|
||||
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if (argc == woptind)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_MISSING,
|
||||
argv[0]);
|
||||
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
for (i=woptind; i<argc; i++)
|
||||
{
|
||||
wchar_t c = input_function_get_code(argv[i]);
|
||||
if (c != (wchar_t)(-1))
|
||||
{
|
||||
/*
|
||||
input_unreadch inserts the specified keypress or
|
||||
readline function at the back of the queue of unused
|
||||
keypresses
|
||||
*/
|
||||
input_queue_ch(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Unknown input function '%ls'\n"),
|
||||
argv[0],
|
||||
argv[i]);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (selection_mode)
|
||||
{
|
||||
size_t start, len;
|
||||
const wchar_t *buffer = reader_get_buffer();
|
||||
if (reader_get_selection(&start, &len))
|
||||
{
|
||||
stdout_buffer.append(buffer + start, len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Check for invalid switch combinations
|
||||
*/
|
||||
if ((search_mode || line_mode || cursor_mode || paging_mode) && (argc-woptind > 1))
|
||||
{
|
||||
|
||||
append_format(stderr_buffer,
|
||||
argv[0],
|
||||
L": Too many arguments\n",
|
||||
NULL);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((buffer_part || tokenize || cut_at_cursor) && (cursor_mode || line_mode || search_mode || paging_mode))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_COMBO,
|
||||
argv[0]);
|
||||
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if ((tokenize || cut_at_cursor) && (argc-woptind))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_COMBO2,
|
||||
argv[0],
|
||||
L"--cut-at-cursor and --tokenize can not be used when setting the commandline");
|
||||
|
||||
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (append_mode && !(argc-woptind))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_COMBO2,
|
||||
argv[0],
|
||||
L"insertion mode switches can not be used when not in insertion mode");
|
||||
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Set default modes
|
||||
*/
|
||||
if (!append_mode)
|
||||
{
|
||||
append_mode = REPLACE_MODE;
|
||||
}
|
||||
|
||||
if (!buffer_part)
|
||||
{
|
||||
buffer_part = STRING_MODE;
|
||||
}
|
||||
|
||||
if (cursor_mode)
|
||||
{
|
||||
if (argc-woptind)
|
||||
{
|
||||
wchar_t *endptr;
|
||||
long new_pos;
|
||||
errno = 0;
|
||||
|
||||
new_pos = wcstol(argv[woptind], &endptr, 10);
|
||||
if (*endptr || errno)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_NOT_NUMBER,
|
||||
argv[0],
|
||||
argv[woptind]);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
}
|
||||
|
||||
current_buffer = reader_get_buffer();
|
||||
new_pos = maxi(0L, mini(new_pos, (long)wcslen(current_buffer)));
|
||||
reader_set_buffer(current_buffer, (size_t)new_pos);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
append_format(stdout_buffer, L"%lu\n", (unsigned long)reader_get_cursor_pos());
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (line_mode)
|
||||
{
|
||||
size_t pos = reader_get_cursor_pos();
|
||||
const wchar_t *buff = reader_get_buffer();
|
||||
append_format(stdout_buffer, L"%lu\n", (unsigned long)parse_util_lineno(buff, pos));
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
if (search_mode)
|
||||
{
|
||||
return ! reader_search_mode();
|
||||
}
|
||||
|
||||
if (paging_mode)
|
||||
{
|
||||
return ! reader_has_pager_contents();
|
||||
}
|
||||
|
||||
|
||||
switch (buffer_part)
|
||||
{
|
||||
case STRING_MODE:
|
||||
{
|
||||
begin = get_buffer();
|
||||
end = begin+wcslen(begin);
|
||||
break;
|
||||
}
|
||||
|
||||
case PROCESS_MODE:
|
||||
{
|
||||
parse_util_process_extent(get_buffer(),
|
||||
get_cursor_pos(),
|
||||
&begin,
|
||||
&end);
|
||||
break;
|
||||
}
|
||||
|
||||
case JOB_MODE:
|
||||
{
|
||||
parse_util_job_extent(get_buffer(),
|
||||
get_cursor_pos(),
|
||||
&begin,
|
||||
&end);
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKEN_MODE:
|
||||
{
|
||||
parse_util_token_extent(get_buffer(),
|
||||
get_cursor_pos(),
|
||||
&begin,
|
||||
&end,
|
||||
0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switch (argc-woptind)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
write_part(begin, end, cut_at_cursor, tokenize);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1:
|
||||
{
|
||||
replace_part(begin, end, argv[woptind], append_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
wcstring sb = argv[woptind];
|
||||
int i;
|
||||
|
||||
for (i=woptind+1; i<argc; i++)
|
||||
{
|
||||
sb.push_back(L'\n');
|
||||
sb.append(argv[i]);
|
||||
}
|
||||
|
||||
replace_part(begin, end, sb.c_str(), append_mode);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,606 +0,0 @@
|
||||
/** \file builtin_complete.c Functions defining the complete builtin
|
||||
|
||||
Functions used for implementing the complete builtin.
|
||||
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "fallback.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "wutil.h"
|
||||
#include "builtin.h"
|
||||
#include "common.h"
|
||||
#include "complete.h"
|
||||
#include "wgetopt.h"
|
||||
#include "parser.h"
|
||||
#include "reader.h"
|
||||
|
||||
/*
|
||||
builtin_complete_* are a set of rather silly looping functions that
|
||||
make sure that all the proper combinations of complete_add or
|
||||
complete_remove get called. This is needed since complete allows you
|
||||
to specify multiple switches on a single commandline, like 'complete
|
||||
-s a -s b -s c', but the complete_add function only accepts one
|
||||
short switch and one long switch.
|
||||
*/
|
||||
|
||||
/**
|
||||
Silly function
|
||||
*/
|
||||
static void builtin_complete_add2(const wchar_t *cmd,
|
||||
int cmd_type,
|
||||
const wchar_t *short_opt,
|
||||
const wcstring_list_t &gnu_opt,
|
||||
const wcstring_list_t &old_opt,
|
||||
int result_mode,
|
||||
const wchar_t *condition,
|
||||
const wchar_t *comp,
|
||||
const wchar_t *desc,
|
||||
int flags)
|
||||
{
|
||||
size_t i;
|
||||
const wchar_t *s;
|
||||
|
||||
for (s=short_opt; *s; s++)
|
||||
{
|
||||
complete_add(cmd,
|
||||
cmd_type,
|
||||
*s,
|
||||
0,
|
||||
0,
|
||||
result_mode,
|
||||
condition,
|
||||
comp,
|
||||
desc,
|
||||
flags);
|
||||
}
|
||||
|
||||
for (i=0; i<gnu_opt.size(); i++)
|
||||
{
|
||||
complete_add(cmd,
|
||||
cmd_type,
|
||||
0,
|
||||
gnu_opt.at(i).c_str(),
|
||||
0,
|
||||
result_mode,
|
||||
condition,
|
||||
comp,
|
||||
desc,
|
||||
flags);
|
||||
}
|
||||
|
||||
for (i=0; i<old_opt.size(); i++)
|
||||
{
|
||||
complete_add(cmd,
|
||||
cmd_type,
|
||||
0,
|
||||
old_opt.at(i).c_str(),
|
||||
1,
|
||||
result_mode,
|
||||
condition,
|
||||
comp,
|
||||
desc,
|
||||
flags);
|
||||
}
|
||||
|
||||
if (old_opt.empty() && gnu_opt.empty() && wcslen(short_opt) == 0)
|
||||
{
|
||||
complete_add(cmd,
|
||||
cmd_type,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
result_mode,
|
||||
condition,
|
||||
comp,
|
||||
desc,
|
||||
flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Silly function
|
||||
*/
|
||||
static void builtin_complete_add(const wcstring_list_t &cmd,
|
||||
const wcstring_list_t &path,
|
||||
const wchar_t *short_opt,
|
||||
wcstring_list_t &gnu_opt,
|
||||
wcstring_list_t &old_opt,
|
||||
int result_mode,
|
||||
int authoritative,
|
||||
const wchar_t *condition,
|
||||
const wchar_t *comp,
|
||||
const wchar_t *desc,
|
||||
int flags)
|
||||
{
|
||||
for (size_t i=0; i<cmd.size(); i++)
|
||||
{
|
||||
builtin_complete_add2(cmd.at(i).c_str(),
|
||||
COMMAND,
|
||||
short_opt,
|
||||
gnu_opt,
|
||||
old_opt,
|
||||
result_mode,
|
||||
condition,
|
||||
comp,
|
||||
desc,
|
||||
flags);
|
||||
|
||||
if (authoritative != -1)
|
||||
{
|
||||
complete_set_authoritative(cmd.at(i).c_str(),
|
||||
COMMAND,
|
||||
authoritative);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (size_t i=0; i<path.size(); i++)
|
||||
{
|
||||
builtin_complete_add2(path.at(i).c_str(),
|
||||
PATH,
|
||||
short_opt,
|
||||
gnu_opt,
|
||||
old_opt,
|
||||
result_mode,
|
||||
condition,
|
||||
comp,
|
||||
desc,
|
||||
flags);
|
||||
|
||||
if (authoritative != -1)
|
||||
{
|
||||
complete_set_authoritative(path.at(i).c_str(),
|
||||
PATH,
|
||||
authoritative);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Silly function
|
||||
*/
|
||||
static void builtin_complete_remove3(const wchar_t *cmd,
|
||||
int cmd_type,
|
||||
wchar_t short_opt,
|
||||
const wcstring_list_t &long_opt,
|
||||
int long_mode)
|
||||
{
|
||||
for (size_t i=0; i<long_opt.size(); i++)
|
||||
{
|
||||
complete_remove(cmd,
|
||||
cmd_type,
|
||||
short_opt,
|
||||
long_opt.at(i).c_str(),
|
||||
long_mode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Silly function
|
||||
*/
|
||||
static void builtin_complete_remove2(const wchar_t *cmd,
|
||||
int cmd_type,
|
||||
const wchar_t *short_opt,
|
||||
const wcstring_list_t &gnu_opt,
|
||||
const wcstring_list_t &old_opt)
|
||||
{
|
||||
const wchar_t *s = (wchar_t *)short_opt;
|
||||
if (*s)
|
||||
{
|
||||
for (; *s; s++)
|
||||
{
|
||||
if (old_opt.empty() && gnu_opt.empty())
|
||||
{
|
||||
complete_remove(cmd,
|
||||
cmd_type,
|
||||
*s,
|
||||
0,
|
||||
0);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
builtin_complete_remove3(cmd,
|
||||
cmd_type,
|
||||
*s,
|
||||
gnu_opt,
|
||||
0);
|
||||
builtin_complete_remove3(cmd,
|
||||
cmd_type,
|
||||
*s,
|
||||
old_opt,
|
||||
1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (gnu_opt.empty() && old_opt.empty())
|
||||
{
|
||||
complete_remove(cmd,
|
||||
cmd_type,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
builtin_complete_remove3(cmd,
|
||||
cmd_type,
|
||||
0,
|
||||
gnu_opt,
|
||||
0);
|
||||
builtin_complete_remove3(cmd,
|
||||
cmd_type,
|
||||
0,
|
||||
old_opt,
|
||||
1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Silly function
|
||||
*/
|
||||
static void builtin_complete_remove(const wcstring_list_t &cmd,
|
||||
const wcstring_list_t &path,
|
||||
const wchar_t *short_opt,
|
||||
const wcstring_list_t &gnu_opt,
|
||||
const wcstring_list_t &old_opt)
|
||||
{
|
||||
for (size_t i=0; i<cmd.size(); i++)
|
||||
{
|
||||
builtin_complete_remove2(cmd.at(i).c_str(),
|
||||
COMMAND,
|
||||
short_opt,
|
||||
gnu_opt,
|
||||
old_opt);
|
||||
}
|
||||
|
||||
for (size_t i=0; i<path.size(); i++)
|
||||
{
|
||||
builtin_complete_remove2(path.at(i).c_str(),
|
||||
PATH,
|
||||
short_opt,
|
||||
gnu_opt,
|
||||
old_opt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
The complete builtin. Used for specifying programmable
|
||||
tab-completions. Calls the functions in complete.c for any heavy
|
||||
lifting. Defined in builtin_complete.c
|
||||
*/
|
||||
static int builtin_complete(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
bool res=false;
|
||||
int argc=0;
|
||||
int result_mode=SHARED;
|
||||
int remove = 0;
|
||||
int authoritative = -1;
|
||||
|
||||
wcstring short_opt;
|
||||
wcstring_list_t gnu_opt, old_opt;
|
||||
const wchar_t *comp=L"", *desc=L"", *condition=L"";
|
||||
|
||||
bool do_complete = false;
|
||||
wcstring do_complete_param;
|
||||
|
||||
wcstring_list_t cmd;
|
||||
wcstring_list_t path;
|
||||
wcstring_list_t wrap_targets;
|
||||
|
||||
static int recursion_level=0;
|
||||
|
||||
argc = builtin_count_args(argv);
|
||||
|
||||
woptind=0;
|
||||
|
||||
while (! res)
|
||||
{
|
||||
static const struct woption
|
||||
long_options[] =
|
||||
{
|
||||
{ L"exclusive", no_argument, 0, 'x' },
|
||||
{ L"no-files", no_argument, 0, 'f' },
|
||||
{ L"require-parameter", no_argument, 0, 'r' },
|
||||
{ L"path", required_argument, 0, 'p' },
|
||||
{ L"command", required_argument, 0, 'c' },
|
||||
{ L"short-option", required_argument, 0, 's' },
|
||||
{ L"long-option", required_argument, 0, 'l' },
|
||||
{ L"old-option", required_argument, 0, 'o' },
|
||||
{ L"description", required_argument, 0, 'd' },
|
||||
{ L"arguments", required_argument, 0, 'a' },
|
||||
{ L"erase", no_argument, 0, 'e' },
|
||||
{ L"unauthoritative", no_argument, 0, 'u' },
|
||||
{ L"authoritative", no_argument, 0, 'A' },
|
||||
{ L"condition", required_argument, 0, 'n' },
|
||||
{ L"wraps", required_argument, 0, 'w' },
|
||||
{ L"do-complete", optional_argument, 0, 'C' },
|
||||
{ L"help", no_argument, 0, 'h' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int opt_index = 0;
|
||||
|
||||
int opt = wgetopt_long(argc,
|
||||
argv,
|
||||
L"a:c:p:s:l:o:d:frxeuAn:C::w:h",
|
||||
long_options,
|
||||
&opt_index);
|
||||
if (opt == -1)
|
||||
break;
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case 0:
|
||||
if (long_options[opt_index].flag != 0)
|
||||
break;
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_UNKNOWN,
|
||||
argv[0],
|
||||
long_options[opt_index].name);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
|
||||
|
||||
res = true;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
result_mode |= EXCLUSIVE;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
result_mode |= NO_FILES;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
result_mode |= NO_COMMON;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
case 'c':
|
||||
{
|
||||
wcstring tmp;
|
||||
if (unescape_string(woptarg, &tmp, UNESCAPE_SPECIAL))
|
||||
{
|
||||
if (opt=='p')
|
||||
path.push_back(tmp);
|
||||
else
|
||||
cmd.push_back(tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
append_format(stderr_buffer, L"%ls: Invalid token '%ls'\n", argv[0], woptarg);
|
||||
res = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd':
|
||||
desc = woptarg;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
authoritative=0;
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
authoritative=1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
short_opt.append(woptarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
gnu_opt.push_back(woptarg);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
old_opt.push_back(woptarg);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
comp = woptarg;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
remove = 1;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
condition = woptarg;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
wrap_targets.push_back(woptarg);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
do_complete = true;
|
||||
do_complete_param = woptarg ? woptarg : reader_get_buffer();
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help(parser, argv[0], stdout_buffer);
|
||||
return 0;
|
||||
|
||||
case '?':
|
||||
builtin_unknown_option(parser, argv[0], argv[woptind-1]);
|
||||
res = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!res)
|
||||
{
|
||||
if (condition && wcslen(condition))
|
||||
{
|
||||
const wcstring condition_string = condition;
|
||||
parse_error_list_t errors;
|
||||
if (parse_util_detect_errors(condition_string, &errors, false /* do not accept incomplete */))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
L"%ls: Condition '%ls' contained a syntax error",
|
||||
argv[0],
|
||||
condition);
|
||||
for (size_t i=0; i < errors.size(); i++)
|
||||
{
|
||||
append_format(stderr_buffer, L"\n%s: ", argv[0]);
|
||||
stderr_buffer.append(errors.at(i).describe(condition_string));
|
||||
}
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!res)
|
||||
{
|
||||
if (comp && wcslen(comp))
|
||||
{
|
||||
wcstring prefix;
|
||||
if (argv[0])
|
||||
{
|
||||
prefix.append(argv[0]);
|
||||
prefix.append(L": ");
|
||||
}
|
||||
|
||||
wcstring err_text;
|
||||
if (parser.detect_errors_in_argument_list(comp, &err_text, prefix.c_str()))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
L"%ls: Completion '%ls' contained a syntax error\n",
|
||||
argv[0],
|
||||
comp);
|
||||
stderr_buffer.append(err_text);
|
||||
stderr_buffer.push_back(L'\n');
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!res)
|
||||
{
|
||||
if (do_complete)
|
||||
{
|
||||
const wchar_t *token;
|
||||
|
||||
parse_util_token_extent(do_complete_param.c_str(), do_complete_param.size(), &token, 0, 0, 0);
|
||||
|
||||
/* Create a scoped transient command line, so that bulitin_commandline will see our argument, not the reader buffer */
|
||||
builtin_commandline_scoped_transient_t temp_buffer(do_complete_param);
|
||||
|
||||
if (recursion_level < 1)
|
||||
{
|
||||
recursion_level++;
|
||||
|
||||
std::vector<completion_t> comp;
|
||||
complete(do_complete_param, comp, COMPLETION_REQUEST_DEFAULT);
|
||||
|
||||
for (size_t i=0; i< comp.size() ; i++)
|
||||
{
|
||||
const completion_t &next = comp.at(i);
|
||||
|
||||
/* Make a fake commandline, and then apply the completion to it. */
|
||||
const wcstring faux_cmdline = token;
|
||||
size_t tmp_cursor = faux_cmdline.size();
|
||||
wcstring faux_cmdline_with_completion = completion_apply_to_command_line(next.completion, next.flags, faux_cmdline, &tmp_cursor, false);
|
||||
|
||||
/* completion_apply_to_command_line will append a space unless COMPLETE_NO_SPACE is set. We don't want to set COMPLETE_NO_SPACE because that won't close quotes. What we want is to close the quote, but not append the space. So we just look for the space and clear it. */
|
||||
if (!(next.flags & COMPLETE_NO_SPACE) && string_suffixes_string(L" ", faux_cmdline_with_completion))
|
||||
{
|
||||
faux_cmdline_with_completion.resize(faux_cmdline_with_completion.size() - 1);
|
||||
}
|
||||
|
||||
/* The input data is meant to be something like you would have on the command line, e.g. includes backslashes. The output should be raw, i.e. unescaped. So we need to unescape the command line. See #1127 */
|
||||
unescape_string_in_place(&faux_cmdline_with_completion, UNESCAPE_DEFAULT);
|
||||
stdout_buffer.append(faux_cmdline_with_completion);
|
||||
|
||||
/* Append any description */
|
||||
if (! next.description.empty())
|
||||
{
|
||||
stdout_buffer.push_back(L'\t');
|
||||
stdout_buffer.append(next.description);
|
||||
}
|
||||
stdout_buffer.push_back(L'\n');
|
||||
}
|
||||
|
||||
recursion_level--;
|
||||
}
|
||||
}
|
||||
else if (woptind != argc)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Too many arguments\n"),
|
||||
argv[0]);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
|
||||
res = true;
|
||||
}
|
||||
else if (cmd.empty() && path.empty())
|
||||
{
|
||||
/* No arguments specified, meaning we print the definitions of
|
||||
* all specified completions to stdout.*/
|
||||
complete_print(stdout_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
int flags = COMPLETE_AUTO_SPACE;
|
||||
|
||||
if (remove)
|
||||
{
|
||||
builtin_complete_remove(cmd,
|
||||
path,
|
||||
short_opt.c_str(),
|
||||
gnu_opt,
|
||||
old_opt);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
builtin_complete_add(cmd,
|
||||
path,
|
||||
short_opt.c_str(),
|
||||
gnu_opt,
|
||||
old_opt,
|
||||
result_mode,
|
||||
authoritative,
|
||||
condition,
|
||||
comp,
|
||||
desc,
|
||||
flags);
|
||||
}
|
||||
|
||||
// Handle wrap targets (probably empty)
|
||||
// We only wrap commands, not paths
|
||||
for (size_t w=0; w < wrap_targets.size(); w++)
|
||||
{
|
||||
const wcstring &wrap_target = wrap_targets.at(w);
|
||||
for (size_t i=0; i < cmd.size(); i++)
|
||||
{
|
||||
|
||||
(remove ? complete_remove_wrapper : complete_add_wrapper)(cmd.at(i), wrap_target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res ? 1 : 0;
|
||||
}
|
||||
351
builtin_jobs.cpp
351
builtin_jobs.cpp
@@ -1,351 +0,0 @@
|
||||
/** \file builtin_jobs.c
|
||||
Functions for executing the jobs builtin.
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#include "fallback.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "wutil.h"
|
||||
#include "builtin.h"
|
||||
#include "proc.h"
|
||||
#include "parser.h"
|
||||
#include "common.h"
|
||||
#include "wgetopt.h"
|
||||
|
||||
|
||||
/**
|
||||
Print modes for the jobs builtin
|
||||
*/
|
||||
enum
|
||||
{
|
||||
JOBS_DEFAULT, /**< Print lots of general info */
|
||||
JOBS_PRINT_PID, /**< Print pid of each process in job */
|
||||
JOBS_PRINT_COMMAND, /**< Print command name of each process in job */
|
||||
JOBS_PRINT_GROUP, /**< Print group id of job */
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE__PROC_SELF_STAT
|
||||
/**
|
||||
Calculates the cpu usage (in percent) of the specified job.
|
||||
*/
|
||||
static int cpu_use(const job_t *j)
|
||||
{
|
||||
double u=0;
|
||||
process_t *p;
|
||||
|
||||
for (p=j->first_process; p; p=p->next)
|
||||
{
|
||||
struct timeval t;
|
||||
int jiffies;
|
||||
gettimeofday(&t, 0);
|
||||
jiffies = proc_get_jiffies(p);
|
||||
|
||||
double t1 = 1000000.0*p->last_time.tv_sec+p->last_time.tv_usec;
|
||||
double t2 = 1000000.0*t.tv_sec+t.tv_usec;
|
||||
|
||||
/* fwprintf( stderr, L"t1 %f t2 %f p1 %d p2 %d\n",
|
||||
t1, t2, jiffies, p->last_jiffies );
|
||||
*/
|
||||
|
||||
u += ((double)(jiffies-p->last_jiffies))/(t2-t1);
|
||||
}
|
||||
return u*1000000;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Print information about the specified job
|
||||
*/
|
||||
static void builtin_jobs_print(const job_t *j, int mode, int header)
|
||||
{
|
||||
process_t *p;
|
||||
switch (mode)
|
||||
{
|
||||
case JOBS_DEFAULT:
|
||||
{
|
||||
|
||||
if (header)
|
||||
{
|
||||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
stdout_buffer.append(_(L"Job\tGroup\t"));
|
||||
#ifdef HAVE__PROC_SELF_STAT
|
||||
stdout_buffer.append(_(L"CPU\t"));
|
||||
#endif
|
||||
stdout_buffer.append(_(L"State\tCommand\n"));
|
||||
}
|
||||
|
||||
append_format(stdout_buffer, L"%d\t%d\t", j->job_id, j->pgid);
|
||||
|
||||
#ifdef HAVE__PROC_SELF_STAT
|
||||
append_format(stdout_buffer, L"%d%%\t", cpu_use(j));
|
||||
#endif
|
||||
stdout_buffer.append(job_is_stopped(j)?_(L"stopped"):_(L"running"));
|
||||
stdout_buffer.append(L"\t");
|
||||
stdout_buffer.append(j->command_wcstr());
|
||||
stdout_buffer.append(L"\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case JOBS_PRINT_GROUP:
|
||||
{
|
||||
if (header)
|
||||
{
|
||||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
stdout_buffer.append(_(L"Group\n"));
|
||||
}
|
||||
append_format(stdout_buffer, L"%d\n", j->pgid);
|
||||
break;
|
||||
}
|
||||
|
||||
case JOBS_PRINT_PID:
|
||||
{
|
||||
if (header)
|
||||
{
|
||||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
stdout_buffer.append(_(L"Process\n"));
|
||||
}
|
||||
|
||||
for (p=j->first_process; p; p=p->next)
|
||||
{
|
||||
append_format(stdout_buffer, L"%d\n", p->pid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JOBS_PRINT_COMMAND:
|
||||
{
|
||||
if (header)
|
||||
{
|
||||
/*
|
||||
Print table header before first job
|
||||
*/
|
||||
stdout_buffer.append(_(L"Command\n"));
|
||||
}
|
||||
|
||||
for (p=j->first_process; p; p=p->next)
|
||||
{
|
||||
append_format(stdout_buffer, L"%ls\n", p->argv0());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
The jobs builtin. Used fopr printing running jobs. Defined in builtin_jobs.c.
|
||||
*/
|
||||
static int builtin_jobs(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
int argc=0;
|
||||
int found=0;
|
||||
int mode=JOBS_DEFAULT;
|
||||
int print_last = 0;
|
||||
|
||||
argc = builtin_count_args(argv);
|
||||
woptind=0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
static const struct woption
|
||||
long_options[] =
|
||||
{
|
||||
{
|
||||
L"pid", no_argument, 0, 'p'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"command", no_argument, 0, 'c'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"group", no_argument, 0, 'g'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"last", no_argument, 0, 'l'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
int opt_index = 0;
|
||||
|
||||
int opt = wgetopt_long(argc,
|
||||
argv,
|
||||
L"pclgh",
|
||||
long_options,
|
||||
&opt_index);
|
||||
if (opt == -1)
|
||||
break;
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case 0:
|
||||
if (long_options[opt_index].flag != 0)
|
||||
break;
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_UNKNOWN,
|
||||
argv[0],
|
||||
long_options[opt_index].name);
|
||||
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
|
||||
|
||||
return 1;
|
||||
|
||||
|
||||
case 'p':
|
||||
mode=JOBS_PRINT_PID;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
mode=JOBS_PRINT_COMMAND;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
mode=JOBS_PRINT_GROUP;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
{
|
||||
print_last = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'h':
|
||||
builtin_print_help(parser, argv[0], stdout_buffer);
|
||||
return 0;
|
||||
|
||||
case '?':
|
||||
builtin_unknown_option(parser, argv[0], argv[woptind-1]);
|
||||
return 1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Do not babble if not interactive
|
||||
*/
|
||||
if (builtin_out_redirect)
|
||||
{
|
||||
found=1;
|
||||
}
|
||||
|
||||
if (print_last)
|
||||
{
|
||||
/*
|
||||
Ignore unconstructed jobs, i.e. ourself.
|
||||
*/
|
||||
job_iterator_t jobs;
|
||||
const job_t *j;
|
||||
while ((j = jobs.next()))
|
||||
{
|
||||
|
||||
if ((j->flags & JOB_CONSTRUCTED) && !job_is_completed(j))
|
||||
{
|
||||
builtin_jobs_print(j, mode, !found);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (woptind < argc)
|
||||
{
|
||||
int i;
|
||||
|
||||
found = 1;
|
||||
|
||||
for (i=woptind; i<argc; i++)
|
||||
{
|
||||
int pid;
|
||||
wchar_t *end;
|
||||
errno=0;
|
||||
pid=fish_wcstoi(argv[i], &end, 10);
|
||||
if (errno || *end)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: '%ls' is not a job\n"),
|
||||
argv[0],
|
||||
argv[i]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const job_t *j = job_get_from_pid(pid);
|
||||
|
||||
if (j && !job_is_completed(j))
|
||||
{
|
||||
builtin_jobs_print(j, mode, !found);
|
||||
}
|
||||
else
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: No suitable job: %d\n"),
|
||||
argv[0],
|
||||
pid);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
job_iterator_t jobs;
|
||||
const job_t *j;
|
||||
while ((j = jobs.next()))
|
||||
{
|
||||
/*
|
||||
Ignore unconstructed jobs, i.e. ourself.
|
||||
*/
|
||||
if ((j->flags & JOB_CONSTRUCTED) && !job_is_completed(j))
|
||||
{
|
||||
builtin_jobs_print(j, mode, !found);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
append_format(stdout_buffer,
|
||||
_(L"%ls: There are no jobs\n"),
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,787 +0,0 @@
|
||||
/* printf - format and print data
|
||||
Copyright (C) 1990-2007 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* Usage: printf format [argument...]
|
||||
|
||||
A front end to the printf function that lets it be used from the shell.
|
||||
|
||||
Backslash escapes:
|
||||
|
||||
\" = double quote
|
||||
\\ = backslash
|
||||
\a = alert (bell)
|
||||
\b = backspace
|
||||
\c = produce no further output
|
||||
\e = escape
|
||||
\f = form feed
|
||||
\n = new line
|
||||
\r = carriage return
|
||||
\t = horizontal tab
|
||||
\v = vertical tab
|
||||
\ooo = octal number (ooo is 1 to 3 digits)
|
||||
\xhh = hexadecimal number (hhh is 1 to 2 digits)
|
||||
\uhhhh = 16-bit Unicode character (hhhh is 4 digits)
|
||||
\Uhhhhhhhh = 32-bit Unicode character (hhhhhhhh is 8 digits)
|
||||
|
||||
Additional directive:
|
||||
|
||||
%b = print an argument string, interpreting backslash escapes,
|
||||
except that octal escapes are of the form \0 or \0ooo.
|
||||
|
||||
The `format' argument is re-used as many times as necessary
|
||||
to convert all of the given arguments.
|
||||
|
||||
David MacKenzie <djm@gnu.ai.mit.edu> */
|
||||
|
||||
/* This file has been imported from source code of printf command in GNU Coreutils version 6.9 */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct builtin_printf_state_t
|
||||
{
|
||||
/* The status of the operation */
|
||||
int exit_code;
|
||||
|
||||
/* Whether we should stop outputting. This gets set in the case of an error, and also with the \c escape. */
|
||||
bool early_exit;
|
||||
|
||||
builtin_printf_state_t() : exit_code(0), early_exit(false)
|
||||
{
|
||||
}
|
||||
|
||||
void verify_numeric(const wchar_t *s, const wchar_t *end, int errcode);
|
||||
|
||||
void print_direc(const wchar_t *start, size_t length, wchar_t conversion,
|
||||
bool have_field_width, int field_width,
|
||||
bool have_precision, int precision,
|
||||
wchar_t const *argument);
|
||||
|
||||
int print_formatted(const wchar_t *format, int argc, wchar_t **argv);
|
||||
|
||||
void fatal_error(const wchar_t *format, ...);
|
||||
|
||||
long print_esc(const wchar_t *escstart, bool octal_0);
|
||||
void print_esc_string(const wchar_t *str);
|
||||
void print_esc_char(wchar_t c);
|
||||
|
||||
void append_output(wchar_t c);
|
||||
void append_output(const wchar_t *c);
|
||||
void append_format_output(const wchar_t *fmt, ...);
|
||||
};
|
||||
|
||||
static bool is_octal_digit(wchar_t c)
|
||||
{
|
||||
return c != L'\0' && wcschr(L"01234567", c) != NULL;
|
||||
}
|
||||
|
||||
static bool is_hex_digit(wchar_t c)
|
||||
{
|
||||
return c != L'\0' && wcschr(L"0123456789ABCDEFabcdef", c) != NULL;
|
||||
}
|
||||
|
||||
static int hex_to_bin(const wchar_t &c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case L'0':
|
||||
return 0;
|
||||
case L'1':
|
||||
return 1;
|
||||
case L'2':
|
||||
return 2;
|
||||
case L'3':
|
||||
return 3;
|
||||
case L'4':
|
||||
return 4;
|
||||
case L'5':
|
||||
return 5;
|
||||
case L'6':
|
||||
return 6;
|
||||
case L'7':
|
||||
return 7;
|
||||
case L'8':
|
||||
return 8;
|
||||
case L'9':
|
||||
return 9;
|
||||
case L'a':
|
||||
case L'A':
|
||||
return 10;
|
||||
case L'b':
|
||||
case L'B':
|
||||
return 11;
|
||||
case L'c':
|
||||
case L'C':
|
||||
return 12;
|
||||
case L'd':
|
||||
case L'D':
|
||||
return 13;
|
||||
case L'e':
|
||||
case L'E':
|
||||
return 14;
|
||||
case L'f':
|
||||
case L'F':
|
||||
return 15;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int octal_to_bin(wchar_t c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case L'0':
|
||||
return 0;
|
||||
case L'1':
|
||||
return 1;
|
||||
case L'2':
|
||||
return 2;
|
||||
case L'3':
|
||||
return 3;
|
||||
case L'4':
|
||||
return 4;
|
||||
case L'5':
|
||||
return 5;
|
||||
case L'6':
|
||||
return 6;
|
||||
case L'7':
|
||||
return 7;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* This message appears in N_() here rather than just in _() below because
|
||||
the sole use would have been in a #define. */
|
||||
static wchar_t const *const cfcc_msg =
|
||||
N_(L"warning: %ls: character(s) following character constant have been ignored");
|
||||
|
||||
double C_STRTOD(wchar_t const *nptr, wchar_t **endptr)
|
||||
{
|
||||
double r;
|
||||
|
||||
const wcstring saved_locale = wsetlocale(LC_NUMERIC, NULL);
|
||||
|
||||
if (!saved_locale.empty())
|
||||
{
|
||||
wsetlocale(LC_NUMERIC, L"C");
|
||||
}
|
||||
|
||||
r = wcstod(nptr, endptr);
|
||||
|
||||
if (!saved_locale.empty())
|
||||
{
|
||||
wsetlocale(LC_NUMERIC, saved_locale.c_str());
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void builtin_printf_state_t::fatal_error(const wchar_t *fmt, ...)
|
||||
{
|
||||
// Don't error twice
|
||||
if (early_exit)
|
||||
return;
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
wcstring errstr = vformat_string(fmt, va);
|
||||
va_end(va);
|
||||
stderr_buffer.append(errstr);
|
||||
if (! string_suffixes_string(L"\n", errstr))
|
||||
stderr_buffer.push_back(L'\n');
|
||||
|
||||
this->exit_code = STATUS_BUILTIN_ERROR;
|
||||
this->early_exit = true;
|
||||
}
|
||||
|
||||
void builtin_printf_state_t::append_output(wchar_t c)
|
||||
{
|
||||
// Don't output if we're done
|
||||
if (early_exit)
|
||||
return;
|
||||
|
||||
stdout_buffer.push_back(c);
|
||||
}
|
||||
|
||||
void builtin_printf_state_t::append_output(const wchar_t *c)
|
||||
{
|
||||
// Don't output if we're done
|
||||
if (early_exit)
|
||||
return;
|
||||
|
||||
stdout_buffer.append(c);
|
||||
}
|
||||
|
||||
void builtin_printf_state_t::append_format_output(const wchar_t *fmt, ...)
|
||||
{
|
||||
// Don't output if we're done
|
||||
if (early_exit)
|
||||
return;
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
append_formatv(stdout_buffer, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
|
||||
void builtin_printf_state_t::verify_numeric(const wchar_t *s, const wchar_t *end, int errcode)
|
||||
{
|
||||
if (errcode != 0)
|
||||
{
|
||||
this->fatal_error(L"%ls: %s", s, strerror(errcode));
|
||||
}
|
||||
else if (*end)
|
||||
{
|
||||
if (s == end)
|
||||
this->fatal_error(_(L"%ls: expected a numeric value"), s);
|
||||
else
|
||||
this->fatal_error(_(L"%ls: value not completely converted"), s);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T raw_string_to_scalar_type(const wchar_t *s, wchar_t ** end);
|
||||
|
||||
// we use wcstoll instead of wcstoimax because FreeBSD 8 has busted wcstoumax and wcstoimax - see #626
|
||||
template<>
|
||||
intmax_t raw_string_to_scalar_type(const wchar_t *s, wchar_t ** end)
|
||||
{
|
||||
return wcstoll(s, end, 0);
|
||||
}
|
||||
|
||||
template<>
|
||||
uintmax_t raw_string_to_scalar_type(const wchar_t *s, wchar_t ** end)
|
||||
{
|
||||
return wcstoull(s, end, 0);
|
||||
}
|
||||
|
||||
template<>
|
||||
long double raw_string_to_scalar_type(const wchar_t *s, wchar_t ** end)
|
||||
{
|
||||
return C_STRTOD(s, end);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T string_to_scalar_type(const wchar_t *s, builtin_printf_state_t *state)
|
||||
{
|
||||
T val;
|
||||
if (*s == L'\"' || *s == L'\'')
|
||||
{
|
||||
wchar_t ch = *++s;
|
||||
val = ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t *end = NULL;
|
||||
errno = 0;
|
||||
val = raw_string_to_scalar_type<T>(s, &end);
|
||||
state->verify_numeric(s, end, errno);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Output a single-character \ escape. */
|
||||
|
||||
void builtin_printf_state_t::print_esc_char(wchar_t c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case L'a': /* Alert. */
|
||||
this->append_output(L'\a');
|
||||
break;
|
||||
case L'b': /* Backspace. */
|
||||
this->append_output(L'\b');
|
||||
break;
|
||||
case L'c': /* Cancel the rest of the output. */
|
||||
this->early_exit = true;
|
||||
break;
|
||||
case L'e': /* Escape */
|
||||
this->append_output(L'\x1B');
|
||||
break;
|
||||
case L'f': /* Form feed. */
|
||||
this->append_output(L'\f');
|
||||
break;
|
||||
case L'n': /* New line. */
|
||||
this->append_output(L'\n');
|
||||
break;
|
||||
case L'r': /* Carriage return. */
|
||||
this->append_output(L'\r');
|
||||
break;
|
||||
case L't': /* Horizontal tab. */
|
||||
this->append_output(L'\t');
|
||||
break;
|
||||
case L'v': /* Vertical tab. */
|
||||
this->append_output(L'\v');
|
||||
break;
|
||||
default:
|
||||
this->append_output(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a \ escape sequence starting at ESCSTART.
|
||||
Return the number of characters in the escape sequence
|
||||
besides the backslash.
|
||||
If OCTAL_0 is nonzero, octal escapes are of the form \0ooo, where o
|
||||
is an octal digit; otherwise they are of the form \ooo. */
|
||||
long builtin_printf_state_t::print_esc(const wchar_t *escstart, bool octal_0)
|
||||
{
|
||||
const wchar_t *p = escstart + 1;
|
||||
int esc_value = 0; /* Value of \nnn escape. */
|
||||
int esc_length; /* Length of \nnn escape. */
|
||||
|
||||
if (*p == L'x')
|
||||
{
|
||||
/* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits. */
|
||||
for (esc_length = 0, ++p; esc_length < 2 && is_hex_digit(*p); ++esc_length, ++p)
|
||||
esc_value = esc_value * 16 + hex_to_bin(*p);
|
||||
if (esc_length == 0)
|
||||
this->fatal_error(_(L"missing hexadecimal number in escape"));
|
||||
this->append_output(ENCODE_DIRECT_BASE + esc_value % 256);
|
||||
}
|
||||
else if (is_octal_digit(*p))
|
||||
{
|
||||
/* Parse \0ooo (if octal_0 && *p == L'0') or \ooo (otherwise).
|
||||
Allow \ooo if octal_0 && *p != L'0'; this is an undocumented
|
||||
extension to POSIX that is compatible with Bash 2.05b. */
|
||||
/* Wrap mod 256, which matches historic behavior */
|
||||
for (esc_length = 0, p += octal_0 && *p == L'0'; esc_length < 3 && is_octal_digit(*p); ++esc_length, ++p)
|
||||
esc_value = esc_value * 8 + octal_to_bin(*p);
|
||||
this->append_output(ENCODE_DIRECT_BASE + esc_value % 256);
|
||||
}
|
||||
else if (*p && wcschr(L"\"\\abcefnrtv", *p))
|
||||
{
|
||||
print_esc_char(*p++);
|
||||
}
|
||||
else if (*p == L'u' || *p == L'U')
|
||||
{
|
||||
wchar_t esc_char = *p;
|
||||
p++;
|
||||
uint32_t uni_value = 0;
|
||||
for (size_t esc_length = 0; esc_length < (esc_char == L'u' ? 4 : 8); esc_length++)
|
||||
{
|
||||
if (! is_hex_digit(*p))
|
||||
{
|
||||
/* Escape sequence must be done. Complain if we didn't get anything */
|
||||
if (esc_length == 0)
|
||||
{
|
||||
this->fatal_error(_(L"Missing hexadecimal number in Unicode escape"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
uni_value = uni_value * 16 + hex_to_bin(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
/* PCA GNU printf respects the limitations described in ISO N717, about which universal characters "shall not" be specified. I believe this limitation is for the benefit of compilers; I see no reason to impose it in builtin_printf.
|
||||
|
||||
If __STDC_ISO_10646__ is defined, then it means wchar_t can and does hold Unicode code points, so just use that. If not defined, use the %lc printf conversion; this probably won't do anything good if your wide character set is not Unicode, but such platforms are exceedingly rare.
|
||||
*/
|
||||
if (uni_value > 0x10FFFF)
|
||||
{
|
||||
this->fatal_error(_(L"Unicode character out of range: \\%c%0*x"), esc_char, (esc_char == L'u' ? 4 : 8), uni_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(__STDC_ISO_10646__)
|
||||
this->append_output(uni_value);
|
||||
#else
|
||||
this->append_format_output(L"%lc", uni_value);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->append_output(L'\\');
|
||||
if (*p)
|
||||
{
|
||||
this->append_output(*p);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
return p - escstart - 1;
|
||||
}
|
||||
|
||||
/* Print string STR, evaluating \ escapes. */
|
||||
|
||||
void builtin_printf_state_t::print_esc_string(const wchar_t *str)
|
||||
{
|
||||
for (; *str; str++)
|
||||
if (*str == L'\\')
|
||||
str += print_esc(str, true);
|
||||
else
|
||||
this->append_output(*str);
|
||||
}
|
||||
|
||||
/* Evaluate a printf conversion specification. START is the start of
|
||||
the directive, LENGTH is its length, and CONVERSION specifies the
|
||||
type of conversion. LENGTH does not include any length modifier or
|
||||
the conversion specifier itself. FIELD_WIDTH and PRECISION are the
|
||||
field width and precision for '*' values, if HAVE_FIELD_WIDTH and
|
||||
HAVE_PRECISION are true, respectively. ARGUMENT is the argument to
|
||||
be formatted. */
|
||||
|
||||
void builtin_printf_state_t::print_direc(const wchar_t *start, size_t length, wchar_t conversion,
|
||||
bool have_field_width, int field_width,
|
||||
bool have_precision, int precision,
|
||||
wchar_t const *argument)
|
||||
{
|
||||
// Start with everything except the conversion specifier
|
||||
wcstring fmt(start, length);
|
||||
|
||||
/* Create a copy of the % directive, with an intmax_t-wide width modifier substituted for any existing integer length modifier. */
|
||||
switch (conversion)
|
||||
{
|
||||
case L'd':
|
||||
case L'i':
|
||||
case L'u':
|
||||
fmt.append(L"ll");
|
||||
break;
|
||||
case L'a':
|
||||
case L'e':
|
||||
case L'f':
|
||||
case L'g':
|
||||
case L'A':
|
||||
case L'E':
|
||||
case L'F':
|
||||
case L'G':
|
||||
fmt.append(L"L");
|
||||
break;
|
||||
case L's':
|
||||
case L'c':
|
||||
fmt.append(L"l");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Append the conversion itself
|
||||
fmt.push_back(conversion);
|
||||
|
||||
switch (conversion)
|
||||
{
|
||||
case L'd':
|
||||
case L'i':
|
||||
{
|
||||
intmax_t arg = string_to_scalar_type<intmax_t>(argument, this);
|
||||
if (! have_field_width)
|
||||
{
|
||||
if (! have_precision)
|
||||
this->append_format_output(fmt.c_str(), arg);
|
||||
else
|
||||
this->append_format_output(fmt.c_str(), precision, arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! have_precision)
|
||||
this->append_format_output(fmt.c_str(), field_width, arg);
|
||||
else
|
||||
this->append_format_output(fmt.c_str(), field_width, precision, arg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case L'o':
|
||||
case L'u':
|
||||
case L'x':
|
||||
case L'X':
|
||||
{
|
||||
uintmax_t arg = string_to_scalar_type<uintmax_t>(argument, this);
|
||||
if (!have_field_width)
|
||||
{
|
||||
if (!have_precision)
|
||||
this->append_format_output(fmt.c_str(), arg);
|
||||
else
|
||||
this->append_format_output(fmt.c_str(), precision, arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!have_precision)
|
||||
this->append_format_output(fmt.c_str(), field_width, arg);
|
||||
else
|
||||
this->append_format_output(fmt.c_str(), field_width, precision, arg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case L'a':
|
||||
case L'A':
|
||||
case L'e':
|
||||
case L'E':
|
||||
case L'f':
|
||||
case L'F':
|
||||
case L'g':
|
||||
case L'G':
|
||||
{
|
||||
long double arg = string_to_scalar_type<long double>(argument, this);
|
||||
if (!have_field_width)
|
||||
{
|
||||
if (!have_precision)
|
||||
this->append_format_output(fmt.c_str(), arg);
|
||||
else
|
||||
this->append_format_output(fmt.c_str(), precision, arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!have_precision)
|
||||
this->append_format_output(fmt.c_str(), field_width, arg);
|
||||
else
|
||||
this->append_format_output(fmt.c_str(), field_width, precision, arg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case L'c':
|
||||
if (!have_field_width)
|
||||
this->append_format_output(fmt.c_str(), *argument);
|
||||
else
|
||||
this->append_format_output(fmt.c_str(), field_width, *argument);
|
||||
break;
|
||||
case L's':
|
||||
if (!have_field_width)
|
||||
{
|
||||
if (!have_precision)
|
||||
{
|
||||
this->append_format_output(fmt.c_str(), argument);
|
||||
}
|
||||
else
|
||||
this->append_format_output(fmt.c_str(), precision, argument);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!have_precision)
|
||||
this->append_format_output(fmt.c_str(), field_width, argument);
|
||||
else
|
||||
this->append_format_output(fmt.c_str(), field_width, precision, argument);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* For each character in str, set the corresponding boolean in the array to the given flag */
|
||||
static inline void modify_allowed_format_specifiers(bool ok[UCHAR_MAX + 1], const char *str, bool flag)
|
||||
{
|
||||
for (const char *c = str; *c != '\0'; c++)
|
||||
{
|
||||
unsigned char idx = static_cast<unsigned char>(*c);
|
||||
ok[idx] = flag;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the text in FORMAT, using ARGV (with ARGC elements) for
|
||||
arguments to any `%' directives.
|
||||
Return the number of elements of ARGV used. */
|
||||
|
||||
int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wchar_t **argv)
|
||||
{
|
||||
int save_argc = argc; /* Preserve original value. */
|
||||
const wchar_t *f; /* Pointer into `format'. */
|
||||
const wchar_t *direc_start; /* Start of % directive. */
|
||||
size_t direc_length; /* Length of % directive. */
|
||||
bool have_field_width; /* True if FIELD_WIDTH is valid. */
|
||||
int field_width = 0; /* Arg to first '*'. */
|
||||
bool have_precision; /* True if PRECISION is valid. */
|
||||
int precision = 0; /* Arg to second '*'. */
|
||||
bool ok[UCHAR_MAX + 1] = { }; /* ok['x'] is true if %x is allowed. */
|
||||
|
||||
for (f = format; *f != L'\0'; ++f)
|
||||
{
|
||||
switch (*f)
|
||||
{
|
||||
case L'%':
|
||||
direc_start = f++;
|
||||
direc_length = 1;
|
||||
have_field_width = have_precision = false;
|
||||
if (*f == L'%')
|
||||
{
|
||||
this->append_output(L'%');
|
||||
break;
|
||||
}
|
||||
if (*f == L'b')
|
||||
{
|
||||
/* FIXME: Field width and precision are not supported
|
||||
for %b, even though POSIX requires it. */
|
||||
if (argc > 0)
|
||||
{
|
||||
print_esc_string(*argv);
|
||||
++argv;
|
||||
--argc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
modify_allowed_format_specifiers(ok, "aAcdeEfFgGiosuxX", true);
|
||||
|
||||
for (;; f++, direc_length++)
|
||||
{
|
||||
switch (*f)
|
||||
{
|
||||
case L'I':
|
||||
case L'\'':
|
||||
modify_allowed_format_specifiers(ok, "aAceEosxX", false);
|
||||
break;
|
||||
case '-':
|
||||
case '+':
|
||||
case ' ':
|
||||
break;
|
||||
case L'#':
|
||||
modify_allowed_format_specifiers(ok, "cdisu", false);
|
||||
break;
|
||||
case '0':
|
||||
modify_allowed_format_specifiers(ok, "cs", false);
|
||||
break;
|
||||
default:
|
||||
goto no_more_flag_characters;
|
||||
}
|
||||
}
|
||||
no_more_flag_characters:
|
||||
;
|
||||
|
||||
if (*f == L'*')
|
||||
{
|
||||
++f;
|
||||
++direc_length;
|
||||
if (argc > 0)
|
||||
{
|
||||
intmax_t width = string_to_scalar_type<intmax_t>(*argv, this);
|
||||
if (INT_MIN <= width && width <= INT_MAX)
|
||||
field_width = static_cast<int>(width);
|
||||
else
|
||||
this->fatal_error(_(L"invalid field width: %ls"), *argv);
|
||||
++argv;
|
||||
--argc;
|
||||
}
|
||||
else
|
||||
{
|
||||
field_width = 0;
|
||||
}
|
||||
have_field_width = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (iswdigit(*f))
|
||||
{
|
||||
++f;
|
||||
++direc_length;
|
||||
}
|
||||
}
|
||||
if (*f == L'.')
|
||||
{
|
||||
++f;
|
||||
++direc_length;
|
||||
modify_allowed_format_specifiers(ok, "c", false);
|
||||
if (*f == L'*')
|
||||
{
|
||||
++f;
|
||||
++direc_length;
|
||||
if (argc > 0)
|
||||
{
|
||||
intmax_t prec = string_to_scalar_type<intmax_t>(*argv, this);
|
||||
if (prec < 0)
|
||||
{
|
||||
/* A negative precision is taken as if the
|
||||
precision were omitted, so -1 is safe
|
||||
here even if prec < INT_MIN. */
|
||||
precision = -1;
|
||||
}
|
||||
else if (INT_MAX < prec)
|
||||
this->fatal_error(_(L"invalid precision: %ls"), *argv);
|
||||
else
|
||||
{
|
||||
precision = static_cast<int>(prec);
|
||||
}
|
||||
++argv;
|
||||
--argc;
|
||||
}
|
||||
else
|
||||
{
|
||||
precision = 0;
|
||||
}
|
||||
have_precision = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (iswdigit(*f))
|
||||
{
|
||||
++f;
|
||||
++direc_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (*f == L'l' || *f == L'L' || *f == L'h' || *f == L'j' || *f == L't' || *f == L'z')
|
||||
++f;
|
||||
|
||||
{
|
||||
wchar_t conversion = *f;
|
||||
if (conversion > 0xFF || ! ok[conversion])
|
||||
{
|
||||
this->fatal_error(_(L"%.*ls: invalid conversion specification"), (int)(f + 1 - direc_start), direc_start);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
print_direc(direc_start, direc_length, *f,
|
||||
have_field_width, field_width,
|
||||
have_precision, precision,
|
||||
(argc <= 0 ? L"" : (argc--, *argv++)));
|
||||
break;
|
||||
|
||||
case L'\\':
|
||||
f += print_esc(f, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
this->append_output(*f);
|
||||
}
|
||||
}
|
||||
return save_argc - argc;
|
||||
}
|
||||
|
||||
static int builtin_printf(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
builtin_printf_state_t state;
|
||||
|
||||
wchar_t *format;
|
||||
int args_used;
|
||||
int argc = builtin_count_args(argv);
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
state.fatal_error(_(L"printf: not enough arguments"));
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
format = argv[1];
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
|
||||
do
|
||||
{
|
||||
args_used = state.print_formatted(format, argc, argv);
|
||||
argc -= args_used;
|
||||
argv += args_used;
|
||||
}
|
||||
while (args_used > 0 && argc > 0 && ! state.early_exit);
|
||||
return state.exit_code;
|
||||
}
|
||||
827
builtin_set.cpp
827
builtin_set.cpp
@@ -1,827 +0,0 @@
|
||||
/** \file builtin_set.c Functions defining the set builtin
|
||||
|
||||
Functions used for implementing the set builtin.
|
||||
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include "fallback.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "wutil.h"
|
||||
#include "builtin.h"
|
||||
#include "env.h"
|
||||
#include "expand.h"
|
||||
#include "common.h"
|
||||
#include "wgetopt.h"
|
||||
#include "proc.h"
|
||||
#include "parser.h"
|
||||
|
||||
/* We know about these buffers */
|
||||
extern wcstring stdout_buffer, stderr_buffer;
|
||||
|
||||
/**
|
||||
Error message for invalid path operations
|
||||
*/
|
||||
#define BUILTIN_SET_PATH_ERROR L"%ls: Warning: path component %ls may not be valid in %ls.\n"
|
||||
|
||||
/**
|
||||
Hint for invalid path operation with a colon
|
||||
*/
|
||||
#define BUILTIN_SET_PATH_HINT L"%ls: Did you mean 'set %ls $%ls %ls'?\n"
|
||||
|
||||
/**
|
||||
Error for mismatch between index count and elements
|
||||
*/
|
||||
#define BUILTIN_SET_ARG_COUNT L"%ls: The number of variable indexes does not match the number of values\n"
|
||||
|
||||
/**
|
||||
Test if the specified variable should be subject to path validation
|
||||
*/
|
||||
static int is_path_variable(const wchar_t *env)
|
||||
{
|
||||
return contains(env, L"PATH", L"CDPATH");
|
||||
}
|
||||
|
||||
/**
|
||||
Call env_set. If this is a path variable, e.g. PATH, validate the
|
||||
elements. On error, print a description of the problem to stderr.
|
||||
*/
|
||||
static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope)
|
||||
{
|
||||
size_t i;
|
||||
int retcode = 0;
|
||||
const wchar_t *val_str=NULL;
|
||||
|
||||
if (is_path_variable(key))
|
||||
{
|
||||
/* Fix for https://github.com/fish-shell/fish-shell/issues/199 . Return success if any path setting succeeds. */
|
||||
bool any_success = false;
|
||||
|
||||
/* Don't bother validating (or complaining about) values that are already present */
|
||||
wcstring_list_t existing_values;
|
||||
const env_var_t existing_variable = env_get_string(key, scope);
|
||||
if (! existing_variable.missing_or_empty())
|
||||
tokenize_variable_array(existing_variable, existing_values);
|
||||
|
||||
for (i=0; i< val.size() ; i++)
|
||||
{
|
||||
const wcstring &dir = val.at(i);
|
||||
if (list_contains_string(existing_values, dir))
|
||||
{
|
||||
any_success = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool show_perror = false;
|
||||
int show_hint = 0;
|
||||
bool error = false;
|
||||
|
||||
struct stat buff;
|
||||
if (wstat(dir, &buff))
|
||||
{
|
||||
error = true;
|
||||
show_perror = true;
|
||||
}
|
||||
|
||||
if (!(S_ISDIR(buff.st_mode)))
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (!error)
|
||||
{
|
||||
any_success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
append_format(stderr_buffer, _(BUILTIN_SET_PATH_ERROR), L"set", dir.c_str(), key);
|
||||
const wchar_t *colon = wcschr(dir.c_str(), L':');
|
||||
|
||||
if (colon && *(colon+1))
|
||||
{
|
||||
show_hint = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (show_perror)
|
||||
{
|
||||
builtin_wperror(L"set");
|
||||
}
|
||||
|
||||
if (show_hint)
|
||||
{
|
||||
append_format(stderr_buffer, _(BUILTIN_SET_PATH_HINT), L"set", key, key, wcschr(dir.c_str(), L':')+1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Fail at setting the path if we tried to set it to something non-empty, but it wound up empty. */
|
||||
if (! val.empty() && ! any_success)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
wcstring sb;
|
||||
if (! val.empty())
|
||||
{
|
||||
for (i=0; i< val.size() ; i++)
|
||||
{
|
||||
sb.append(val[i]);
|
||||
if (i<val.size() - 1)
|
||||
{
|
||||
sb.append(ARRAY_SEP_STR);
|
||||
}
|
||||
}
|
||||
val_str = sb.c_str();
|
||||
}
|
||||
|
||||
switch (env_set(key, val_str, scope | ENV_USER))
|
||||
{
|
||||
case ENV_PERM:
|
||||
{
|
||||
append_format(stderr_buffer, _(L"%ls: Tried to change the read-only variable '%ls'\n"), L"set", key);
|
||||
retcode=1;
|
||||
break;
|
||||
}
|
||||
|
||||
case ENV_SCOPE:
|
||||
{
|
||||
append_format(stderr_buffer, _(L"%ls: Tried to set the special variable '%ls' with the wrong scope\n"), L"set", key);
|
||||
retcode=1;
|
||||
break;
|
||||
}
|
||||
|
||||
case ENV_INVALID:
|
||||
{
|
||||
append_format(stderr_buffer, _(L"%ls: Tried to set the special variable '%ls' to an invalid value\n"), L"set", key);
|
||||
retcode=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Extract indexes from a destination argument of the form name[index1 index2...]
|
||||
|
||||
\param indexes the list to insert the new indexes into
|
||||
\param src the source string to parse
|
||||
\param name the name of the element. Return null if the name in \c src does not match this name
|
||||
\param var_count the number of elements in the array to parse.
|
||||
|
||||
\return the total number of indexes parsed, or -1 on error
|
||||
*/
|
||||
static int parse_index(std::vector<long> &indexes,
|
||||
const wchar_t *src,
|
||||
const wchar_t *name,
|
||||
size_t var_count)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
int count = 0;
|
||||
const wchar_t *src_orig = src;
|
||||
|
||||
if (src == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*src != L'\0' && (iswalnum(*src) || *src == L'_'))
|
||||
{
|
||||
src++;
|
||||
}
|
||||
|
||||
if (*src != L'[')
|
||||
{
|
||||
append_format(stderr_buffer, _(BUILTIN_SET_ARG_COUNT), L"set");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = src-src_orig;
|
||||
|
||||
if ((wcsncmp(src_orig, name, len)!=0) || (wcslen(name) != (len)))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Multiple variable names specified in single call (%ls and %.*ls)\n"),
|
||||
L"set",
|
||||
name,
|
||||
len,
|
||||
src_orig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
src++;
|
||||
|
||||
while (iswspace(*src))
|
||||
{
|
||||
src++;
|
||||
}
|
||||
|
||||
while (*src != L']')
|
||||
{
|
||||
wchar_t *end;
|
||||
|
||||
long l_ind;
|
||||
|
||||
errno = 0;
|
||||
|
||||
l_ind = wcstol(src, &end, 10);
|
||||
|
||||
if (end==src || errno)
|
||||
{
|
||||
append_format(stderr_buffer, _(L"%ls: Invalid index starting at '%ls'\n"), L"set", src);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (l_ind < 0)
|
||||
{
|
||||
l_ind = var_count+l_ind+1;
|
||||
}
|
||||
|
||||
src = end;
|
||||
if (*src==L'.' && *(src+1)==L'.')
|
||||
{
|
||||
src+=2;
|
||||
long l_ind2 = wcstol(src, &end, 10);
|
||||
if (end==src || errno)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
src = end;
|
||||
|
||||
if (l_ind2 < 0)
|
||||
{
|
||||
l_ind2 = var_count+l_ind2+1;
|
||||
}
|
||||
int direction = l_ind2<l_ind ? -1 : 1 ;
|
||||
for (long jjj = l_ind; jjj*direction <= l_ind2*direction; jjj+=direction)
|
||||
{
|
||||
// debug(0, L"Expand range [set]: %i\n", jjj);
|
||||
indexes.push_back(jjj);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
indexes.push_back(l_ind);
|
||||
count++;
|
||||
}
|
||||
while (iswspace(*src)) src++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int update_values(wcstring_list_t &list,
|
||||
std::vector<long> &indexes,
|
||||
wcstring_list_t &values)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
/* Replace values where needed */
|
||||
for (i = 0; i < indexes.size(); i++)
|
||||
{
|
||||
/*
|
||||
The '- 1' below is because the indices in fish are
|
||||
one-based, but the vector uses zero-based indices
|
||||
*/
|
||||
long ind = indexes[i] - 1;
|
||||
const wcstring newv = values[ i ];
|
||||
if (ind < 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if ((size_t)ind >= list.size())
|
||||
{
|
||||
list.resize(ind+1);
|
||||
}
|
||||
|
||||
// free((void *) al_get(list, ind));
|
||||
list[ ind ] = newv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Erase from a list of wcstring values at specified indexes
|
||||
*/
|
||||
static void erase_values(wcstring_list_t &list, const std::vector<long> &indexes)
|
||||
{
|
||||
// Make a set of indexes.
|
||||
// This both sorts them into ascending order and removes duplicates.
|
||||
const std::set<long> indexes_set(indexes.begin(), indexes.end());
|
||||
|
||||
// Now walk the set backwards, so we encounter larger indexes first, and remove elements at the given (1-based) indexes.
|
||||
std::set<long>::const_reverse_iterator iter;
|
||||
for (iter = indexes_set.rbegin(); iter != indexes_set.rend(); ++iter)
|
||||
{
|
||||
long val = *iter;
|
||||
if (val > 0 && (size_t)val <= list.size())
|
||||
{
|
||||
// One-based indexing!
|
||||
list.erase(list.begin() + val - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Print the names of all environment variables in the scope, with or without shortening,
|
||||
with or without values, with or without escaping
|
||||
*/
|
||||
static void print_variables(int include_values, int esc, bool shorten_ok, int scope)
|
||||
{
|
||||
wcstring_list_t names = env_get_names(scope);
|
||||
sort(names.begin(), names.end());
|
||||
|
||||
for (size_t i = 0; i < names.size(); i++)
|
||||
{
|
||||
const wcstring key = names.at(i);
|
||||
const wcstring e_key = escape_string(key, 0);
|
||||
|
||||
stdout_buffer.append(e_key);
|
||||
|
||||
if (include_values)
|
||||
{
|
||||
env_var_t value = env_get_string(key, scope);
|
||||
if (!value.missing())
|
||||
{
|
||||
int shorten = 0;
|
||||
|
||||
if (shorten_ok && value.length() > 64)
|
||||
{
|
||||
shorten = 1;
|
||||
value.resize(60);
|
||||
}
|
||||
|
||||
wcstring e_value = esc ? expand_escape_variable(value) : value;
|
||||
|
||||
stdout_buffer.append(L" ");
|
||||
stdout_buffer.append(e_value);
|
||||
|
||||
if (shorten)
|
||||
{
|
||||
stdout_buffer.push_back(ellipsis_char);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
stdout_buffer.append(L"\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
The set builtin. Creates, updates and erases environment variables
|
||||
and environemnt variable arrays.
|
||||
*/
|
||||
static int builtin_set(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
/** Variables used for parsing the argument list */
|
||||
const struct woption long_options[] =
|
||||
{
|
||||
{ L"export", no_argument, 0, 'x' },
|
||||
{ L"global", no_argument, 0, 'g' },
|
||||
{ L"local", no_argument, 0, 'l' },
|
||||
{ L"erase", no_argument, 0, 'e' },
|
||||
{ L"names", no_argument, 0, 'n' },
|
||||
{ L"unexport", no_argument, 0, 'u' },
|
||||
{ L"universal", no_argument, 0, 'U' },
|
||||
{ L"long", no_argument, 0, 'L' },
|
||||
{ L"query", no_argument, 0, 'q' },
|
||||
{ L"help", no_argument, 0, 'h' },
|
||||
{ 0, 0, 0, 0 }
|
||||
} ;
|
||||
|
||||
const wchar_t *short_options = L"+xglenuULqh";
|
||||
|
||||
int argc = builtin_count_args(argv);
|
||||
|
||||
/*
|
||||
Flags to set the work mode
|
||||
*/
|
||||
int local = 0, global = 0, exportv = 0;
|
||||
int erase = 0, list = 0, unexport=0;
|
||||
int universal = 0, query=0;
|
||||
bool shorten_ok = true;
|
||||
bool preserve_incoming_failure_exit_status = true;
|
||||
const int incoming_exit_status = proc_get_last_status();
|
||||
|
||||
/*
|
||||
Variables used for performing the actual work
|
||||
*/
|
||||
wchar_t *dest = 0;
|
||||
int retcode=0;
|
||||
int scope;
|
||||
int slice=0;
|
||||
int i;
|
||||
|
||||
const wchar_t *bad_char = NULL;
|
||||
|
||||
|
||||
/* Parse options to obtain the requested operation and the modifiers */
|
||||
woptind = 0;
|
||||
while (1)
|
||||
{
|
||||
int c = wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
|
||||
if (c == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
erase = 1;
|
||||
preserve_incoming_failure_exit_status = false;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
list = 1;
|
||||
preserve_incoming_failure_exit_status = false;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
exportv = 1;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
local = 1;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
global = 1;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
unexport = 1;
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
universal = 1;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
shorten_ok = false;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
query = 1;
|
||||
preserve_incoming_failure_exit_status = false;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help(parser, argv[0], stdout_buffer);
|
||||
return 0;
|
||||
|
||||
case '?':
|
||||
builtin_unknown_option(parser, argv[0], argv[woptind-1]);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Ok, all arguments have been parsed, let's validate them
|
||||
*/
|
||||
|
||||
/*
|
||||
If we are checking the existance of a variable (-q) we can not
|
||||
also specify scope
|
||||
*/
|
||||
|
||||
if (query && (erase || list))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_COMBO,
|
||||
argv[0]);
|
||||
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* We can't both list and erase variables */
|
||||
if (erase && list)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_COMBO,
|
||||
argv[0]);
|
||||
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Variables can only have one scope
|
||||
*/
|
||||
if (local + global + universal > 1)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_GLOCAL,
|
||||
argv[0]);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Variables can only have one export status
|
||||
*/
|
||||
if (exportv && unexport)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_EXPUNEXP,
|
||||
argv[0]);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate the scope value for variable assignement
|
||||
*/
|
||||
scope = (local ? ENV_LOCAL : 0) | (global ? ENV_GLOBAL : 0) | (exportv ? ENV_EXPORT : 0) | (unexport ? ENV_UNEXPORT : 0) | (universal ? ENV_UNIVERSAL:0) | ENV_USER;
|
||||
|
||||
if (query)
|
||||
{
|
||||
/*
|
||||
Query mode. Return the number of variables that do not exist
|
||||
out of the specified variables.
|
||||
*/
|
||||
int i;
|
||||
for (i=woptind; i<argc; i++)
|
||||
{
|
||||
wchar_t *arg = argv[i];
|
||||
int slice=0;
|
||||
|
||||
if (!(dest = wcsdup(arg)))
|
||||
{
|
||||
DIE_MEM();
|
||||
}
|
||||
|
||||
if (wcschr(dest, L'['))
|
||||
{
|
||||
slice = 1;
|
||||
*wcschr(dest, L'[')=0;
|
||||
}
|
||||
|
||||
if (slice)
|
||||
{
|
||||
std::vector<long> indexes;
|
||||
wcstring_list_t result;
|
||||
size_t j;
|
||||
|
||||
env_var_t dest_str = env_get_string(dest, scope);
|
||||
if (! dest_str.missing())
|
||||
tokenize_variable_array(dest_str, result);
|
||||
|
||||
if (!parse_index(indexes, arg, dest, result.size()))
|
||||
{
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
retcode = 1;
|
||||
break;
|
||||
}
|
||||
for (j=0; j < indexes.size() ; j++)
|
||||
{
|
||||
long idx = indexes[j];
|
||||
if (idx < 1 || (size_t)idx > result.size())
|
||||
{
|
||||
retcode++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!env_exist(arg, scope))
|
||||
{
|
||||
retcode++;
|
||||
}
|
||||
}
|
||||
|
||||
free(dest);
|
||||
|
||||
}
|
||||
return retcode;
|
||||
}
|
||||
|
||||
if (list)
|
||||
{
|
||||
/* Maybe we should issue an error if there are any other arguments? */
|
||||
print_variables(0, 0, shorten_ok, scope);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (woptind == argc)
|
||||
{
|
||||
/*
|
||||
Print values of variables
|
||||
*/
|
||||
|
||||
if (erase)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Erase needs a variable name\n"),
|
||||
argv[0]);
|
||||
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
retcode = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
print_variables(1, 1, shorten_ok, scope);
|
||||
}
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
if (!(dest = wcsdup(argv[woptind])))
|
||||
{
|
||||
DIE_MEM();
|
||||
}
|
||||
|
||||
if (wcschr(dest, L'['))
|
||||
{
|
||||
slice = 1;
|
||||
*wcschr(dest, L'[')=0;
|
||||
}
|
||||
|
||||
if (!wcslen(dest))
|
||||
{
|
||||
free(dest);
|
||||
append_format(stderr_buffer, BUILTIN_ERR_VARNAME_ZERO, argv[0]);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((bad_char = wcsvarname(dest)))
|
||||
{
|
||||
append_format(stderr_buffer, BUILTIN_ERR_VARCHAR, argv[0], *bad_char);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
free(dest);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
set assignment can work in two modes, either using slices or
|
||||
using the whole array. We detect which mode is used here.
|
||||
*/
|
||||
|
||||
if (slice)
|
||||
{
|
||||
|
||||
/*
|
||||
Slice mode
|
||||
*/
|
||||
std::vector<long> indexes;
|
||||
wcstring_list_t result;
|
||||
|
||||
const env_var_t dest_str = env_get_string(dest, scope);
|
||||
if (! dest_str.missing())
|
||||
{
|
||||
tokenize_variable_array(dest_str, result);
|
||||
}
|
||||
else if (erase)
|
||||
{
|
||||
retcode = 1;
|
||||
}
|
||||
|
||||
if (!retcode)
|
||||
{
|
||||
for (; woptind<argc; woptind++)
|
||||
{
|
||||
if (!parse_index(indexes, argv[woptind], dest, result.size()))
|
||||
{
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
retcode = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
size_t idx_count = indexes.size();
|
||||
size_t val_count = argc-woptind-1;
|
||||
|
||||
if (!erase)
|
||||
{
|
||||
if (val_count < idx_count)
|
||||
{
|
||||
append_format(stderr_buffer, _(BUILTIN_SET_ARG_COUNT), argv[0]);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
retcode=1;
|
||||
break;
|
||||
}
|
||||
if (val_count == idx_count)
|
||||
{
|
||||
woptind++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!retcode)
|
||||
{
|
||||
/*
|
||||
Slice indexes have been calculated, do the actual work
|
||||
*/
|
||||
|
||||
if (erase)
|
||||
{
|
||||
erase_values(result, indexes);
|
||||
my_env_set(dest, result, scope);
|
||||
}
|
||||
else
|
||||
{
|
||||
wcstring_list_t value;
|
||||
|
||||
while (woptind < argc)
|
||||
{
|
||||
value.push_back(argv[woptind++]);
|
||||
}
|
||||
|
||||
if (update_values(result,
|
||||
indexes,
|
||||
value))
|
||||
{
|
||||
append_format(stderr_buffer, L"%ls: ", argv[0]);
|
||||
append_format(stderr_buffer, ARRAY_BOUNDS_ERR);
|
||||
stderr_buffer.push_back(L'\n');
|
||||
}
|
||||
|
||||
my_env_set(dest, result, scope);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
woptind++;
|
||||
|
||||
/*
|
||||
No slicing
|
||||
*/
|
||||
if (erase)
|
||||
{
|
||||
if (woptind != argc)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Values cannot be specfied with erase\n"),
|
||||
argv[0]);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
retcode=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
retcode = env_remove(dest, scope);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wcstring_list_t val;
|
||||
for (i=woptind; i<argc; i++)
|
||||
val.push_back(argv[i]);
|
||||
retcode = my_env_set(dest, val, scope);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we are setting variables above the effective scope.
|
||||
See https://github.com/fish-shell/fish-shell/issues/806
|
||||
*/
|
||||
|
||||
env_var_t global_dest = env_get_string(dest, ENV_GLOBAL);
|
||||
if (universal && ! global_dest.missing())
|
||||
{
|
||||
append_format(stderr_buffer, _(L"%ls: Warning: universal scope selected, but a global variable '%ls' exists.\n"), L"set", dest);
|
||||
}
|
||||
|
||||
free(dest);
|
||||
|
||||
if (retcode == STATUS_BUILTIN_OK && preserve_incoming_failure_exit_status)
|
||||
retcode = incoming_exit_status;
|
||||
return retcode;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
/** \file builtin_set_color.cpp Functions defining the set_color builtin
|
||||
|
||||
Functions used for implementing the set_color builtin.
|
||||
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include "builtin.h"
|
||||
#include "color.h"
|
||||
#include "output.h"
|
||||
|
||||
#if HAVE_NCURSES_H
|
||||
#include <ncurses.h>
|
||||
#elif HAVE_NCURSES_CURSES_H
|
||||
#include <ncurses/curses.h>
|
||||
#else
|
||||
#include <curses.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_TERM_H
|
||||
#include <term.h>
|
||||
#elif HAVE_NCURSES_TERM_H
|
||||
#include <ncurses/term.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* We know about these buffers */
|
||||
extern wcstring stdout_buffer, stderr_buffer;
|
||||
|
||||
/**
|
||||
Error message for invalid path operations
|
||||
*/
|
||||
#define BUILTIN_SET_PATH_ERROR L"%ls: Warning: path component %ls may not be valid in %ls.\n"
|
||||
|
||||
/**
|
||||
Hint for invalid path operation with a colon
|
||||
*/
|
||||
#define BUILTIN_SET_PATH_HINT L"%ls: Did you mean 'set %ls $%ls %ls'?\n"
|
||||
|
||||
/**
|
||||
Error for mismatch between index count and elements
|
||||
*/
|
||||
#define BUILTIN_SET_ARG_COUNT L"%ls: The number of variable indexes does not match the number of values\n"
|
||||
|
||||
static void print_colors(void)
|
||||
{
|
||||
const wcstring_list_t result = rgb_color_t::named_color_names();
|
||||
size_t i;
|
||||
for (i=0; i < result.size(); i++)
|
||||
{
|
||||
stdout_buffer.append(result.at(i));
|
||||
stdout_buffer.push_back(L'\n');
|
||||
}
|
||||
}
|
||||
|
||||
/* function we set as the output writer */
|
||||
static std::string builtin_set_color_output;
|
||||
static int set_color_builtin_outputter(char c)
|
||||
{
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
builtin_set_color_output.push_back(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
set_color builtin
|
||||
*/
|
||||
static int builtin_set_color(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
/** Variables used for parsing the argument list */
|
||||
const struct woption long_options[] =
|
||||
{
|
||||
{ L"background", required_argument, 0, 'b'},
|
||||
{ L"help", no_argument, 0, 'h' },
|
||||
{ L"bold", no_argument, 0, 'o' },
|
||||
{ L"underline", no_argument, 0, 'u' },
|
||||
{ L"version", no_argument, 0, 'v' },
|
||||
{ L"print-colors", no_argument, 0, 'c' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
const wchar_t *short_options = L"b:hvocu";
|
||||
|
||||
int argc = builtin_count_args(argv);
|
||||
|
||||
/* Some code passes variables to set_color that don't exist, like $fish_user_whatever. As a hack, quietly return failure. */
|
||||
if (argc <= 1)
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const wchar_t *bgcolor = NULL;
|
||||
bool bold = false, underline=false;
|
||||
int errret;
|
||||
|
||||
/* Parse options to obtain the requested operation and the modifiers */
|
||||
woptind = 0;
|
||||
while (1)
|
||||
{
|
||||
int c = wgetopt_long(argc, argv, short_options, long_options, 0);
|
||||
|
||||
if (c == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
bgcolor = woptarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
builtin_print_help(parser, argv[0], stdout_buffer);
|
||||
return STATUS_BUILTIN_OK;
|
||||
|
||||
case 'o':
|
||||
bold = true;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
underline = true;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
print_colors();
|
||||
return STATUS_BUILTIN_OK;
|
||||
|
||||
case '?':
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remaining arguments are foreground color */
|
||||
std::vector<rgb_color_t> fgcolors;
|
||||
for (; woptind < argc; woptind++)
|
||||
{
|
||||
rgb_color_t fg = rgb_color_t(argv[woptind]);
|
||||
if (fg.is_none() || fg.is_ignore())
|
||||
{
|
||||
append_format(stderr_buffer, _(L"%ls: Unknown color '%ls'\n"), argv[0], argv[woptind]);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
fgcolors.push_back(fg);
|
||||
}
|
||||
|
||||
if (fgcolors.empty() && bgcolor == NULL && !bold && !underline)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
_(L"%ls: Expected an argument\n"),
|
||||
argv[0]);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
// #1323: We may have multiple foreground colors. Choose the best one.
|
||||
// If we had no foreground coor, we'll get none(); if we have at least one we expect not-none
|
||||
const rgb_color_t fg = best_color(fgcolors, output_get_color_support());
|
||||
assert(fgcolors.empty() || !(fg.is_none() || fg.is_ignore()));
|
||||
|
||||
const rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : L"");
|
||||
if (bgcolor && (bg.is_none() || bg.is_ignore()))
|
||||
{
|
||||
append_format(stderr_buffer, _(L"%ls: Unknown color '%ls'\n"), argv[0], bgcolor);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
/* Make sure that the term exists */
|
||||
if (cur_term == NULL && setupterm(0, STDOUT_FILENO, &errret) == ERR)
|
||||
{
|
||||
append_format(stderr_buffer, _(L"%ls: Could not set up terminal\n"), argv[0]);
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
Test if we have at least basic support for setting fonts, colors
|
||||
and related bits - otherwise just give up...
|
||||
*/
|
||||
if (! exit_attribute_mode)
|
||||
{
|
||||
return STATUS_BUILTIN_ERROR;
|
||||
}
|
||||
|
||||
/* Save old output function so we can restore it */
|
||||
int (* const saved_writer_func)(char) = output_get_writer();
|
||||
|
||||
/* Set our output function, which writes to a std::string */
|
||||
builtin_set_color_output.clear();
|
||||
output_set_writer(set_color_builtin_outputter);
|
||||
|
||||
if (bold)
|
||||
{
|
||||
if (enter_bold_mode)
|
||||
writembs(tparm(enter_bold_mode));
|
||||
}
|
||||
|
||||
if (underline)
|
||||
{
|
||||
if (enter_underline_mode)
|
||||
writembs(enter_underline_mode);
|
||||
}
|
||||
|
||||
if (bgcolor != NULL)
|
||||
{
|
||||
if (bg.is_normal())
|
||||
{
|
||||
write_color(rgb_color_t::black(), false /* not is_fg */);
|
||||
writembs(tparm(exit_attribute_mode));
|
||||
}
|
||||
}
|
||||
|
||||
if (! fg.is_none())
|
||||
{
|
||||
if (fg.is_normal() || fg.is_reset())
|
||||
{
|
||||
write_color(rgb_color_t::black(), true /* is_fg */);
|
||||
writembs(tparm(exit_attribute_mode));
|
||||
}
|
||||
else
|
||||
{
|
||||
write_color(fg, true /* is_fg */);
|
||||
}
|
||||
}
|
||||
|
||||
if (bgcolor != NULL)
|
||||
{
|
||||
if (! bg.is_normal() && ! bg.is_reset())
|
||||
{
|
||||
write_color(bg, false /* not is_fg */);
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore saved writer function */
|
||||
output_set_writer(saved_writer_func);
|
||||
|
||||
/* Output the collected string */
|
||||
stdout_buffer.append(str2wcstring(builtin_set_color_output));
|
||||
builtin_set_color_output.clear();
|
||||
|
||||
return STATUS_BUILTIN_OK;
|
||||
}
|
||||
970
builtin_test.cpp
970
builtin_test.cpp
@@ -1,970 +0,0 @@
|
||||
/** \file builtin_test.cpp Functions defining the test builtin
|
||||
|
||||
Functions used for implementing the test builtin.
|
||||
Implemented from scratch (yes, really) by way of IEEE 1003.1 as reference.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "builtin.h"
|
||||
#include "wutil.h"
|
||||
#include "proc.h"
|
||||
#include <sys/stat.h>
|
||||
#include <memory>
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
BUILTIN_TEST_SUCCESS = STATUS_BUILTIN_OK,
|
||||
BUILTIN_TEST_FAIL = STATUS_BUILTIN_ERROR
|
||||
};
|
||||
|
||||
|
||||
int builtin_test(parser_t &parser, wchar_t **argv);
|
||||
|
||||
namespace test_expressions
|
||||
{
|
||||
|
||||
enum token_t
|
||||
{
|
||||
test_unknown, // arbitrary string
|
||||
|
||||
test_bang, // "!", inverts sense
|
||||
|
||||
test_filetype_b, // "-b", for block special files
|
||||
test_filetype_c, // "-c", for character special files
|
||||
test_filetype_d, // "-d", for directories
|
||||
test_filetype_e, // "-e", for files that exist
|
||||
test_filetype_f, // "-f", for for regular files
|
||||
test_filetype_G, // "-G", for check effective group id
|
||||
test_filetype_g, // "-g", for set-group-id
|
||||
test_filetype_h, // "-h", for symbolic links
|
||||
test_filetype_L, // "-L", same as -h
|
||||
test_filetype_O, // "-O", for check effective user id
|
||||
test_filetype_p, // "-p", for FIFO
|
||||
test_filetype_S, // "-S", socket
|
||||
|
||||
test_filesize_s, // "-s", size greater than zero
|
||||
|
||||
test_filedesc_t, // "-t", whether the fd is associated with a terminal
|
||||
|
||||
test_fileperm_r, // "-r", read permission
|
||||
test_fileperm_u, // "-u", whether file is setuid
|
||||
test_fileperm_w, // "-w", whether file write permission is allowed
|
||||
test_fileperm_x, // "-x", whether file execute/search is allowed
|
||||
|
||||
test_string_n, // "-n", non-empty string
|
||||
test_string_z, // "-z", true if length of string is 0
|
||||
test_string_equal, // "=", true if strings are identical
|
||||
test_string_not_equal, // "!=", true if strings are not identical
|
||||
|
||||
test_number_equal, // "-eq", true if numbers are equal
|
||||
test_number_not_equal, // "-ne", true if numbers are not equal
|
||||
test_number_greater, // "-gt", true if first number is larger than second
|
||||
test_number_greater_equal, // "-ge", true if first number is at least second
|
||||
test_number_lesser, // "-lt", true if first number is smaller than second
|
||||
test_number_lesser_equal, // "-le", true if first number is at most second
|
||||
|
||||
test_combine_and, // "-a", true if left and right are both true
|
||||
test_combine_or, // "-o", true if either left or right is true
|
||||
|
||||
test_paren_open, // "(", open paren
|
||||
test_paren_close, // ")", close paren
|
||||
};
|
||||
|
||||
static bool binary_primary_evaluate(test_expressions::token_t token, const wcstring &left, const wcstring &right, wcstring_list_t &errors);
|
||||
static bool unary_primary_evaluate(test_expressions::token_t token, const wcstring &arg, wcstring_list_t &errors);
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
UNARY_PRIMARY = 1 << 0,
|
||||
BINARY_PRIMARY = 1 << 1
|
||||
};
|
||||
|
||||
static const struct token_info_t
|
||||
{
|
||||
token_t tok;
|
||||
const wchar_t *string;
|
||||
unsigned int flags;
|
||||
} token_infos[] =
|
||||
{
|
||||
{test_unknown, L"", 0},
|
||||
{test_bang, L"!", 0},
|
||||
{test_filetype_b, L"-b", UNARY_PRIMARY},
|
||||
{test_filetype_c, L"-c", UNARY_PRIMARY},
|
||||
{test_filetype_d, L"-d", UNARY_PRIMARY},
|
||||
{test_filetype_e, L"-e", UNARY_PRIMARY},
|
||||
{test_filetype_f, L"-f", UNARY_PRIMARY},
|
||||
{test_filetype_G, L"-G", UNARY_PRIMARY},
|
||||
{test_filetype_g, L"-g", UNARY_PRIMARY},
|
||||
{test_filetype_h, L"-h", UNARY_PRIMARY},
|
||||
{test_filetype_L, L"-L", UNARY_PRIMARY},
|
||||
{test_filetype_O, L"-O", UNARY_PRIMARY},
|
||||
{test_filetype_p, L"-p", UNARY_PRIMARY},
|
||||
{test_filetype_S, L"-S", UNARY_PRIMARY},
|
||||
{test_filesize_s, L"-s", UNARY_PRIMARY},
|
||||
{test_filedesc_t, L"-t", UNARY_PRIMARY},
|
||||
{test_fileperm_r, L"-r", UNARY_PRIMARY},
|
||||
{test_fileperm_u, L"-u", UNARY_PRIMARY},
|
||||
{test_fileperm_w, L"-w", UNARY_PRIMARY},
|
||||
{test_fileperm_x, L"-x", UNARY_PRIMARY},
|
||||
{test_string_n, L"-n", UNARY_PRIMARY},
|
||||
{test_string_z, L"-z", UNARY_PRIMARY},
|
||||
{test_string_equal, L"=", BINARY_PRIMARY},
|
||||
{test_string_not_equal, L"!=", BINARY_PRIMARY},
|
||||
{test_number_equal, L"-eq", BINARY_PRIMARY},
|
||||
{test_number_not_equal, L"-ne", BINARY_PRIMARY},
|
||||
{test_number_greater, L"-gt", BINARY_PRIMARY},
|
||||
{test_number_greater_equal, L"-ge", BINARY_PRIMARY},
|
||||
{test_number_lesser, L"-lt", BINARY_PRIMARY},
|
||||
{test_number_lesser_equal, L"-le", BINARY_PRIMARY},
|
||||
{test_combine_and, L"-a", 0},
|
||||
{test_combine_or, L"-o", 0},
|
||||
{test_paren_open, L"(", 0},
|
||||
{test_paren_close, L")", 0}
|
||||
};
|
||||
|
||||
const token_info_t *token_for_string(const wcstring &str)
|
||||
{
|
||||
for (size_t i=0; i < sizeof token_infos / sizeof *token_infos; i++)
|
||||
{
|
||||
if (str == token_infos[i].string)
|
||||
{
|
||||
return &token_infos[i];
|
||||
}
|
||||
}
|
||||
return &token_infos[0]; //unknown
|
||||
}
|
||||
|
||||
|
||||
/* Grammar.
|
||||
|
||||
<expr> = <combining_expr>
|
||||
|
||||
<combining_expr> = <unary_expr> and/or <combining_expr> |
|
||||
<unary_expr>
|
||||
|
||||
<unary_expr> = bang <unary_expr> |
|
||||
<primary>
|
||||
|
||||
<primary> = <unary_primary> arg |
|
||||
arg <binary_primary> arg |
|
||||
'(' <expr> ')'
|
||||
|
||||
*/
|
||||
|
||||
class expression;
|
||||
class test_parser
|
||||
{
|
||||
private:
|
||||
wcstring_list_t strings;
|
||||
wcstring_list_t errors;
|
||||
|
||||
expression *error(const wchar_t *fmt, ...);
|
||||
void add_error(const wchar_t *fmt, ...);
|
||||
|
||||
const wcstring &arg(unsigned int idx)
|
||||
{
|
||||
return strings.at(idx);
|
||||
}
|
||||
|
||||
public:
|
||||
test_parser(const wcstring_list_t &val) : strings(val)
|
||||
{ }
|
||||
|
||||
expression *parse_expression(unsigned int start, unsigned int end);
|
||||
expression *parse_3_arg_expression(unsigned int start, unsigned int end);
|
||||
expression *parse_4_arg_expression(unsigned int start, unsigned int end);
|
||||
expression *parse_combining_expression(unsigned int start, unsigned int end);
|
||||
expression *parse_unary_expression(unsigned int start, unsigned int end);
|
||||
|
||||
expression *parse_primary(unsigned int start, unsigned int end);
|
||||
expression *parse_parenthentical(unsigned int start, unsigned int end);
|
||||
expression *parse_unary_primary(unsigned int start, unsigned int end);
|
||||
expression *parse_binary_primary(unsigned int start, unsigned int end);
|
||||
expression *parse_just_a_string(unsigned int start, unsigned int end);
|
||||
|
||||
static expression *parse_args(const wcstring_list_t &args, wcstring &err);
|
||||
};
|
||||
|
||||
struct range_t
|
||||
{
|
||||
unsigned int start;
|
||||
unsigned int end;
|
||||
|
||||
range_t(unsigned s, unsigned e) : start(s), end(e) { }
|
||||
};
|
||||
|
||||
|
||||
/* Base class for expressions */
|
||||
class expression
|
||||
{
|
||||
protected:
|
||||
expression(token_t what, range_t where) : token(what), range(where) { }
|
||||
|
||||
public:
|
||||
const token_t token;
|
||||
range_t range;
|
||||
|
||||
virtual ~expression() { }
|
||||
|
||||
// evaluate returns true if the expression is true (i.e. BUILTIN_TEST_SUCCESS)
|
||||
virtual bool evaluate(wcstring_list_t &errors) = 0;
|
||||
};
|
||||
|
||||
typedef std::auto_ptr<expression> expr_ref_t;
|
||||
|
||||
/* Single argument like -n foo or "just a string" */
|
||||
class unary_primary : public expression
|
||||
{
|
||||
public:
|
||||
wcstring arg;
|
||||
unary_primary(token_t tok, range_t where, const wcstring &what) : expression(tok, where), arg(what) { }
|
||||
bool evaluate(wcstring_list_t &errors);
|
||||
};
|
||||
|
||||
/* Two argument primary like foo != bar */
|
||||
class binary_primary : public expression
|
||||
{
|
||||
public:
|
||||
wcstring arg_left;
|
||||
wcstring arg_right;
|
||||
|
||||
binary_primary(token_t tok, range_t where, const wcstring &left, const wcstring &right) : expression(tok, where), arg_left(left), arg_right(right)
|
||||
{ }
|
||||
bool evaluate(wcstring_list_t &errors);
|
||||
};
|
||||
|
||||
/* Unary operator like bang */
|
||||
class unary_operator : public expression
|
||||
{
|
||||
public:
|
||||
expr_ref_t subject;
|
||||
unary_operator(token_t tok, range_t where, expr_ref_t &exp) : expression(tok, where), subject(exp) { }
|
||||
bool evaluate(wcstring_list_t &errors);
|
||||
};
|
||||
|
||||
/* Combining expression. Contains a list of AND or OR expressions. It takes more than two so that we don't have to worry about precedence in the parser. */
|
||||
class combining_expression : public expression
|
||||
{
|
||||
public:
|
||||
const std::vector<expression *> subjects;
|
||||
const std::vector<token_t> combiners;
|
||||
|
||||
combining_expression(token_t tok, range_t where, const std::vector<expression *> &exprs, const std::vector<token_t> &combs) : expression(tok, where), subjects(exprs), combiners(combs)
|
||||
{
|
||||
/* We should have one more subject than combiner */
|
||||
assert(subjects.size() == combiners.size() + 1);
|
||||
}
|
||||
|
||||
/* We are responsible for destroying our expressions */
|
||||
virtual ~combining_expression()
|
||||
{
|
||||
for (size_t i=0; i < subjects.size(); i++)
|
||||
{
|
||||
delete subjects[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool evaluate(wcstring_list_t &errors);
|
||||
};
|
||||
|
||||
/* Parenthetical expression */
|
||||
class parenthetical_expression : public expression
|
||||
{
|
||||
public:
|
||||
expr_ref_t contents;
|
||||
parenthetical_expression(token_t tok, range_t where, expr_ref_t &expr) : expression(tok, where), contents(expr) { }
|
||||
|
||||
virtual bool evaluate(wcstring_list_t &errors);
|
||||
};
|
||||
|
||||
void test_parser::add_error(const wchar_t *fmt, ...)
|
||||
{
|
||||
assert(fmt != NULL);
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
this->errors.push_back(vformat_string(fmt, va));
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
expression *test_parser::error(const wchar_t *fmt, ...)
|
||||
{
|
||||
assert(fmt != NULL);
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
this->errors.push_back(vformat_string(fmt, va));
|
||||
va_end(va);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
expression *test_parser::parse_unary_expression(unsigned int start, unsigned int end)
|
||||
{
|
||||
if (start >= end)
|
||||
{
|
||||
return error(L"Missing argument at index %u", start);
|
||||
}
|
||||
token_t tok = token_for_string(arg(start))->tok;
|
||||
if (tok == test_bang)
|
||||
{
|
||||
expr_ref_t subject(parse_unary_expression(start + 1, end));
|
||||
if (subject.get())
|
||||
{
|
||||
return new unary_operator(tok, range_t(start, subject->range.end), subject);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return parse_primary(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse a combining expression (AND, OR) */
|
||||
expression *test_parser::parse_combining_expression(unsigned int start, unsigned int end)
|
||||
{
|
||||
if (start >= end)
|
||||
return NULL;
|
||||
|
||||
std::vector<expression *> subjects;
|
||||
std::vector<token_t> combiners;
|
||||
unsigned int idx = start;
|
||||
bool first = true;
|
||||
|
||||
while (idx < end)
|
||||
{
|
||||
|
||||
if (! first)
|
||||
{
|
||||
/* This is not the first expression, so we expect a combiner. */
|
||||
token_t combiner = token_for_string(arg(idx))->tok;
|
||||
if (combiner != test_combine_and && combiner != test_combine_or)
|
||||
{
|
||||
/* Not a combiner, we're done */
|
||||
this->errors.insert(this->errors.begin(), format_string(L"Expected a combining operator like '-a' at index %u", idx));
|
||||
break;
|
||||
}
|
||||
combiners.push_back(combiner);
|
||||
idx++;
|
||||
}
|
||||
|
||||
/* Parse another expression */
|
||||
expression *expr = parse_unary_expression(idx, end);
|
||||
if (! expr)
|
||||
{
|
||||
add_error(L"Missing argument at index %u", idx);
|
||||
if (! first)
|
||||
{
|
||||
/* Clean up the dangling combiner, since it never got its right hand expression */
|
||||
combiners.pop_back();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Go to the end of this expression */
|
||||
idx = expr->range.end;
|
||||
subjects.push_back(expr);
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (! subjects.empty())
|
||||
{
|
||||
/* Our new expression takes ownership of all expressions we created. The token we pass is irrelevant. */
|
||||
return new combining_expression(test_combine_and, range_t(start, idx), subjects, combiners);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No subjects */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
expression *test_parser::parse_unary_primary(unsigned int start, unsigned int end)
|
||||
{
|
||||
/* We need two arguments */
|
||||
if (start >= end)
|
||||
{
|
||||
return error(L"Missing argument at index %u", start);
|
||||
}
|
||||
if (start + 1 >= end)
|
||||
{
|
||||
return error(L"Missing argument at index %u", start + 1);
|
||||
}
|
||||
|
||||
/* All our unary primaries are prefix, so the operator is at start. */
|
||||
const token_info_t *info = token_for_string(arg(start));
|
||||
if (!(info->flags & UNARY_PRIMARY))
|
||||
return NULL;
|
||||
|
||||
return new unary_primary(info->tok, range_t(start, start + 2), arg(start + 1));
|
||||
}
|
||||
|
||||
expression *test_parser::parse_just_a_string(unsigned int start, unsigned int end)
|
||||
{
|
||||
/* Handle a string as a unary primary that is not a token of any other type.
|
||||
e.g. 'test foo -a bar' should evaluate to true
|
||||
We handle this with a unary primary of test_string_n
|
||||
*/
|
||||
|
||||
/* We need one arguments */
|
||||
if (start >= end)
|
||||
{
|
||||
return error(L"Missing argument at index %u", start);
|
||||
}
|
||||
|
||||
const token_info_t *info = token_for_string(arg(start));
|
||||
if (info->tok != test_unknown)
|
||||
{
|
||||
return error(L"Unexpected argument type at index %u", start);
|
||||
}
|
||||
|
||||
/* This is hackish; a nicer way to implement this would be with a "just a string" expression type */
|
||||
return new unary_primary(test_string_n, range_t(start, start + 1), arg(start));
|
||||
}
|
||||
|
||||
#if 0
|
||||
expression *test_parser::parse_unary_primary(unsigned int start, unsigned int end)
|
||||
{
|
||||
/* We need either one or two arguments */
|
||||
if (start >= end)
|
||||
{
|
||||
return error(L"Missing argument at index %u", start);
|
||||
}
|
||||
|
||||
/* The index of the argument to the unary primary */
|
||||
unsigned int arg_idx;
|
||||
|
||||
/* All our unary primaries are prefix, so any operator is at start. But it also may just be a string, with no operator. */
|
||||
const token_info_t *info = token_for_string(arg(start));
|
||||
if (info->flags & UNARY_PRIMARY)
|
||||
{
|
||||
/* We have an operator. Skip the operator argument */
|
||||
arg_idx = start + 1;
|
||||
|
||||
/* We have some freedom here...do we allow other tokens for the argument to operate on?
|
||||
For example, should 'test -n =' work? I say yes. So no typechecking on the next token. */
|
||||
|
||||
}
|
||||
else if (info->tok == test_unknown)
|
||||
{
|
||||
/* "Just a string. */
|
||||
arg_idx = start;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Here we don't allow arbitrary tokens as "just a string." I.e. 'test = -a =' should have a parse error. We could relax this at some point. */
|
||||
return error(L"Parse error at argument index %u", start);
|
||||
}
|
||||
|
||||
/* Verify we have the argument we want, i.e. test -n should fail to parse */
|
||||
if (arg_idx >= end)
|
||||
{
|
||||
return error(L"Missing argument at index %u", arg_idx);
|
||||
}
|
||||
|
||||
return new unary_primary(info->tok, range_t(start, arg_idx + 1), arg(arg_idx));
|
||||
}
|
||||
#endif
|
||||
|
||||
expression *test_parser::parse_binary_primary(unsigned int start, unsigned int end)
|
||||
{
|
||||
/* We need three arguments */
|
||||
for (unsigned int idx = start; idx < start + 3; idx++)
|
||||
{
|
||||
if (idx >= end)
|
||||
{
|
||||
return error(L"Missing argument at index %u", idx);
|
||||
}
|
||||
}
|
||||
|
||||
/* All our binary primaries are infix, so the operator is at start + 1. */
|
||||
const token_info_t *info = token_for_string(arg(start + 1));
|
||||
if (!(info->flags & BINARY_PRIMARY))
|
||||
return NULL;
|
||||
|
||||
return new binary_primary(info->tok, range_t(start, start + 3), arg(start), arg(start + 2));
|
||||
}
|
||||
|
||||
expression *test_parser::parse_parenthentical(unsigned int start, unsigned int end)
|
||||
{
|
||||
/* We need at least three arguments: open paren, argument, close paren */
|
||||
if (start + 3 >= end)
|
||||
return NULL;
|
||||
|
||||
/* Must start with an open expression */
|
||||
const token_info_t *open_paren = token_for_string(arg(start));
|
||||
if (open_paren->tok != test_paren_open)
|
||||
return NULL;
|
||||
|
||||
/* Parse a subexpression */
|
||||
expression *subexr_ptr = parse_expression(start + 1, end);
|
||||
if (! subexr_ptr)
|
||||
return NULL;
|
||||
expr_ref_t subexpr(subexr_ptr);
|
||||
|
||||
/* Parse a close paren */
|
||||
unsigned close_index = subexpr->range.end;
|
||||
assert(close_index <= end);
|
||||
if (close_index == end)
|
||||
{
|
||||
return error(L"Missing close paren at index %u", close_index);
|
||||
}
|
||||
const token_info_t *close_paren = token_for_string(arg(close_index));
|
||||
if (close_paren->tok != test_paren_close)
|
||||
{
|
||||
return error(L"Expected close paren at index %u", close_index);
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return new parenthetical_expression(test_paren_open, range_t(start, close_index+1), subexpr);
|
||||
}
|
||||
|
||||
expression *test_parser::parse_primary(unsigned int start, unsigned int end)
|
||||
{
|
||||
if (start >= end)
|
||||
{
|
||||
return error(L"Missing argument at index %u", start);
|
||||
}
|
||||
|
||||
expression *expr = NULL;
|
||||
if (! expr) expr = parse_parenthentical(start, end);
|
||||
if (! expr) expr = parse_unary_primary(start, end);
|
||||
if (! expr) expr = parse_binary_primary(start, end);
|
||||
if (! expr) expr = parse_just_a_string(start, end);
|
||||
return expr;
|
||||
}
|
||||
|
||||
// See IEEE 1003.1 breakdown of the behavior for different parameter counts
|
||||
expression *test_parser::parse_3_arg_expression(unsigned int start, unsigned int end)
|
||||
{
|
||||
assert(end - start == 3);
|
||||
expression *result = NULL;
|
||||
|
||||
const token_info_t *center_token = token_for_string(arg(start + 1));
|
||||
if (center_token->flags & BINARY_PRIMARY)
|
||||
{
|
||||
result = parse_binary_primary(start, end);
|
||||
}
|
||||
else if (center_token->tok == test_combine_and || center_token->tok == test_combine_or)
|
||||
{
|
||||
expr_ref_t left(parse_unary_expression(start, start + 1));
|
||||
expr_ref_t right(parse_unary_expression(start + 2, start + 3));
|
||||
if (left.get() && right.get())
|
||||
{
|
||||
// Transfer ownership to the vector of subjects
|
||||
std::vector<token_t> combiners(1, center_token->tok);
|
||||
std::vector<expression *> subjects;
|
||||
subjects.push_back(left.release());
|
||||
subjects.push_back(right.release());
|
||||
result = new combining_expression(center_token->tok, range_t(start, end), subjects, combiners);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = parse_unary_expression(start, end);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expression *test_parser::parse_4_arg_expression(unsigned int start, unsigned int end)
|
||||
{
|
||||
assert(end - start == 4);
|
||||
expression *result = NULL;
|
||||
|
||||
token_t first_token = token_for_string(arg(start))->tok;
|
||||
if (first_token == test_bang)
|
||||
{
|
||||
expr_ref_t subject(parse_3_arg_expression(start + 1, end));
|
||||
if (subject.get())
|
||||
{
|
||||
result = new unary_operator(first_token, range_t(start, subject->range.end), subject);
|
||||
}
|
||||
}
|
||||
else if (first_token == test_paren_open)
|
||||
{
|
||||
result = parse_parenthentical(start, end);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = parse_combining_expression(start, end);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
expression *test_parser::parse_expression(unsigned int start, unsigned int end)
|
||||
{
|
||||
if (start >= end)
|
||||
{
|
||||
return error(L"Missing argument at index %u", start);
|
||||
}
|
||||
|
||||
unsigned int argc = end - start;
|
||||
switch (argc)
|
||||
{
|
||||
case 0:
|
||||
assert(0); //should have been caught by the above test
|
||||
return NULL;
|
||||
|
||||
case 1:
|
||||
{
|
||||
return error(L"Missing argument at index %u", start + 1);
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
return parse_unary_expression(start, end);
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
return parse_3_arg_expression(start, end);
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
return parse_4_arg_expression(start, end);
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return parse_combining_expression(start, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expression *test_parser::parse_args(const wcstring_list_t &args, wcstring &err)
|
||||
{
|
||||
/* Empty list and one-arg list should be handled by caller */
|
||||
assert(args.size() > 1);
|
||||
|
||||
test_parser parser(args);
|
||||
expression *result = parser.parse_expression(0, (unsigned int)args.size());
|
||||
|
||||
/* Handle errors */
|
||||
for (size_t i = 0; i < parser.errors.size(); i++)
|
||||
{
|
||||
err.append(L"test: ");
|
||||
err.append(parser.errors.at(i));
|
||||
err.push_back(L'\n');
|
||||
// For now we only show the first error
|
||||
break;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
/* It's also an error if there are any unused arguments. This is not detected by parse_expression() */
|
||||
assert(result->range.end <= args.size());
|
||||
if (result->range.end < args.size())
|
||||
{
|
||||
if (err.empty())
|
||||
{
|
||||
append_format(err, L"test: unexpected argument at index %lu: '%ls'\n", (unsigned long)result->range.end, args.at(result->range.end).c_str());
|
||||
}
|
||||
|
||||
delete result;
|
||||
result = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool unary_primary::evaluate(wcstring_list_t &errors)
|
||||
{
|
||||
return unary_primary_evaluate(token, arg, errors);
|
||||
}
|
||||
|
||||
bool binary_primary::evaluate(wcstring_list_t &errors)
|
||||
{
|
||||
return binary_primary_evaluate(token, arg_left, arg_right, errors);
|
||||
}
|
||||
|
||||
bool unary_operator::evaluate(wcstring_list_t &errors)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
case test_bang:
|
||||
assert(subject.get());
|
||||
return ! subject->evaluate(errors);
|
||||
default:
|
||||
errors.push_back(format_string(L"Unknown token type in %s", __func__));
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool combining_expression::evaluate(wcstring_list_t &errors)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
case test_combine_and:
|
||||
case test_combine_or:
|
||||
{
|
||||
/* One-element case */
|
||||
if (subjects.size() == 1)
|
||||
return subjects.at(0)->evaluate(errors);
|
||||
|
||||
/* Evaluate our lists, remembering that AND has higher precedence than OR. We can visualize this as a sequence of OR expressions of AND expressions. */
|
||||
assert(combiners.size() + 1 == subjects.size());
|
||||
assert(! subjects.empty());
|
||||
|
||||
size_t idx = 0, max = subjects.size();
|
||||
bool or_result = false;
|
||||
while (idx < max)
|
||||
{
|
||||
if (or_result)
|
||||
{
|
||||
/* Short circuit */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Evaluate a stream of AND starting at given subject index. It may only have one element. */
|
||||
bool and_result = true;
|
||||
for (; idx < max; idx++)
|
||||
{
|
||||
/* Evaluate it, short-circuiting */
|
||||
and_result = and_result && subjects.at(idx)->evaluate(errors);
|
||||
|
||||
/* If the combiner at this index (which corresponding to how we combine with the next subject) is not AND, then exit the loop */
|
||||
if (idx + 1 < max && combiners.at(idx) != test_combine_and)
|
||||
{
|
||||
idx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* OR it in */
|
||||
or_result = or_result || and_result;
|
||||
}
|
||||
return or_result;
|
||||
}
|
||||
|
||||
default:
|
||||
errors.push_back(format_string(L"Unknown token type in %s", __func__));
|
||||
return BUILTIN_TEST_FAIL;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool parenthetical_expression::evaluate(wcstring_list_t &errors)
|
||||
{
|
||||
return contents->evaluate(errors);
|
||||
}
|
||||
|
||||
/* IEEE 1003.1 says nothing about what it means for two strings to be "algebraically equal". For example, should we interpret 0x10 as 0, 10, or 16? Here we use only base 10 and use wcstoll, which allows for leading + and -, and leading whitespace. This matches bash. */
|
||||
static bool parse_number(const wcstring &arg, long long *out)
|
||||
{
|
||||
const wchar_t *str = arg.c_str();
|
||||
wchar_t *endptr = NULL;
|
||||
*out = wcstoll(str, &endptr, 10);
|
||||
return endptr && *endptr == L'\0';
|
||||
}
|
||||
|
||||
static bool binary_primary_evaluate(test_expressions::token_t token, const wcstring &left, const wcstring &right, wcstring_list_t &errors)
|
||||
{
|
||||
using namespace test_expressions;
|
||||
long long left_num, right_num;
|
||||
switch (token)
|
||||
{
|
||||
case test_string_equal:
|
||||
return left == right;
|
||||
|
||||
case test_string_not_equal:
|
||||
return left != right;
|
||||
|
||||
case test_number_equal:
|
||||
return parse_number(left, &left_num) && parse_number(right, &right_num) && left_num == right_num;
|
||||
|
||||
case test_number_not_equal:
|
||||
return parse_number(left, &left_num) && parse_number(right, &right_num) && left_num != right_num;
|
||||
|
||||
case test_number_greater:
|
||||
return parse_number(left, &left_num) && parse_number(right, &right_num) && left_num > right_num;
|
||||
|
||||
case test_number_greater_equal:
|
||||
return parse_number(left, &left_num) && parse_number(right, &right_num) && left_num >= right_num;
|
||||
|
||||
case test_number_lesser:
|
||||
return parse_number(left, &left_num) && parse_number(right, &right_num) && left_num < right_num;
|
||||
|
||||
case test_number_lesser_equal:
|
||||
return parse_number(left, &left_num) && parse_number(right, &right_num) && left_num <= right_num;
|
||||
|
||||
default:
|
||||
errors.push_back(format_string(L"Unknown token type in %s", __func__));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool unary_primary_evaluate(test_expressions::token_t token, const wcstring &arg, wcstring_list_t &errors)
|
||||
{
|
||||
using namespace test_expressions;
|
||||
struct stat buf;
|
||||
long long num;
|
||||
switch (token)
|
||||
{
|
||||
case test_filetype_b: // "-b", for block special files
|
||||
return !wstat(arg, &buf) && S_ISBLK(buf.st_mode);
|
||||
|
||||
case test_filetype_c: // "-c", for character special files
|
||||
return !wstat(arg, &buf) && S_ISCHR(buf.st_mode);
|
||||
|
||||
case test_filetype_d: // "-d", for directories
|
||||
return !wstat(arg, &buf) && S_ISDIR(buf.st_mode);
|
||||
|
||||
case test_filetype_e: // "-e", for files that exist
|
||||
return !wstat(arg, &buf);
|
||||
|
||||
case test_filetype_f: // "-f", for for regular files
|
||||
return !wstat(arg, &buf) && S_ISREG(buf.st_mode);
|
||||
|
||||
case test_filetype_G: // "-G", for check effective group id
|
||||
return !wstat(arg, &buf) && getegid() == buf.st_gid;
|
||||
|
||||
case test_filetype_g: // "-g", for set-group-id
|
||||
return !wstat(arg, &buf) && (S_ISGID & buf.st_mode);
|
||||
|
||||
case test_filetype_h: // "-h", for symbolic links
|
||||
case test_filetype_L: // "-L", same as -h
|
||||
return !lwstat(arg, &buf) && S_ISLNK(buf.st_mode);
|
||||
|
||||
case test_filetype_O: // "-O", for check effective user id
|
||||
return !wstat(arg, &buf) && geteuid() == buf.st_uid;
|
||||
|
||||
case test_filetype_p: // "-p", for FIFO
|
||||
return !wstat(arg, &buf) && S_ISFIFO(buf.st_mode);
|
||||
|
||||
case test_filetype_S: // "-S", socket
|
||||
return !wstat(arg, &buf) && S_ISSOCK(buf.st_mode);
|
||||
|
||||
case test_filesize_s: // "-s", size greater than zero
|
||||
return !wstat(arg, &buf) && buf.st_size > 0;
|
||||
|
||||
case test_filedesc_t: // "-t", whether the fd is associated with a terminal
|
||||
return parse_number(arg, &num) && num == (int)num && isatty((int)num);
|
||||
|
||||
case test_fileperm_r: // "-r", read permission
|
||||
return !waccess(arg, R_OK);
|
||||
|
||||
case test_fileperm_u: // "-u", whether file is setuid
|
||||
return !wstat(arg, &buf) && (S_ISUID & buf.st_mode);
|
||||
|
||||
case test_fileperm_w: // "-w", whether file write permission is allowed
|
||||
return !waccess(arg, W_OK);
|
||||
|
||||
case test_fileperm_x: // "-x", whether file execute/search is allowed
|
||||
return !waccess(arg, X_OK);
|
||||
|
||||
case test_string_n: // "-n", non-empty string
|
||||
return ! arg.empty();
|
||||
|
||||
case test_string_z: // "-z", true if length of string is 0
|
||||
return arg.empty();
|
||||
|
||||
default:
|
||||
errors.push_back(format_string(L"Unknown token type in %s", __func__));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Evaluate a conditional expression given the arguments.
|
||||
* If fromtest is set, the caller is the test or [ builtin;
|
||||
* with the pointer giving the name of the command.
|
||||
* for POSIX conformance this supports a more limited range
|
||||
* of functionality.
|
||||
*
|
||||
* Return status is the final shell status, i.e. 0 for true,
|
||||
* 1 for false and 2 for error.
|
||||
*/
|
||||
int builtin_test(parser_t &parser, wchar_t **argv)
|
||||
{
|
||||
using namespace test_expressions;
|
||||
|
||||
/* The first argument should be the name of the command ('test') */
|
||||
if (! argv[0])
|
||||
return BUILTIN_TEST_FAIL;
|
||||
|
||||
/* Whether we are invoked with bracket '[' or not */
|
||||
const bool is_bracket = ! wcscmp(argv[0], L"[");
|
||||
|
||||
size_t argc = 0;
|
||||
while (argv[argc + 1])
|
||||
argc++;
|
||||
|
||||
/* If we're bracket, the last argument ought to be ]; we ignore it. Note that argc is the number of arguments after the command name; thus argv[argc] is the last argument. */
|
||||
if (is_bracket)
|
||||
{
|
||||
if (! wcscmp(argv[argc], L"]"))
|
||||
{
|
||||
/* Ignore the closing bracketp */
|
||||
argc--;
|
||||
}
|
||||
else
|
||||
{
|
||||
builtin_show_error(L"[: the last argument must be ']'\n");
|
||||
return BUILTIN_TEST_FAIL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Collect the arguments into a list */
|
||||
const wcstring_list_t args(argv + 1, argv + 1 + argc);
|
||||
|
||||
switch (argc)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// Per 1003.1, exit false
|
||||
return BUILTIN_TEST_FAIL;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
// Per 1003.1, exit true if the arg is non-empty
|
||||
return args.at(0).empty() ? BUILTIN_TEST_FAIL : BUILTIN_TEST_SUCCESS;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Try parsing. If expr is not nil, we are responsible for deleting it.
|
||||
wcstring err;
|
||||
expression *expr = test_parser::parse_args(args, err);
|
||||
if (! expr)
|
||||
{
|
||||
#if 0
|
||||
printf("Oops! test was given args:\n");
|
||||
for (size_t i=0; i < argc; i++)
|
||||
{
|
||||
printf("\t%ls\n", args.at(i).c_str());
|
||||
}
|
||||
printf("and returned parse error: %ls\n", err.c_str());
|
||||
#endif
|
||||
builtin_show_error(err);
|
||||
return BUILTIN_TEST_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
wcstring_list_t eval_errors;
|
||||
bool result = expr->evaluate(eval_errors);
|
||||
if (! eval_errors.empty())
|
||||
{
|
||||
printf("test returned eval errors:\n");
|
||||
for (size_t i=0; i < eval_errors.size(); i++)
|
||||
{
|
||||
printf("\t%ls\n", eval_errors.at(i).c_str());
|
||||
}
|
||||
}
|
||||
delete expr;
|
||||
return result ? BUILTIN_TEST_SUCCESS : BUILTIN_TEST_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -1,512 +0,0 @@
|
||||
/** \file builtin_ulimit.c Functions defining the ulimit builtin
|
||||
|
||||
Functions used for implementing the ulimit builtin.
|
||||
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <wctype.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "fallback.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "builtin.h"
|
||||
#include "common.h"
|
||||
#include "wgetopt.h"
|
||||
|
||||
|
||||
/**
|
||||
Struct describing a resource limit
|
||||
*/
|
||||
struct resource_t
|
||||
{
|
||||
/**
|
||||
Resource id
|
||||
*/
|
||||
int resource;
|
||||
/**
|
||||
Description of resource
|
||||
*/
|
||||
const wchar_t *desc;
|
||||
/**
|
||||
Switch used on commandline to specify resource
|
||||
*/
|
||||
wchar_t switch_char;
|
||||
/**
|
||||
The implicit multiplier used when setting getting values
|
||||
*/
|
||||
int multiplier;
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
Array of resource_t structs, describing all known resource types.
|
||||
*/
|
||||
static const struct resource_t resource_arr[] =
|
||||
{
|
||||
{
|
||||
RLIMIT_CORE, L"Maximum size of core files created", L'c', 1024
|
||||
}
|
||||
,
|
||||
{
|
||||
RLIMIT_DATA, L"Maximum size of a process’s data segment", L'd', 1024
|
||||
}
|
||||
,
|
||||
{
|
||||
RLIMIT_FSIZE, L"Maximum size of files created by the shell", L'f', 1024
|
||||
}
|
||||
,
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
{
|
||||
RLIMIT_MEMLOCK, L"Maximum size that may be locked into memory", L'l', 1024
|
||||
}
|
||||
,
|
||||
#endif
|
||||
#ifdef RLIMIT_RSS
|
||||
{
|
||||
RLIMIT_RSS, L"Maximum resident set size", L'm', 1024
|
||||
}
|
||||
,
|
||||
#endif
|
||||
{
|
||||
RLIMIT_NOFILE, L"Maximum number of open file descriptors", L'n', 1
|
||||
}
|
||||
,
|
||||
{
|
||||
RLIMIT_STACK, L"Maximum stack size", L's', 1024
|
||||
}
|
||||
,
|
||||
{
|
||||
RLIMIT_CPU, L"Maximum amount of cpu time in seconds", L't', 1
|
||||
}
|
||||
,
|
||||
#ifdef RLIMIT_NPROC
|
||||
{
|
||||
RLIMIT_NPROC, L"Maximum number of processes available to a single user", L'u', 1
|
||||
}
|
||||
,
|
||||
#endif
|
||||
#ifdef RLIMIT_AS
|
||||
{
|
||||
RLIMIT_AS, L"Maximum amount of virtual memory available to the shell", L'v', 1024
|
||||
}
|
||||
,
|
||||
#endif
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
Get the implicit multiplication factor for the specified resource limit
|
||||
*/
|
||||
static int get_multiplier(int what)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; resource_arr[i].desc; i++)
|
||||
{
|
||||
if (resource_arr[i].resource == what)
|
||||
{
|
||||
return resource_arr[i].multiplier;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
Return the value for the specified resource limit. This function
|
||||
does _not_ multiply the limit value by the multiplier constant used
|
||||
by the commandline ulimit.
|
||||
*/
|
||||
static rlim_t get(int resource, int hard)
|
||||
{
|
||||
struct rlimit ls;
|
||||
|
||||
getrlimit(resource, &ls);
|
||||
|
||||
return hard ? ls.rlim_max:ls.rlim_cur;
|
||||
}
|
||||
|
||||
/**
|
||||
Print the value of the specified resource limit
|
||||
*/
|
||||
static void print(int resource, int hard)
|
||||
{
|
||||
rlim_t l = get(resource, hard);
|
||||
|
||||
if (l == RLIM_INFINITY)
|
||||
stdout_buffer.append(L"unlimited\n");
|
||||
else
|
||||
append_format(stdout_buffer, L"%d\n", l / get_multiplier(resource));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Print values of all resource limits
|
||||
*/
|
||||
static void print_all(int hard)
|
||||
{
|
||||
int i;
|
||||
int w=0;
|
||||
|
||||
for (i=0; resource_arr[i].desc; i++)
|
||||
{
|
||||
w=maxi(w, fish_wcswidth(resource_arr[i].desc));
|
||||
}
|
||||
|
||||
for (i=0; resource_arr[i].desc; i++)
|
||||
{
|
||||
struct rlimit ls;
|
||||
rlim_t l;
|
||||
getrlimit(resource_arr[i].resource, &ls);
|
||||
l = hard ? ls.rlim_max:ls.rlim_cur;
|
||||
|
||||
const wchar_t *unit = ((resource_arr[i].resource==RLIMIT_CPU)?L"(seconds, ":(get_multiplier(resource_arr[i].resource)==1?L"(":L"(kB, "));
|
||||
|
||||
append_format(stdout_buffer,
|
||||
L"%-*ls %10ls-%lc) ",
|
||||
w,
|
||||
resource_arr[i].desc,
|
||||
unit,
|
||||
resource_arr[i].switch_char);
|
||||
|
||||
if (l == RLIM_INFINITY)
|
||||
{
|
||||
stdout_buffer.append(L"unlimited\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
append_format(stdout_buffer, L"%d\n", l/get_multiplier(resource_arr[i].resource));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the description for the specified resource limit
|
||||
*/
|
||||
static const wchar_t *get_desc(int what)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; resource_arr[i].desc; i++)
|
||||
{
|
||||
if (resource_arr[i].resource == what)
|
||||
{
|
||||
return resource_arr[i].desc;
|
||||
}
|
||||
}
|
||||
return L"Not a resource";
|
||||
}
|
||||
|
||||
/**
|
||||
Set the new value of the specified resource limit. This function
|
||||
does _not_ multiply the limit value by the multiplier constant used
|
||||
by the commandline ulimit.
|
||||
*/
|
||||
static int set(int resource, int hard, int soft, rlim_t value)
|
||||
{
|
||||
struct rlimit ls;
|
||||
getrlimit(resource, &ls);
|
||||
|
||||
if (hard)
|
||||
{
|
||||
ls.rlim_max = value;
|
||||
}
|
||||
|
||||
if (soft)
|
||||
{
|
||||
ls.rlim_cur = value;
|
||||
|
||||
/*
|
||||
Do not attempt to set the soft limit higher than the hard limit
|
||||
*/
|
||||
if ((value == RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY) ||
|
||||
(value != RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY && value > ls.rlim_max))
|
||||
{
|
||||
ls.rlim_cur = ls.rlim_max;
|
||||
}
|
||||
}
|
||||
|
||||
if (setrlimit(resource, &ls))
|
||||
{
|
||||
if (errno == EPERM)
|
||||
append_format(stderr_buffer, L"ulimit: Permission denied when changing resource of type '%ls'\n", get_desc(resource));
|
||||
else
|
||||
builtin_wperror(L"ulimit");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
The ulimit builtin, used for setting resource limits. Defined in
|
||||
builtin_ulimit.c.
|
||||
*/
|
||||
static int builtin_ulimit(parser_t &parser, wchar_t ** argv)
|
||||
{
|
||||
int hard=0;
|
||||
int soft=0;
|
||||
|
||||
int what = RLIMIT_FSIZE;
|
||||
int report_all = 0;
|
||||
|
||||
int argc = builtin_count_args(argv);
|
||||
|
||||
woptind=0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
static const struct woption
|
||||
long_options[] =
|
||||
{
|
||||
{
|
||||
L"all", no_argument, 0, 'a'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"hard", no_argument, 0, 'H'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"soft", no_argument, 0, 'S'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"core-size", no_argument, 0, 'c'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"data-size", no_argument, 0, 'd'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"file-size", no_argument, 0, 'f'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"lock-size", no_argument, 0, 'l'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"resident-set-size", no_argument, 0, 'm'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"file-descriptor-count", no_argument, 0, 'n'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"stack-size", no_argument, 0, 's'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"cpu-time", no_argument, 0, 't'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"process-count", no_argument, 0, 'u'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"virtual-memory-size", no_argument, 0, 'v'
|
||||
}
|
||||
,
|
||||
{
|
||||
L"help", no_argument, 0, 'h'
|
||||
}
|
||||
,
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
int opt_index = 0;
|
||||
|
||||
int opt = wgetopt_long(argc,
|
||||
argv,
|
||||
L"aHScdflmnstuvh",
|
||||
long_options,
|
||||
&opt_index);
|
||||
if (opt == -1)
|
||||
break;
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case 0:
|
||||
if (long_options[opt_index].flag != 0)
|
||||
break;
|
||||
append_format(stderr_buffer,
|
||||
BUILTIN_ERR_UNKNOWN,
|
||||
argv[0],
|
||||
long_options[opt_index].name);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
|
||||
return 1;
|
||||
|
||||
case L'a':
|
||||
report_all=1;
|
||||
break;
|
||||
|
||||
case L'H':
|
||||
hard=1;
|
||||
break;
|
||||
|
||||
case L'S':
|
||||
soft=1;
|
||||
break;
|
||||
|
||||
case L'c':
|
||||
what=RLIMIT_CORE;
|
||||
break;
|
||||
|
||||
case L'd':
|
||||
what=RLIMIT_DATA;
|
||||
break;
|
||||
|
||||
case L'f':
|
||||
what=RLIMIT_FSIZE;
|
||||
break;
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
case L'l':
|
||||
what=RLIMIT_MEMLOCK;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef RLIMIT_RSS
|
||||
case L'm':
|
||||
what=RLIMIT_RSS;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case L'n':
|
||||
what=RLIMIT_NOFILE;
|
||||
break;
|
||||
|
||||
case L's':
|
||||
what=RLIMIT_STACK;
|
||||
break;
|
||||
|
||||
case L't':
|
||||
what=RLIMIT_CPU;
|
||||
break;
|
||||
|
||||
#ifdef RLIMIT_NPROC
|
||||
case L'u':
|
||||
what=RLIMIT_NPROC;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef RLIMIT_AS
|
||||
case L'v':
|
||||
what=RLIMIT_AS;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case L'h':
|
||||
builtin_print_help(parser, argv[0], stdout_buffer);
|
||||
return 0;
|
||||
|
||||
case L'?':
|
||||
builtin_unknown_option(parser, argv[0], argv[woptind-1]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (report_all)
|
||||
{
|
||||
if (argc - woptind == 0)
|
||||
{
|
||||
print_all(hard);
|
||||
}
|
||||
else
|
||||
{
|
||||
stderr_buffer.append(argv[0]);
|
||||
stderr_buffer.append(L": Too many arguments\n");
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (argc - woptind)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
/*
|
||||
Show current limit value
|
||||
*/
|
||||
print(what, hard);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1:
|
||||
{
|
||||
/*
|
||||
Change current limit value
|
||||
*/
|
||||
rlim_t new_limit;
|
||||
wchar_t *end;
|
||||
|
||||
/*
|
||||
Set both hard and soft limits if nothing else was specified
|
||||
*/
|
||||
if (!(hard+soft))
|
||||
{
|
||||
hard=soft=1;
|
||||
}
|
||||
|
||||
if (wcscasecmp(argv[woptind], L"unlimited")==0)
|
||||
{
|
||||
new_limit = RLIM_INFINITY;
|
||||
}
|
||||
else if (wcscasecmp(argv[woptind], L"hard")==0)
|
||||
{
|
||||
new_limit = get(what, 1);
|
||||
}
|
||||
else if (wcscasecmp(argv[woptind], L"soft")==0)
|
||||
{
|
||||
new_limit = get(what, soft);
|
||||
}
|
||||
else
|
||||
{
|
||||
errno=0;
|
||||
new_limit = wcstol(argv[woptind], &end, 10);
|
||||
if (errno || *end)
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
L"%ls: Invalid limit '%ls'\n",
|
||||
argv[0],
|
||||
argv[woptind]);
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
new_limit *= get_multiplier(what);
|
||||
}
|
||||
|
||||
return set(what, hard, soft, new_limit);
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
stderr_buffer.append(argv[0]);
|
||||
stderr_buffer.append(L": Too many arguments\n");
|
||||
builtin_print_help(parser, argv[0], stderr_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
371
color.cpp
371
color.cpp
@@ -1,371 +0,0 @@
|
||||
/** \file color.cpp Color class implementation
|
||||
*/
|
||||
|
||||
#include "color.h"
|
||||
#include "fallback.h"
|
||||
|
||||
bool rgb_color_t::try_parse_special(const wcstring &special)
|
||||
{
|
||||
memset(&data, 0, sizeof data);
|
||||
const wchar_t *name = special.c_str();
|
||||
if (! wcscasecmp(name, L"normal"))
|
||||
{
|
||||
this->type = type_normal;
|
||||
}
|
||||
else if (! wcscasecmp(name, L"reset"))
|
||||
{
|
||||
this->type = type_reset;
|
||||
}
|
||||
else if (! wcscasecmp(name, L"ignore"))
|
||||
{
|
||||
this->type = type_ignore;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->type = type_none;
|
||||
}
|
||||
return this->type != type_none;
|
||||
}
|
||||
|
||||
static int parse_hex_digit(wchar_t x)
|
||||
{
|
||||
switch (x)
|
||||
{
|
||||
case L'0':
|
||||
return 0x0;
|
||||
case L'1':
|
||||
return 0x1;
|
||||
case L'2':
|
||||
return 0x2;
|
||||
case L'3':
|
||||
return 0x3;
|
||||
case L'4':
|
||||
return 0x4;
|
||||
case L'5':
|
||||
return 0x5;
|
||||
case L'6':
|
||||
return 0x6;
|
||||
case L'7':
|
||||
return 0x7;
|
||||
case L'8':
|
||||
return 0x8;
|
||||
case L'9':
|
||||
return 0x9;
|
||||
case L'a':
|
||||
case L'A':
|
||||
return 0xA;
|
||||
case L'b':
|
||||
case L'B':
|
||||
return 0xB;
|
||||
case L'c':
|
||||
case L'C':
|
||||
return 0xC;
|
||||
case L'd':
|
||||
case L'D':
|
||||
return 0xD;
|
||||
case L'e':
|
||||
case L'E':
|
||||
return 0xE;
|
||||
case L'f':
|
||||
case L'F':
|
||||
return 0xF;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long squared_difference(long p1, long p2)
|
||||
{
|
||||
unsigned long diff = (unsigned long)labs(p1 - p2);
|
||||
return diff * diff;
|
||||
}
|
||||
|
||||
static unsigned char convert_color(const unsigned char rgb[3], const uint32_t *colors, size_t color_count)
|
||||
{
|
||||
long r = rgb[0], g = rgb[1], b = rgb[2];
|
||||
unsigned long best_distance = (unsigned long)(-1);
|
||||
unsigned char best_index = (unsigned char)(-1);
|
||||
for (unsigned char idx = 0; idx < color_count; idx++)
|
||||
{
|
||||
uint32_t color = colors[idx];
|
||||
long test_r = (color >> 16) & 0xFF, test_g = (color >> 8) & 0xFF, test_b = (color >> 0) & 0xFF;
|
||||
unsigned long distance = squared_difference(r, test_r) + squared_difference(g, test_g) + squared_difference(b, test_b);
|
||||
if (distance <= best_distance)
|
||||
{
|
||||
best_index = idx;
|
||||
best_distance = distance;
|
||||
}
|
||||
}
|
||||
return best_index;
|
||||
|
||||
}
|
||||
|
||||
bool rgb_color_t::try_parse_rgb(const wcstring &name)
|
||||
{
|
||||
memset(&data, 0, sizeof data);
|
||||
/* We support the following style of rgb formats (case insensitive):
|
||||
#FA3
|
||||
#F3A035
|
||||
FA3
|
||||
F3A035
|
||||
*/
|
||||
|
||||
size_t digit_idx = 0, len = name.size();
|
||||
|
||||
/* Skip any leading # */
|
||||
if (len > 0 && name.at(0) == L'#')
|
||||
digit_idx++;
|
||||
|
||||
bool success = false;
|
||||
size_t i;
|
||||
if (len - digit_idx == 3)
|
||||
{
|
||||
// type FA3
|
||||
for (i=0; i < 3; i++)
|
||||
{
|
||||
int val = parse_hex_digit(name.at(digit_idx++));
|
||||
if (val < 0) break;
|
||||
data.color.rgb[i] = val*16+val;
|
||||
}
|
||||
success = (i == 3);
|
||||
}
|
||||
else if (len - digit_idx == 6)
|
||||
{
|
||||
// type F3A035
|
||||
for (i=0; i < 3; i++)
|
||||
{
|
||||
int hi = parse_hex_digit(name.at(digit_idx++));
|
||||
int lo = parse_hex_digit(name.at(digit_idx++));
|
||||
if (lo < 0 || hi < 0) break;
|
||||
data.color.rgb[i] = hi*16+lo;
|
||||
}
|
||||
success = (i == 3);
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
this->type = type_rgb;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
struct named_color_t
|
||||
{
|
||||
const wchar_t * name;
|
||||
unsigned char idx;
|
||||
unsigned char rgb[3];
|
||||
};
|
||||
|
||||
static const named_color_t named_colors[11] =
|
||||
{
|
||||
{L"black", 0, {0, 0, 0}},
|
||||
{L"red", 1, {0xFF, 0, 0}},
|
||||
{L"green", 2, {0, 0xFF, 0}},
|
||||
{L"brown", 3, {0x72, 0x50, 0}},
|
||||
{L"yellow", 3, {0xFF, 0xFF, 0}},
|
||||
{L"blue", 4, {0, 0, 0xFF}},
|
||||
{L"magenta", 5, {0xFF, 0, 0xFF}},
|
||||
{L"purple", 5, {0xFF, 0, 0xFF}},
|
||||
{L"cyan", 6, {0, 0xFF, 0xFF}},
|
||||
{L"white", 7, {0xFF, 0xFF, 0xFF}},
|
||||
{L"normal", 8, {0xFF, 0xFF, 0XFF}}
|
||||
};
|
||||
|
||||
wcstring_list_t rgb_color_t::named_color_names(void)
|
||||
{
|
||||
size_t count = sizeof named_colors / sizeof *named_colors;
|
||||
wcstring_list_t result;
|
||||
result.reserve(count);
|
||||
for (size_t i=0; i < count; i++)
|
||||
{
|
||||
result.push_back(named_colors[i].name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool rgb_color_t::try_parse_named(const wcstring &str)
|
||||
{
|
||||
memset(&data, 0, sizeof data);
|
||||
size_t max = sizeof named_colors / sizeof *named_colors;
|
||||
for (size_t idx=0; idx < max; idx++)
|
||||
{
|
||||
if (0 == wcscasecmp(str.c_str(), named_colors[idx].name))
|
||||
{
|
||||
data.name_idx = named_colors[idx].idx;
|
||||
this->type = type_named;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const wchar_t *name_for_color_idx(unsigned char idx)
|
||||
{
|
||||
size_t max = sizeof named_colors / sizeof *named_colors;
|
||||
for (size_t i=0; i < max; i++)
|
||||
{
|
||||
if (named_colors[i].idx == idx)
|
||||
{
|
||||
return named_colors[i].name;
|
||||
}
|
||||
}
|
||||
return L"unknown";
|
||||
}
|
||||
|
||||
rgb_color_t::rgb_color_t(unsigned char t, unsigned char i) : type(t), flags(), data()
|
||||
{
|
||||
data.name_idx = i;
|
||||
}
|
||||
|
||||
rgb_color_t rgb_color_t::normal()
|
||||
{
|
||||
return rgb_color_t(type_normal);
|
||||
}
|
||||
rgb_color_t rgb_color_t::reset()
|
||||
{
|
||||
return rgb_color_t(type_reset);
|
||||
}
|
||||
rgb_color_t rgb_color_t::ignore()
|
||||
{
|
||||
return rgb_color_t(type_ignore);
|
||||
}
|
||||
rgb_color_t rgb_color_t::none()
|
||||
{
|
||||
return rgb_color_t(type_none);
|
||||
}
|
||||
rgb_color_t rgb_color_t::white()
|
||||
{
|
||||
return rgb_color_t(type_named, 7);
|
||||
}
|
||||
rgb_color_t rgb_color_t::black()
|
||||
{
|
||||
return rgb_color_t(type_named, 0);
|
||||
}
|
||||
|
||||
static unsigned char term8_color_for_rgb(const unsigned char rgb[3])
|
||||
{
|
||||
const uint32_t kColors[] =
|
||||
{
|
||||
0x000000, //Black
|
||||
0xFF0000, //Red
|
||||
0x00FF00, //Green
|
||||
0xFFFF00, //Yellow
|
||||
0x0000FF, //Blue
|
||||
0xFF00FF, //Magenta
|
||||
0x00FFFF, //Cyan
|
||||
0xFFFFFF, //White
|
||||
};
|
||||
return convert_color(rgb, kColors, sizeof kColors / sizeof *kColors);
|
||||
}
|
||||
|
||||
static unsigned char term256_color_for_rgb(const unsigned char rgb[3])
|
||||
{
|
||||
const uint32_t kColors[240] =
|
||||
{
|
||||
0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f,
|
||||
0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af,
|
||||
0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff,
|
||||
0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f,
|
||||
0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af,
|
||||
0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff,
|
||||
0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f,
|
||||
0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af,
|
||||
0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff,
|
||||
0x870000, 0x87005f, 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f,
|
||||
0x875f87, 0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, 0x878787, 0x8787af,
|
||||
0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff,
|
||||
0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f,
|
||||
0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af,
|
||||
0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff,
|
||||
0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f,
|
||||
0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, 0xafd787, 0xafd7af,
|
||||
0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff,
|
||||
0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f,
|
||||
0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af,
|
||||
0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff,
|
||||
0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f,
|
||||
0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af,
|
||||
0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff,
|
||||
0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f,
|
||||
0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, 0xffd700, 0xffd75f, 0xffd787, 0xffd7af,
|
||||
0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffd7, 0xffffff,
|
||||
0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e,
|
||||
0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e,
|
||||
0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee
|
||||
};
|
||||
return 16 + convert_color(rgb, kColors, sizeof kColors / sizeof *kColors);
|
||||
}
|
||||
|
||||
unsigned char rgb_color_t::to_term256_index() const
|
||||
{
|
||||
assert(type == type_rgb);
|
||||
return term256_color_for_rgb(data.color.rgb);
|
||||
}
|
||||
|
||||
color24_t rgb_color_t::to_color24() const
|
||||
{
|
||||
assert(type == type_rgb);
|
||||
return data.color;
|
||||
}
|
||||
|
||||
unsigned char rgb_color_t::to_name_index() const
|
||||
{
|
||||
assert(type == type_named || type == type_rgb);
|
||||
if (type == type_named)
|
||||
{
|
||||
return data.name_idx;
|
||||
}
|
||||
else if (type == type_rgb)
|
||||
{
|
||||
return term8_color_for_rgb(data.color.rgb);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is an error */
|
||||
return (unsigned char)(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void rgb_color_t::parse(const wcstring &str)
|
||||
{
|
||||
bool success = false;
|
||||
if (! success) success = try_parse_special(str);
|
||||
if (! success) success = try_parse_named(str);
|
||||
if (! success) success = try_parse_rgb(str);
|
||||
if (! success)
|
||||
{
|
||||
memset(&this->data, 0, sizeof this->data);
|
||||
this->type = type_none;
|
||||
}
|
||||
}
|
||||
|
||||
rgb_color_t::rgb_color_t(const wcstring &str)
|
||||
{
|
||||
this->parse(str);
|
||||
}
|
||||
|
||||
rgb_color_t::rgb_color_t(const std::string &str)
|
||||
{
|
||||
this->parse(str2wcstring(str));
|
||||
}
|
||||
|
||||
wcstring rgb_color_t::description() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case type_none:
|
||||
return L"none";
|
||||
case type_named:
|
||||
return format_string(L"named(%d: %ls)", (int)data.name_idx, name_for_color_idx(data.name_idx));
|
||||
case type_rgb:
|
||||
return format_string(L"rgb(0x%02x%02x%02x)", data.color.rgb[0], data.color.rgb[1], data.color.rgb[2]);
|
||||
case type_reset:
|
||||
return L"reset";
|
||||
case type_normal:
|
||||
return L"normal";
|
||||
case type_ignore:
|
||||
return L"ignore";
|
||||
default:
|
||||
abort();
|
||||
return L"";
|
||||
}
|
||||
}
|
||||
185
color.h
185
color.h
@@ -1,185 +0,0 @@
|
||||
/** \file color.h Color class.
|
||||
*/
|
||||
#ifndef FISH_COLOR_H
|
||||
#define FISH_COLOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstddef>
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
|
||||
/* 24 bit color */
|
||||
struct color24_t
|
||||
{
|
||||
unsigned char rgb[3];
|
||||
};
|
||||
|
||||
/* A type that represents a color. We work hard to keep it at a size of 4 bytes. */
|
||||
class rgb_color_t
|
||||
{
|
||||
|
||||
/* Types */
|
||||
enum
|
||||
{
|
||||
type_none,
|
||||
type_named,
|
||||
type_rgb,
|
||||
type_normal,
|
||||
type_reset,
|
||||
type_ignore
|
||||
};
|
||||
unsigned char type:4;
|
||||
|
||||
/* Flags */
|
||||
enum
|
||||
{
|
||||
flag_bold = 1 << 0,
|
||||
flag_underline = 1 << 1
|
||||
};
|
||||
unsigned char flags:4;
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char name_idx; //0-10
|
||||
color24_t color;
|
||||
} data;
|
||||
|
||||
/** Try parsing a special color name like "normal" */
|
||||
bool try_parse_special(const wcstring &str);
|
||||
|
||||
/** Try parsing an rgb color like "#F0A030" */
|
||||
bool try_parse_rgb(const wcstring &str);
|
||||
|
||||
/** Try parsing an explicit color name like "magenta" */
|
||||
bool try_parse_named(const wcstring &str);
|
||||
|
||||
/* Parsing entry point */
|
||||
void parse(const wcstring &str);
|
||||
|
||||
/** Private constructor */
|
||||
explicit rgb_color_t(unsigned char t, unsigned char i=0);
|
||||
|
||||
public:
|
||||
|
||||
/** Default constructor of type none */
|
||||
explicit rgb_color_t() : type(type_none), flags(), data() {}
|
||||
|
||||
/** Parse a color from a string */
|
||||
explicit rgb_color_t(const wcstring &str);
|
||||
explicit rgb_color_t(const std::string &str);
|
||||
|
||||
/** Returns white */
|
||||
static rgb_color_t white();
|
||||
|
||||
/** Returns black */
|
||||
static rgb_color_t black();
|
||||
|
||||
/** Returns the reset special color */
|
||||
static rgb_color_t reset();
|
||||
|
||||
/** Returns the normal special color */
|
||||
static rgb_color_t normal();
|
||||
|
||||
/** Returns the ignore special color */
|
||||
static rgb_color_t ignore();
|
||||
|
||||
/** Returns the none special color */
|
||||
static rgb_color_t none();
|
||||
|
||||
/** Returns whether the color is the ignore special color */
|
||||
bool is_ignore(void) const
|
||||
{
|
||||
return type == type_ignore;
|
||||
}
|
||||
|
||||
/** Returns whether the color is the normal special color */
|
||||
bool is_normal(void) const
|
||||
{
|
||||
return type == type_normal;
|
||||
}
|
||||
|
||||
/** Returns whether the color is the reset special color */
|
||||
bool is_reset(void) const
|
||||
{
|
||||
return type == type_reset;
|
||||
}
|
||||
|
||||
/** Returns whether the color is the none special color */
|
||||
bool is_none(void) const
|
||||
{
|
||||
return type == type_none;
|
||||
}
|
||||
|
||||
/** Returns whether the color is a named color (like "magenta") */
|
||||
bool is_named(void) const
|
||||
{
|
||||
return type == type_named;
|
||||
}
|
||||
|
||||
/** Returns whether the color is specified via RGB components */
|
||||
bool is_rgb(void) const
|
||||
{
|
||||
return type == type_rgb;
|
||||
}
|
||||
|
||||
/** Returns whether the color is special, that is, not rgb or named */
|
||||
bool is_special(void) const
|
||||
{
|
||||
return type != type_named && type != type_rgb;
|
||||
}
|
||||
|
||||
/** Returns a description of the color */
|
||||
wcstring description() const;
|
||||
|
||||
/** Returns the name index for the given color. Requires that the color be named or RGB. */
|
||||
unsigned char to_name_index() const;
|
||||
|
||||
/** Returns the term256 index for the given color. Requires that the color be RGB. */
|
||||
unsigned char to_term256_index() const;
|
||||
|
||||
/** Returns the 24 bit color for the given color. Requires that the color be RGB. */
|
||||
color24_t to_color24() const;
|
||||
|
||||
/** Returns whether the color is bold */
|
||||
bool is_bold() const
|
||||
{
|
||||
return !!(flags & flag_bold);
|
||||
}
|
||||
|
||||
/** Set whether the color is bold */
|
||||
void set_bold(bool x)
|
||||
{
|
||||
if (x) flags |= flag_bold;
|
||||
else flags &= ~flag_bold;
|
||||
}
|
||||
|
||||
/** Returns whether the color is underlined */
|
||||
bool is_underline() const
|
||||
{
|
||||
return !!(flags & flag_underline);
|
||||
}
|
||||
|
||||
/** Set whether the color is underlined */
|
||||
void set_underline(bool x)
|
||||
{
|
||||
if (x) flags |= flag_underline;
|
||||
else flags &= ~flag_underline;
|
||||
}
|
||||
|
||||
/** Compare two colors for equality */
|
||||
bool operator==(const rgb_color_t &other) const
|
||||
{
|
||||
return type == other.type && ! memcmp(&data, &other.data, sizeof data);
|
||||
}
|
||||
|
||||
/** Compare two colors for inequality */
|
||||
bool operator!=(const rgb_color_t &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
/** Returns the names of all named colors */
|
||||
static wcstring_list_t named_color_names(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
2418
common.cpp
2418
common.cpp
File diff suppressed because it is too large
Load Diff
924
common.h
924
common.h
@@ -1,924 +0,0 @@
|
||||
/** \file common.h
|
||||
Prototypes for various functions, mostly string utilities, that are used by most parts of fish.
|
||||
*/
|
||||
|
||||
#ifndef FISH_COMMON_H
|
||||
/**
|
||||
Header guard
|
||||
*/
|
||||
#define FISH_COMMON_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <termios.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include "util.h"
|
||||
|
||||
/**
|
||||
Avoid writing the type name twice in a common "static_cast-initialization".
|
||||
Caveat: This doesn't work with type names containing commas!
|
||||
*/
|
||||
#define CAST_INIT(type, dst, src) type dst = static_cast<type >(src)
|
||||
|
||||
class completion_t;
|
||||
|
||||
/* Common string type */
|
||||
typedef std::wstring wcstring;
|
||||
typedef std::vector<wcstring> wcstring_list_t;
|
||||
|
||||
/**
|
||||
Maximum number of bytes used by a single utf-8 character
|
||||
*/
|
||||
#define MAX_UTF8_BYTES 6
|
||||
|
||||
/**
|
||||
This is in the unicode private use area.
|
||||
*/
|
||||
#define ENCODE_DIRECT_BASE 0xf100
|
||||
|
||||
/**
|
||||
Highest legal ascii value
|
||||
*/
|
||||
#define ASCII_MAX 127u
|
||||
|
||||
/**
|
||||
Highest legal 16-bit unicode value
|
||||
*/
|
||||
#define UCS2_MAX 0xffffu
|
||||
|
||||
/**
|
||||
Highest legal byte value
|
||||
*/
|
||||
#define BYTE_MAX 0xffu
|
||||
|
||||
/** BOM value */
|
||||
#define UTF8_BOM_WCHAR 0xFEFFu
|
||||
|
||||
/* Flags for unescape_string functions */
|
||||
enum
|
||||
{
|
||||
/* Default behavior */
|
||||
UNESCAPE_DEFAULT = 0,
|
||||
|
||||
/* Escape special fish syntax characters like the semicolon */
|
||||
UNESCAPE_SPECIAL = 1 << 0,
|
||||
|
||||
/* Allow incomplete escape sequences */
|
||||
UNESCAPE_INCOMPLETE = 1 << 1
|
||||
};
|
||||
typedef unsigned int unescape_flags_t;
|
||||
|
||||
/* Flags for the escape() and escape_string() functions */
|
||||
enum
|
||||
{
|
||||
/** Escape all characters, including magic characters like the semicolon */
|
||||
ESCAPE_ALL = 1 << 0,
|
||||
|
||||
/** Do not try to use 'simplified' quoted escapes, and do not use empty quotes as the empty string */
|
||||
ESCAPE_NO_QUOTED = 1 << 1,
|
||||
|
||||
/** Do not escape tildes */
|
||||
ESCAPE_NO_TILDE = 1 << 2
|
||||
};
|
||||
typedef unsigned int escape_flags_t;
|
||||
|
||||
/* Directions */
|
||||
enum selection_direction_t
|
||||
{
|
||||
/* visual directions */
|
||||
direction_north,
|
||||
direction_east,
|
||||
direction_south,
|
||||
direction_west,
|
||||
direction_page_north,
|
||||
direction_page_south,
|
||||
|
||||
/* logical directions */
|
||||
direction_next,
|
||||
direction_prev,
|
||||
|
||||
/* special value that means deselect */
|
||||
direction_deselect
|
||||
};
|
||||
|
||||
inline bool selection_direction_is_cardinal(selection_direction_t dir)
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case direction_north:
|
||||
case direction_page_north:
|
||||
case direction_east:
|
||||
case direction_page_south:
|
||||
case direction_south:
|
||||
case direction_west:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Helper macro for errors
|
||||
*/
|
||||
#define VOMIT_ON_FAILURE(a) do { if (0 != (a)) { VOMIT_ABORT(errno, #a); } } while (0)
|
||||
#define VOMIT_ON_FAILURE_NO_ERRNO(a) do { int err = (a); if (0 != err) { VOMIT_ABORT(err, #a); } } while (0)
|
||||
#define VOMIT_ABORT(err, str) do { int code = (err); fprintf(stderr, "%s failed on line %d in file %s: %d (%s)\n", str, __LINE__, __FILE__, code, strerror(code)); abort(); } while(0)
|
||||
|
||||
/** Exits without invoking destructors (via _exit), useful for code after fork. */
|
||||
void exit_without_destructors(int code) __attribute__((noreturn));
|
||||
|
||||
/**
|
||||
Save the shell mode on startup so we can restore them on exit
|
||||
*/
|
||||
extern struct termios shell_modes;
|
||||
|
||||
/**
|
||||
The character to use where the text has been truncated. Is an
|
||||
ellipsis on unicode system and a $ on other systems.
|
||||
*/
|
||||
extern wchar_t ellipsis_char;
|
||||
|
||||
/* Character representing an omitted newline at the end of text */
|
||||
extern wchar_t omitted_newline_char;
|
||||
|
||||
/**
|
||||
The verbosity level of fish. If a call to debug has a severity
|
||||
level higher than \c debug_level, it will not be printed.
|
||||
*/
|
||||
extern int debug_level;
|
||||
|
||||
/**
|
||||
Profiling flag. True if commands should be profiled.
|
||||
*/
|
||||
extern bool g_profiling_active;
|
||||
|
||||
/**
|
||||
Name of the current program. Should be set at startup. Used by the
|
||||
debug function.
|
||||
*/
|
||||
extern const wchar_t *program_name;
|
||||
|
||||
/* Variants of read() and write() that ignores return values, defeating a warning */
|
||||
void read_ignore(int fd, void *buff, size_t count);
|
||||
void write_ignore(int fd, const void *buff, size_t count);
|
||||
|
||||
/**
|
||||
This macro is used to check that an input argument is not null. It
|
||||
is a bit lika a non-fatal form of assert. Instead of exit-ing on
|
||||
failure, the current function is ended at once. The second
|
||||
parameter is the return value of the current function on failure.
|
||||
*/
|
||||
#define CHECK( arg, retval ) \
|
||||
if (!(arg)) \
|
||||
{ \
|
||||
debug( 0, \
|
||||
"function %s called with null value for argument %s. ", \
|
||||
__func__, \
|
||||
#arg ); \
|
||||
bugreport(); \
|
||||
show_stackframe(); \
|
||||
return retval; \
|
||||
}
|
||||
|
||||
/**
|
||||
Pause for input, then exit the program. If supported, print a backtrace first.
|
||||
*/
|
||||
#define FATAL_EXIT() \
|
||||
{ \
|
||||
char exit_read_buff; \
|
||||
show_stackframe(); \
|
||||
read_ignore( 0, &exit_read_buff, 1 ); \
|
||||
exit_without_destructors( 1 ); \
|
||||
} \
|
||||
|
||||
|
||||
/**
|
||||
Exit program at once, leaving an error message about running out of memory.
|
||||
*/
|
||||
#define DIE_MEM() \
|
||||
{ \
|
||||
fwprintf( stderr, \
|
||||
L"fish: Out of memory on line %ld of file %s, shutting down fish\n", \
|
||||
(long)__LINE__, \
|
||||
__FILE__ ); \
|
||||
FATAL_EXIT(); \
|
||||
}
|
||||
|
||||
/**
|
||||
Check if signals are blocked. If so, print an error message and
|
||||
return from the function performing this check.
|
||||
*/
|
||||
#define CHECK_BLOCK(retval) \
|
||||
if (signal_is_blocked()) \
|
||||
{ \
|
||||
debug( 0, \
|
||||
"function %s called while blocking signals. ", \
|
||||
__func__); \
|
||||
bugreport(); \
|
||||
show_stackframe(); \
|
||||
return retval; \
|
||||
}
|
||||
|
||||
/**
|
||||
Shorthand for wgettext call
|
||||
*/
|
||||
#define _(wstr) wgettext(wstr)
|
||||
|
||||
/**
|
||||
Noop, used to tell xgettext that a string should be translated,
|
||||
even though it is not directly sent to wgettext.
|
||||
*/
|
||||
#define N_(wstr) wstr
|
||||
|
||||
/**
|
||||
Check if the specified string element is a part of the specified string list
|
||||
*/
|
||||
#define contains( str, ... ) contains_internal( str, 0, __VA_ARGS__, NULL )
|
||||
|
||||
/**
|
||||
Print a stack trace to stderr
|
||||
*/
|
||||
void show_stackframe();
|
||||
|
||||
|
||||
/**
|
||||
Read a line from the stream f into the string. Returns
|
||||
the number of bytes read or -1 on failure.
|
||||
|
||||
If the carriage return character is encountered, it is
|
||||
ignored. fgetws() considers the line to end if reading the file
|
||||
results in either a newline (L'\n') character, the null (L'\\0')
|
||||
character or the end of file (WEOF) character.
|
||||
*/
|
||||
int fgetws2(wcstring *s, FILE *f);
|
||||
|
||||
|
||||
/**
|
||||
Returns a wide character string equivalent of the
|
||||
specified multibyte character string
|
||||
|
||||
This function encodes illegal character sequences in a reversible
|
||||
way using the private use area.
|
||||
*/
|
||||
wcstring str2wcstring(const char *in);
|
||||
wcstring str2wcstring(const char *in, size_t len);
|
||||
wcstring str2wcstring(const std::string &in);
|
||||
|
||||
/**
|
||||
Returns a newly allocated multibyte character string equivalent of
|
||||
the specified wide character string
|
||||
|
||||
This function decodes illegal character sequences in a reversible
|
||||
way using the private use area.
|
||||
*/
|
||||
char *wcs2str(const wchar_t *in);
|
||||
char *wcs2str(const wcstring &in);
|
||||
std::string wcs2string(const wcstring &input);
|
||||
|
||||
/** Test if a string prefixes another. Returns true if a is a prefix of b */
|
||||
bool string_prefixes_string(const wcstring &proposed_prefix, const wcstring &value);
|
||||
bool string_prefixes_string(const wchar_t *proposed_prefix, const wcstring &value);
|
||||
|
||||
/** Test if a string is a suffix of another */
|
||||
bool string_suffixes_string(const wcstring &proposed_suffix, const wcstring &value);
|
||||
bool string_suffixes_string(const wchar_t *proposed_suffix, const wcstring &value);
|
||||
|
||||
/** Test if a string prefixes another without regard to case. Returns true if a is a prefix of b */
|
||||
bool string_prefixes_string_case_insensitive(const wcstring &proposed_prefix, const wcstring &value);
|
||||
|
||||
enum fuzzy_match_type_t
|
||||
{
|
||||
/* We match the string exactly: FOOBAR matches FOOBAR */
|
||||
fuzzy_match_exact = 0,
|
||||
|
||||
/* We match a prefix of the string: FO matches FOOBAR */
|
||||
fuzzy_match_prefix,
|
||||
|
||||
/* We match the string exactly, but in a case insensitive way: foobar matches FOOBAR */
|
||||
fuzzy_match_case_insensitive,
|
||||
|
||||
/* We match a prefix of the string, in a case insensitive way: foo matches FOOBAR */
|
||||
fuzzy_match_prefix_case_insensitive,
|
||||
|
||||
/* We match a substring of the string: OOBA matches FOOBAR */
|
||||
fuzzy_match_substring,
|
||||
|
||||
/* A subsequence match with insertions only: FBR matches FOOBAR */
|
||||
fuzzy_match_subsequence_insertions_only,
|
||||
|
||||
/* We don't match the string */
|
||||
fuzzy_match_none
|
||||
};
|
||||
|
||||
/* Indicates where a match type requires replacing the entire token */
|
||||
static inline bool match_type_requires_full_replacement(fuzzy_match_type_t t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case fuzzy_match_exact:
|
||||
case fuzzy_match_prefix:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Indicates where a match shares a prefix with the string it matches */
|
||||
static inline bool match_type_shares_prefix(fuzzy_match_type_t t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case fuzzy_match_exact:
|
||||
case fuzzy_match_prefix:
|
||||
case fuzzy_match_case_insensitive:
|
||||
case fuzzy_match_prefix_case_insensitive:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Test if string is a fuzzy match to another */
|
||||
struct string_fuzzy_match_t
|
||||
{
|
||||
enum fuzzy_match_type_t type;
|
||||
|
||||
/* Strength of the match. The value depends on the type. Lower is stronger. */
|
||||
size_t match_distance_first;
|
||||
size_t match_distance_second;
|
||||
|
||||
/* Constructor */
|
||||
string_fuzzy_match_t(enum fuzzy_match_type_t t, size_t distance_first = 0, size_t distance_second = 0);
|
||||
|
||||
/* Return -1, 0, 1 if this match is (respectively) better than, equal to, or worse than rhs */
|
||||
int compare(const string_fuzzy_match_t &rhs) const;
|
||||
};
|
||||
|
||||
/* Compute a fuzzy match for a string. If maximum_match is not fuzzy_match_none, limit the type to matches at or below that type. */
|
||||
string_fuzzy_match_t string_fuzzy_match_string(const wcstring &string, const wcstring &match_against, fuzzy_match_type_t limit_type = fuzzy_match_none);
|
||||
|
||||
|
||||
/** Test if a list contains a string using a linear search. */
|
||||
bool list_contains_string(const wcstring_list_t &list, const wcstring &str);
|
||||
|
||||
|
||||
void assert_is_main_thread(const char *who);
|
||||
#define ASSERT_IS_MAIN_THREAD_TRAMPOLINE(x) assert_is_main_thread(x)
|
||||
#define ASSERT_IS_MAIN_THREAD() ASSERT_IS_MAIN_THREAD_TRAMPOLINE(__FUNCTION__)
|
||||
|
||||
void assert_is_background_thread(const char *who);
|
||||
#define ASSERT_IS_BACKGROUND_THREAD_TRAMPOLINE(x) assert_is_background_thread(x)
|
||||
#define ASSERT_IS_BACKGROUND_THREAD() ASSERT_IS_BACKGROUND_THREAD_TRAMPOLINE(__FUNCTION__)
|
||||
|
||||
/* Useful macro for asserting that a lock is locked. This doesn't check whether this thread locked it, which it would be nice if it did, but here it is anyways. */
|
||||
void assert_is_locked(void *mutex, const char *who, const char *caller);
|
||||
#define ASSERT_IS_LOCKED(x) assert_is_locked((void *)(&x), #x, __FUNCTION__)
|
||||
|
||||
/** Format the specified size (in bytes, kilobytes, etc.) into the specified stringbuffer. */
|
||||
wcstring format_size(long long sz);
|
||||
|
||||
/** Version of format_size that does not allocate memory. */
|
||||
void format_size_safe(char buff[128], unsigned long long sz);
|
||||
|
||||
/** Our crappier versions of debug which is guaranteed to not allocate any memory, or do anything other than call write(). This is useful after a call to fork() with threads. */
|
||||
void debug_safe(int level, const char *msg, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL, const char *param5 = NULL, const char *param6 = NULL, const char *param7 = NULL, const char *param8 = NULL, const char *param9 = NULL, const char *param10 = NULL, const char *param11 = NULL, const char *param12 = NULL);
|
||||
|
||||
/** Writes out a long safely */
|
||||
void format_long_safe(char buff[64], long val);
|
||||
void format_long_safe(wchar_t buff[64], long val);
|
||||
|
||||
|
||||
template<typename T>
|
||||
T from_string(const wcstring &x)
|
||||
{
|
||||
T result;
|
||||
std::wstringstream stream(x);
|
||||
stream >> result;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T from_string(const std::string &x)
|
||||
{
|
||||
T result = T();
|
||||
std::stringstream stream(x);
|
||||
stream >> result;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
wcstring to_string(const T &x)
|
||||
{
|
||||
std::wstringstream stream;
|
||||
stream << x;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
/* wstringstream is a huge memory pig. Let's provide some specializations where we can. */
|
||||
template<>
|
||||
inline wcstring to_string(const long &x)
|
||||
{
|
||||
wchar_t buff[128];
|
||||
format_long_safe(buff, x);
|
||||
return wcstring(buff);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool from_string(const std::string &x)
|
||||
{
|
||||
return ! x.empty() && strchr("YTyt1", x.at(0));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool from_string(const wcstring &x)
|
||||
{
|
||||
return ! x.empty() && wcschr(L"YTyt1", x.at(0));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline wcstring to_string(const int &x)
|
||||
{
|
||||
return to_string(static_cast<long>(x));
|
||||
}
|
||||
|
||||
wchar_t **make_null_terminated_array(const wcstring_list_t &lst);
|
||||
char **make_null_terminated_array(const std::vector<std::string> &lst);
|
||||
|
||||
/* Helper class for managing a null-terminated array of null-terminated strings (of some char type) */
|
||||
template <typename CharType_t>
|
||||
class null_terminated_array_t
|
||||
{
|
||||
CharType_t **array;
|
||||
|
||||
/* No assignment or copying */
|
||||
void operator=(null_terminated_array_t rhs);
|
||||
null_terminated_array_t(const null_terminated_array_t &);
|
||||
|
||||
typedef std::vector<std::basic_string<CharType_t> > string_list_t;
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
size_t len = 0;
|
||||
if (array != NULL)
|
||||
{
|
||||
while (array[len] != NULL)
|
||||
{
|
||||
len++;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void free(void)
|
||||
{
|
||||
::free((void *)array);
|
||||
array = NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
null_terminated_array_t() : array(NULL) { }
|
||||
null_terminated_array_t(const string_list_t &argv) : array(make_null_terminated_array(argv))
|
||||
{
|
||||
}
|
||||
|
||||
~null_terminated_array_t()
|
||||
{
|
||||
this->free();
|
||||
}
|
||||
|
||||
void set(const string_list_t &argv)
|
||||
{
|
||||
this->free();
|
||||
this->array = make_null_terminated_array(argv);
|
||||
}
|
||||
|
||||
const CharType_t * const *get() const
|
||||
{
|
||||
return array;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
this->free();
|
||||
}
|
||||
};
|
||||
|
||||
/* Helper function to convert from a null_terminated_array_t<wchar_t> to a null_terminated_array_t<char_t> */
|
||||
void convert_wide_array_to_narrow(const null_terminated_array_t<wchar_t> &arr, null_terminated_array_t<char> *output);
|
||||
|
||||
/* Helper class to cache a narrow version of a wcstring in a malloc'd buffer, so that we can read it after fork() */
|
||||
class narrow_string_rep_t
|
||||
{
|
||||
private:
|
||||
const char *str;
|
||||
|
||||
/* No copying */
|
||||
narrow_string_rep_t &operator=(const narrow_string_rep_t &);
|
||||
narrow_string_rep_t(const narrow_string_rep_t &x);
|
||||
|
||||
public:
|
||||
~narrow_string_rep_t()
|
||||
{
|
||||
free((void *)str);
|
||||
}
|
||||
|
||||
narrow_string_rep_t() : str(NULL) {}
|
||||
|
||||
void set(const wcstring &s)
|
||||
{
|
||||
free((void *)str);
|
||||
str = wcs2str(s.c_str());
|
||||
}
|
||||
|
||||
const char *get() const
|
||||
{
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
bool is_forked_child();
|
||||
|
||||
|
||||
class mutex_lock_t
|
||||
{
|
||||
public:
|
||||
pthread_mutex_t mutex;
|
||||
mutex_lock_t()
|
||||
{
|
||||
VOMIT_ON_FAILURE_NO_ERRNO(pthread_mutex_init(&mutex, NULL));
|
||||
}
|
||||
|
||||
~mutex_lock_t()
|
||||
{
|
||||
VOMIT_ON_FAILURE_NO_ERRNO(pthread_mutex_destroy(&mutex));
|
||||
}
|
||||
};
|
||||
|
||||
/* Basic scoped lock class */
|
||||
class scoped_lock
|
||||
{
|
||||
pthread_mutex_t *lock_obj;
|
||||
bool locked;
|
||||
|
||||
/* No copying */
|
||||
scoped_lock &operator=(const scoped_lock &);
|
||||
scoped_lock(const scoped_lock &);
|
||||
|
||||
public:
|
||||
void lock(void);
|
||||
void unlock(void);
|
||||
scoped_lock(pthread_mutex_t &mutex);
|
||||
scoped_lock(mutex_lock_t &lock);
|
||||
~scoped_lock();
|
||||
};
|
||||
|
||||
class rwlock_t
|
||||
{
|
||||
public:
|
||||
pthread_rwlock_t rwlock;
|
||||
rwlock_t()
|
||||
{
|
||||
VOMIT_ON_FAILURE_NO_ERRNO(pthread_rwlock_init(&rwlock, NULL));
|
||||
}
|
||||
|
||||
~rwlock_t()
|
||||
{
|
||||
VOMIT_ON_FAILURE_NO_ERRNO(pthread_rwlock_destroy(&rwlock));
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Scoped lock class for rwlocks
|
||||
*/
|
||||
class scoped_rwlock
|
||||
{
|
||||
pthread_rwlock_t *rwlock_obj;
|
||||
bool locked;
|
||||
bool locked_shared;
|
||||
|
||||
/* No copying */
|
||||
scoped_rwlock &operator=(const scoped_lock &);
|
||||
scoped_rwlock(const scoped_lock &);
|
||||
|
||||
public:
|
||||
void lock(void);
|
||||
void unlock(void);
|
||||
void lock_shared(void);
|
||||
void unlock_shared(void);
|
||||
/*
|
||||
upgrade shared lock to exclusive.
|
||||
equivalent to `lock.unlock_shared(); lock.lock();`
|
||||
*/
|
||||
void upgrade(void);
|
||||
scoped_rwlock(pthread_rwlock_t &rwlock, bool shared = false);
|
||||
scoped_rwlock(rwlock_t &rwlock, bool shared = false);
|
||||
~scoped_rwlock();
|
||||
};
|
||||
|
||||
/**
|
||||
A scoped manager to save the current value of some variable, and optionally
|
||||
set it to a new value. On destruction it restores the variable to its old
|
||||
value.
|
||||
|
||||
This can be handy when there are multiple code paths to exit a block.
|
||||
*/
|
||||
template <typename T>
|
||||
class scoped_push
|
||||
{
|
||||
T * const ref;
|
||||
T saved_value;
|
||||
bool restored;
|
||||
|
||||
public:
|
||||
scoped_push(T *r): ref(r), saved_value(*r), restored(false)
|
||||
{
|
||||
}
|
||||
|
||||
scoped_push(T *r, const T &new_value) : ref(r), saved_value(*r), restored(false)
|
||||
{
|
||||
*r = new_value;
|
||||
}
|
||||
|
||||
~scoped_push()
|
||||
{
|
||||
restore();
|
||||
}
|
||||
|
||||
void restore()
|
||||
{
|
||||
if (!restored)
|
||||
{
|
||||
std::swap(*ref, saved_value);
|
||||
restored = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* Wrapper around wcstok */
|
||||
class wcstokenizer
|
||||
{
|
||||
wchar_t *buffer, *str, *state;
|
||||
const wcstring sep;
|
||||
|
||||
/* No copying */
|
||||
wcstokenizer &operator=(const wcstokenizer &);
|
||||
wcstokenizer(const wcstokenizer &);
|
||||
|
||||
public:
|
||||
wcstokenizer(const wcstring &s, const wcstring &separator);
|
||||
bool next(wcstring &result);
|
||||
~wcstokenizer();
|
||||
};
|
||||
|
||||
/**
|
||||
Appends a path component, with a / if necessary
|
||||
*/
|
||||
void append_path_component(wcstring &path, const wcstring &component);
|
||||
|
||||
wcstring format_string(const wchar_t *format, ...);
|
||||
wcstring vformat_string(const wchar_t *format, va_list va_orig);
|
||||
void append_format(wcstring &str, const wchar_t *format, ...);
|
||||
void append_formatv(wcstring &str, const wchar_t *format, va_list ap);
|
||||
|
||||
/**
|
||||
Test if the given string is a valid variable name.
|
||||
|
||||
\return null if this is a valid name, and a pointer to the first invalid character otherwise
|
||||
*/
|
||||
|
||||
const wchar_t *wcsvarname(const wchar_t *str);
|
||||
|
||||
|
||||
/**
|
||||
Test if the given string is a valid function name.
|
||||
|
||||
\return null if this is a valid name, and a pointer to the first invalid character otherwise
|
||||
*/
|
||||
|
||||
const wchar_t *wcsfuncname(const wchar_t *str);
|
||||
|
||||
/**
|
||||
Test if the given string is valid in a variable name
|
||||
|
||||
\return true if this is a valid name, false otherwise
|
||||
*/
|
||||
|
||||
bool wcsvarchr(wchar_t chr);
|
||||
|
||||
/**
|
||||
Convenience variants on fish_wcwswidth().
|
||||
|
||||
See fallback.h for the normal definitions.
|
||||
*/
|
||||
int fish_wcswidth(const wchar_t *str);
|
||||
int fish_wcswidth(const wcstring& str);
|
||||
|
||||
/**
|
||||
This functions returns the end of the quoted substring beginning at
|
||||
\c in. The type of quoting character is detemrined by examining \c
|
||||
in. Returns 0 on error.
|
||||
|
||||
\param in the position of the opening quote
|
||||
*/
|
||||
wchar_t *quote_end(const wchar_t *in);
|
||||
|
||||
/**
|
||||
A call to this function will reset the error counter. Some
|
||||
functions print out non-critical error messages. These should check
|
||||
the error_count before, and skip printing the message if
|
||||
MAX_ERROR_COUNT messages have been printed. The error_reset()
|
||||
should be called after each interactive command executes, to allow
|
||||
new messages to be printed.
|
||||
*/
|
||||
void error_reset();
|
||||
|
||||
/**
|
||||
This function behaves exactly like a wide character equivalent of
|
||||
the C function setlocale, except that it will also try to detect if
|
||||
the user is using a Unicode character set, and if so, use the
|
||||
unicode ellipsis character as ellipsis, instead of '$'.
|
||||
*/
|
||||
wcstring wsetlocale(int category, const wchar_t *locale);
|
||||
|
||||
/**
|
||||
Checks if \c needle is included in the list of strings specified. A warning is printed if needle is zero.
|
||||
|
||||
\param needle the string to search for in the list
|
||||
|
||||
\return zero if needle is not found, of if needle is null, non-zero otherwise
|
||||
*/
|
||||
__sentinel bool contains_internal(const wchar_t *needle, int vararg_handle, ...);
|
||||
__sentinel bool contains_internal(const wcstring &needle, int vararg_handle, ...);
|
||||
|
||||
/**
|
||||
Call read while blocking the SIGCHLD signal. Should only be called
|
||||
if you _know_ there is data available for reading, or the program
|
||||
will hang until there is data.
|
||||
*/
|
||||
long read_blocked(int fd, void *buf, size_t count);
|
||||
|
||||
/**
|
||||
Loop a write request while failure is non-critical. Return -1 and set errno
|
||||
in case of critical error.
|
||||
*/
|
||||
ssize_t write_loop(int fd, const char *buff, size_t count);
|
||||
|
||||
/**
|
||||
Loop a read request while failure is non-critical. Return -1 and set errno
|
||||
in case of critical error.
|
||||
*/
|
||||
ssize_t read_loop(int fd, void *buff, size_t count);
|
||||
|
||||
|
||||
/**
|
||||
Issue a debug message with printf-style string formating and
|
||||
automatic line breaking. The string will begin with the string \c
|
||||
program_name, followed by a colon and a whitespace.
|
||||
|
||||
Because debug is often called to tell the user about an error,
|
||||
before using wperror to give a specific error message, debug will
|
||||
never ever modify the value of errno.
|
||||
|
||||
\param level the priority of the message. Lower number means higher priority. Messages with a priority_number higher than \c debug_level will be ignored..
|
||||
\param msg the message format string.
|
||||
|
||||
Example:
|
||||
|
||||
<code>debug( 1, L"Pi = %.3f", M_PI );</code>
|
||||
|
||||
will print the string 'fish: Pi = 3.141', given that debug_level is 1 or higher, and that program_name is 'fish'.
|
||||
*/
|
||||
void debug(int level, const char *msg, ...);
|
||||
void debug(int level, const wchar_t *msg, ...);
|
||||
|
||||
/** Writes a string to stderr, followed by a newline */
|
||||
void print_stderr(const wcstring &str);
|
||||
|
||||
/**
|
||||
Replace special characters with backslash escape sequences. Newline is
|
||||
replaced with \n, etc.
|
||||
|
||||
\param in The string to be escaped
|
||||
\param flags Flags to control the escaping
|
||||
\return The escaped string
|
||||
*/
|
||||
|
||||
wcstring escape(const wchar_t *in, escape_flags_t flags);
|
||||
wcstring escape_string(const wcstring &in, escape_flags_t flags);
|
||||
|
||||
/**
|
||||
Expand backslashed escapes and substitute them with their unescaped
|
||||
counterparts. Also optionally change the wildcards, the tilde
|
||||
character and a few more into constants which are defined in a
|
||||
private use area of Unicode. This assumes wchar_t is a unicode
|
||||
character set.
|
||||
*/
|
||||
|
||||
/** Unescapes a string in-place. A true result indicates the string was unescaped, a false result indicates the string was unmodified. */
|
||||
bool unescape_string_in_place(wcstring *str, unescape_flags_t escape_special);
|
||||
|
||||
/** Unescapes a string, returning the unescaped value by reference. On failure, the output is set to an empty string. */
|
||||
bool unescape_string(const wchar_t *input, wcstring *output, unescape_flags_t escape_special);
|
||||
bool unescape_string(const wcstring &input, wcstring *output, unescape_flags_t escape_special);
|
||||
|
||||
|
||||
/**
|
||||
Returns the width of the terminal window, so that not all
|
||||
functions that use these values continually have to keep track of
|
||||
it separately.
|
||||
|
||||
Only works if common_handle_winch is registered to handle winch signals.
|
||||
*/
|
||||
int common_get_width();
|
||||
/**
|
||||
Returns the height of the terminal window, so that not all
|
||||
functions that use these values continually have to keep track of
|
||||
it separatly.
|
||||
|
||||
Only works if common_handle_winch is registered to handle winch signals.
|
||||
*/
|
||||
int common_get_height();
|
||||
|
||||
/**
|
||||
Handle a window change event by looking up the new window size and
|
||||
saving it in an internal variable used by common_get_wisth and
|
||||
common_get_height().
|
||||
*/
|
||||
void common_handle_winch(int signal);
|
||||
|
||||
/**
|
||||
Write paragraph of output to the specified stringbuffer, and redo
|
||||
the linebreaks to fit the current screen.
|
||||
*/
|
||||
void write_screen(const wcstring &msg, wcstring &buff);
|
||||
|
||||
/**
|
||||
Tokenize the specified string into the specified wcstring_list_t.
|
||||
\param val the input string. The contents of this string is not changed.
|
||||
\param out the list in which to place the elements.
|
||||
*/
|
||||
void tokenize_variable_array(const wcstring &val, wcstring_list_t &out);
|
||||
|
||||
/**
|
||||
Make sure the specified direcotry exists. If needed, try to create
|
||||
it and any currently not existing parent directories..
|
||||
|
||||
\return 0 if, at the time of function return the directory exists, -1 otherwise.
|
||||
*/
|
||||
int create_directory(const wcstring &d);
|
||||
|
||||
/**
|
||||
Print a short message about how to file a bug report to stderr
|
||||
*/
|
||||
void bugreport();
|
||||
|
||||
/**
|
||||
Return the number of seconds from the UNIX epoch, with subsecond
|
||||
precision. This function uses the gettimeofday function, and will
|
||||
have the same precision as that function.
|
||||
|
||||
If an error occurs, NAN is returned.
|
||||
*/
|
||||
double timef();
|
||||
|
||||
/**
|
||||
Call the following function early in main to set the main thread.
|
||||
This is our replacement for pthread_main_np().
|
||||
*/
|
||||
void set_main_thread();
|
||||
bool is_main_thread();
|
||||
|
||||
/** Configures thread assertions for testing */
|
||||
void configure_thread_assertions_for_testing();
|
||||
|
||||
/** Set up a guard to complain if we try to do certain things (like take a lock) after calling fork */
|
||||
void setup_fork_guards(void);
|
||||
|
||||
/** Save the value of tcgetpgrp so we can restore it on exit */
|
||||
void save_term_foreground_process_group(void);
|
||||
void restore_term_foreground_process_group(void);
|
||||
|
||||
/** Return whether we are the child of a fork */
|
||||
bool is_forked_child(void);
|
||||
void assert_is_not_forked_child(const char *who);
|
||||
#define ASSERT_IS_NOT_FORKED_CHILD_TRAMPOLINE(x) assert_is_not_forked_child(x)
|
||||
#define ASSERT_IS_NOT_FORKED_CHILD() ASSERT_IS_NOT_FORKED_CHILD_TRAMPOLINE(__FUNCTION__)
|
||||
|
||||
/** Macro to help suppress potentially unused variable warnings */
|
||||
#define USE(var) (void)(var)
|
||||
|
||||
extern "C" {
|
||||
__attribute__((noinline)) void debug_thread_error(void);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
2295
complete.cpp
2295
complete.cpp
File diff suppressed because it is too large
Load Diff
278
complete.h
278
complete.h
@@ -1,278 +0,0 @@
|
||||
/** \file complete.h
|
||||
Prototypes for functions related to tab-completion.
|
||||
|
||||
These functions are used for storing and retrieving tab-completion
|
||||
data, as well as for performing tab-completion.
|
||||
*/
|
||||
|
||||
#ifndef FISH_COMPLETE_H
|
||||
|
||||
/**
|
||||
Header guard
|
||||
*/
|
||||
#define FISH_COMPLETE_H
|
||||
|
||||
|
||||
#include <wchar.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "common.h"
|
||||
/**
|
||||
* Use all completions
|
||||
*/
|
||||
#define SHARED 0
|
||||
/**
|
||||
* Do not use file completion
|
||||
*/
|
||||
#define NO_FILES 1
|
||||
/**
|
||||
* Require a parameter after completion
|
||||
*/
|
||||
#define NO_COMMON 2
|
||||
/**
|
||||
* Only use the argument list specifies with completion after
|
||||
* option. This is the same as (NO_FILES | NO_COMMON)
|
||||
*/
|
||||
#define EXCLUSIVE 3
|
||||
|
||||
/**
|
||||
* Command is a path
|
||||
*/
|
||||
#define PATH 1
|
||||
/**
|
||||
* Command is not a path
|
||||
*/
|
||||
#define COMMAND 0
|
||||
|
||||
/**
|
||||
* Separator between completion and description
|
||||
*/
|
||||
#define COMPLETE_SEP L'\004'
|
||||
|
||||
/**
|
||||
* Separator between completion and description
|
||||
*/
|
||||
#define COMPLETE_SEP_STR L"\004"
|
||||
|
||||
/**
|
||||
* Character that separates the completion and description on
|
||||
* programmable completions
|
||||
*/
|
||||
#define PROG_COMPLETE_SEP L'\t'
|
||||
|
||||
enum
|
||||
{
|
||||
/**
|
||||
Do not insert space afterwards if this is the only completion. (The
|
||||
default is to try insert a space)
|
||||
*/
|
||||
COMPLETE_NO_SPACE = 1 << 0,
|
||||
|
||||
/** This is not the suffix of a token, but replaces it entirely */
|
||||
COMPLETE_REPLACES_TOKEN = 1 << 2,
|
||||
|
||||
/** This completion may or may not want a space at the end - guess by
|
||||
checking the last character of the completion. */
|
||||
COMPLETE_AUTO_SPACE = 1 << 3,
|
||||
|
||||
/** This completion should be inserted as-is, without escaping. */
|
||||
COMPLETE_DONT_ESCAPE = 1 << 4,
|
||||
|
||||
/** If you do escape, don't escape tildes */
|
||||
COMPLETE_DONT_ESCAPE_TILDES = 1 << 5
|
||||
};
|
||||
typedef int complete_flags_t;
|
||||
|
||||
|
||||
class completion_t
|
||||
{
|
||||
|
||||
private:
|
||||
/* No public default constructor */
|
||||
completion_t();
|
||||
public:
|
||||
|
||||
/* Destructor. Not inlining it saves code size. */
|
||||
~completion_t();
|
||||
|
||||
/** The completion string */
|
||||
wcstring completion;
|
||||
|
||||
/** The description for this completion */
|
||||
wcstring description;
|
||||
|
||||
/** The type of fuzzy match */
|
||||
string_fuzzy_match_t match;
|
||||
|
||||
/**
|
||||
Flags determining the completion behaviour.
|
||||
|
||||
Determines whether a space should be inserted after this
|
||||
completion if it is the only possible completion using the
|
||||
COMPLETE_NO_SPACE flag.
|
||||
|
||||
The COMPLETE_NO_CASE can be used to signal that this completion
|
||||
is case insensitive.
|
||||
*/
|
||||
complete_flags_t flags;
|
||||
|
||||
/* Construction. Note: defining these so that they are not inlined reduces the executable size. */
|
||||
completion_t(const wcstring &comp, const wcstring &desc = wcstring(), string_fuzzy_match_t match = string_fuzzy_match_t(fuzzy_match_exact), complete_flags_t flags_val = 0);
|
||||
completion_t(const completion_t &);
|
||||
completion_t &operator=(const completion_t &);
|
||||
|
||||
/* Compare two completions. No operating overlaoding to make this always explicit (there's potentially multiple ways to compare completions). */
|
||||
|
||||
/* "Naturally less than" means in a natural ordering, where digits are treated as numbers. For example, foo10 is naturally greater than foo2 (but alphabetically less than it) */
|
||||
static bool is_naturally_less_than(const completion_t &a, const completion_t &b);
|
||||
static bool is_alphabetically_equal_to(const completion_t &a, const completion_t &b);
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
COMPLETION_REQUEST_DEFAULT = 0,
|
||||
COMPLETION_REQUEST_AUTOSUGGESTION = 1 << 0, // indicates the completion is for an autosuggestion
|
||||
COMPLETION_REQUEST_DESCRIPTIONS = 1 << 1, // indicates that we want descriptions
|
||||
COMPLETION_REQUEST_FUZZY_MATCH = 1 << 2 // indicates that we don't require a prefix match
|
||||
};
|
||||
typedef uint32_t completion_request_flags_t;
|
||||
|
||||
/**
|
||||
|
||||
Add a completion.
|
||||
|
||||
All supplied values are copied, they should be freed by or otherwise
|
||||
disposed by the caller.
|
||||
|
||||
Examples:
|
||||
|
||||
The command 'gcc -o' requires that a file follows it, so the
|
||||
NO_COMMON option is suitable. This can be done using the following
|
||||
line:
|
||||
|
||||
complete -c gcc -s o -r
|
||||
|
||||
The command 'grep -d' required that one of the strings 'read',
|
||||
'skip' or 'recurse' is used. As such, it is suitable to specify that
|
||||
a completion requires one of them. This can be done using the
|
||||
following line:
|
||||
|
||||
complete -c grep -s d -x -a "read skip recurse"
|
||||
|
||||
|
||||
\param cmd Command to complete.
|
||||
\param cmd_type If cmd_type is PATH, cmd will be interpreted as the absolute
|
||||
path of the program (optionally containing wildcards), otherwise it
|
||||
will be interpreted as the command name.
|
||||
\param short_opt The single character name of an option. (-a is a short option,
|
||||
--all and -funroll are long options)
|
||||
\param long_opt The multi character name of an option. (-a is a short option,
|
||||
--all and -funroll are long options)
|
||||
\param long_mode Whether to use old style, single dash long options.
|
||||
\param result_mode Whether to search further completions when this
|
||||
completion has been succesfully matched. If result_mode is SHARED,
|
||||
any other completions may also be used. If result_mode is NO_FILES,
|
||||
file completion should not be used, but other completions may be
|
||||
used. If result_mode is NO_COMMON, on option may follow it - only a
|
||||
parameter. If result_mode is EXCLUSIVE, no option may follow it, and
|
||||
file completion is not performed.
|
||||
\param comp A space separated list of completions which may contain subshells.
|
||||
\param desc A description of the completion.
|
||||
\param condition a command to be run to check it this completion should be used.
|
||||
If \c condition is empty, the completion is always used.
|
||||
\param flags A set of completion flags
|
||||
*/
|
||||
void complete_add(const wchar_t *cmd,
|
||||
bool cmd_is_path,
|
||||
wchar_t short_opt,
|
||||
const wchar_t *long_opt,
|
||||
int long_mode,
|
||||
int result_mode,
|
||||
const wchar_t *condition,
|
||||
const wchar_t *comp,
|
||||
const wchar_t *desc,
|
||||
int flags);
|
||||
/**
|
||||
Sets whether the completion list for this command is complete. If
|
||||
true, any options not matching one of the provided options will be
|
||||
flagged as an error by syntax highlighting.
|
||||
*/
|
||||
void complete_set_authoritative(const wchar_t *cmd, bool cmd_type, bool authoritative);
|
||||
|
||||
/**
|
||||
Remove a previously defined completion
|
||||
*/
|
||||
void complete_remove(const wchar_t *cmd,
|
||||
bool cmd_is_path,
|
||||
wchar_t short_opt,
|
||||
const wchar_t *long_opt,
|
||||
int long_mode);
|
||||
|
||||
|
||||
/** Find all completions of the command cmd, insert them into out.
|
||||
*/
|
||||
void complete(const wcstring &cmd,
|
||||
std::vector<completion_t> &comp,
|
||||
completion_request_flags_t flags);
|
||||
|
||||
/**
|
||||
Print a list of all current completions into the string.
|
||||
|
||||
\param out The string to write completions to
|
||||
*/
|
||||
void complete_print(wcstring &out);
|
||||
|
||||
/**
|
||||
Tests if the specified option is defined for the specified command
|
||||
*/
|
||||
int complete_is_valid_option(const wcstring &str,
|
||||
const wcstring &opt,
|
||||
wcstring_list_t *inErrorsOrNull,
|
||||
bool allow_autoload);
|
||||
|
||||
/**
|
||||
Tests if the specified argument is valid for the specified option
|
||||
and command
|
||||
*/
|
||||
bool complete_is_valid_argument(const wcstring &str,
|
||||
const wcstring &opt,
|
||||
const wcstring &arg);
|
||||
|
||||
|
||||
/**
|
||||
Load command-specific completions for the specified command. This
|
||||
is done automatically whenever completing any given command, so
|
||||
there is no need to call this except in the case of completions
|
||||
with internal dependencies.
|
||||
|
||||
\param cmd the command for which to load command-specific completions
|
||||
\param reload should the commands completions be reloaded, even if they where
|
||||
previously loaded. (This is set to true on actual completions, so that
|
||||
changed completion are updated in running shells)
|
||||
*/
|
||||
void complete_load(const wcstring &cmd, bool reload);
|
||||
|
||||
/**
|
||||
Create a new completion entry
|
||||
|
||||
\param completions The array of completions to append to
|
||||
\param comp The completion string
|
||||
\param desc The description of the completion
|
||||
\param flags completion flags
|
||||
|
||||
*/
|
||||
void append_completion(std::vector<completion_t> &completions, const wcstring &comp, const wcstring &desc = wcstring(), int flags = 0, string_fuzzy_match_t match = string_fuzzy_match_t(fuzzy_match_exact));
|
||||
|
||||
/* Function used for testing */
|
||||
void complete_set_variable_names(const wcstring_list_t *names);
|
||||
|
||||
/* Support for "wrap targets." A wrap target is a command that completes liek another command. The target chain is the sequence of wraps (A wraps B wraps C...). Any loops in the chain are silently ignored. */
|
||||
bool complete_add_wrapper(const wcstring &command, const wcstring &wrap_target);
|
||||
bool complete_remove_wrapper(const wcstring &command, const wcstring &wrap_target);
|
||||
wcstring_list_t complete_get_wrap_chain(const wcstring &command);
|
||||
|
||||
/* Wonky interface: returns all wraps. Even-values are the commands, odd values are the targets. */
|
||||
wcstring_list_t complete_get_wrap_pairs();
|
||||
|
||||
#endif
|
||||
376
config.guess
vendored
376
config.guess
vendored
@@ -1,14 +1,12 @@
|
||||
#! /bin/sh
|
||||
# Attempt to guess a canonical system name.
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
# 2011, 2012 Free Software Foundation, Inc.
|
||||
# Copyright 1992-2015 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2012-02-10'
|
||||
timestamp='2015-03-04'
|
||||
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
@@ -22,19 +20,17 @@ timestamp='2012-02-10'
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
|
||||
# Originally written by Per Bothner. Please send patches (context
|
||||
# diff format) to <config-patches@gnu.org> and include a ChangeLog
|
||||
# entry.
|
||||
# the same distribution terms that you use for the rest of that
|
||||
# program. This Exception is an additional permission under section 7
|
||||
# of the GNU General Public License, version 3 ("GPLv3").
|
||||
#
|
||||
# This script attempts to guess a canonical system name similar to
|
||||
# config.sub. If it succeeds, it prints the system name on stdout, and
|
||||
# exits with 0. Otherwise, it exits with 1.
|
||||
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
|
||||
#
|
||||
# You can get the latest version of this script from:
|
||||
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
|
||||
#
|
||||
# Please send patches to <config-patches@gnu.org>.
|
||||
|
||||
|
||||
me=`echo "$0" | sed -e 's,.*/,,'`
|
||||
|
||||
@@ -54,9 +50,7 @@ version="\
|
||||
GNU config.guess ($timestamp)
|
||||
|
||||
Originally written by Per Bothner.
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
|
||||
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1992-2015 Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
@@ -138,6 +132,27 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
|
||||
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
|
||||
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
|
||||
|
||||
case "${UNAME_SYSTEM}" in
|
||||
Linux|GNU|GNU/*)
|
||||
# If the system lacks a compiler, then just pick glibc.
|
||||
# We could probably try harder.
|
||||
LIBC=gnu
|
||||
|
||||
eval $set_cc_for_build
|
||||
cat <<-EOF > $dummy.c
|
||||
#include <features.h>
|
||||
#if defined(__UCLIBC__)
|
||||
LIBC=uclibc
|
||||
#elif defined(__dietlibc__)
|
||||
LIBC=dietlibc
|
||||
#else
|
||||
LIBC=gnu
|
||||
#endif
|
||||
EOF
|
||||
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
|
||||
;;
|
||||
esac
|
||||
|
||||
# Note: order is significant - the case branches are not exclusive.
|
||||
|
||||
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
@@ -153,20 +168,27 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
# Note: NetBSD doesn't particularly care about the vendor
|
||||
# portion of the name. We always set it to "unknown".
|
||||
sysctl="sysctl -n hw.machine_arch"
|
||||
UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
|
||||
/usr/sbin/$sysctl 2>/dev/null || echo unknown)`
|
||||
UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
|
||||
/sbin/$sysctl 2>/dev/null || \
|
||||
/usr/sbin/$sysctl 2>/dev/null || \
|
||||
echo unknown)`
|
||||
case "${UNAME_MACHINE_ARCH}" in
|
||||
armeb) machine=armeb-unknown ;;
|
||||
arm*) machine=arm-unknown ;;
|
||||
sh3el) machine=shl-unknown ;;
|
||||
sh3eb) machine=sh-unknown ;;
|
||||
sh5el) machine=sh5le-unknown ;;
|
||||
earmv*)
|
||||
arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
|
||||
endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
|
||||
machine=${arch}${endian}-unknown
|
||||
;;
|
||||
*) machine=${UNAME_MACHINE_ARCH}-unknown ;;
|
||||
esac
|
||||
# The Operating System including object format, if it has switched
|
||||
# to ELF recently, or will in the future.
|
||||
case "${UNAME_MACHINE_ARCH}" in
|
||||
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
|
||||
arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
|
||||
eval $set_cc_for_build
|
||||
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
|
||||
| grep -q __ELF__
|
||||
@@ -182,6 +204,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
os=netbsd
|
||||
;;
|
||||
esac
|
||||
# Determine ABI tags.
|
||||
case "${UNAME_MACHINE_ARCH}" in
|
||||
earm*)
|
||||
expr='s/^earmv[0-9]/-eabi/;s/eb$//'
|
||||
abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
|
||||
;;
|
||||
esac
|
||||
# The OS release
|
||||
# Debian GNU/NetBSD machines have a different userland, and
|
||||
# thus, need a distinct triplet. However, they do not need
|
||||
@@ -198,7 +227,11 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
|
||||
# contains redundant information, the shorter form:
|
||||
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
|
||||
echo "${machine}-${os}${release}"
|
||||
echo "${machine}-${os}${release}${abi}"
|
||||
exit ;;
|
||||
*:Bitrig:*:*)
|
||||
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
|
||||
echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:OpenBSD:*:*)
|
||||
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
|
||||
@@ -302,7 +335,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
|
||||
echo arm-acorn-riscix${UNAME_RELEASE}
|
||||
exit ;;
|
||||
arm:riscos:*:*|arm:RISCOS:*:*)
|
||||
arm*:riscos:*:*|arm*:RISCOS:*:*)
|
||||
echo arm-unknown-riscos
|
||||
exit ;;
|
||||
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
|
||||
@@ -560,8 +593,9 @@ EOF
|
||||
else
|
||||
IBM_ARCH=powerpc
|
||||
fi
|
||||
if [ -x /usr/bin/oslevel ] ; then
|
||||
IBM_REV=`/usr/bin/oslevel`
|
||||
if [ -x /usr/bin/lslpp ] ; then
|
||||
IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
|
||||
awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
|
||||
else
|
||||
IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
|
||||
fi
|
||||
@@ -801,10 +835,13 @@ EOF
|
||||
i*:CYGWIN*:*)
|
||||
echo ${UNAME_MACHINE}-pc-cygwin
|
||||
exit ;;
|
||||
*:MINGW64*:*)
|
||||
echo ${UNAME_MACHINE}-pc-mingw64
|
||||
exit ;;
|
||||
*:MINGW*:*)
|
||||
echo ${UNAME_MACHINE}-pc-mingw32
|
||||
exit ;;
|
||||
i*:MSYS*:*)
|
||||
*:MSYS*:*)
|
||||
echo ${UNAME_MACHINE}-pc-msys
|
||||
exit ;;
|
||||
i*:windows32*:*)
|
||||
@@ -852,21 +889,21 @@ EOF
|
||||
exit ;;
|
||||
*:GNU:*:*)
|
||||
# the GNU system
|
||||
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
|
||||
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
|
||||
exit ;;
|
||||
*:GNU/*:*:*)
|
||||
# other systems with GNU libc and userland
|
||||
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
|
||||
exit ;;
|
||||
i*86:Minix:*:*)
|
||||
echo ${UNAME_MACHINE}-pc-minix
|
||||
exit ;;
|
||||
aarch64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
aarch64_be:Linux:*:*)
|
||||
UNAME_MACHINE=aarch64_be
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
alpha:Linux:*:*)
|
||||
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
|
||||
@@ -879,59 +916,57 @@ EOF
|
||||
EV68*) UNAME_MACHINE=alphaev68 ;;
|
||||
esac
|
||||
objdump --private-headers /bin/sh | grep -q ld.so.1
|
||||
if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
|
||||
if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
arc:Linux:*:* | arceb:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
arm*:Linux:*:*)
|
||||
eval $set_cc_for_build
|
||||
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
|
||||
| grep -q __ARM_EABI__
|
||||
then
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
else
|
||||
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
|
||||
| grep -q __ARM_PCS_VFP
|
||||
then
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnueabi
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
|
||||
else
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
|
||||
fi
|
||||
fi
|
||||
exit ;;
|
||||
avr32*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
cris:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-axis-linux-gnu
|
||||
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
|
||||
exit ;;
|
||||
crisv32:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-axis-linux-gnu
|
||||
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
|
||||
exit ;;
|
||||
e2k:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
frv:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
hexagon:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
i*86:Linux:*:*)
|
||||
LIBC=gnu
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
#ifdef __dietlibc__
|
||||
LIBC=dietlibc
|
||||
#endif
|
||||
EOF
|
||||
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
|
||||
echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
|
||||
echo ${UNAME_MACHINE}-pc-linux-${LIBC}
|
||||
exit ;;
|
||||
ia64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
m32r*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
m68*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
mips:Linux:*:* | mips64:Linux:*:*)
|
||||
eval $set_cc_for_build
|
||||
@@ -950,54 +985,63 @@ EOF
|
||||
#endif
|
||||
EOF
|
||||
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
|
||||
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
|
||||
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
|
||||
;;
|
||||
or32:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
openrisc*:Linux:*:*)
|
||||
echo or1k-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
or32:Linux:*:* | or1k*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
padre:Linux:*:*)
|
||||
echo sparc-unknown-linux-gnu
|
||||
echo sparc-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
parisc64:Linux:*:* | hppa64:Linux:*:*)
|
||||
echo hppa64-unknown-linux-gnu
|
||||
echo hppa64-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
parisc:Linux:*:* | hppa:Linux:*:*)
|
||||
# Look for CPU level
|
||||
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
|
||||
PA7*) echo hppa1.1-unknown-linux-gnu ;;
|
||||
PA8*) echo hppa2.0-unknown-linux-gnu ;;
|
||||
*) echo hppa-unknown-linux-gnu ;;
|
||||
PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
|
||||
PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
|
||||
*) echo hppa-unknown-linux-${LIBC} ;;
|
||||
esac
|
||||
exit ;;
|
||||
ppc64:Linux:*:*)
|
||||
echo powerpc64-unknown-linux-gnu
|
||||
echo powerpc64-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
ppc:Linux:*:*)
|
||||
echo powerpc-unknown-linux-gnu
|
||||
echo powerpc-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
ppc64le:Linux:*:*)
|
||||
echo powerpc64le-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
ppcle:Linux:*:*)
|
||||
echo powerpcle-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
s390:Linux:*:* | s390x:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-ibm-linux
|
||||
echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
|
||||
exit ;;
|
||||
sh64*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
sh*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
sparc:Linux:*:* | sparc64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
tile*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
vax:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-dec-linux-gnu
|
||||
echo ${UNAME_MACHINE}-dec-linux-${LIBC}
|
||||
exit ;;
|
||||
x86_64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
xtensa*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
|
||||
exit ;;
|
||||
i*86:DYNIX/ptx:4*:*)
|
||||
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
|
||||
@@ -1201,6 +1245,9 @@ EOF
|
||||
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
|
||||
echo i586-pc-haiku
|
||||
exit ;;
|
||||
x86_64:Haiku:*:*)
|
||||
echo x86_64-unknown-haiku
|
||||
exit ;;
|
||||
SX-4:SUPER-UX:*:*)
|
||||
echo sx4-nec-superux${UNAME_RELEASE}
|
||||
exit ;;
|
||||
@@ -1227,19 +1274,31 @@ EOF
|
||||
exit ;;
|
||||
*:Darwin:*:*)
|
||||
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
|
||||
case $UNAME_PROCESSOR in
|
||||
i386)
|
||||
eval $set_cc_for_build
|
||||
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
|
||||
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
|
||||
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
grep IS_64BIT_ARCH >/dev/null
|
||||
then
|
||||
UNAME_PROCESSOR="x86_64"
|
||||
fi
|
||||
fi ;;
|
||||
unknown) UNAME_PROCESSOR=powerpc ;;
|
||||
esac
|
||||
eval $set_cc_for_build
|
||||
if test "$UNAME_PROCESSOR" = unknown ; then
|
||||
UNAME_PROCESSOR=powerpc
|
||||
fi
|
||||
if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
|
||||
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
|
||||
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
|
||||
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
|
||||
grep IS_64BIT_ARCH >/dev/null
|
||||
then
|
||||
case $UNAME_PROCESSOR in
|
||||
i386) UNAME_PROCESSOR=x86_64 ;;
|
||||
powerpc) UNAME_PROCESSOR=powerpc64 ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
elif test "$UNAME_PROCESSOR" = i386 ; then
|
||||
# Avoid executing cc on OS X 10.9, as it ships with a stub
|
||||
# that puts up a graphical alert prompting to install
|
||||
# developer tools. Any system running Mac OS X 10.7 or
|
||||
# later (Darwin 11 and later) is required to have a 64-bit
|
||||
# processor. This is not true of the ARM version of Darwin
|
||||
# that Apple uses in portable devices.
|
||||
UNAME_PROCESSOR=x86_64
|
||||
fi
|
||||
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
|
||||
exit ;;
|
||||
*:procnto*:*:* | *:QNX:[0123456789]*:*)
|
||||
@@ -1256,7 +1315,7 @@ EOF
|
||||
NEO-?:NONSTOP_KERNEL:*:*)
|
||||
echo neo-tandem-nsk${UNAME_RELEASE}
|
||||
exit ;;
|
||||
NSE-?:NONSTOP_KERNEL:*:*)
|
||||
NSE-*:NONSTOP_KERNEL:*:*)
|
||||
echo nse-tandem-nsk${UNAME_RELEASE}
|
||||
exit ;;
|
||||
NSR-?:NONSTOP_KERNEL:*:*)
|
||||
@@ -1330,157 +1389,6 @@ EOF
|
||||
exit ;;
|
||||
esac
|
||||
|
||||
#echo '(No uname command or uname output not recognized.)' 1>&2
|
||||
#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
|
||||
|
||||
eval $set_cc_for_build
|
||||
cat >$dummy.c <<EOF
|
||||
#ifdef _SEQUENT_
|
||||
# include <sys/types.h>
|
||||
# include <sys/utsname.h>
|
||||
#endif
|
||||
main ()
|
||||
{
|
||||
#if defined (sony)
|
||||
#if defined (MIPSEB)
|
||||
/* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
|
||||
I don't know.... */
|
||||
printf ("mips-sony-bsd\n"); exit (0);
|
||||
#else
|
||||
#include <sys/param.h>
|
||||
printf ("m68k-sony-newsos%s\n",
|
||||
#ifdef NEWSOS4
|
||||
"4"
|
||||
#else
|
||||
""
|
||||
#endif
|
||||
); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (__arm) && defined (__acorn) && defined (__unix)
|
||||
printf ("arm-acorn-riscix\n"); exit (0);
|
||||
#endif
|
||||
|
||||
#if defined (hp300) && !defined (hpux)
|
||||
printf ("m68k-hp-bsd\n"); exit (0);
|
||||
#endif
|
||||
|
||||
#if defined (NeXT)
|
||||
#if !defined (__ARCHITECTURE__)
|
||||
#define __ARCHITECTURE__ "m68k"
|
||||
#endif
|
||||
int version;
|
||||
version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
|
||||
if (version < 4)
|
||||
printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
|
||||
else
|
||||
printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
|
||||
exit (0);
|
||||
#endif
|
||||
|
||||
#if defined (MULTIMAX) || defined (n16)
|
||||
#if defined (UMAXV)
|
||||
printf ("ns32k-encore-sysv\n"); exit (0);
|
||||
#else
|
||||
#if defined (CMU)
|
||||
printf ("ns32k-encore-mach\n"); exit (0);
|
||||
#else
|
||||
printf ("ns32k-encore-bsd\n"); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (__386BSD__)
|
||||
printf ("i386-pc-bsd\n"); exit (0);
|
||||
#endif
|
||||
|
||||
#if defined (sequent)
|
||||
#if defined (i386)
|
||||
printf ("i386-sequent-dynix\n"); exit (0);
|
||||
#endif
|
||||
#if defined (ns32000)
|
||||
printf ("ns32k-sequent-dynix\n"); exit (0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (_SEQUENT_)
|
||||
struct utsname un;
|
||||
|
||||
uname(&un);
|
||||
|
||||
if (strncmp(un.version, "V2", 2) == 0) {
|
||||
printf ("i386-sequent-ptx2\n"); exit (0);
|
||||
}
|
||||
if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
|
||||
printf ("i386-sequent-ptx1\n"); exit (0);
|
||||
}
|
||||
printf ("i386-sequent-ptx\n"); exit (0);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (vax)
|
||||
# if !defined (ultrix)
|
||||
# include <sys/param.h>
|
||||
# if defined (BSD)
|
||||
# if BSD == 43
|
||||
printf ("vax-dec-bsd4.3\n"); exit (0);
|
||||
# else
|
||||
# if BSD == 199006
|
||||
printf ("vax-dec-bsd4.3reno\n"); exit (0);
|
||||
# else
|
||||
printf ("vax-dec-bsd\n"); exit (0);
|
||||
# endif
|
||||
# endif
|
||||
# else
|
||||
printf ("vax-dec-bsd\n"); exit (0);
|
||||
# endif
|
||||
# else
|
||||
printf ("vax-dec-ultrix\n"); exit (0);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined (alliant) && defined (i860)
|
||||
printf ("i860-alliant-bsd\n"); exit (0);
|
||||
#endif
|
||||
|
||||
exit (1);
|
||||
}
|
||||
EOF
|
||||
|
||||
$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
|
||||
{ echo "$SYSTEM_NAME"; exit; }
|
||||
|
||||
# Apollos put the system type in the environment.
|
||||
|
||||
test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
|
||||
|
||||
# Convex versions that predate uname can use getsysinfo(1)
|
||||
|
||||
if [ -x /usr/convex/getsysinfo ]
|
||||
then
|
||||
case `getsysinfo -f cpu_type` in
|
||||
c1*)
|
||||
echo c1-convex-bsd
|
||||
exit ;;
|
||||
c2*)
|
||||
if getsysinfo -f scalar_acc
|
||||
then echo c32-convex-bsd
|
||||
else echo c2-convex-bsd
|
||||
fi
|
||||
exit ;;
|
||||
c34*)
|
||||
echo c34-convex-bsd
|
||||
exit ;;
|
||||
c38*)
|
||||
echo c38-convex-bsd
|
||||
exit ;;
|
||||
c4*)
|
||||
echo c4-convex-bsd
|
||||
exit ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
cat >&2 <<EOF
|
||||
$0: unable to guess system type
|
||||
|
||||
|
||||
134
config.sub
vendored
134
config.sub
vendored
@@ -1,24 +1,18 @@
|
||||
#! /bin/sh
|
||||
# Configuration validation subroutine script.
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||
# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
# 2011, 2012 Free Software Foundation, Inc.
|
||||
# Copyright 1992-2015 Free Software Foundation, Inc.
|
||||
|
||||
timestamp='2012-04-18'
|
||||
timestamp='2015-03-08'
|
||||
|
||||
# This file is (in principle) common to ALL GNU software.
|
||||
# The presence of a machine in this file suggests that SOME GNU software
|
||||
# can handle that machine. It does not imply ALL GNU software can.
|
||||
#
|
||||
# This file is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# This file is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
@@ -26,11 +20,12 @@ timestamp='2012-04-18'
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
# the same distribution terms that you use for the rest of that
|
||||
# program. This Exception is an additional permission under section 7
|
||||
# of the GNU General Public License, version 3 ("GPLv3").
|
||||
|
||||
|
||||
# Please send patches to <config-patches@gnu.org>. Submit a context
|
||||
# diff and a properly formatted GNU ChangeLog entry.
|
||||
# Please send patches to <config-patches@gnu.org>.
|
||||
#
|
||||
# Configuration subroutine to validate and canonicalize a configuration type.
|
||||
# Supply the specified configuration type as an argument.
|
||||
@@ -73,9 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>."
|
||||
version="\
|
||||
GNU config.sub ($timestamp)
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
|
||||
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
||||
Free Software Foundation, Inc.
|
||||
Copyright 1992-2015 Free Software Foundation, Inc.
|
||||
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||
@@ -123,8 +116,8 @@ esac
|
||||
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
|
||||
case $maybe_os in
|
||||
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
|
||||
linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
|
||||
knetbsd*-gnu* | netbsd*-gnu* | \
|
||||
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
|
||||
knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
|
||||
kopensolaris*-gnu* | \
|
||||
storm-chaos* | os2-emx* | rtmk-nova*)
|
||||
os=-$maybe_os
|
||||
@@ -156,7 +149,7 @@ case $os in
|
||||
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
|
||||
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
|
||||
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
|
||||
-apple | -axis | -knuth | -cray | -microblaze)
|
||||
-apple | -axis | -knuth | -cray | -microblaze*)
|
||||
os=
|
||||
basic_machine=$1
|
||||
;;
|
||||
@@ -259,21 +252,24 @@ case $basic_machine in
|
||||
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
|
||||
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
|
||||
| am33_2.0 \
|
||||
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
|
||||
| be32 | be64 \
|
||||
| arc | arceb \
|
||||
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
|
||||
| avr | avr32 \
|
||||
| be32 | be64 \
|
||||
| bfin \
|
||||
| c4x | clipper \
|
||||
| c4x | c8051 | clipper \
|
||||
| d10v | d30v | dlx | dsp16xx \
|
||||
| epiphany \
|
||||
| fido | fr30 | frv \
|
||||
| e2k | epiphany \
|
||||
| fido | fr30 | frv | ft32 \
|
||||
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
|
||||
| hexagon \
|
||||
| i370 | i860 | i960 | ia64 \
|
||||
| ip2k | iq2000 \
|
||||
| k1om \
|
||||
| le32 | le64 \
|
||||
| lm32 \
|
||||
| m32c | m32r | m32rle | m68000 | m68k | m88k \
|
||||
| maxq | mb | microblaze | mcore | mep | metag \
|
||||
| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
|
||||
| mips | mipsbe | mipseb | mipsel | mipsle \
|
||||
| mips16 \
|
||||
| mips64 | mips64el \
|
||||
@@ -287,23 +283,26 @@ case $basic_machine in
|
||||
| mips64vr5900 | mips64vr5900el \
|
||||
| mipsisa32 | mipsisa32el \
|
||||
| mipsisa32r2 | mipsisa32r2el \
|
||||
| mipsisa32r6 | mipsisa32r6el \
|
||||
| mipsisa64 | mipsisa64el \
|
||||
| mipsisa64r2 | mipsisa64r2el \
|
||||
| mipsisa64r6 | mipsisa64r6el \
|
||||
| mipsisa64sb1 | mipsisa64sb1el \
|
||||
| mipsisa64sr71k | mipsisa64sr71kel \
|
||||
| mipsr5900 | mipsr5900el \
|
||||
| mipstx39 | mipstx39el \
|
||||
| mn10200 | mn10300 \
|
||||
| moxie \
|
||||
| mt \
|
||||
| msp430 \
|
||||
| nds32 | nds32le | nds32be \
|
||||
| nios | nios2 \
|
||||
| nios | nios2 | nios2eb | nios2el \
|
||||
| ns16k | ns32k \
|
||||
| open8 \
|
||||
| or32 \
|
||||
| open8 | or1k | or1knd | or32 \
|
||||
| pdp10 | pdp11 | pj | pjl \
|
||||
| powerpc | powerpc64 | powerpc64le | powerpcle \
|
||||
| pyramid \
|
||||
| riscv32 | riscv64 \
|
||||
| rl78 | rx \
|
||||
| score \
|
||||
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
|
||||
@@ -314,6 +313,7 @@ case $basic_machine in
|
||||
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
|
||||
| ubicom32 \
|
||||
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
|
||||
| visium \
|
||||
| we32k \
|
||||
| x86 | xc16x | xstormy16 | xtensa \
|
||||
| z8k | z80)
|
||||
@@ -328,7 +328,10 @@ case $basic_machine in
|
||||
c6x)
|
||||
basic_machine=tic6x-unknown
|
||||
;;
|
||||
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
|
||||
leon|leon[3-9])
|
||||
basic_machine=sparc-$basic_machine
|
||||
;;
|
||||
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
|
||||
basic_machine=$basic_machine-unknown
|
||||
os=-none
|
||||
;;
|
||||
@@ -370,26 +373,28 @@ case $basic_machine in
|
||||
| aarch64-* | aarch64_be-* \
|
||||
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
|
||||
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
|
||||
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
|
||||
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
|
||||
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
||||
| avr-* | avr32-* \
|
||||
| be32-* | be64-* \
|
||||
| bfin-* | bs2000-* \
|
||||
| c[123]* | c30-* | [cjt]90-* | c4x-* \
|
||||
| clipper-* | craynv-* | cydra-* \
|
||||
| c8051-* | clipper-* | craynv-* | cydra-* \
|
||||
| d10v-* | d30v-* | dlx-* \
|
||||
| elxsi-* \
|
||||
| e2k-* | elxsi-* \
|
||||
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
|
||||
| h8300-* | h8500-* \
|
||||
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
|
||||
| hexagon-* \
|
||||
| i*86-* | i860-* | i960-* | ia64-* \
|
||||
| ip2k-* | iq2000-* \
|
||||
| k1om-* \
|
||||
| le32-* | le64-* \
|
||||
| lm32-* \
|
||||
| m32c-* | m32r-* | m32rle-* \
|
||||
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
|
||||
| m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
|
||||
| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
|
||||
| microblaze-* | microblazeel-* \
|
||||
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
|
||||
| mips16-* \
|
||||
| mips64-* | mips64el-* \
|
||||
@@ -403,18 +408,22 @@ case $basic_machine in
|
||||
| mips64vr5900-* | mips64vr5900el-* \
|
||||
| mipsisa32-* | mipsisa32el-* \
|
||||
| mipsisa32r2-* | mipsisa32r2el-* \
|
||||
| mipsisa32r6-* | mipsisa32r6el-* \
|
||||
| mipsisa64-* | mipsisa64el-* \
|
||||
| mipsisa64r2-* | mipsisa64r2el-* \
|
||||
| mipsisa64r6-* | mipsisa64r6el-* \
|
||||
| mipsisa64sb1-* | mipsisa64sb1el-* \
|
||||
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
|
||||
| mipsr5900-* | mipsr5900el-* \
|
||||
| mipstx39-* | mipstx39el-* \
|
||||
| mmix-* \
|
||||
| mt-* \
|
||||
| msp430-* \
|
||||
| nds32-* | nds32le-* | nds32be-* \
|
||||
| nios-* | nios2-* \
|
||||
| nios-* | nios2-* | nios2eb-* | nios2el-* \
|
||||
| none-* | np1-* | ns16k-* | ns32k-* \
|
||||
| open8-* \
|
||||
| or1k*-* \
|
||||
| orion-* \
|
||||
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
|
||||
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
|
||||
@@ -432,6 +441,7 @@ case $basic_machine in
|
||||
| ubicom32-* \
|
||||
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
|
||||
| vax-* \
|
||||
| visium-* \
|
||||
| we32k-* \
|
||||
| x86-* | x86_64-* | xc16x-* | xps100-* \
|
||||
| xstormy16-* | xtensa*-* \
|
||||
@@ -508,6 +518,9 @@ case $basic_machine in
|
||||
basic_machine=i386-pc
|
||||
os=-aros
|
||||
;;
|
||||
asmjs)
|
||||
basic_machine=asmjs-unknown
|
||||
;;
|
||||
aux)
|
||||
basic_machine=m68k-apple
|
||||
os=-aux
|
||||
@@ -769,6 +782,9 @@ case $basic_machine in
|
||||
basic_machine=m68k-isi
|
||||
os=-sysv
|
||||
;;
|
||||
leon-*|leon[3-9]-*)
|
||||
basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
|
||||
;;
|
||||
m68knommu)
|
||||
basic_machine=m68k-unknown
|
||||
os=-linux
|
||||
@@ -788,11 +804,15 @@ case $basic_machine in
|
||||
basic_machine=ns32k-utek
|
||||
os=-sysv
|
||||
;;
|
||||
microblaze)
|
||||
microblaze*)
|
||||
basic_machine=microblaze-xilinx
|
||||
;;
|
||||
mingw64)
|
||||
basic_machine=x86_64-pc
|
||||
os=-mingw64
|
||||
;;
|
||||
mingw32)
|
||||
basic_machine=i386-pc
|
||||
basic_machine=i686-pc
|
||||
os=-mingw32
|
||||
;;
|
||||
mingw32ce)
|
||||
@@ -820,6 +840,10 @@ case $basic_machine in
|
||||
basic_machine=powerpc-unknown
|
||||
os=-morphos
|
||||
;;
|
||||
moxiebox)
|
||||
basic_machine=moxie-unknown
|
||||
os=-moxiebox
|
||||
;;
|
||||
msdos)
|
||||
basic_machine=i386-pc
|
||||
os=-msdos
|
||||
@@ -828,7 +852,7 @@ case $basic_machine in
|
||||
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
|
||||
;;
|
||||
msys)
|
||||
basic_machine=i386-pc
|
||||
basic_machine=i686-pc
|
||||
os=-msys
|
||||
;;
|
||||
mvs)
|
||||
@@ -1019,7 +1043,11 @@ case $basic_machine in
|
||||
basic_machine=i586-unknown
|
||||
os=-pw32
|
||||
;;
|
||||
rdos)
|
||||
rdos | rdos64)
|
||||
basic_machine=x86_64-pc
|
||||
os=-rdos
|
||||
;;
|
||||
rdos32)
|
||||
basic_machine=i386-pc
|
||||
os=-rdos
|
||||
;;
|
||||
@@ -1346,29 +1374,29 @@ case $os in
|
||||
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
|
||||
| -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
|
||||
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
|
||||
| -sym* | -kopensolaris* \
|
||||
| -sym* | -kopensolaris* | -plan9* \
|
||||
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
|
||||
| -aos* | -aros* \
|
||||
| -aos* | -aros* | -cloudabi* \
|
||||
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
|
||||
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
|
||||
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
|
||||
| -openbsd* | -solidbsd* \
|
||||
| -bitrig* | -openbsd* | -solidbsd* \
|
||||
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
|
||||
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
|
||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||
| -chorusos* | -chorusrdb* | -cegcc* \
|
||||
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
||||
| -mingw32* | -linux-gnu* | -linux-android* \
|
||||
| -linux-newlib* | -linux-uclibc* \
|
||||
| -uxpv* | -beos* | -mpeix* | -udk* \
|
||||
| -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
|
||||
| -linux-newlib* | -linux-musl* | -linux-uclibc* \
|
||||
| -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
|
||||
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
|
||||
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
|
||||
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
|
||||
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
|
||||
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
|
||||
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
|
||||
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
|
||||
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
|
||||
# Remember, each alternative MUST END IN *, to match a version number.
|
||||
;;
|
||||
-qnx*)
|
||||
@@ -1492,9 +1520,6 @@ case $os in
|
||||
-aros*)
|
||||
os=-aros
|
||||
;;
|
||||
-kaos*)
|
||||
os=-kaos
|
||||
;;
|
||||
-zvmoe)
|
||||
os=-zvmoe
|
||||
;;
|
||||
@@ -1543,6 +1568,9 @@ case $basic_machine in
|
||||
c4x-* | tic4x-*)
|
||||
os=-coff
|
||||
;;
|
||||
c8051-*)
|
||||
os=-elf
|
||||
;;
|
||||
hexagon-*)
|
||||
os=-elf
|
||||
;;
|
||||
|
||||
586
configure.ac
586
configure.ac
@@ -13,10 +13,8 @@ m4_syscmd([build_tools/git_version_gen.sh 2>/dev/null])
|
||||
AC_PREREQ([2.60])
|
||||
AC_INIT(fish,
|
||||
m4_esyscmd([cut -f 3 -d ' ' FISH-BUILD-VERSION-FILE | tr -d '\n']),
|
||||
fish-users@lists.sf.net)
|
||||
|
||||
conf_arg=$@
|
||||
|
||||
fish-users@lists.sourceforge.net)
|
||||
ac_clean_files=a.out.dSYM
|
||||
#
|
||||
# List of output variables produced by this configure script
|
||||
#
|
||||
@@ -24,7 +22,8 @@ conf_arg=$@
|
||||
AC_SUBST(HAVE_GETTEXT)
|
||||
AC_SUBST(HAVE_DOXYGEN)
|
||||
AC_SUBST(LDFLAGS_FISH)
|
||||
|
||||
AC_SUBST(WCHAR_T_BITS)
|
||||
AC_SUBST(EXTRA_PCRE2)
|
||||
|
||||
#
|
||||
# If needed, run autoconf to regenerate the configure file
|
||||
@@ -50,7 +49,7 @@ if test configure -ot configure.ac; then
|
||||
AC_MSG_ERROR(
|
||||
[cannot find the autoconf program in your path.
|
||||
This program needs to be run whenever the configure.ac file is modified.
|
||||
Please install it and try again.]
|
||||
Please install autoconf and try again.]
|
||||
)
|
||||
fi
|
||||
else
|
||||
@@ -75,7 +74,7 @@ if test ! -f ./config.h.in -o config.h.in -ot configure.ac; then
|
||||
AC_MSG_ERROR(
|
||||
[cannot find the autoheader program in your path.
|
||||
This program needs to be run whenever the configure.ac file is modified.
|
||||
Please install it and try again.]
|
||||
Please install autotools and try again.]
|
||||
)
|
||||
fi
|
||||
else
|
||||
@@ -86,19 +85,24 @@ fi
|
||||
# Set up various programs needed for install
|
||||
# Note AC_PROG_CXX sets CXXFLAGS if not set, which we want
|
||||
# So ensure this happens before we modify CXXFLAGS below
|
||||
#
|
||||
|
||||
AC_PROG_CXX([g++ c++])
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_SED
|
||||
# Do CC also, because PCRE2 will use it.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_STDC # c99
|
||||
AC_PROG_CXX
|
||||
AC_LANG(C++)
|
||||
|
||||
echo "CXXFLAGS: $CXXFLAGS"
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MKDIR_P
|
||||
AC_PROG_AWK
|
||||
AC_PROG_FGREP
|
||||
AC_PROG_SED
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
#
|
||||
# Tell autoconf to create config.h header
|
||||
#
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
AC_CANONICAL_TARGET
|
||||
|
||||
|
||||
#
|
||||
@@ -107,9 +111,15 @@ AC_CONFIG_HEADERS(config.h)
|
||||
#
|
||||
|
||||
AH_BOTTOM([#if __GNUC__ >= 3
|
||||
#ifndef __warn_unused
|
||||
#define __warn_unused __attribute__ ((warn_unused_result))
|
||||
#endif
|
||||
#ifndef __sentinel
|
||||
#define __sentinel __attribute__ ((sentinel))
|
||||
#endif
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__ ((packed))
|
||||
#endif
|
||||
#else
|
||||
#define __warn_unused
|
||||
#define __sentinel
|
||||
@@ -190,8 +200,7 @@ AS_IF([test "$use_doxygen" != "no"],
|
||||
# where off_t can be either 32 or 64 bit, the latter size is used. On
|
||||
# other systems, this should do nothing. (Hopefully)
|
||||
#
|
||||
|
||||
CXXFLAGS="$CXXFLAGS -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64"
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
|
||||
# fish does not use exceptions
|
||||
@@ -204,119 +213,23 @@ CXXFLAGS="$CXXFLAGS -fno-exceptions"
|
||||
# But signed comparison warnings are way too aggressive
|
||||
#
|
||||
|
||||
CXXFLAGS="$CXXFLAGS -Wall -Wno-sign-compare"
|
||||
CXXFLAGS="$CXXFLAGS -Wextra"
|
||||
|
||||
#
|
||||
# This is needed in order to get the really cool backtraces on Linux
|
||||
#
|
||||
|
||||
if test `uname` != "Darwin"; then
|
||||
LDFLAGS_FISH="$LDFLAGS_FISH -rdynamic"
|
||||
fi
|
||||
|
||||
#
|
||||
# On Cygwin, we need to add some flags for ncurses.
|
||||
#
|
||||
case `uname` in
|
||||
CYGWIN*)
|
||||
echo "adding flags for ncurses on Cygwin"
|
||||
CXXFLAGS="$CXXFLAGS -I/usr/include -I/usr/include/ncursesw"
|
||||
LDFLAGS_FISH="$LDFLAGS_FISH -L/usr/lib/ncursesw"
|
||||
;;
|
||||
esac
|
||||
|
||||
#
|
||||
# If we are compiling against glibc, set some flags to work around
|
||||
# some rather stupid attempts to hide prototypes for *wprintf
|
||||
# functions, as well as prototypes of various gnu extensions.
|
||||
#
|
||||
|
||||
AC_MSG_CHECKING([if we are compiling against glibc])
|
||||
AC_RUN_IFELSE(
|
||||
[
|
||||
AC_LANG_PROGRAM(
|
||||
[
|
||||
#include <stdlib.h>
|
||||
#ifdef __GLIBC__
|
||||
#define STATUS 0
|
||||
#else
|
||||
#define STATUS 1
|
||||
#endif
|
||||
],
|
||||
[
|
||||
return STATUS;
|
||||
]
|
||||
)
|
||||
],
|
||||
[glibc=yes],
|
||||
[glibc=no]
|
||||
)
|
||||
|
||||
if test "$glibc" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
|
||||
#
|
||||
# This gives us access to prototypes for gnu extensions and C99
|
||||
# functions if we are compiling agains glibc. All GNU extensions
|
||||
# that are used must have a fallback implementation available in
|
||||
# fallback.h, in order to keep fish working on non-gnu platforms.
|
||||
#
|
||||
|
||||
CXXFLAGS="$CXXFLAGS -D_GNU_SOURCE=1 -D_ISO99_SOURCE=1"
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Test cpu for special handling of ppc
|
||||
#
|
||||
# This is used to skip use of tputs on ppc systems, since it seemed to
|
||||
# be broken, at least on older debin-based systems. This is obviously
|
||||
# not the right way to to detect whether this workaround should be
|
||||
# used, since it catches far to many systems, but I do not have the
|
||||
# hardware available to narrow this problem down, and in practice, it
|
||||
# seems that tputs is never really needed.
|
||||
#
|
||||
|
||||
AC_CANONICAL_TARGET
|
||||
|
||||
if test $target_cpu = powerpc; then
|
||||
AC_DEFINE([TPUTS_KLUDGE],[1],[Evil kludge to get Power based machines to work])
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Solaris-specific flags go here
|
||||
#
|
||||
|
||||
AC_MSG_CHECKING([if we are under Solaris])
|
||||
case $target_os in
|
||||
solaris*)
|
||||
AC_DEFINE( __EXTENSIONS__, 1, [Macro to enable additional prototypes under Solaris])
|
||||
AC_MSG_RESULT(yes)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT(no)
|
||||
;;
|
||||
esac
|
||||
|
||||
#
|
||||
# BSD-specific flags go here
|
||||
#
|
||||
|
||||
AC_MSG_CHECKING([if we are under BSD])
|
||||
case $target_os in
|
||||
*bsd*)
|
||||
AC_DEFINE( __BSD_VISIBLE, 1, [Macro to enable additional prototypes under BSD])
|
||||
AC_DEFINE( _NETBSD_SOURCE, 1, [Macro to enable additional prototypes under BSD])
|
||||
AC_MSG_RESULT(yes)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT(no)
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_MSG_CHECKING([for -rdynamic linker flag])
|
||||
prev_LDFLAGS="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS -rdynamic"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],
|
||||
[
|
||||
AC_MSG_RESULT([yes])
|
||||
LDFLAGS_FISH="$LDFLAGS_FISH -rdynamic"
|
||||
], [
|
||||
AC_MSG_RESULT([no])
|
||||
LDFLAGS_FISH="$LDFLAGS_FISH"
|
||||
])
|
||||
LDFLAGS="$prev_LDFLAGS"
|
||||
|
||||
#
|
||||
# See if Linux procfs is present. This is used to get extra
|
||||
@@ -325,18 +238,6 @@ esac
|
||||
|
||||
AC_CHECK_FILES([/proc/self/stat])
|
||||
|
||||
|
||||
#
|
||||
# This is ued to tell the wgetopt library to translate strings. This
|
||||
# way wgetopt can be dropped into any project without requiring i18n.
|
||||
#
|
||||
|
||||
AC_DEFINE(
|
||||
[HAVE_TRANSLATE_H],
|
||||
[1],
|
||||
[Define to 1 if the wgettext function should be used for translating strings.]
|
||||
)
|
||||
|
||||
# Disable curses macros that conflict with the STL
|
||||
AC_DEFINE([NCURSES_NOMACROS], [1], [Define to 1 to disable ncurses macros that conflict with the STL])
|
||||
AC_DEFINE([NOMACROS], [1], [Define to 1 to disable curses macros that conflict with the STL])
|
||||
@@ -354,7 +255,7 @@ AC_SEARCH_LIBS( nanosleep, rt, , [AC_MSG_ERROR([Cannot find the rt library, need
|
||||
AC_SEARCH_LIBS( shm_open, rt, , [AC_MSG_ERROR([Cannot find the rt library, needed to build this package.] )] )
|
||||
AC_SEARCH_LIBS( pthread_create, pthread, , [AC_MSG_ERROR([Cannot find the pthread library, needed to build this package.] )] )
|
||||
AC_SEARCH_LIBS( setupterm, [ncurses tinfo curses], , [AC_MSG_ERROR([Could not find a curses implementation, needed to build fish. If this is Linux, try running 'sudo apt-get install libncurses5-dev' or 'sudo yum install ncurses-devel'])] )
|
||||
AC_SEARCH_LIBS( [nan], [m], [AC_DEFINE( [HAVE_NAN], [1], [Define to 1 if you have the nan function])] )
|
||||
AC_SEARCH_LIBS( [dladdr], [dl] )
|
||||
|
||||
if test x$local_gettext != xno; then
|
||||
AC_SEARCH_LIBS( gettext, intl,,)
|
||||
@@ -370,139 +271,20 @@ if test x$local_gettext != xno; then
|
||||
AC_CHECK_HEADERS([libintl.h])
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADER(
|
||||
[regex.h],
|
||||
[
|
||||
AC_DEFINE(
|
||||
[HAVE_REGEX_H],
|
||||
[1],
|
||||
[Define to 1 if you have the <regex.h> header file.]
|
||||
)
|
||||
],
|
||||
[AC_MSG_ERROR([Could not find the header regex.h, needed to build fish])]
|
||||
)
|
||||
|
||||
#
|
||||
# On some platforms (Solaris 10) adding -std=c99 in turn requires that
|
||||
# _POSIX_C_SOURCE be defined to 200112L otherwise several
|
||||
# POSIX-specific, non-ISO-C99 types/prototypes are made unavailable
|
||||
# e.g. siginfo_t. Defining _XOPEN_SOURCE to 600 is compatible with
|
||||
# the _POSIX_C_SOURCE value and provides a little assurance that
|
||||
# extension functions' prototypes are available, e.g. killpg().
|
||||
#
|
||||
# Some other platforms (OS X), will remove types/prototypes/macros
|
||||
# e.g. SIGWINCH if either _POSIX_C_SOURCE or _XOPEN_SOURCE is defined.
|
||||
#
|
||||
# This test adds these macros only if they enable a program that uses
|
||||
# both Posix and non-standard features to compile, and that program
|
||||
# does not compile without these macros.
|
||||
#
|
||||
# We try to make everyone happy.
|
||||
#
|
||||
# The ordering of the various autoconf tests is very critical as well:
|
||||
#
|
||||
# * This test needs to be run _after_ header detection tests, so that
|
||||
# the proper headers are included.
|
||||
#
|
||||
# * This test needs to be run _before_ testing for the presense of any
|
||||
# prototypes or other language functinality.
|
||||
#
|
||||
# * This test should be (but does not need to be) run after the
|
||||
# conditional definition of __EXTENSIONS__, to avoid redundant tests.
|
||||
# Get the size in bits of wchar_t, needed for configuring the pcre2 build
|
||||
# and for code that #includes pcre2.h
|
||||
#
|
||||
|
||||
XCXXFLAGS="$CXXFLAGS"
|
||||
|
||||
echo checking how to use -D_XOPEN_SOURCE=600 and -D_POSIX_C_SOURCE=200112L...
|
||||
local_found_posix_switch=no
|
||||
|
||||
for i in "" "-D_POSIX_C_SOURCE=200112L" "-D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200112L"; do
|
||||
|
||||
AC_MSG_CHECKING( if switches \"$i\" works)
|
||||
CXXFLAGS="$XCXXFLAGS $i"
|
||||
|
||||
#
|
||||
# Try to run this program, which should test various extensions
|
||||
# and Posix functionality. If this program works, then everything
|
||||
# should work. Hopefully.
|
||||
#
|
||||
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* POSIX, C89 and C99: POSIX extends this header.
|
||||
* For: kill(), killpg(), siginfo_t, sigset_t,
|
||||
* struct sigaction, sigemptyset(), sigaction(),
|
||||
* SIGIO and SIGWINCH. */
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_SIGINFO_H
|
||||
/* Neither POSIX, C89 nor C99: Solaris-specific (others?).
|
||||
* For: siginfo_t (also defined by signal.h when in
|
||||
* POSIX/extensions mode). */
|
||||
#include <siginfo.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
/* As above (under at least Linux and FreeBSD). */
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
],
|
||||
[
|
||||
/* Avert high-level optimisation, by making the program's
|
||||
* return value depend on all tested identifiers. */
|
||||
long ret = 0;
|
||||
/* POSIX only: might be unhidden by _POSIX_C_SOURCE. */
|
||||
struct sigaction sa;
|
||||
sigset_t ss;
|
||||
siginfo_t info;
|
||||
ret += (long)(void *)&info + kill( 0, 0 ) +
|
||||
sigaction( 0, &sa, 0 ) + sigemptyset( &ss );
|
||||
/* Extended-POSIX: might be unhidden by _XOPEN_SOURCE. */
|
||||
ret += killpg( 0, 0 );
|
||||
/* Non-standard: might be hidden by the macros. */
|
||||
{
|
||||
struct winsize termsize;
|
||||
ret += (long)(void *)&termsize;
|
||||
ret += SIGWINCH + TIOCGWINSZ + SIGIO;
|
||||
}
|
||||
return ret;
|
||||
|
||||
],
|
||||
local_cv_use__posix_c_source=yes,
|
||||
local_cv_use__posix_c_source=no,
|
||||
)
|
||||
|
||||
if test x$local_cv_use__posix_c_source = xyes; then
|
||||
AC_MSG_RESULT( yes )
|
||||
local_found_posix_switch=yes
|
||||
break;
|
||||
else
|
||||
AC_MSG_RESULT( no )
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
#
|
||||
# We didn't find any combination of switches that worked - revert to
|
||||
# no switches and hope that the fallbacks work. A warning will be
|
||||
# printed at the end of the configure script.
|
||||
#
|
||||
|
||||
if test ! x$local_found_posix_switch = xyes; then
|
||||
CXXFLAGS="$XCXXFLAGS"
|
||||
fi
|
||||
AC_CHECK_SIZEOF(wchar_t)
|
||||
WCHAR_T_BITS=`expr 8 \* $ac_cv_sizeof_wchar_t`
|
||||
AC_DEFINE_UNQUOTED([WCHAR_T_BITS], [$WCHAR_T_BITS], [The size of wchar_t in bits.])
|
||||
|
||||
#
|
||||
# Detect nanoseconds fields in struct stat
|
||||
#
|
||||
AC_CHECK_MEMBERS([struct stat.st_ctime_nsec])
|
||||
AC_CHECK_MEMBERS([struct stat.st_mtimespec.tv_nsec])
|
||||
AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec])
|
||||
|
||||
@@ -512,16 +294,20 @@ AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec])
|
||||
AC_STRUCT_DIRENT_D_TYPE
|
||||
|
||||
#
|
||||
# Check for presense of various functions used by fish
|
||||
# Check for presence of various functions used by fish
|
||||
#
|
||||
|
||||
AC_CHECK_FUNCS( wcsdup wcsndup wcslen wcscasecmp wcsncasecmp fwprintf )
|
||||
AC_CHECK_FUNCS( futimes wcwidth wcswidth wcstok fputwc fgetwc )
|
||||
AC_CHECK_FUNCS( wcstol wcslcat wcslcpy lrand48_r killpg mkostemp )
|
||||
AC_CHECK_FUNCS( backtrace backtrace_symbols sysconf getifaddrs )
|
||||
AC_CHECK_FUNCS( wcsndup )
|
||||
AC_CHECK_FUNCS( futimes )
|
||||
AC_CHECK_FUNCS( wcslcpy lrand48_r killpg )
|
||||
AC_CHECK_FUNCS( backtrace_symbols getifaddrs )
|
||||
AC_CHECK_FUNCS( futimens clock_gettime )
|
||||
AC_CHECK_FUNCS( getpwent )
|
||||
|
||||
AC_CHECK_DECL( [mkostemp], [ AC_CHECK_FUNCS([mkostemp]) ] )
|
||||
|
||||
if test x$local_gettext != xno; then
|
||||
AC_CHECK_FUNCS( gettext dcgettext )
|
||||
AC_CHECK_FUNCS( gettext )
|
||||
|
||||
#
|
||||
# The Makefile also needs to know if we have gettext, so it knows if
|
||||
@@ -535,45 +321,6 @@ fi
|
||||
# features that Autoconf doesn't tell us about
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# Check if realpath accepts null for its second argument
|
||||
#
|
||||
|
||||
AC_MSG_CHECKING([if realpath accepts null for its second argument])
|
||||
AC_RUN_IFELSE(
|
||||
[
|
||||
AC_LANG_PROGRAM(
|
||||
[
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
],
|
||||
[
|
||||
int status;
|
||||
char *res;
|
||||
res = realpath( "somefile", 0 );
|
||||
status = !(res != 0 || errno == ENOENT);
|
||||
exit( status );
|
||||
]
|
||||
)
|
||||
],
|
||||
[have_realpath_null=yes],
|
||||
[have_realpath_null=no]
|
||||
)
|
||||
|
||||
if test "$have_realpath_null" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(
|
||||
[HAVE_REALPATH_NULL],
|
||||
[1],
|
||||
[Define to 1 if realpath accepts null for its second argument.]
|
||||
)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Check if struct winsize and TIOCGWINSZ exist
|
||||
#
|
||||
@@ -607,41 +354,6 @@ AC_LINK_IFELSE(
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# If we have a fwprintf in libc, test that it actually works. As of
|
||||
# March 2006, it is broken under DragonFly BSD.
|
||||
#
|
||||
|
||||
if test "$ac_cv_func_fwprintf" = yes; then
|
||||
|
||||
AC_MSG_CHECKING([if fwprintf is broken])
|
||||
AC_RUN_IFELSE(
|
||||
[
|
||||
AC_LANG_PROGRAM(
|
||||
[
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
#include <wchar.h>
|
||||
],
|
||||
[
|
||||
setlocale( LC_ALL, "" );
|
||||
fwprintf( stderr, L"%ls%ls", L"", L"fish:" );
|
||||
]
|
||||
)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([HAVE_BROKEN_FWPRINTF], [1], [Define to 1 one if the implemented fwprintf is broken])
|
||||
]
|
||||
)
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check for _nl_msg_cat_cntr symbol
|
||||
AC_MSG_CHECKING([for _nl_msg_cat_cntr symbol])
|
||||
AC_TRY_LINK(
|
||||
@@ -649,6 +361,7 @@ AC_TRY_LINK(
|
||||
#if HAVE_LIBINTL_H
|
||||
#include <libintl.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
],
|
||||
[
|
||||
extern int _nl_msg_cat_cntr;
|
||||
@@ -669,30 +382,6 @@ else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Check for __environ symbol
|
||||
AC_MSG_CHECKING([for __environ symbol])
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
#include <unistd.h>
|
||||
],
|
||||
[
|
||||
extern char **__environ;
|
||||
char **tmp = __environ;
|
||||
exit(tmp!=0);
|
||||
],
|
||||
have___environ=yes,
|
||||
have___environ=no
|
||||
)
|
||||
if test "$have___environ" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(
|
||||
[HAVE___ENVIRON],
|
||||
[1],
|
||||
[Define to 1 if the __environ symbol is exported.]
|
||||
)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Check for sys_errlist
|
||||
AC_MSG_CHECKING([for sys_errlist array])
|
||||
@@ -744,42 +433,6 @@ else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Check if getopt_long exists and works
|
||||
AC_MSG_CHECKING([if getopt_long exists and works])
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
#if HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
],
|
||||
[
|
||||
static struct option
|
||||
long_options[] =
|
||||
{
|
||||
0, 0, 0, 0
|
||||
}
|
||||
;
|
||||
int opt = getopt_long( 0,
|
||||
0,
|
||||
0,
|
||||
long_options,
|
||||
0 );
|
||||
|
||||
],
|
||||
have_working_getopt_long=yes,
|
||||
have_working_getopt_long=no
|
||||
)
|
||||
if test "$have_working_getopt_long" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(
|
||||
[HAVE_WORKING_GETOPT_LONG],
|
||||
[1],
|
||||
[Define to 1 if getopt_long exists and works.]
|
||||
)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Check for Solaris curses tputs having fixed length parameter list.
|
||||
AC_MSG_CHECKING([if we are using non varargs tparm.])
|
||||
AC_COMPILE_IFELSE(
|
||||
@@ -788,6 +441,8 @@ AC_COMPILE_IFELSE(
|
||||
[
|
||||
#if HAVE_NCURSES_H
|
||||
#include <ncurses.h>
|
||||
#elif HAVE_NCURSES_CURSES_H
|
||||
#include <ncurses/curses.h>
|
||||
#else
|
||||
#include <curses.h>
|
||||
#endif
|
||||
@@ -817,15 +472,124 @@ else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Tell the world what we know
|
||||
pcre2_min_version=10.21
|
||||
EXTRA_PCRE2=
|
||||
AC_ARG_WITH(
|
||||
included-pcre2,
|
||||
AS_HELP_STRING(
|
||||
[--without-included-pcre2],
|
||||
[build against the system PCRE2 library instead of the bundled version]
|
||||
),
|
||||
[included_pcre2=$withval],
|
||||
[included_pcre2=auto]
|
||||
)
|
||||
|
||||
if test "x$included_pcre2" != "xyes"; then
|
||||
|
||||
# test for pcre2-config
|
||||
# can use either pcre2-config or pkgconfig here but only implement the former for now
|
||||
AC_CHECK_PROG(PCRE2_CONFIG, pcre2-config, pcre2-config)
|
||||
|
||||
if test "x$PCRE2_CONFIG" != "x"; then
|
||||
dnl AC_MSG_CHECKING([for $WCHAR_T_BITS-bit PCRE2])
|
||||
XLIBS="$LIBS"
|
||||
LIBS="$LIBS "`$PCRE2_CONFIG --libs$WCHAR_T_BITS 2>/dev/null`
|
||||
XCXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS "`$PCRE2_CONFIG --cflags`
|
||||
|
||||
# cheat a bit here. the exact library is determined by $WCHAR_T_BITS,
|
||||
# and so AC_CHECK_LIB won't work (can't use a variable as library name)
|
||||
# AC_SEARCH_LIBS will use the existing $LIBS flags with no additional library first
|
||||
AC_SEARCH_LIBS([pcre2_compile_$WCHAR_T_BITS], [],
|
||||
[ # pcre2 lib found, check for minimum version
|
||||
pcre2_version=`$PCRE2_CONFIG --version`
|
||||
AS_VERSION_COMPARE([$pcre2_version], [$pcre2_min_version],
|
||||
[ # version < minimum
|
||||
AC_MSG_NOTICE([system PCRE2 library version $pcre2_version, need $pcre2_min_version or later])
|
||||
if test "x$included_pcre2" = "xno"; then
|
||||
# complain about pcre2 version
|
||||
AC_MSG_ERROR([system PCRE2 library is too old, but --without-included-pcre2 was given.])
|
||||
else
|
||||
# use the internal version; undo changes to LIBS/CXXFLAGS
|
||||
included_pcre2=yes
|
||||
LIBS="$XLIBS"
|
||||
CXXFLAGS="$XCXXFLAGS"
|
||||
fi
|
||||
],
|
||||
[ # version == minimum
|
||||
working_pcre2=yes
|
||||
],
|
||||
[ # version > minimum
|
||||
working_pcre2=yes
|
||||
]
|
||||
)
|
||||
],
|
||||
[ # fail case; undo the changes to LIBS/CXXFLAGS
|
||||
working_pcre2=no
|
||||
LIBS="$XLIBS"
|
||||
CXXFLAGS="$XCXXFLAGS"
|
||||
]
|
||||
)
|
||||
fi
|
||||
|
||||
if test "x$working_pcre2" = "xyes"; then
|
||||
AC_MSG_NOTICE([using system PCRE2 library])
|
||||
else
|
||||
# pcre2 size wrong or pcre2-config not found
|
||||
# is it OK to use the included version?
|
||||
if test "x$included_pcre2" = "xno"; then
|
||||
# complain
|
||||
AC_MSG_ERROR([cannot find system pcre2-config, but --without-included-pcre2 was given.
|
||||
Make sure pcre2-config is installed and available in PATH.
|
||||
You may need to install the PCRE2 development library for your system.])
|
||||
else
|
||||
# use the internal version
|
||||
included_pcre2=yes
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Re-test as value may have changed.
|
||||
if test "x$included_pcre2" = "xyes"; then
|
||||
# Build configure/Makefile for pcre2
|
||||
AC_MSG_NOTICE([using included PCRE2 library])
|
||||
# unfortunately these get added to the global configuration
|
||||
ac_configure_args="$ac_configure_args --disable-pcre2-8 --enable-pcre2-$WCHAR_T_BITS --disable-shared"
|
||||
AC_CONFIG_SUBDIRS([pcre2-10.21])
|
||||
|
||||
PCRE2_CXXFLAGS='-I$(PCRE2_DIR)/src'
|
||||
PCRE2_LIBS='-L$(PCRE2_LIBDIR) -lpcre2-$(PCRE2_WIDTH)'
|
||||
|
||||
# Make the binary depend on the PCRE2 libraries so they get built
|
||||
EXTRA_PCRE2='$(PCRE2_LIB)'
|
||||
CXXFLAGS="$CXXFLAGS $PCRE2_CXXFLAGS"
|
||||
LIBS="$LIBS $PCRE2_LIBS"
|
||||
fi
|
||||
|
||||
# Allow configurable extra directories.
|
||||
AC_SUBST(extra_completionsdir)
|
||||
AC_ARG_WITH([extra-completionsdir],
|
||||
AS_HELP_STRING([--with-extra-completionsdir=DIR],
|
||||
[path for extra completions]),
|
||||
[extra_completionsdir=$withval],
|
||||
[extra_completionsdir='${datadir}/fish/vendor_completions.d'])
|
||||
|
||||
AC_SUBST(extra_functionsdir)
|
||||
AC_ARG_WITH([extra_functionsdir],
|
||||
AS_HELP_STRING([--with-extra-functionsdir=DIR],
|
||||
[path for extra functions]),
|
||||
[extra_functionsdir=$withval],
|
||||
[extra_functionsdir='${datadir}/fish/vendor_functions.d'])
|
||||
|
||||
AC_SUBST(extra_confdir)
|
||||
AC_ARG_WITH([extra-confdir],
|
||||
AS_HELP_STRING([--with-extra-confdir=DIR],
|
||||
[path for extra conf]),
|
||||
[extra_confdir=$withval],
|
||||
[extra_confdir='${datadir}/fish/vendor_conf.d'])
|
||||
|
||||
# Tell the world what we know.
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
if test ! x$local_found_posix_switch = xyes; then
|
||||
echo "Can't find a combination of switches to enable common extensions like detecting window size."
|
||||
echo "Some fish features may be disabled."
|
||||
fi
|
||||
|
||||
echo "fish is now configured."
|
||||
echo "Use 'make' and 'make install' to build and install fish."
|
||||
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- python -*-
|
||||
|
||||
# Program to generate fish completion function for wajig.
|
||||
# It runs 'wajig command' and analyzes the output to build a
|
||||
# completion file which it writes to stdout.
|
||||
# To use the result, direct stdout to
|
||||
# ~/.fish.d/completions/wajig.fish.
|
||||
|
||||
# Author Reuben Thomas, from Don Rozenberg's bash_completion.py and
|
||||
# fish's apt-get.fish.
|
||||
|
||||
import os
|
||||
import re
|
||||
import pprint
|
||||
pp = pprint.PrettyPrinter()
|
||||
|
||||
def escape_quotes(s):
|
||||
return re.sub('\'', '\\\'', s)
|
||||
|
||||
# Run wajig command
|
||||
f = os.popen('wajig commands', 'r')
|
||||
|
||||
lines = f.readlines()
|
||||
|
||||
option_patt = r'^-([a-z]*)\|--([a-z]*) +([^ ].*)'
|
||||
option_patt_r = re.compile(option_patt)
|
||||
|
||||
command_patt = r'^([a-z-]*) +([^ ].*)'
|
||||
command_patt_r = re.compile(command_patt)
|
||||
|
||||
os_str = []
|
||||
os_str.append('')
|
||||
ol_str = []
|
||||
ol_str.append('')
|
||||
oh_str = []
|
||||
oh_str.append('')
|
||||
o_i = 0
|
||||
|
||||
c_str = []
|
||||
c_str.append('')
|
||||
ch_str = []
|
||||
ch_str.append('')
|
||||
c_i = 0
|
||||
|
||||
for l in lines:
|
||||
l = l.strip()
|
||||
if l == '' or l.find(':') > -1 or l.find('Run') == 0:
|
||||
continue
|
||||
if l.find('-') == 0:
|
||||
mo = option_patt_r.search(l)
|
||||
if mo == None:
|
||||
continue
|
||||
os_str[o_i] = mo.group(1)
|
||||
os_str.append('')
|
||||
ol_str[o_i] = mo.group(2)
|
||||
ol_str.append('')
|
||||
oh_str[o_i] = escape_quotes(mo.group(3))
|
||||
oh_str.append('')
|
||||
o_i += 1
|
||||
else:
|
||||
mo = command_patt_r.search(l)
|
||||
if mo == None:
|
||||
continue
|
||||
c_str[c_i] = mo.group(1)
|
||||
c_str.append('')
|
||||
ch_str[c_i] = escape_quotes(mo.group(2))
|
||||
ch_str.append('')
|
||||
c_i += 1
|
||||
|
||||
# For debugging, print the commands and options.
|
||||
#print
|
||||
#pp.pprint(c_str)
|
||||
|
||||
#print
|
||||
#pp.pprint(os_str)
|
||||
#print
|
||||
#pp.pprint(ol_str)
|
||||
|
||||
part1 = '''function __fish_wajig_no_subcommand -d (N_ 'Test if wajig has yet to be given the subcommand')
|
||||
for i in (commandline -opc)
|
||||
if contains -- $i'''
|
||||
|
||||
part2 = '''
|
||||
return 1
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function __fish_wajig_use_package -d (N_ 'Test if wajig command should have packages as potential completion')
|
||||
for i in (commandline -opc)
|
||||
if contains -- $i contains bug build build-depend changelog dependents describe detail hold install installr installrs installs list list-files news package purge purge-depend readme recursive recommended reconfigure reinstall remove remove-depend repackage show showinstall showremove showupgrade size sizes source suggested unhold upgrade versions whatis
|
||||
return 0
|
||||
end
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
complete -c wajig -n '__fish_wajig_use_package' -a '(__fish_print_packages)' -d (N_ 'Package')'''
|
||||
|
||||
wajig = part1
|
||||
|
||||
#add the commands.
|
||||
for i in range(0, len(c_str) - 1):
|
||||
wajig = "%s %s" % (wajig, c_str[i])
|
||||
|
||||
#add part2
|
||||
wajig = "%s%s" % (wajig, part2)
|
||||
|
||||
#add the options.
|
||||
wajig = "%s%s" % (wajig, os_str[0].lstrip())
|
||||
for i in range(1, len(os_str) - 1):
|
||||
wajig = "%s\ncomplete -c apt-get -s %s -l %s -d (N_ '%s')" % (wajig, os_str[i], ol_str[i], oh_str[i])
|
||||
|
||||
#add the commands.
|
||||
for i in range(0, len(c_str) - 1):
|
||||
wajig = "%s\ncomplete -f -n '__fish_wajig_no_subcommand' -c wajig -a '%s' -d(N_ '%s')" % (wajig, c_str[i], ch_str[i])
|
||||
|
||||
#print it all
|
||||
print wajig
|
||||
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
44
debian/control
vendored
Normal file
44
debian/control
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
Source: fish
|
||||
Section: shells
|
||||
Priority: extra
|
||||
Maintainer: ridiculous_fish <corydoras@ridiculousfish.com>
|
||||
Uploaders: David Adam <zanchey@ucc.gu.uwa.edu.au>
|
||||
Build-Depends: debhelper (>= 8.0.0), libncurses5-dev, autoconf, autotools-dev, dh-autoreconf, gettext
|
||||
# When libpcre2-dev is available on all supported Debian versions, add a dependency on that.
|
||||
Standards-Version: 3.9.4
|
||||
Homepage: http://fishshell.com/
|
||||
Vcs-Git: git://github.com/fish-shell/fish-shell.git
|
||||
Vcs-Browser: https://github.com/fish-shell/fish-shell
|
||||
|
||||
Package: fish
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, fish-common (= ${source:Version}), passwd (>= 4.0.3-10), bc, gettext-base, man-db
|
||||
Recommends: xsel (>=1.2.0), xdg-utils
|
||||
Description: friendly interactive shell
|
||||
Fish is a command-line shell for modern systems, focusing on user-friendliness,
|
||||
sensibility and discoverability in interactive use. The syntax is simple, but
|
||||
not POSIX compliant.
|
||||
|
||||
Package: fish-common
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}
|
||||
Recommends: fish, python (>=2.6), xdg-utils
|
||||
Replaces: fish (<= 2.1.1.dfsg-2)
|
||||
Description: friendly interactive shell (architecture-independent files)
|
||||
Fish is a command-line shell for modern systems, focusing on user-friendliness,
|
||||
sensibility and discoverability in interactive use. The syntax is simple, but
|
||||
not POSIX compliant.
|
||||
.
|
||||
This package contains the common fish files shared by all architectures.
|
||||
|
||||
Package: fish-dbg
|
||||
Architecture: any
|
||||
Section: debug
|
||||
Priority: extra
|
||||
Depends: fish (= ${binary:Version}), ${misc:Depends}
|
||||
Description: debugging symbols for friendly interactive shell
|
||||
Fish is a command-line shell for modern systems, focusing on user-friendliness,
|
||||
sensibility and discoverability in interactive use. The syntax is simple, but
|
||||
not POSIX compliant.
|
||||
.
|
||||
This package contains the debugging symbols for fish.
|
||||
101
debian/copyright
vendored
Normal file
101
debian/copyright
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
This work was packaged for Debian by David Adam <zanchey@ucc.gu.uwa.edu.au>
|
||||
on Thu, 14 Jun 2012 20:33:34 +0800, based on work by James Vega
|
||||
<jamessan@jamessan.com>. Modifications from the downstream Debian maintainer,
|
||||
Tristan Seligmann <mithrandi@debian.org>, have also been included.
|
||||
|
||||
It was downloaded from:
|
||||
|
||||
https://github.com/fish-shell/fish-shell
|
||||
|
||||
Upstream Authors:
|
||||
|
||||
Axel Liljencrantz
|
||||
ridiculous_fish
|
||||
|
||||
Copyright:
|
||||
|
||||
Copyright (C) 2005-2008 Axel Liljencrantz
|
||||
Copyright (C) 2011-2012 ridiculous_fish
|
||||
|
||||
License:
|
||||
|
||||
Copyright (C) 2005-2008 Axel Liljencrantz
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA.
|
||||
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
|
||||
|
||||
Fish contains code from the PCRE2 library to support regular expressions. This
|
||||
code, created by Philip Hazel, is distributed under the terms of the BSD
|
||||
license. Copyright © 1997-2015 University of Cambridge.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
- 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.
|
||||
|
||||
- Neither the name of the University of Cambridge nor the names of any
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
|
||||
Fish also contains small amounts of code under the OpenBSD license, namely a
|
||||
version of the function strlcpy, modified for use with wide character strings.
|
||||
This code is copyrighted by Todd C. Miller (1998). It also contains code from
|
||||
tmux, copyrighted by Nicholas Marriott <nicm@users.sourceforge.net> (2007), and
|
||||
made available under an identical license.
|
||||
|
||||
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.
|
||||
|
||||
Fish contains code from the glibc library, namely the wcstok function
|
||||
in fallback.c. This code is licensed under the LGPL.
|
||||
|
||||
On Debian systems, the complete text of the GNU Lesser General
|
||||
Public License can be found in `/usr/share/common-licenses/LGPL'.
|
||||
|
||||
The Debian packaging is:
|
||||
|
||||
Copyright (C) 2005 James Vega <jamessan@jamessan.com>
|
||||
Copyright (C) 2012 David Adam <zanchey@ucc.gu.uwa.edu.au>
|
||||
Copyright (C) 2015 Tristan Seligmann <mithrandi@debian.org>
|
||||
|
||||
and is licensed under the GPL version 2, see above.
|
||||
11
debian/fish-common.doc-base
vendored
Normal file
11
debian/fish-common.doc-base
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
Document: fish
|
||||
Title: Debian fish Manual
|
||||
Author: Axel Liljencrantz <axel@liljencrantz.se>
|
||||
Abstract: This guide documents fish, a shell
|
||||
geared towards interactive use.
|
||||
Section: Shells
|
||||
|
||||
Format: HTML
|
||||
Index: /usr/share/doc/fish/index.html
|
||||
Files: /usr/share/doc/fish/*.html
|
||||
|
||||
1
debian/fish-common.docs
vendored
Normal file
1
debian/fish-common.docs
vendored
Normal file
@@ -0,0 +1 @@
|
||||
README.md
|
||||
2
debian/fish-common.install
vendored
Normal file
2
debian/fish-common.install
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
debian/tmp/etc
|
||||
debian/tmp/usr/share
|
||||
4
debian/fish-common.lintian-overrides
vendored
Normal file
4
debian/fish-common.lintian-overrides
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# These directories are intentionally empty.
|
||||
fish-common: package-contains-empty-directory usr/share/fish/vendor_completions.d/
|
||||
fish-common: package-contains-empty-directory usr/share/fish/vendor_conf.d/
|
||||
fish-common: package-contains-empty-directory usr/share/fish/vendor_functions.d/
|
||||
1
debian/fish.install
vendored
Normal file
1
debian/fish.install
vendored
Normal file
@@ -0,0 +1 @@
|
||||
debian/tmp/usr/bin
|
||||
47
debian/fish.postinst
vendored
Normal file
47
debian/fish.postinst
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/bin/sh
|
||||
# postinst script for fish
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postinst> `configure' <most-recently-configured-version>
|
||||
# * <old-postinst> `abort-upgrade' <new version>
|
||||
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
|
||||
# <new-version>
|
||||
# * <postinst> `abort-remove'
|
||||
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
|
||||
# <failed-install-package> <version> `removing'
|
||||
# <conflicting-package> <version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
add_shell() {
|
||||
if ! type add-shell > /dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
|
||||
add-shell /usr/bin/fish
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
add_shell
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
37
debian/fish.postrm
vendored
Normal file
37
debian/fish.postrm
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/bin/sh
|
||||
# postrm script for fish
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postrm> `remove'
|
||||
# * <postrm> `purge'
|
||||
# * <old-postrm> `upgrade' <new-version>
|
||||
# * <new-postrm> `failed-upgrade' <old-version>
|
||||
# * <new-postrm> `abort-install'
|
||||
# * <new-postrm> `abort-install' <old-version>
|
||||
# * <new-postrm> `abort-upgrade' <old-version>
|
||||
# * <disappearer's-postrm> `disappear' <overwriter>
|
||||
# <overwriter-version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
|
||||
case "$1" in
|
||||
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postrm called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
46
debian/fish.prerm
vendored
Normal file
46
debian/fish.prerm
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
# prerm script for fish
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <prerm> `remove'
|
||||
# * <old-prerm> `upgrade' <new-version>
|
||||
# * <new-prerm> `failed-upgrade' <old-version>
|
||||
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
|
||||
# * <deconfigured's-prerm> `deconfigure' `in-favour'
|
||||
# <package-being-installed> <version> `removing'
|
||||
# <conflicting-package> <version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
remove_shell() {
|
||||
if ! type remove-shell > /dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
|
||||
remove-shell /usr/bin/fish
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
remove|deconfigure)
|
||||
remove_shell
|
||||
;;
|
||||
|
||||
upgrade|failed-upgrade)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "prerm called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
2
debian/menu
vendored
Normal file
2
debian/menu
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
?package(fish):needs="text" section="Applications/Shells"\
|
||||
title="fish" command="/usr/bin/fish"
|
||||
22
debian/rules
vendored
Executable file
22
debian/rules
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
export DH_VERBOSE=1
|
||||
|
||||
# dpkg-dev 1.16.1 doesn't export buildflags
|
||||
# can be removed once on dh compat level 9
|
||||
DPKG_EXPORT_BUILDFLAGS = 1
|
||||
-include /usr/share/dpkg/buildflags.mk
|
||||
|
||||
%:
|
||||
dh $@ --with autotools-dev,autoreconf
|
||||
|
||||
override_dh_installdocs:
|
||||
dh_installdocs --link-doc=fish
|
||||
|
||||
override_dh_strip:
|
||||
dh_strip --dbg-package=fish-dbg
|
||||
|
||||
# Don't run tests; they don't work until fish is installed
|
||||
override_dh_auto_test:
|
||||
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
||||
@@ -1,6 +1,6 @@
|
||||
# Formatting guide for fish docs
|
||||
|
||||
The fish documentation has been updated to support Doxygen 1.8.7+, and while the main benefit of this change is extensive Markdown support, the addition of a fish lexicon and syntax filter, combined with semantic markup rules allows for automatic formatting enhancements across the HTML user_docs, the developer docs and the man pages.
|
||||
The fish documentation has been updated to support Doxygen 1.8.7+, and while the main benefit of this change is extensive Markdown support, the addition of a fish lexicon and syntax filter, combined with semantic markup rules allows for automatic formatting enhancements across the HTML user_docs and man pages.
|
||||
|
||||
Initially my motivation was to fix a problem with long options ([Issue #1557](https://github.com/fish-shell/fish-shell/issues/1557) on GitHub), but as I worked on fixing the issue I realised there was an opportunity to simplify, reinforce and clarify the current documentation, hopefully making further contribution easier and cleaner, while allowing the documentation examples to presented more clearly with less author effort.
|
||||
|
||||
@@ -56,18 +56,14 @@ is transformed into:
|
||||
|
||||
`@cmnd{echo} @args{hello} @args{world}`
|
||||
|
||||
which is then transformed by Doxygen into an HTML version (`make user_doc`):
|
||||
which is then transformed by Doxygen into an HTML version (`make doc`):
|
||||
|
||||
`<span class="command">echo</span> <span class="argument">hello</span> <span class="argument">world</span>`
|
||||
|
||||
A man page version (`make share/man`):
|
||||
And a man page version (`make share/man`):
|
||||
|
||||
__echo__ hello world
|
||||
|
||||
And a simple HTML version for the developer docs (`make doc`) and the LATEX/PDF manual (`make doc/refman.pdf`):
|
||||
|
||||
`echo hello world`
|
||||
|
||||
### Fonts
|
||||
|
||||
In older browsers, it was easy to set the fonts used for the three basic type styles (serif, sans-serif and monospace). Modern browsers have removed these options in their respective quests for simplification, assuming the content author will provide suitable styles for the content in the site's CSS, or the end user will provide overriding styles manually. Doxygen's default styling is very simple and most users will just accept this default.
|
||||
@@ -154,19 +150,25 @@ The following can be used in \\fish blocks to render some fish scenarios. These
|
||||
|
||||
### Custom formatting tags
|
||||
|
||||
- `<s>`: auto\<s\>suggestion\</s\>.
|
||||
- `<m>`: \<m\>Matched\</m\> items, such as tab completions.
|
||||
- `<sm>`: Matched items \<sm\>searched\<sm\> for, like grep results.
|
||||
- `<error>`: \<error\>This would be shown as an error.\</error\>
|
||||
- `<asis>`: \<asis\>This test will not be parsed for fish markup.\</asis\>
|
||||
- `<outp>`: \<outp\>This would be rendered as command/script output.\</outp\>
|
||||
```html
|
||||
<u>: <u>These words are underlined.</u>
|
||||
<s>: auto<s>suggestion</s>.
|
||||
<m>: <m>Matched</m> items, such as tab completions.
|
||||
<sm>: Matched items <sm>searched</sm> for, like grep results.
|
||||
<bs>: Render the contents with a preceding backslash. Useful when presenting output.
|
||||
<error>: <error>This would be shown as an error.</error>
|
||||
<asis>: <asis>This text will not be parsed for fish markup.</asis>
|
||||
<outp>: <outp>This would be rendered as command/script output.</outp>
|
||||
{{ and }}: Required when wanting curly braces in regular expression example.
|
||||
```
|
||||
|
||||
### Prompts and cursors
|
||||
|
||||
- `>_`: Display a basic prompt.
|
||||
- `~>_`: Display a prompt with a the home directory as the current working directory.
|
||||
- `___` (3 underscores): Display a cursor.
|
||||
|
||||
```html
|
||||
>_: Display a basic prompt.
|
||||
~>_: Display a prompt with a the home directory as the current working directory.
|
||||
___ (3 underscores): Display a cursor.
|
||||
```
|
||||
|
||||
### Keyboard shortcuts: @key{} and @cursor_key{}
|
||||
|
||||
@@ -248,15 +250,4 @@ end
|
||||
# NOT PORTABLE! Paths would be need to be updated on other systems.
|
||||
```
|
||||
|
||||
### Developer docs and LATEX/PDF output
|
||||
|
||||
- HTML developer docs tested on Ubuntu 14.04, CentOS 6.5 and Mac OS X 10.9.
|
||||
- LATEX/PDF reference manual tested on Mac OS X 10.9 using MacTEX. PDF production returns an error (due to Doxygen's use of an outdated 'float' package), but manual PDF output is ok.
|
||||
|
||||
### Future changes
|
||||
|
||||
1. The documentation creation process would be better if it could be modularised further and moved out of the makefile into a number of supporting scripts. This would allow both the automake and Xcode build processes to use the documentation scripts directly.
|
||||
2. Remove the Doxygen dependency entirely for the user documentation. This would be very acheivable now that the bulk of the documentation is in Markdown.
|
||||
3. It would be useful to gauge what parts of the documentation are actually used by users. Judging by the amount of 'missing comment' errors during the developer docs build phase, this aspect of the docs has been rather neglected. If it is not longer used or useful, then this could change the future direction of the documentation and significantly streamline the process.
|
||||
|
||||
#### Author: Mark Griffiths [@GitHub](https://github.com/MarkGriffiths)
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
\subsection abbr-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
abbr -a word="phrase"
|
||||
abbr -s
|
||||
abbr -l
|
||||
abbr -e word
|
||||
abbr --add word phrase...
|
||||
abbr --show
|
||||
abbr --list
|
||||
abbr --erase word
|
||||
\endfish
|
||||
|
||||
\subsection abbr-description Description
|
||||
@@ -14,11 +14,24 @@ abbr -e word
|
||||
|
||||
Abbreviations are user-defined character sequences or words that are replaced with longer phrases after they are entered. For example, a frequently-run command such as `git checkout` can be abbreviated to `gco`. After entering `gco` and pressing @key{Space} or @key{Enter}, the full text `git checkout` will appear in the command line.
|
||||
|
||||
Abbreviations are stored, by default, in a universal variable.
|
||||
Abbreviations are stored in a variable named `fish_user_abbreviations`. This is automatically created as a universal variable the first time an abbreviation is created. If you want your abbreviations to be private to a particular fish session you can put the following in your *~/.config/fish/config.fish* file before you define your first abbrevation:
|
||||
|
||||
\fish
|
||||
if status --is-interactive
|
||||
set -g fish_user_abbreviations
|
||||
abbr --add first 'echo my first abbreviation'
|
||||
abbr --add second 'echo my second abbreviation'
|
||||
# etcetera
|
||||
end
|
||||
\endfish
|
||||
|
||||
You can create abbreviations directly on the command line and they will be saved automatically and made visible to other fish sessions if `fish_user_abbreviations` is a universal variable. If you keep the variable as universal, `abbr --add` statements in <a href="tutorial.html#tut_startup">config.fish</a> will do nothing but slow down startup slightly.
|
||||
|
||||
\subsection abbr-options Options
|
||||
|
||||
The following parameters are available:
|
||||
|
||||
- `-a WORD PHRASE` or `--add WORD PHRASE` Adds a new abbreviation, where WORD will be expanded to PHRASE.
|
||||
- `-a WORD PHRASE` or `--add WORD PHRASE` Adds a new abbreviation, causing WORD to be expanded to PHRASE.
|
||||
|
||||
- `-s` or `--show` Show all abbreviated words and their expanded phrases in a manner suitable for export and import.
|
||||
|
||||
@@ -26,6 +39,8 @@ The following parameters are available:
|
||||
|
||||
- `-e WORD` or `--erase WORD` Erase the abbreviation WORD.
|
||||
|
||||
Note: fish version 2.1 supported `-a WORD=PHRASE`. This syntax is now deprecated but will still be converted.
|
||||
|
||||
\subsection abbr-example Examples
|
||||
|
||||
\fish
|
||||
|
||||
@@ -18,6 +18,8 @@ alias NAME=DEFINITION
|
||||
|
||||
You cannot create an alias to a function with the same name.
|
||||
|
||||
Note that spaces need to be escaped in the call to alias just like in the commandline _even inside the quotes_.
|
||||
|
||||
|
||||
\subsection alias-example Example
|
||||
|
||||
@@ -31,4 +33,8 @@ alias rmi "rm -i"
|
||||
function rmi
|
||||
rm -i $argv
|
||||
end
|
||||
|
||||
# This needs to have the spaces escaped or "Chrome.app..." will be seen as an argument to "/Applications/Google":
|
||||
|
||||
alias chrome='/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome banana'
|
||||
\endfish
|
||||
|
||||
@@ -7,12 +7,11 @@ COMMAND1; and COMMAND2
|
||||
|
||||
\subsection and-description Description
|
||||
|
||||
`and` is used to execute a command if the current exit status (as set by the last previous command) is 0.
|
||||
`and` is used to execute a command if the current exit status (as set by the previous command) is 0.
|
||||
|
||||
`and` does not change the current exit status.
|
||||
|
||||
The exit status of the last foreground command to exit can always be accessed using the <a href="index.html#variables-status">$status</a> variable.
|
||||
`and` statements may be used as part of the condition in an <a href="#if">`if`</a> or <a href="#while">`while`</a> block. See the documentation for <a href="#if">`if`</a> and <a href="#while">`while`</a> for examples.
|
||||
|
||||
`and` does not change the current exit status. The exit status of the last foreground command to exit can always be accessed using the <a href="index.html#variables-status">$status</a> variable.
|
||||
|
||||
\subsection and-example Example
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 12 KiB |
@@ -31,7 +31,7 @@ When multiple `COMMAND`s are provided, they are all run in the specified order w
|
||||
|
||||
If no `SEQUENCE` is provided, all bindings (or just the bindings in the specified `MODE`) are printed. If `SEQUENCE` is provided without `COMMAND`, just the binding matching that sequence is printed.
|
||||
|
||||
Key bindings are not saved between sessions by default. To save custom keybindings, edit the `fish_user_key_bindings` function and insert the appropriate `bind` statements.
|
||||
Key bindings are not saved between sessions by default. **Bare `bind` statements in <a href="index.html#initialization">config.fish</a> won't have any effect because it is sourced before the default keybindings are setup.** To save custom keybindings, put the `bind` statements into a function called `fish_user_key_bindings`, which will be <a href="tutorial.html#tut_autoload">autoloaded</a>.
|
||||
|
||||
Key bindings may use "modes", which mimics Vi's modal input behavior. The default mode is "default", and every bind applies to a single mode. The mode can be viewed/changed with the `$fish_bind_mode` variable.
|
||||
|
||||
@@ -53,12 +53,20 @@ The following parameters are available:
|
||||
|
||||
The following special input functions are available:
|
||||
|
||||
- `accept-autosuggestion`, accept the current autosuggestion completely
|
||||
|
||||
- `backward-char`, moves one character to the left
|
||||
|
||||
- `backward-bigword`, move one whitespace-delimited word to the left
|
||||
|
||||
- `backward-delete-char`, deletes one character of input to the left of the cursor
|
||||
|
||||
- `backward-kill-bigword`, move the whitespace-delimited word to the left of the cursor to the killring
|
||||
|
||||
- `backward-kill-line`, move everything from the beginning of the line to the cursor to the killring
|
||||
|
||||
- `backward-kill-path-component`, move one path component to the left of the cursor (everything from the last "/" or whitespace exclusive) to the killring
|
||||
|
||||
- `backward-kill-word`, move the word to the left of the cursor to the killring
|
||||
|
||||
- `backward-word`, move one word to the left
|
||||
@@ -67,23 +75,25 @@ The following special input functions are available:
|
||||
|
||||
- `beginning-of-line`, move to the beginning of the line
|
||||
|
||||
- `begin-selection`, start selecting text
|
||||
|
||||
- `capitalize-word`, make the current word begin with a capital letter
|
||||
|
||||
- `complete`, guess the remainder of the current token
|
||||
|
||||
- `complete-and-search`, invoke the searchable pager on completion options
|
||||
|
||||
- `delete-char`, delete one character to the right of the cursor
|
||||
|
||||
- `delete-line`, delete the entire line
|
||||
|
||||
- `downcase-word`, make the current word lowercase
|
||||
|
||||
- `dump-functions`, print a list of all key-bindings
|
||||
|
||||
- `end-of-history`, move to the end of the history
|
||||
|
||||
- `end-of-line`, move to the end of the line
|
||||
|
||||
- `explain`, print a description of possible problems with the current command
|
||||
- `end-selection`, end selecting text
|
||||
|
||||
- `forward-bigword`, move one whitespace-delimited word to the right
|
||||
|
||||
- `forward-char`, move one character to the right
|
||||
|
||||
@@ -93,12 +103,24 @@ The following special input functions are available:
|
||||
|
||||
- `history-search-forward`, search the history for the next match
|
||||
|
||||
- `kill-bigword`, move the next whitespace-delimited word to the killring
|
||||
|
||||
- `kill-line`, move everything from the cursor to the end of the line to the killring
|
||||
|
||||
- `kill-selection`, move the selected text to the killring
|
||||
|
||||
- `kill-whole-line`, move the line to the killring
|
||||
|
||||
- `kill-word`, move the next word to the killring
|
||||
|
||||
- `suppress-autosuggestion`, remove the current autosuggestion
|
||||
|
||||
- `swap-selection-start-stop`, go to the other end of the highlighted text without changing the selection
|
||||
|
||||
- `transpose-chars`, transpose two characters to the left of the cursor
|
||||
|
||||
- `transpose-words`, transpose two words to the left of the cursor
|
||||
|
||||
- `upcase-word`, make the current word uppercase
|
||||
|
||||
- `yank`, insert the latest entry of the killring into the buffer
|
||||
@@ -109,7 +131,7 @@ The following special input functions are available:
|
||||
\subsection bind-example Examples
|
||||
|
||||
\fish
|
||||
bind \cd 'exit'
|
||||
bind <asis>\\cd</asis> 'exit'
|
||||
\endfish
|
||||
Causes `fish` to exit when @key{Control,D} is pressed.
|
||||
|
||||
@@ -120,6 +142,15 @@ Performs a history search when the @key{Page Up} key is pressed.
|
||||
|
||||
\fish
|
||||
set -g fish_key_bindings fish_vi_key_bindings
|
||||
bind -M insert \cc kill-whole-line force-repaint
|
||||
bind -M insert \\cc kill-whole-line force-repaint
|
||||
\endfish
|
||||
Turns on Vi key bindings and rebinds @key{Control,C} to clear the input line.
|
||||
|
||||
|
||||
\subsection special-case-escape Special Case: The escape Character
|
||||
|
||||
The escape key can be used standalone, for example, to switch from insertion mode to normal mode when using Vi keybindings. Escape may also be used as a "meta" key, to indicate the start of an escape sequence, such as function or arrow keys. Custom bindings can also be defined that begin with an escape character.
|
||||
|
||||
fish waits for a period after receiving the escape character, to determine whether it is standalone or part of an escape sequence. While waiting, additional key presses make the escape key behave as a meta key. If no other key presses come in, it is handled as a standalone escape. The waiting period is set to 300 milliseconds (0.3 seconds) in the default key bindings and 10 milliseconds in the vi key bindings. It can be configured by setting the `fish_escape_delay_ms` variable to a value between 10 and 5000 ms. It is recommended that this be a universal variable that you set once from an interactive session.
|
||||
|
||||
Note: fish 2.2.0 and earlier used a default of 10 milliseconds, and provided no way to configure it. That effectively made it impossible to use escape as a meta key.
|
||||
|
||||
@@ -14,6 +14,7 @@ If `DIRECTORY` is a relative path, the paths found in the `CDPATH` environment v
|
||||
|
||||
Note that the shell will attempt to change directory without requiring `cd` if the name of a directory is provided (starting with `.`, `/` or `~`, or ending with `/`).
|
||||
|
||||
Fish also ships a wrapper function around the builtin `cd` that understands `cd -` as changing to the previous directory. See also <a href="commands.html#prevd">`prevd`</a>. This wrapper function maintains a history of the 25 most recently visited directories in the `$dirprev` and `$dirnext` global variables.
|
||||
|
||||
\subsection cd-example Examples
|
||||
|
||||
|
||||
@@ -57,3 +57,24 @@ The following options output metadata about the commandline state:
|
||||
\subsection commandline-example Example
|
||||
|
||||
`commandline -j $history[3]` replaces the job under the cursor with the third item from the command line history.
|
||||
|
||||
If the commandline contains
|
||||
\fish
|
||||
>_ echo $fl___ounder >&2 | less; and echo $catfish
|
||||
\endfish
|
||||
|
||||
(with the cursor on the "o" of "flounder")
|
||||
|
||||
Then the following invocations behave like this:
|
||||
\fish
|
||||
>_ commandline -t
|
||||
$flounder
|
||||
>_ commandline -ct
|
||||
$fl
|
||||
>_ commandline -b # or just commandline
|
||||
echo $flounder >&2 | less; and echo $catfish
|
||||
>_ commandline -p
|
||||
echo $flounder >&2
|
||||
>_ commandline -j
|
||||
echo $flounder >&2 | less
|
||||
\endfish
|
||||
|
||||
@@ -3,11 +3,18 @@
|
||||
\subsection complete-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
complete ( -c | --command | -p | --path ) COMMAND
|
||||
[( -s | --short-option ) SHORT_OPTION]
|
||||
[( -l | --long-option | -o | --old-option ) LONG_OPTION]
|
||||
[( -c | --command | -p | --path ) COMMAND]...
|
||||
[( -e | --erase )]
|
||||
[( -s | --short-option ) SHORT_OPTION]...
|
||||
[( -l | --long-option | -o | --old-option ) LONG_OPTION]...
|
||||
[( -a | --arguments ) OPTION_ARGUMENTS]
|
||||
[( -w | --wraps ) WRAPPED_COMMAND]
|
||||
[( -f | --no-files )]
|
||||
[( -r | --require-parameter )]
|
||||
[( -x | --exclusive )]
|
||||
[( -w | --wraps ) WRAPPED_COMMAND]...
|
||||
[( -n | --condition ) CONDITION]
|
||||
[( -d | --description ) DESCRIPTION]
|
||||
complete ( -C[STRING] | --do-complete[=STRING] )
|
||||
\endfish
|
||||
|
||||
\subsection complete-description Description
|
||||
@@ -22,31 +29,37 @@ the fish manual.
|
||||
|
||||
- `LONG_OPTION` is a multi character option for the command.
|
||||
|
||||
- `OPTION_ARGUMENTS` is parameter containing a space-separated list of possible option-arguments, which may contain subshells.
|
||||
- `OPTION_ARGUMENTS` is parameter containing a space-separated list of possible option-arguments, which may contain command substitutions.
|
||||
|
||||
- `DESCRIPTION` is a description of what the option and/or option arguments do.
|
||||
|
||||
- `-C STRING` or `--do-complete=STRING` makes complete try to find all possible completions for the specified string.
|
||||
- `-c COMMAND` or `--command COMMAND` specifies that `COMMAND` is the name of the command.
|
||||
|
||||
- `-w WRAPPED_COMMAND` or `--wraps=WRAPPED_COMMAND` causes the specified command to inherit completions from the wrapped command.
|
||||
- `-p COMMAND` or `--path COMMAND` specifies that `COMMAND` is the absolute path of the program (optionally containing wildcards).
|
||||
|
||||
- `-e` or `--erase` implies that the specified completion should be deleted.
|
||||
- `-e` or `--erase` deletes the specified completion.
|
||||
|
||||
- `-f` or `--no-files` specifies that the option specified by this completion may not be followed by a filename.
|
||||
- `-s SHORT_OPTION` or `--short-option=SHORT_OPTION` adds a short option to the completions list.
|
||||
|
||||
- `-l LONG_OPTION` or `--long-option=LONG_OPTION` adds a GNU style long option to the completions list.
|
||||
|
||||
- `-o LONG_OPTION` or `--old-option=LONG_OPTION` adds an old style long option to the completions list (See below for details).
|
||||
|
||||
- `-a OPTION_ARGUMENTS` or `--arguments=OPTION_ARGUMENTS` adds the specified option arguments to the completions list.
|
||||
|
||||
- `-f` or `--no-files` specifies that the options specified by this completion may not be followed by a filename.
|
||||
|
||||
- `-r` or `--require-parameter` specifies that the options specified by this completion always must have an option argument, i.e. may not be followed by another option.
|
||||
|
||||
- `-x` or `--exclusive` implies both `-r` and `-f`.
|
||||
|
||||
- `-w WRAPPED_COMMAND` or `--wraps=WRAPPED_COMMAND` causes the specified command to inherit completions from the wrapped command (See below for details).
|
||||
|
||||
- `-n` or `--condition` specifies a shell command that must return 0 if the completion is to be used. This makes it possible to specify completions that should only be used in some cases.
|
||||
|
||||
- `-o` or `--old-option` implies that the command uses old long style options with only one dash.
|
||||
- `-CSTRING` or `--do-complete=STRING` makes complete try to find all possible completions for the specified string.
|
||||
|
||||
- `-p` or `--path` implies that the string `COMMAND` is the full path of the command.
|
||||
|
||||
- `-r` or `--require-parameter` specifies that the option specified by this completion always must have an option argument, i.e. may not be followed by another option.
|
||||
|
||||
- `-u` or `--unauthoritative` implies that there may be more options than the ones specified, and that fish should not assume that options not listed are spelling errors.
|
||||
|
||||
- `-A` or `--authoritative` implies that there may be no more options than the ones specified, and that fish should assume that options not listed are spelling errors.
|
||||
|
||||
- `-x` or `--exclusive` implies both `-r` and `-f`.
|
||||
- `-C` or `--do-complete` with no argument makes complete try to find all possible completions for the current command line buffer. If the shell is not in interactive mode, an error is returned.
|
||||
|
||||
Command specific tab-completions in `fish` are based on the notion of options and arguments. An option is a parameter which begins with a hyphen, such as '`-h`', '`-help`' or '`--help`'. Arguments are parameters that do not begin with a hyphen. Fish recognizes three styles of options, the same styles as the GNU version of the getopt library. These styles are:
|
||||
|
||||
@@ -54,13 +67,21 @@ Command specific tab-completions in `fish` are based on the notion of options an
|
||||
|
||||
- Old style long options, like '`-Wall`'. Old style long options can be more than one character long, are preceded by a single hyphen and may not be grouped together. Option arguments are specified in the following parameter ('`-ao null`').
|
||||
|
||||
- GNU style long options, like '`--colors`'. GNU style long options can be more than one character long, are preceded by two hyphens, and may not be grouped together. Option arguments may be specified in the following parameter ('`--quoting-style`') or by appending the option with a '`=`' and the value ('`--quoting-style=shell`'). GNU style long options may be abbreviated so long as the abbreviation is unique ('`--h`') is equivalent to '`--help`' if help is the only long option beginning with an 'h').
|
||||
- GNU style long options, like '`--colors`'. GNU style long options can be more than one character long, are preceded by two hyphens, and may not be grouped together. Option arguments may be specified in the following parameter ('`--quoting-style shell`') or by appending the option with a '`=`' and the value ('`--quoting-style=shell`'). GNU style long options may be abbreviated so long as the abbreviation is unique ('`--h`') is equivalent to '`--help`' if help is the only long option beginning with an 'h').
|
||||
|
||||
The options for specifying command name, command path, or command switches may all be used multiple times to specify multiple commands which have the same completion or multiple switches accepted by a command.
|
||||
The options for specifying command name and command path may be used multiple times to define the same completions for multiple commands.
|
||||
|
||||
The `-w` or `--wraps` options causes the specified command to inherit completions from another command. The inheriting command is said to "wrap" the inherited command. The wrapping command may have its own completions in addition to inherited ones. A command may wrap multiple commands, and wrapping is transitive: if A wraps B, and B wraps C, then A automatically inherits all of C's completions. Wrapping can be removed using the `-e` or `--erase` options.
|
||||
The options for specifying command switches and wrapped commands may be used multiple times to define multiple completions for the command(s) in a single call.
|
||||
|
||||
When erasing completions, it is possible to either erase all completions for a specific command by specifying `complete -e -c COMMAND`, or by specifying a specific completion option to delete by specifying either a long, short or old style option.
|
||||
Invoking `complete` multiple times for the same command adds the new definitions on top of any existing completions defined for the command.
|
||||
|
||||
When `-a` or `--arguments` is specified in conjunction with long, short, or old style options, the specified arguments are only used as completions when attempting to complete an argument for any of the specified options. If `-a` or `--arguments` is specified without any long, short, or old style options, the specified arguments are used when completing any argument to the command (except when completing an option argument that was specified with `-r` or `--require-parameter`).
|
||||
|
||||
Command substitutions found in `OPTION_ARGUMENTS` are not expected to return a space-separated list of arguments. Instead they must return a newline-separated list of arguments, and each argument may optionally have a tab character followed by the argument description. Any description provided in this way overrides a description given with `-d` or `--description`.
|
||||
|
||||
The `-w` or `--wraps` options causes the specified command to inherit completions from another command. The inheriting command is said to "wrap" the inherited command. The wrapping command may have its own completions in addition to inherited ones. A command may wrap multiple commands, and wrapping is transitive: if A wraps B, and B wraps C, then A automatically inherits all of C's completions. Wrapping can be removed using the `-e` or `--erase` options. Note that wrapping only works for completions specified with `-c` or `--command` and are ignored when specifying completions with `-p` or `--path`.
|
||||
|
||||
When erasing completions, it is possible to either erase all completions for a specific command by specifying `complete -c COMMAND -e`, or by specifying a specific completion option to delete by specifying either a long, short or old style option.
|
||||
|
||||
|
||||
\subsection complete-example Example
|
||||
@@ -91,7 +112,7 @@ This can be written as:
|
||||
complete -c rpm -n "__fish_contains_opt -s e erase" -l nodeps -d "Don't check dependencies"
|
||||
\endfish
|
||||
|
||||
where `__fish_contains_opt` is a function that checks the commandline buffer for the presence of a specified set of options.
|
||||
where `__fish_contains_opt` is a function that checks the command line buffer for the presence of a specified set of options.
|
||||
|
||||
To implement an alias, use the `-w` or `--wraps` option:
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ A program should be designed to make its features as easy as possible to discove
|
||||
Rationale:
|
||||
A program whose features are discoverable turns a new user into an expert in a shorter span of time, since the user will become an expert on the program simply by using it.
|
||||
|
||||
The main benefit of a graphical program over a command-line-based program is discoverability. In a graphical program, one can discover all the common features by simply looking at the user interface and guessing what the different buttons, menus and other widgets do. The traditional way to discover features in command-line programs is through manual pages. This requires both that the user starts to use a different program, and then she/he remembers the new information until the next time she/he uses the same program.
|
||||
The main benefit of a graphical program over a command-line-based program is discoverability. In a graphical program, one can discover all the common features by simply looking at the user interface and guessing what the different buttons, menus and other widgets do. The traditional way to discover features in command-line programs is through manual pages. This requires both that the user starts to use a different program, and then they remember the new information until the next time they use the same program.
|
||||
|
||||
Examples:
|
||||
- Everything should be tab-completable, and every tab completion should have a description.
|
||||
@@ -99,7 +99,7 @@ Examples:
|
||||
|
||||
- The help manual should be easy to read, easily available from the shell, complete and contain many examples
|
||||
|
||||
- The language should be uniform, so that once the user understands the command/argument syntax, she/he will know the whole language, and be able to use tab-completion to discover new features.
|
||||
- The language should be uniform, so that once the user understands the command/argument syntax, they will know the whole language, and be able to use tab-completion to discover new features.
|
||||
|
||||
|
||||
\htmlonly[block]
|
||||
|
||||
@@ -10,3 +10,5 @@ dirh
|
||||
`dirh` prints the current directory history. The current position in the history is highlighted using the color defined in the `fish_color_history_current` environment variable.
|
||||
|
||||
`dirh` does not accept any parameters.
|
||||
|
||||
Note that the `cd` command limits directory history to the 25 most recently visited directories. The history is stored in the `$dirprev` and `$dirnext` variables.
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
\subsection dirs-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
dirs
|
||||
dirs -c
|
||||
\endfish
|
||||
|
||||
\subsection dirs-description Description
|
||||
|
||||
`dirs` prints the current directory stack, as created by the <a href="#pushd">`pushd`</a> command.
|
||||
|
||||
With "-c", it clears the directory stack instead.
|
||||
|
||||
`dirs` does not accept any parameters.
|
||||
|
||||
@@ -55,6 +55,6 @@ echo 'Hello World'
|
||||
Print hello world to stdout
|
||||
|
||||
\fish
|
||||
echo -e 'Top\nBottom'
|
||||
echo -e 'Top\\nBottom'
|
||||
\endfish
|
||||
Print Top and Bottom on separate lines, using an escape sequence
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
- <a href='#faq-greeting'>How do I change the greeting message?</a>
|
||||
- <a href='#faq-history'>Why doesn't history substitution ("!$" etc.) work?</a>
|
||||
- <a href='#faq-uninstalling'>How do I uninstall fish?</a>
|
||||
- <a href='#faq-third-party'>Where can I find extra tools for fish?</a>
|
||||
|
||||
\htmlonly[block]
|
||||
</div>
|
||||
@@ -117,7 +118,7 @@ Use the <a href="commands.html#fish_update_completions">`fish_update_completions
|
||||
|
||||
<i>For example if `~/images` is a symlink to `~/Documents/Images`, if I write '`cd images`', my prompt will say `~/Documents/Images`, not `~/images`.</i>
|
||||
|
||||
Because it is impossible to consistently keep symlinked directories unresolved. It is indeed possible to do this partially, and many other shells do so. But it was felt there are enough serious corner cases that this is a bad idea. Most such issues have to do with how '..' is handled, and are varitations of the following example:
|
||||
Because it is impossible to consistently keep symlinked directories unresolved. It is indeed possible to do this partially, and many other shells do so. But it was felt there are enough serious corner cases that this is a bad idea. Most such issues have to do with how '..' is handled, and are variations of the following example:
|
||||
|
||||
Writing `cd images; ls ..` given the above directory structure would list the contents of `~/Documents`, not of `~`, even though using `cd ..` changes the current directory to `~`, and the prompt, the `pwd` builtin and many other directory information sources suggest that the current directory is `~/images` and its parent is `~`. This issue is not possible to fix without either making every single command into a builtin, breaking Unix semantics or implementing kludges in every single command. This issue can also be seen when doing IO redirection.
|
||||
|
||||
@@ -136,10 +137,10 @@ The `open` command uses the MIME type database and the `.desktop` files used by
|
||||
<hr>
|
||||
\section faq-default How do I make fish my default shell?
|
||||
|
||||
If you installed fish manually (e.g. by compiling it, not by using a package manager), you first need to add fish to the list of shells by executing the following command (assuming you installed fish in /usr/local) as root:
|
||||
If you installed fish manually (e.g. by compiling it, not by using a package manager), you first need to add fish to the list of shells by executing the following command (assuming you installed fish in /usr/local):
|
||||
|
||||
\fish{cli-dark}
|
||||
echo /usr/local/bin/fish >>/etc/shells
|
||||
echo /usr/local/bin/fish | sudo tee -a /etc/shells
|
||||
\endfish
|
||||
|
||||
If you installed a prepackaged version of fish, the package manager should have already done this for you.
|
||||
@@ -212,9 +213,26 @@ Next, do the following (assuming fish was installed to /usr/local):
|
||||
rm -Rf /usr/local/etc/fish /usr/local/share/fish ~/.config/fish
|
||||
rm /usr/local/share/man/man1/fish*.1
|
||||
cd /usr/local/bin
|
||||
rm -f fish mimedb fishd fish_indent
|
||||
rm -f fish fish_indent
|
||||
\endfish
|
||||
|
||||
<hr>
|
||||
\section faq-reserved-chars Unicode private-use characters reserved by fish
|
||||
|
||||
Fish reserves the <a href="http://www.unicode.org/faq/private_use.html">Unicode private-use character range</a> from U+F600 thru U+F73F for internal use. Any attempt to feed characters in that range to fish will result in them being replaced by the Unicode "replacement character" U+FFFD. This includes both interactive input as well as any file read by fish (but not programs run by fish).
|
||||
|
||||
<hr>
|
||||
\section faq-third-party Where can I find extra tools for fish?
|
||||
|
||||
The fish user community extends fish in unique and useful ways via scripts that aren't always appropriate for bundling with the fish package. Typically because they solve a niche problem unlikely to appeal to a broad audience. You can find those extensions, including prompts, themes and useful functions, in various third-party repositories. These include:
|
||||
|
||||
- <a href="https://github.com/fisherman/fisherman">Fisherman</a>
|
||||
- <a href="https://github.com/tuvistavie/fundle">Fundle</a>
|
||||
- <a href="https://github.com/oh-my-fish/oh-my-fish">Oh My Fish</a>
|
||||
- <a href="https://github.com/justinmayer/tacklebox">Tacklebox</a>
|
||||
|
||||
This is not an exhaustive list and the fish project has no opinion regarding the merits of the repositories listed above or the scripts found therein. We mention these only because you may find within them a solution to a need you have such as supporting the `&&` and `||` operators or improved integration with other tools that you use.
|
||||
|
||||
\htmlonly[block]
|
||||
</div>
|
||||
\endhtmlonly
|
||||
|
||||
@@ -9,7 +9,7 @@ fg [PID]
|
||||
|
||||
`fg` brings the specified <a href="index.html#syntax-job-control">job</a> to the foreground, resuming it if it is stopped. While a foreground job is executed, fish is suspended. If no job is specified, the last job to be used is put in the foreground. If PID is specified, the job with the specified group ID is put in the foreground.
|
||||
|
||||
The PID of the desired process is usually found by using <a href="index.html#expand-process">process expansion</a>.
|
||||
The PID of the desired process is usually found by using <a href="index.html#expand-process">process expansion</a>. Fish is capable of expanding far more than just the numeric PID, including referencing itself and finding PIDs by name.
|
||||
|
||||
|
||||
\subsection fg-example Example
|
||||
|
||||
@@ -25,4 +25,6 @@ The following options are available:
|
||||
|
||||
- `-v` or `--version` display version and exit
|
||||
|
||||
- `-D` or `--debug-stack-frames=DEBUG_LEVEL` specify how many stack frames to display when debug messages are written. The default is zero. A value of 3 or 4 is usually sufficient to gain insight into how a given debug call was reached but you can specify a value up to 128.
|
||||
|
||||
The fish exit status is generally the exit status of the last foreground command. If fish is exiting because of a parse error, the exit status is 127.
|
||||
|
||||
@@ -7,14 +7,22 @@ fish_indent [OPTIONS]
|
||||
|
||||
\subsection fish_indent-description Description
|
||||
|
||||
`fish_indent` is used to indent a piece of fish code. `fish_indent` reads commands from standard input and outputs them to standard output.
|
||||
`fish_indent` is used to indent a piece of fish code. `fish_indent` reads commands from standard input and outputs them to standard output or a specified file.
|
||||
|
||||
The following options are available:
|
||||
|
||||
- `-i` or `--no-indent` do not indent commands; only reformat to one job per line
|
||||
- `-w` or `--write` indents a specified file and immediately writes to that file.
|
||||
|
||||
- `-v` or `--version` displays the current fish version and then exits
|
||||
- `-i` or `--no-indent` do not indent commands; only reformat to one job per line.
|
||||
|
||||
- `-v` or `--version` displays the current fish version and then exits.
|
||||
|
||||
- `--ansi` colorizes the output using ANSI escape sequences, appropriate for the current $TERM, using the colors defined in the environment (such as `$fish_color_command`).
|
||||
|
||||
- `--html` outputs HTML, which supports syntax highlighting if the appropriate CSS is defined. The CSS class names are the same as the variable names, such as `fish_color_command`
|
||||
- `--html` outputs HTML, which supports syntax highlighting if the appropriate CSS is defined. The CSS class names are the same as the variable names, such as `fish_color_command`.
|
||||
|
||||
- `-d` or `--debug-level=DEBUG_LEVEL` enables debug output and specifies a verbosity level (like `fish -d`). Defaults to 0.
|
||||
|
||||
- `-D` or `--debug-stack-frames=DEBUG_LEVEL` specify how many stack frames to display when debug messages are written. The default is zero. A value of 3 or 4 is usually sufficient to gain insight into how a given debug call was reached but you can specify a value up to 128.
|
||||
|
||||
- `--dump-parse-tree` dumps information about the parsed statements to stderr. This is likely to be of interest only to people working on the fish source code.
|
||||
|
||||
33
doc_src/fish_key_reader.txt
Normal file
33
doc_src/fish_key_reader.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
\section fish_key_reader fish_key_reader - explore what characters keyboard keys send
|
||||
|
||||
\subsection fish_key_reader-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
fish_key_reader [OPTIONS]
|
||||
\endfish
|
||||
|
||||
\subsection fish_key_reader-description Description
|
||||
|
||||
`fish_key_reader` is used to study input received from the terminal and can help with key binds. The program is interactive and works on standard input. Individual characters themselves and their hexadecimal values are displayed.
|
||||
|
||||
The tool will write an example `bind` command matching the character sequence captured to stdout. If the character sequence matches a special key name (see `bind --key-names`), both `bind CHARS ...` and `bind -k KEYNAME ...` usage will be shown. Additional details about the characters received, such as the delay between chars, are written to stderr.
|
||||
|
||||
The following options are available:
|
||||
|
||||
- `-c` or `--continuous` begins a session where multiple key sequences can be inspected. By default the program exits after capturing a single key sequence.
|
||||
|
||||
- `-d` or `--debug-level=DEBUG_LEVEL` enables debug output and specifies a verbosity level (like `fish -d`). Defaults to 0.
|
||||
|
||||
- `-D` or `--debug-stack-frames=DEBUG_LEVEL` specify how many stack frames to display when debug messages are written. The default is zero. A value of 3 or 4 is usually sufficient to gain insight into how a given debug call was reached but you can specify a value up to 128.
|
||||
|
||||
- `-h` or `--help` prints usage information.
|
||||
|
||||
\subsection fish_key_reader-usage-notes Usage Notes
|
||||
|
||||
The delay in milliseconds since the previous character was received is included in the diagnostic information written to stderr. This information may be useful to determine the optimal `fish_escape_delay_ms` setting or learn the amount of lag introduced by tools like `ssh`, `mosh` or `tmux`.
|
||||
|
||||
`fish_key_reader` intentionally disables handling of many signals. To terminate `fish_key_reader` in `--continuous` mode do:
|
||||
|
||||
- press `Ctrl-C` twice, or
|
||||
- press `Ctrl-D` twice, or
|
||||
- type `exit`, or
|
||||
- type `quit`
|
||||
11
doc_src/fish_mode_prompt.txt
Normal file
11
doc_src/fish_mode_prompt.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
\section fish_mode_prompt fish_mode_prompt - define the appearance of the mode indicator
|
||||
|
||||
\subsection fish_mode_prompt-synopsis Synopsis
|
||||
|
||||
fish_mode_prompt will output the mode indicator for use in vi-mode.
|
||||
|
||||
\subsection fish_mode_prompt-description Description
|
||||
|
||||
The output of `fish_mode_prompt` will be displayed in the mode indicator position to the left of the regular prompt.
|
||||
|
||||
Multiple lines are not supported in `fish_mode_prompt`.
|
||||
@@ -20,7 +20,7 @@ A simple right prompt:
|
||||
|
||||
\fish
|
||||
function fish_right_prompt -d "Write out the right prompt"
|
||||
date "+%m/%d/%y"
|
||||
date '+%m/%d/%y'
|
||||
end
|
||||
\endfish
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
408-600-6421\section fish_vi_mode fish_vi_mode - Enable vi mode
|
||||
\section fish_vi_mode fish_vi_mode - Enable vi mode
|
||||
|
||||
\subsection fish_vi_mode-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
@@ -7,4 +7,6 @@ fish_vi_mode
|
||||
|
||||
\subsection fish_vi_mode-description Description
|
||||
|
||||
This function is deprecated. Please call `fish_vi_key_bindings directly`
|
||||
|
||||
`fish_vi_mode` enters a vi-like command editing mode. To always start in vi mode, add `fish_vi_mode` to your `config.fish` file.
|
||||
|
||||
@@ -9,7 +9,7 @@ funced [OPTIONS] NAME
|
||||
|
||||
`funced` provides an interface to edit the definition of the function `NAME`.
|
||||
|
||||
If the `$EDITOR` environment variable is set, it will be used as the program to edit the function. Otherwise, a built-in editor will be used.
|
||||
If the `$VISUAL` environment variable is set, it will be used as the program to edit the function. If `$VISUAL` is unset but `$EDITOR` is set, that will be used. Otherwise, a built-in editor will be used.
|
||||
|
||||
If there is no function called `NAME` a new function will be created with the specified name
|
||||
|
||||
|
||||
@@ -8,3 +8,5 @@ funcsave FUNCTION_NAME
|
||||
\subsection funcsave-description Description
|
||||
|
||||
`funcsave` saves the current definition of a function to a file in the fish configuration directory. This function will be automatically loaded by current and future fish sessions. This can be useful if you have interactively created a new function and wish to save it for later use.
|
||||
|
||||
Note that because fish loads functions on-demand, saved functions will not function as <a href="index.html#event">event handlers</a> until they are run or sourced otherwise. To activate an event handler for every new shell, add the function to your <a href="index.html#initialization">shell initialization file</a> instead of using `funcsave`.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
\subsection function-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
function [OPTIONS] NAME; BODY; end
|
||||
function NAME [OPTIONS]; BODY; end
|
||||
\endfish
|
||||
|
||||
\subsection function-description Description
|
||||
|
||||
@@ -2,33 +2,51 @@
|
||||
|
||||
\subsection history-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
history ( --merge | --save | --clear )
|
||||
history ( --search | --delete ) [ --prefix "prefix string" | --contains "search string" ]
|
||||
history search [ --show-time ] [ --case-sensitive ] [ --exact | --prefix | --contains ] [ --max=n ] [ --null ] [ "search string"... ]
|
||||
history delete [ --show-time ] [ --case-sensitive ] [ --exact | --prefix | --contains ] "search string"...
|
||||
history merge
|
||||
history save
|
||||
history clear
|
||||
history ( -h | --help )
|
||||
\endfish
|
||||
|
||||
\subsection history-description Description
|
||||
|
||||
`history` is used to list, search and delete the history of commands used.
|
||||
`history` is used to search, delete, and otherwise manipulate the history of interactive commands.
|
||||
|
||||
Note that for backwards compatibility each subcommand can also be specified as a long option. For example, rather than `history search` you can type `history --search`. Those long options are deprecated and will be removed in a future release.
|
||||
|
||||
The following operations (sub-commands) are available:
|
||||
|
||||
- `search` returns history items matching the search string. If no search string is provided it returns all history items. This is the default operation if no other operation is specified. You only have to explicitly say `history search` if you wish to search for one of the subcommands. The `--contains` search option will be used if you don't specify a different search option. Entries are ordered newest to oldest. If stdout is attached to a tty the output will be piped through your pager by the history function. The history builtin simply writes the results to stdout.
|
||||
|
||||
- `delete` deletes history items. Without the `--prefix` or `--contains` options, the exact match of the specified text will be deleted. If you don't specify `--exact` a prompt will be displayed before any items are deleted asking you which entries are to be deleted. You can enter the word "all" to delete all matching entries. You can enter a single ID (the number in square brackets) to delete just that single entry. You can enter more than one ID separated by a space to delete multiple entries. Just press [enter] to not delete anything. Note that the interactive delete behavior is a feature of the history function. The history builtin only supports `--exact --case-sensitive` deletion.
|
||||
|
||||
- `merge` immediately incorporates history changes from other sessions. Ordinarily `fish` ignores history changes from sessions started after the current one. This command applies those changes immediately.
|
||||
|
||||
- `save` immediately writes all changes to the history file. The shell automatically saves the history file; this option is provided for internal use and should not normally need to be used by the user.
|
||||
|
||||
- `clear` clears the history file. A prompt is displayed before the history is erased asking you to confirm you really want to clear all history unless `builtin history` is used.
|
||||
|
||||
The following options are available:
|
||||
- `--merge` immediately incorporates history changes from other sessions. Ordinarily `fish` ignores history changes from sessions started after the current one. This command applies those changes immediately.
|
||||
|
||||
- `--save` saves all changes in the history file. The shell automatically saves the history file; this option is provided for internal use.
|
||||
These flags can appear before or immediately after one of the sub-commands listed above.
|
||||
|
||||
- `--clear` clears the history file. A prompt is displayed before the history is erased.
|
||||
- `-C` or `--case-sensitive` does a case-sensitive search. The default is case-insensitive. Note that prior to fish 2.4.0 the default was case-sensitive.
|
||||
|
||||
- `--search` returns history items in keeping with the `--prefix` or `--contains` options.
|
||||
- `-c` or `--contains` searches or deletes items in the history that contain the specified text string. This is the default for the `--search` flag. This is not currently supported by the `--delete` flag.
|
||||
|
||||
- `--delete` deletes history items.
|
||||
- `-e` or `--exact` searches or deletes items in the history that exactly match the specified text string. This is the default for the `--delete` flag. Note that the match is case-insensitive by default. If you really want an exact match, including letter case, you must use the `-C` or `--case-sensitive` flag.
|
||||
|
||||
- `--prefix` searches or deletes items in the history that begin with the specified text string.
|
||||
- `-p` or `--prefix` searches or deletes items in the history that begin with the specified text string. This is not currently supported by the `--delete` flag.
|
||||
|
||||
- `--contains` searches or deletes items in the history that contain the specified text string.
|
||||
- `-t` or `--show-time` prepends each history entry with the date and time the entry was recorded . By default it uses the strftime format `# %c%n`. You can specify another format; e.g., `--show-time='%Y-%m-%d %H:%M:%S '` or `--show-time='%a%I%p'`. The short option, `-t` doesn't accept a stftime format string; it only uses the default format. Any strftime format is allowed, including `%s` to get the raw UNIX seconds since the epoch. Note that `--with-time` is also allowed but is deprecated and will be removed at a future date.
|
||||
|
||||
If `--search` is specified without `--contains` or `--prefix`, `--contains` will be assumed.
|
||||
- `-z` or `--null` causes history entries written by the search operations to be terminated by a NUL character rather than a newline. This allows the output to be processed by `read -z` to correctly handle multiline history entries.
|
||||
|
||||
If `--delete` is specified without `--contains` or `--prefix`, only a history item which exactly matches the parameter will be erased. No prompt will be given. If `--delete` is specified with either of these parameters, an interactive prompt will be displayed before any items are deleted.
|
||||
- `-<number>` `-n <number>` or `--max=<number>` limits the matched history items to the first "n" matching entries. This is only valid for `history search`.
|
||||
|
||||
- `-h` or `--help` display help for this command.
|
||||
|
||||
\subsection history-examples Example
|
||||
|
||||
@@ -40,5 +58,11 @@ history --search --contains "foo"
|
||||
# Outputs a list of all previous commands containing the string "foo".
|
||||
|
||||
history --delete --prefix "foo"
|
||||
# Interactively deletes the record of previous commands which start with "foo".
|
||||
# Interactively deletes commands which start with "foo" from the history.
|
||||
# You can select more than one entry by entering their IDs seperated by a space.
|
||||
|
||||
\subsection history-notes Notes
|
||||
|
||||
If you specify both `--prefix` and `--contains` the last flag seen is used.
|
||||
|
||||
\endfish
|
||||
|
||||
@@ -12,11 +12,10 @@ end
|
||||
|
||||
`if` will execute the command `CONDITION`. If the condition's exit status is 0, the commands `COMMANDS_TRUE` will execute. If the exit status is not 0 and `else` is given, `COMMANDS_FALSE` will be executed.
|
||||
|
||||
In order to use the exit status of multiple commands as the condition of an if block, use <a href="#begin">`begin; ...; end`</a> and the short circuit commands <a href="commands.html#and">`and`</a> and <a href="commands.html#or">`or`</a>.
|
||||
You can use <a href="#and">`and`</a> or <a href="#or">`or`</a> in the condition. See the second example below.
|
||||
|
||||
The exit status of the last foreground command to exit can always be accessed using the <a href="index.html#variables-status">$status</a> variable.
|
||||
|
||||
|
||||
\subsection if-example Example
|
||||
|
||||
The following code will print `foo.txt exists` if the file foo.txt exists and is a regular file, otherwise it will print `bar.txt exists` if the file bar.txt exists and is a regular file, otherwise it will print `foo.txt and bar.txt do not exist`.
|
||||
@@ -30,3 +29,11 @@ else
|
||||
echo foo.txt and bar.txt do not exist
|
||||
end
|
||||
\endfish
|
||||
|
||||
The following code will print "foo.txt exists and is readable" if foo.txt is a regular file and readable
|
||||
\fish
|
||||
if test -f foo.txt
|
||||
and test -r foo.txt
|
||||
echo "foo.txt exists and is readable"
|
||||
end
|
||||
\endfish
|
||||
|
||||
@@ -59,7 +59,7 @@ Switches differ between commands and are documented in the manual page for each
|
||||
|
||||
\subsection quotes Quotes
|
||||
|
||||
Sometimes features such as <a href="#expand">parameter expansion</a> and <a href="#escapes">character escapes</a> get in the way. When that happens, the user can write a parameter within quotes, either `'` (single quote) or `"` (double quote). There is one important difference between single quoted and double quoted strings: When using double quoted string, <a href="#expand-variable">variable expansion</a> still takes place. Other than that, a quoted parameter will not be parameter expanded, may contain spaces, and escape sequences are ignored. The only backslash escape accepted within single quotes is `\'`, which escapes a single quote and `\\`, which escapes the backslash symbol. The only backslash escapes accepted within double quotes are `\"`, which escapes a double quote, `\$`, which escapes a dollar character, `\` followed by a newline, which deletes the backslash and the newline, and lastly `\\`, which escapes the backslash symbol. Single quotes have no special meaning within double quotes and vice versa.
|
||||
Sometimes features such as <a href="#expand">parameter expansion</a> and <a href="#escapes">character escapes</a> get in the way. When that happens, the user can write a parameter within quotes, either `'` (single quote) or `"` (double quote). There is one important difference between single quoted and double quoted strings: When using double quoted string, <a href="#expand-variable">variable expansion</a> still takes place. Other than that, no other kind of expansion (including <a href="#expand-brace">brace expansion</a> and parameter expansion) will take place, the parameter may contain spaces, and escape sequences are ignored. The only backslash escape accepted within single quotes is `\'`, which escapes a single quote and `\\`, which escapes the backslash symbol. The only backslash escapes accepted within double quotes are `\"`, which escapes a double quote, `\$`, which escapes a dollar character, `\` followed by a newline, which deletes the backslash and the newline, and lastly `\\`, which escapes the backslash symbol. Single quotes have no special meaning within double quotes and vice versa.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -80,14 +80,14 @@ would remove the two files 'cumbersome' and 'filename.txt'.
|
||||
|
||||
Some characters can not be written directly on the command line. For these characters, so called escape sequences are provided. These are:
|
||||
|
||||
- '<code>\\a</code>' escapes the alert character
|
||||
- '<code>\\b</code>' escapes the backspace character
|
||||
- '<code>\\e</code>' escapes the escape character
|
||||
- '<code>\\f</code>' escapes the form feed character
|
||||
- '<code>\\n</code>' escapes a newline character
|
||||
- '<code>\\r</code>' escapes the carriage return character
|
||||
- '<code>\\t</code>' escapes the tab character
|
||||
- '<code>\\v</code>' escapes the vertical tab character
|
||||
- '<code>\\a</code>' represents the alert character
|
||||
- '<code>\\b</code>' represents the backspace character
|
||||
- '<code>\\e</code>' represents the escape character
|
||||
- '<code>\\f</code>' represents the form feed character
|
||||
- '<code>\\n</code>' represents a newline character
|
||||
- '<code>\\r</code>' represents the carriage return character
|
||||
- '<code>\\t</code>' represents the tab character
|
||||
- '<code>\\v</code>' represents the vertical tab character
|
||||
- '<code>\\ </code>' escapes the space character
|
||||
- '<code>\\$</code>' escapes the dollar character
|
||||
- '<code>\\\\</code>' escapes the backslash character
|
||||
@@ -110,18 +110,18 @@ Some characters can not be written directly on the command line. For these chara
|
||||
- '<code>\\"</code>' escapes the quote character
|
||||
- '<code>\\'</code>' escapes the apostrophe character
|
||||
|
||||
- '<code>\\x<i>xx</i></code>', where <code><i>xx</i></code> is a hexadecimal number, escapes the ascii character with the specified value. For example, `\x9` is the tab character.
|
||||
- '<code>\\x<i>xx</i></code>', where <code><i>xx</i></code> is a hexadecimal number, represents the ascii character with the specified value. For example, `\x9` is the tab character.
|
||||
|
||||
- '<code>\\X<i>xx</i></code>', where <code><i>xx</i></code> is a hexadecimal number, escapes a byte of data with the specified value. If you are using a mutibyte encoding, this can be used to enter
|
||||
- '<code>\\X<i>xx</i></code>', where <code><i>xx</i></code> is a hexadecimal number, represents a byte of data with the specified value. If you are using a multibyte encoding, this can be used to enter
|
||||
invalid strings. Only use this if you know what you are doing.
|
||||
|
||||
- '<code>\\<i>ooo</i></code>', where <code><i>ooo</i></code> is an octal number, escapes the ascii character with the specified value. For example, `\011` is the tab character.
|
||||
- '<code>\\<i>ooo</i></code>', where <code><i>ooo</i></code> is an octal number, represents the ascii character with the specified value. For example, `\011` is the tab character.
|
||||
|
||||
- '<code>\\u<i>xxxx</i></code>', where <code><i>xxxx</i></code> is a hexadecimal number, escapes the 16-bit Unicode character with the specified value. For example, `\u9` is the tab character.
|
||||
- '<code>\\u<i>xxxx</i></code>', where <code><i>xxxx</i></code> is a hexadecimal number, represents the 16-bit Unicode character with the specified value. For example, `\u9` is the tab character.
|
||||
|
||||
- '<code>\\U<i>xxxxxxxx</i></code>', where <code><i>xxxxxxxx</i></code> is a hexadecimal number, escapes the 32-bit Unicode character with the specified value. For example, `\U9` is the tab character.
|
||||
- '<code>\\U<i>xxxxxxxx</i></code>', where <code><i>xxxxxxxx</i></code> is a hexadecimal number, represents the 32-bit Unicode character with the specified value. For example, `\U9` is the tab character.
|
||||
|
||||
- '<code>\\c<i>x</i></code>', where <code><i>x</i></code> is a letter of the alphabet, escapes the control sequence generated by pressing the control key and the specified letter. For example, `\ci` is the tab character
|
||||
- '<code>\\c<i>x</i></code>', where <code><i>x</i></code> is a letter of the alphabet, represents the control sequence generated by pressing the control key and the specified letter. For example, `\ci` is the tab character
|
||||
|
||||
|
||||
\subsection redirects Input/Output (IO) redirection
|
||||
@@ -146,6 +146,8 @@ An example of a file redirection is `echo hello > output.txt`, which directs the
|
||||
- To append standard output to a file, write `>>DESTINATION_FILE`
|
||||
- To append standard error to a file, write `^^DESTINATION_FILE`
|
||||
|
||||
- To not overwrite ("clobber") an existing file, write '>?DESTINATION' or '^?DESTINATION'
|
||||
|
||||
`DESTINATION` can be one of the following:
|
||||
|
||||
- A filename. The output will be written to the specified file.
|
||||
@@ -179,7 +181,7 @@ will call the `cat` program with the parameter 'foo.txt', which will print the c
|
||||
Pipes usually connect file descriptor 1 (standard output) of the first process to file descriptor 0 (standard input) of the second process. It is possible use a different output file descriptor by prepending the desired FD number and then output redirect symbol to the pipe. For example:
|
||||
|
||||
\fish
|
||||
make fish 2> | less
|
||||
make fish 2>| less
|
||||
\endfish
|
||||
|
||||
will attempt to build the fish program, and any errors will be shown using the less pager.
|
||||
@@ -236,7 +238,7 @@ There are a few important things that need to be noted about aliases:
|
||||
|
||||
- Always take care to add the `$argv` variable to the list of parameters to the wrapped command. This makes sure that if the user specifies any additional parameters to the function, they are passed on to the underlying command.
|
||||
|
||||
- If the alias has the same name as the aliased command, it is necessary to refix the call to the program with `command` in order to tell fish that the unction should not call itself, but rather a command with the same name. ailing to do so will cause infinite recursion bugs.
|
||||
- If the alias has the same name as the aliased command, it is necessary to prefix the call to the program with `command` in order to tell fish that the function should not call itself, but rather a command with the same name. Failing to do so will cause infinite recursion bugs.
|
||||
|
||||
To easily create a function of this form, you can use the <a href="commands.html#alias">alias</a> command.
|
||||
|
||||
@@ -247,10 +249,22 @@ Functions can be defined on the commandline or in a configuration file, but they
|
||||
|
||||
Fish automatically searches through any directories in the array variable `$fish_function_path`, and any functions defined are automatically loaded when needed. A function definition file must have a filename consisting of the name of the function plus the suffix '`.fish`'.
|
||||
|
||||
The default value for `$fish_function_path` is `~/.config/fish/functions` `/etc/fish/functions` `/usr/share/fish/functions`. The exact path to the last two of these may be slightly different depending on what install path prefix was chosen at configuration time. The rationale behind having three different directories is that the first one is for user specific functions, the second one is for system-wide additional functions and the last one is for default fish functions. The path list is searched in order, meaning that by default, the system administrator can override default fish functions, and the user can override functions defined by the system administrator.
|
||||
By default, Fish searches the following for functions, using the first available file that it finds:
|
||||
- A directory for end-users to keep their own functions, usually `~/.config/fish/functions` (controlled by the `XDG_CONFIG_HOME` environment variable).
|
||||
- A directory for systems administrators to install functions for all users on the system, usually `/etc/fish/functions`.
|
||||
- A directory for third-party software vendors to ship their own functions for their software, usually `/usr/share/fish/vendor_functions.d`.
|
||||
- The functions shipped with fish, usually installed in `/usr/share/fish/functions`.
|
||||
|
||||
These paths are controlled by parameters set at build, install, or run time, and may vary from the defaults listed above.
|
||||
|
||||
This wide search may be confusing. If you are unsure, your functions probably belong in `~/.config/fish/functions`.
|
||||
|
||||
It is very important that function definition files only contain the definition for the specified function and nothing else. Otherwise, it is possible that autoloading a function files requires that the function already be loaded, which creates a circular dependency.
|
||||
|
||||
Autoloading also won't work for <a href=#event>event handlers</a>, since fish cannot know that a function is supposed to be executed when an event occurs when it hasn't yet loaded the function. See the <a href=#event>event handlers</a> section for more information.
|
||||
|
||||
If you are developing another program, you may wish to install functions which are available for all users of the fish shell on a system. They can be installed to the "vendor" functions directory. As this path may vary from system to system, the `pkgconfig` framework should be used to discover this path with the output of `pkg-config --variable functionsdir fish`.
|
||||
|
||||
|
||||
\subsubsection syntax-conditional Conditional execution of code and flow control
|
||||
|
||||
@@ -271,13 +285,13 @@ This is a short explanation of some of the commonly used words in fish.
|
||||
|
||||
- <b>command</b> a program that the shell can run.
|
||||
|
||||
- <b>function</b> a block of commands that can be called as if they where a single command. By using functions, it is possible to string together multiple smaller commands into one more advanced command.
|
||||
- <b>function</b> a block of commands that can be called as if they were a single command. By using functions, it is possible to string together multiple smaller commands into one more advanced command.
|
||||
|
||||
- <b>job</b> a running pipeline or command
|
||||
|
||||
- <b>pipeline</b> a set of commands stringed together so that the output of one command is the input of the next command
|
||||
|
||||
- <b>redirection</b> a operation that changes one of the input/output streams associated with a job
|
||||
- <b>redirection</b> an operation that changes one of the input/output streams associated with a job
|
||||
|
||||
- <b>switch</b> a special flag sent as an argument to a command that will alter the behavior of the command. A switch almost always begins with one or two hyphens.
|
||||
|
||||
@@ -293,7 +307,7 @@ Help on a specific builtin can also be obtained with the `-h` parameter. For ins
|
||||
|
||||
\section autosuggestions Autosuggestions
|
||||
|
||||
fish suggests commands as you type, based on command history, completions, and valid file paths. As you type commands, you will see a completion offered after the cursor, in a muted gray color (which can be changed with the `fish_color_autosuggestion` variable).
|
||||
fish suggests commands as you type, based on command history, completions, and valid file paths. As you type commands, you will see a suggestion offered after the cursor, in a muted gray color (which can be changed with the `fish_color_autosuggestion` variable).
|
||||
|
||||
To accept the autosuggestion (replacing the command line contents), press right arrow or @key{Control,F}. To accept the first suggested word, press @key{Alt,→,Right} or @key{Alt,F}. If the autosuggestion is not what you want, just ignore it: it won't execute unless you accept it.
|
||||
|
||||
@@ -302,7 +316,7 @@ Autosuggestions are a powerful way to quickly summon frequently entered commands
|
||||
|
||||
\section completion Tab completion
|
||||
|
||||
Tab completion is one of the most time saving features of any modern shell. By tapping the tab key, the user asks `fish` to guess the rest of the command or parameter that the user is currently typing. If `fish` can only find one possible completion, `fish` will write it out. If there is more than one completion, `fish` will write out the longest prefix that all completions have in common. If the completions differ on the first character, a list of all possible completions is printed. The list features descriptions of the completions and if the list doesn't fit the screen, it is scrollable by using the arrow keys, the page up/page down keys, the tab key or the space bar. Pressing any other key will exit the list and insert the pressed key into the command line.
|
||||
Tab completion is one of the most time saving features of any modern shell. By tapping the tab key, the user asks `fish` to guess the rest of the command or parameter that the user is currently typing. If `fish` can only find one possible completion, `fish` will write it out. If there is more than one completion, `fish` will write out the longest prefix that all completions have in common. If the completions differ on the first character, a list of all possible completions is printed. The list features descriptions of the completions and if the list doesn't fit the screen, it is scrollable by using the arrow keys, the page up/page down keys, the tab key or the space bar. Once the list has been entered, pressing any other key will start a search. If the list has not been entered, pressing any other key will exit the list and insert the pressed key into the command line.
|
||||
|
||||
These are the general purpose tab completions that `fish` provides:
|
||||
|
||||
@@ -343,7 +357,7 @@ To provide a list of possible completions for myprog, use the `-a` switch. If `m
|
||||
complete -c myprog -s o -l output -a "yes no"
|
||||
\endfish
|
||||
|
||||
There are also special switches for specifying that a switch requires an argument, to disable filename completion, to create completions that are only available in some combinations, etc.. For a complete description of the various switches accepted by the `complete` command, see the documentationfor the <a href="commands.html#complete">complete</a> builtin, or write `complete --help` inside the `fish` shell.
|
||||
There are also special switches for specifying that a switch requires an argument, to disable filename completion, to create completions that are only available in some combinations, etc.. For a complete description of the various switches accepted by the `complete` command, see the documentation for the <a href="commands.html#complete">complete</a> builtin, or write `complete --help` inside the `fish` shell.
|
||||
|
||||
For examples of how to write your own complex completions, study the completions in `/usr/share/fish/completions`. (The exact path depends on your chosen installation prefix and may be slightly different)
|
||||
|
||||
@@ -362,7 +376,7 @@ Functions beginning with the string `__fish_print_` print a newline separated li
|
||||
|
||||
- `__fish_complete_pids` prints a list of all processes IDs with the command name as description.
|
||||
|
||||
- `__fish_complete_suffix SUFFIX` performs file completion allowing only files ending in SUFFIX. The mimetype database is used to find a suitable description.
|
||||
- `__fish_complete_suffix SUFFIX` performs file completion allowing only files ending in SUFFIX, with an optional description.
|
||||
|
||||
- `__fish_complete_users` prints a list of all users with their full name as description.
|
||||
|
||||
@@ -379,9 +393,20 @@ Functions beginning with the string `__fish_print_` print a newline separated li
|
||||
|
||||
Completions can be defined on the commandline or in a configuration file, but they can also be automatically loaded. Fish automatically searches through any directories in the array variable `$fish_complete_path`, and any completions defined are automatically loaded when needed. A completion file must have a filename consisting of the name of the command to complete and the suffix '`.fish`'.
|
||||
|
||||
The default value for `$fish_complete_path` is `~/.config/fish/completions` `/etc/fish/completions` `/usr/share/fish/vendor_completions.d` `/usr/share/fish/completions` `~/.local/share/generated_completions`. (Some paths may be slightly different depending on where fish is installed). If a suitable file is found in one of these directories, it will be automatically loaded and the search will be stopped. The large number of directories searched may be confusing. It is to allow, respectively, user-specific completions, system-wide completions, completions installed by other packages, default completions that ship with fish, and finally, completions generated from manual pages. If you are unsure, put your completions in `~/.config/fish/completions`.
|
||||
By default, Fish searches the following for completions, using the first available file that it finds:
|
||||
- A directory for end-users to keep their own completions, usually `~/.config/fish/completions` (controlled by the `XDG_CONFIG_HOME` environment variable);
|
||||
- A directory for systems administrators to install completions for all users on the system, usually `/etc/fish/completions`;
|
||||
- A directory for third-party software vendors to ship their own completions for their software, usually `/usr/share/fish/vendor_completions.d`;
|
||||
- The completions shipped with fish, usually installed in `/usr/share/fish/completions`; and
|
||||
- Completions automatically generated from the operating system's manual, usually stored in `~/.local/share/fish/generated_completions`.
|
||||
|
||||
If you have written new completions for a common Unix command, please consider sharing your work by submitting it via the instructions in <a href="#more-help">Further help and development</a>. If you are developing another program and would like to ship completions with your program, install them to `/usr/share/fish/vendor_completions.d` or similar directory. Systems using the `pkgconfig` framework can discover this path from the output of `pkg-config --variable completionsdir fish`.
|
||||
These paths are controlled by parameters set at build, install, or run time, and may vary from the defaults listed above.
|
||||
|
||||
This wide search may be confusing. If you are unsure, your completions probably belong in `~/.config/fish/completions`.
|
||||
|
||||
If you have written new completions for a common Unix command, please consider sharing your work by submitting it via the instructions in <a href="#more-help">Further help and development</a>.
|
||||
|
||||
If you are developing another program and would like to ship completions with your program, install them to the "vendor" completions directory. As this path may vary from system to system, the `pkgconfig` framework should be used to discover this path with the output of `pkg-config --variable completionsdir fish`.
|
||||
|
||||
|
||||
\section expand Parameter expansion (Globbing)
|
||||
@@ -397,7 +422,19 @@ If a star (`*`) or a question mark (`?`) is present in the parameter, `fish` att
|
||||
|
||||
- `*` can match any string of characters not containing '/'. This includes matching an empty string.
|
||||
|
||||
- `**` matches any string of characters. This includes matching an empty string. The string may include the `/` character but does not need to.
|
||||
- `**` matches any string of characters. This includes matching an empty string. The matched string may include the `/` character; that is, it recurses into subdirectories. Note that augmenting this wildcard with other strings will not match files in the current working directory (`$PWD`) if you separate the strings with a slash ("/"). This is unlike other shells such as zsh. For example, `**\/*.fish` in zsh will match `.fish` files in the PWD but in fish will only match such files in a subdirectory. In fish you should type `***.fish` to match files in the PWD as well as subdirectories.
|
||||
|
||||
Other shells, such as zsh, provide a rich glob syntax for restricting the files matched by globs. For example, `**(.)`, to only match regular files. Fish prefers to defer such features to programs, such as `find`, rather than reinventing the wheel. Thus, if you want to limit the wildcard expansion to just regular files the fish approach is to define and use a function. For example,
|
||||
|
||||
\fish{cli-dark}
|
||||
function ff --description 'Like ** but only returns plain files.'
|
||||
# This also ignores .git directories.
|
||||
find . \( -name .git -type d -prune \) -o -type f | \
|
||||
sed -n -e '/^\.\/\.git$/n' -e 's/^\.\///p'
|
||||
end
|
||||
\endfish
|
||||
|
||||
You would then use it in place of `**` like this, `my_prog (ff)`, to pass only regular files in or below $PWD to `my_prog`.
|
||||
|
||||
Wildcard matches are sorted case insensitively. When sorting matches containing numbers, consecutive digits are considered to be one element, so that the strings '1' '5' and '12' would be sorted in the order given.
|
||||
|
||||
@@ -411,8 +448,19 @@ Examples:
|
||||
|
||||
- `**` matches any files and directories in the current directory and all of its subdirectories.
|
||||
|
||||
Note that if no matches are found for a specific wildcard, it will expand into zero arguments, i.e. to nothing. If none of the wildcarded arguments sent to a command result in any matches, the command will not be executed. If this happens when using the shell interactively, a warning will also be printed.
|
||||
Note that for most commands, if any wildcard fails to expand, the command is not executed, <a href='#variables-status'>`$status`</a> is set to nonzero, and a warning is printed. This behavior is consistent with setting `shopt -s failglob` in bash. There are exactly 3 exceptions, namely <a href="commands.html#set">`set`</a>, <a href="commands.html#count">`count`</a> and <a href="commands.html#for">`for`</a>. Their globs are permitted to expand to zero arguments, as with `shopt -s nullglob` in bash.
|
||||
|
||||
Examples:
|
||||
\fish
|
||||
ls *.foo
|
||||
# Lists the .foo files, or warns if there aren't any.
|
||||
|
||||
set foos *.foo
|
||||
if count $foos >/dev/null
|
||||
ls $foos
|
||||
end
|
||||
# Lists the .foo files, if any.
|
||||
\endfish
|
||||
|
||||
\subsection expand-command-substitution Command substitution
|
||||
|
||||
@@ -458,7 +506,7 @@ A dollar sign followed by a string of characters is expanded into the value of t
|
||||
|
||||
Undefined and empty variables expand to nothing.
|
||||
|
||||
To separate a variable name from text it should immediately be followed by, encase the variable within braces.
|
||||
To separate a variable name from text encase the variable within double-quotes or braces.
|
||||
|
||||
Examples:
|
||||
\fish
|
||||
@@ -468,15 +516,17 @@ echo $HOME
|
||||
echo $nonexistentvariable
|
||||
# Prints no output.
|
||||
|
||||
echo The plural of $WORD is {$WORD}s
|
||||
echo The plural of $WORD is "$WORD"s
|
||||
# Prints "The plural of cat is cats" when $WORD is set to cat.
|
||||
echo The plural of $WORD is {$WORD}s
|
||||
# ditto
|
||||
\endfish
|
||||
|
||||
Note that without the braces, fish will try to expand a variable called `$WORDs`, which may not exist.
|
||||
Note that without the quotes or braces, fish will try to expand a variable called `$WORDs`, which may not exist.
|
||||
|
||||
The latter syntax works by exploiting <a href="#expand-brace">brace expansion</a>; care should be taken with array variables and undefined variables, as these behave very differently to POSIX shells.
|
||||
The latter syntax `{$WORD}` works by exploiting <a href="#expand-brace">brace expansion</a>; care should be taken with zero-element array variables and undefined variables, as these expand as a <a href="#cartesian-product">cartesian product</a>, so they eliminate the string.
|
||||
|
||||
Variable expansion is the only type of expansion performed on double quoted strings. There is, however, an important difference in how variables are expanded when quoted and when unquoted. An unquoted variable expansion will result in a variable number of arguments. For example, if the variable `$foo` has zero elements or is undefined, the argument `$foo` will expand to zero elements. If the variable $foo is an array of five elements, the argument `$foo` will expand to five elements. When quoted, like `"$foo"`, a variable expansion will always result in exactly one argument. Undefined variables will expand to the empty string, and array variables will be concatenated using the space character. The dangers noted in the third example above can therefore be avoided by wrapping the variable in double quotes (`echo {"$WORD"}s`).
|
||||
Variable expansion is the only type of expansion performed on double quoted strings. There is, however, an important difference in how variables are expanded when quoted and when unquoted. An unquoted variable expansion will result in a variable number of arguments. For example, if the variable `$foo` has zero elements or is undefined, the argument `$foo` will expand to zero elements. If the variable $foo is an array of five elements, the argument `$foo` will expand to five elements. When quoted, like `"$foo"`, a variable expansion will always result in exactly one argument. Undefined variables will expand to the empty string, and array variables will be concatenated using the space character.
|
||||
|
||||
There is one further notable feature of fish variable expansion. Consider the following code snippet:
|
||||
|
||||
@@ -496,6 +546,34 @@ end
|
||||
The above code demonstrates how to use multiple '`$`' symbols to expand the value of a variable as a variable name. One can think of the `$` symbol as a variable dereference operator. When using this feature together with array brackets, the brackets will always match the innermost `$` dereference. Thus, `$$foo[5]` will always mean the fifth element of the `foo` variable should be dereferenced, not the fifth element of the doubly dereferenced variable `foo`. The latter can instead be expressed as `$$foo[1][5]`.
|
||||
|
||||
|
||||
\subsection cartesian-product Cartesian Products
|
||||
|
||||
Lists adjacent to other lists or strings are expanded as cartesian products:
|
||||
|
||||
Examples:
|
||||
\fish{cli-dark}
|
||||
>_ echo {good,bad}" apples"
|
||||
<outp>good apples bad apples</outp>
|
||||
|
||||
>_ set -l a x y z
|
||||
>_ set -l b 1 2 3
|
||||
|
||||
>_ echo $a$b
|
||||
<outp>x1 y1 z1 x2 y2 z2 x3 y3 z3</outp>
|
||||
|
||||
>_ echo $a"-"$b
|
||||
<outp>x-1 y-1 z-1 x-2 y-2 z-2 x-3 y-3 z-3</outp>
|
||||
|
||||
>_ echo {x,y,z}$b
|
||||
<outp>x1 y1 z1 x2 y2 z2 x3 y3 z3</outp>
|
||||
|
||||
>_ echo {$b}word
|
||||
<outp>1word 2word 3word</outp>
|
||||
\endfish
|
||||
|
||||
Be careful when you try to use braces to separate variable names from text. The dangers noted in the last example above can be avoided by wrapping the variable in double quotes instead of braces (`echo "$b"word`).
|
||||
|
||||
|
||||
\subsection expand-index-range Index range expansion
|
||||
|
||||
Both command substitution and shell variable expansion support accessing only specific items by providing a set of indices in square brackets. It's often needed to access a sequence of elements. To do this, use the range operator '`..`' for this. A range '`a..b`', where range limits 'a' and 'b' are integer numbers, is expanded into a sequence of indices '`a a+1 a+2 ... b`' or '`a a-1 a-2 ... b`' depending on which of 'a' or 'b' is higher. The negative range limits are calculated from the end of the array or command substitution.
|
||||
@@ -547,6 +625,8 @@ The `%` (percent) character at the beginning of a parameter followed by a string
|
||||
|
||||
- If the string is the entire word `self`, the shell's PID is the result.
|
||||
|
||||
- Otherwise, if the string is the entire word `last`, the last job's PID is the result.
|
||||
|
||||
- Otherwise, if the string is the ID of a job, the result is the process group ID of the job.
|
||||
|
||||
- Otherwise, if any child processes match the specified string, their PIDs are the result of the expansion.
|
||||
@@ -559,7 +639,7 @@ This form of expansion is useful for commands like kill and fg, which take proce
|
||||
|
||||
Example:
|
||||
|
||||
`fg %ema` will search for a process whose command line begins with the letters 'ema', such as emacs, and if found, put it in the foreground.
|
||||
`fg %%ema` will search for a process whose command line begins with the letters 'ema', such as emacs, and if found, put it in the foreground.
|
||||
|
||||
`kill -s SIGINT %3` will send the SIGINT signal to the job with job ID 3.
|
||||
|
||||
@@ -631,12 +711,14 @@ echo $pirate
|
||||
|
||||
\subsection variables-universal More on universal variables
|
||||
|
||||
Universal variables are variables that are shared between all the users fish sessions on the computer. Fish stores many of its configuration options as universal variables. This means that in order to change fish settings, all you have to do is change the variable value once, and it will be automatically updated for all sessions, and preserved across computer reboots and login/logout.
|
||||
Universal variables are variables that are shared between all the users' fish sessions on the computer. Fish stores many of its configuration options as universal variables. This means that in order to change fish settings, all you have to do is change the variable value once, and it will be automatically updated for all sessions, and preserved across computer reboots and login/logout.
|
||||
|
||||
To see universal variables in action, start two fish sessions side by side, and issue the following command in one of them `set fish_color_cwd blue`. Since `fish_color_cwd` is a universal variable, the color of the current working directory listing in the prompt will instantly change to blue on both terminals.
|
||||
|
||||
<a href="#variables-universal">Universal variables</a> are stored in the file `.config/fish/fishd.MACHINE_ID`, where MACHINE_ID is typically your MAC address. Do not edit this file directly, as your edits may be overwritten. Edit them through fish scripts or by using fish interactively instead.
|
||||
|
||||
Do not append to universal variables in <a href="index.html#initialization">config.fish</a>, because these variables will then get longer with each new shell instance. Instead, simply set them once at the command line.
|
||||
|
||||
|
||||
\subsection variables-functions Variable scope for functions
|
||||
|
||||
@@ -721,17 +803,18 @@ All arrays are one-dimensional and cannot contain other arrays, although it is p
|
||||
|
||||
\subsection variables-special Special variables
|
||||
|
||||
The user can change the settings of `fish` by changing the values of
|
||||
certain environment variables.
|
||||
|
||||
- `BROWSER`, the user's preferred web browser. If this variable is set, fish will use the specified browser instead of the system default browser to display the fish documentation.
|
||||
|
||||
- `CDPATH`, an array of directories in which to search for the new directory for the `cd` builtin. By default, the fish configuration defines `CDPATH` to be a universal variable with the values `.` and `~`.
|
||||
The user can change the settings of `fish` by changing the values of certain variables.
|
||||
|
||||
- A large number of variable starting with the prefixes `fish_color` and `fish_pager_color.` See <a href='#variables-color'>Variables for changing highlighting colors</a> for more information.
|
||||
|
||||
- `fish_greeting`, the greeting message printed on startup.
|
||||
|
||||
- `fish_escape_delay_ms` overrides the default timeout of 300ms (default key bindings) or 10ms (vi key bindings) after seeing an escape character before giving up on matching a key binding. See the documentation for the <a href='bind.html#special-case-escape'>bind</a> builtin command. This delay facilitates using escape as a meta key.
|
||||
|
||||
- `BROWSER`, the user's preferred web browser. If this variable is set, fish will use the specified browser instead of the system default browser to display the fish documentation.
|
||||
|
||||
- `CDPATH`, an array of directories in which to search for the new directory for the `cd` builtin.
|
||||
|
||||
- `LANG`, `LC_ALL`, `LC_COLLATE`, `LC_CTYPE`, `LC_MESSAGES`, `LC_MONETARY`, `LC_NUMERIC` and `LC_TIME` set the language option for the shell and subprograms. See the section <a href='#variables-locale'>Locale variables</a> for more information.
|
||||
|
||||
- `fish_user_paths`, an array of directories that are prepended to `PATH`. This can be a universal variable.
|
||||
@@ -760,6 +843,14 @@ certain environment variables.
|
||||
|
||||
- `CMD_DURATION`, the runtime of the last command in milliseconds.
|
||||
|
||||
- `FISH_VERSION`, the version of the currently running fish
|
||||
|
||||
- `COLUMNS`, the current width of the terminal
|
||||
|
||||
- `LINES`, the current height of the terminal
|
||||
|
||||
- `SHLVL`, the level of nesting of shells
|
||||
|
||||
The names of these variables are mostly derived from the csh family of shells and differ from the ones used by Bourne style shells such as bash.
|
||||
|
||||
Variables whose name are in uppercase are exported to the commands started by fish, while those in lowercase are not exported. This rule is not enforced by fish, but it is good coding practice to use casing to distinguish between exported and unexported variables. `fish` also uses several variables internally. Such variables are prefixed with the string `__FISH` or `__fish.` These should never be used by the user. Changing their value may break fish.
|
||||
@@ -817,6 +908,12 @@ The following variables are available to change the highlighting colors in fish:
|
||||
|
||||
- `fish_color_cwd`, the color used for the current working directory in the default prompt
|
||||
|
||||
- `fish_color_autosuggestion`, the color used for autosuggestions
|
||||
|
||||
- `fish_color_user`, the color used to print the current username in some of fish default prompts
|
||||
|
||||
- `fish_color_host`, the color used to print the current host system in some of fish default prompts
|
||||
|
||||
Additionally, the following variables are available to change the highlighting in the completion pager:
|
||||
|
||||
- `fish_pager_color_prefix`, the color of the prefix string, i.e. the string that is to be completed
|
||||
@@ -856,18 +953,23 @@ For a list of all builtins, functions and commands shipped with fish, see the <a
|
||||
|
||||
The `fish` editor features copy and paste, a searchable history and many editor functions that can be bound to special keyboard shortcuts.
|
||||
|
||||
Similar to bash, fish has Emacs and Vi editing modes. The default editing mode is Emacs. You can switch to Vi mode with `fish_vi_key_bindings` and switch back with `fish_default_key_bindings`.
|
||||
Similar to bash, fish has Emacs and Vi editing modes. The default editing mode is Emacs. You can switch to Vi mode with `fish_vi_key_bindings` and switch back with `fish_default_key_bindings`. You can also make your own key bindings by creating a function and setting $fish_key_bindings to its name. For example:
|
||||
|
||||
\fish
|
||||
function hybrid_bindings --description "Vi-style bindings that inherit emacs-style bindings in all modes"
|
||||
for mode in default insert visual
|
||||
fish_default_key_bindings -M $mode
|
||||
end
|
||||
fish_vi_key_bindings --no-erase
|
||||
end
|
||||
set -g fish_key_bindings hybrid_bindings
|
||||
\endfish
|
||||
|
||||
\subsection emacs-mode Emacs mode commands
|
||||
\subsection shared-binds Shared bindings
|
||||
|
||||
- @key{Tab} <a href="#completion">completes</a> the current token.
|
||||
Some bindings are shared between emacs- and vi-mode because they aren't text editing bindings or because what Vi/Vim does for a particular key doesn't make sense for a shell.
|
||||
|
||||
- @key{Home} or @key{Control,A} moves the cursor to the beginning of the line.
|
||||
|
||||
- @key{End} or @key{Control,E} moves to the end of line. If the cursor is already at the end of the line, and an autosuggestion is available, @key{End} or @key{Control,E} accepts the autosuggestion.
|
||||
|
||||
- @cursor_key{←,Left} (or @key{Control,B}) and @cursor_key{→,Right} (or @key{Control,F}) move the cursor left or right by one character. If the cursor is already at the end of the line, and an autosuggestion is available, the @cursor_key{→,Right} key and the @key{Control,F} combination accept the suggestion.
|
||||
- @key{Tab} <a href="#completion">completes</a> the current token. @key{Shift, Tab} completes the current token and starts the pager's search mode.
|
||||
|
||||
- @key{Alt,←,Left} and @key{Alt,→,Right} move the cursor one word left or right, or moves forward/backward in the directory history if the command line is empty. If the cursor is already at the end of the line, and an autosuggestion is available, @key{Alt,→,Right} (or @key{Alt,F}) accepts the first word in the suggestion.
|
||||
|
||||
@@ -875,40 +977,68 @@ Similar to bash, fish has Emacs and Vi editing modes. The default editing mode i
|
||||
|
||||
- @key{Alt,↑,Up} and @key{Alt,↓,Down} search the command history for the previous/next token containing the token under the cursor before the search was started. If the commandline was not on a token when the search started, all tokens match. See the <a href='#history'>history</a> section for more information on history searching.
|
||||
|
||||
- @key{Delete} and @key{Backspace} removes one character forwards or backwards respectively.
|
||||
|
||||
- @key{Control,C} deletes the entire line.
|
||||
|
||||
- @key{Control,D} delete one character to the right of the cursor. If the command line is empty, @key{Control,D} will exit fish.
|
||||
|
||||
- @key{Control,K} moves contents from the cursor to the end of line to the <a href="#killring">killring</a>.
|
||||
|
||||
- @key{Control,U} moves contents from the beginning of line to the cursor to the <a href="#killring">killring</a>.
|
||||
|
||||
- @key{Control,L} clears and repaints the screen.
|
||||
|
||||
- @key{Control,W} moves the previous word to the <a href="#killring">killring</a>.
|
||||
- @key{Control,W} moves the previous path component (everything up to the previous "/") to the <a href="#killring">killring</a>.
|
||||
|
||||
- @key{Alt,D} moves the next word to the <a href="#killring">killring</a>.
|
||||
|
||||
- @key{Alt,W} prints a short description of the command under the cursor.
|
||||
- @key{Alt,H} (or @key{F1}) shows the manual page for the current command, if one exists.
|
||||
|
||||
- @key{Alt,L} lists the contents of the current directory, unless the cursor is over a directory argument, in which case the contents of that directory will be listed.
|
||||
|
||||
- @key{Alt,P} adds the string '`| less;`' to the end of the job under the cursor. The result is that the output of the command will be paged.
|
||||
|
||||
- @key{Alt,W} prints a short description of the command under the cursor.
|
||||
|
||||
\subsection emacs-mode Emacs mode commands
|
||||
|
||||
- @key{Home} or @key{Control,A} moves the cursor to the beginning of the line.
|
||||
|
||||
- @key{End} or @key{Control,E} moves to the end of line. If the cursor is already at the end of the line, and an autosuggestion is available, @key{End} or @key{Control,E} accepts the autosuggestion.
|
||||
|
||||
- @cursor_key{←,Left} (or @key{Control,B}) and @cursor_key{→,Right} (or @key{Control,F}) move the cursor left or right by one character. If the cursor is already at the end of the line, and an autosuggestion is available, the @cursor_key{→,Right} key and the @key{Control,F} combination accept the suggestion.
|
||||
|
||||
- @key{Delete} and @key{Backspace} removes one character forwards or backwards respectively.
|
||||
|
||||
- @key{Control,K} moves contents from the cursor to the end of line to the <a href="#killring">killring</a>.
|
||||
|
||||
- @key{Alt,C} capitalizes the current word.
|
||||
|
||||
- @key{Alt,U} makes the current word uppercase.
|
||||
|
||||
- @key{Alt,H} (or @key{F1}) shows the manual page for the current command, if one exists.
|
||||
- @key{Control, t} transposes the last two characters
|
||||
|
||||
- @key{Alt,t} transposes the last two words
|
||||
|
||||
|
||||
You can change these key bindings using the <a href="commands.html#bind">bind</a> builtin command.
|
||||
|
||||
|
||||
\subsection vi-mode Vi mode commands
|
||||
|
||||
Vi mode allows for the use of Vi-like commands at the prompt. Initially, <a href="#vi-mode-insert">insert mode</a> is active. @key{Escape} enters <a href="#vi-mode-command">command mode</a>. The commands available in command, insert and visual mode are described below.
|
||||
Vi mode allows for the use of Vi-like commands at the prompt. Initially, <a href="#vi-mode-insert">insert mode</a> is active. @key{Escape} enters <a href="#vi-mode-command">command mode</a>. The commands available in command, insert and visual mode are described below. Vi mode shares <a href="#shared-binds">some bindings</a> with <a href="#emacs-mode">Emacs mode</a>.
|
||||
|
||||
It is also possible to add all emacs-mode bindings to vi-mode by using something like
|
||||
|
||||
\fish
|
||||
function fish_user_key_bindings
|
||||
# Execute this once per mode that emacs bindings should be used in
|
||||
fish_default_key_bindings -M insert
|
||||
# Without an argument, fish_vi_key_bindings will default to
|
||||
# resetting all bindings.
|
||||
# The argument specifies the initial mode (insert, "default" or visual).
|
||||
fish_vi_key_bindings insert
|
||||
end
|
||||
\endfish
|
||||
|
||||
When in vi-mode, the <a href="fish_mode_prompt.html">`fish_mode_prompt`</a> function will display a mode indicator to the left of the prompt. The `fish_vi_cursor` function will be used to change the cursor's shape depending on the mode in supported terminals. To disable this feature, override it with an empty function.
|
||||
|
||||
\subsubsection vi-mode-command Command mode
|
||||
|
||||
@@ -938,21 +1068,18 @@ Command mode is also known as normal mode.
|
||||
|
||||
- @key{[} and @key{]} search the command history for the previous/next token containing the token under the cursor before the search was started. See the <a href='#history'>history</a> section for more information on history searching.
|
||||
|
||||
- @key{Control, X} copies the current buffer to the system's clipboard, @key{Control, V} inserts the clipboard contents.
|
||||
- @key{Control,C} deletes the entire line.
|
||||
|
||||
- @key{Backspace} moves the cursor left.
|
||||
|
||||
\subsubsection vi-mode-insert Insert mode
|
||||
|
||||
- @key{Tab} <a href="#completion">completes</a> the current token.
|
||||
|
||||
- @key{Escape} or @key{Control,C} enters <a href="#vi-mode-command">command mode</a>.
|
||||
|
||||
- @cursor_key{↑,Up} and @cursor_key{↓,Down} search the command history. See the <a href='#history'>history</a> section for more information on history searching.
|
||||
- @key{Control,x} moves the cursor to the end of the line. If an autosuggestion is available, it will be accepted completely.
|
||||
|
||||
- @key{Control,W} moves the previous word to the <a href="#killring">killring</a>.
|
||||
|
||||
- @key{Control,U} moves contents from the beginning of line to the cursor to the <a href="#killring">killring</a>.
|
||||
|
||||
- @key{Control,B} and @key{Control,F} move the cursor one word left or right. If the cursor is already at the end of the line, and an autosuggestion is available, @key{Control,F} accepts the first word in the suggestion.
|
||||
- @key{Backspace} removes one character to the left.
|
||||
|
||||
\subsubsection vi-mode-visual Visual mode
|
||||
|
||||
@@ -968,9 +1095,6 @@ Command mode is also known as normal mode.
|
||||
|
||||
`fish` uses an Emacs style kill ring for copy and paste functionality. Use @key{Control,K} to cut from the current cursor position to the end of the line. The string that is cut (a.k.a. killed) is inserted into a linked list of kills, called the kill ring. To paste the latest value from the kill ring use @key{Control,Y}. After pasting, use @key{Alt,Y} to rotate to the previous kill.
|
||||
|
||||
If the environment variable `DISPLAY` is set and the `xsel` program is installed, `fish` will try to connect to the X Windows server specified by this variable, and use the clipboard on the X server for copying and pasting.
|
||||
|
||||
|
||||
\subsection history-search Searchable history
|
||||
|
||||
After a command has been entered, it is inserted at the end of a history list. Any duplicate history items are automatically removed. By pressing the up and down keys, the user can search forwards and backwards in the history. If the current command line is not empty when starting a history search, only the commands containing the string entered into the command line are shown.
|
||||
@@ -981,7 +1105,7 @@ History searches can be aborted by pressing the escape key.
|
||||
|
||||
Prefixing the commandline with a space will prevent the entire line from being stored in the history.
|
||||
|
||||
The history is stored in the file `~/.config/fish/fish_history`.
|
||||
The history is stored in the file `~/.local/share/fish/fish_history` (or `$XDG_DATA_HOME/fish/fish_history` if that variable is set).
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -1007,7 +1131,7 @@ The fish commandline editor works exactly the same in single line mode and in mu
|
||||
|
||||
Normally when `fish` starts a program, this program will be put in the foreground, meaning it will take control of the terminal and `fish` will be stopped until the program finishes. Sometimes this is not desirable. For example, you may wish to start an application with a graphical user interface from the terminal, and then be able to continue using the shell. In such cases, there are several ways in which the user can change fish's behavior.
|
||||
|
||||
-# By ending a command with the `&` (ampersand) symbol, the user tells `fish` to put the specified command into the background. A background process will be run simultaneous with `fish`. `fish` will retain control of the terminal, so the program will not be able to read from the keyboard.
|
||||
-# By ending a command with the `&` (ampersand) symbol, the user tells `fish` to put the specified command into the background. A background process will be run simultaneous with `fish`. `fish` will retain control of the terminal, so the program will not be able to read from the keyboard.
|
||||
|
||||
-# By pressing @key{Control,Z}, the user stops a currently running foreground program and returns control to `fish`. Some programs do not support this feature, or remap it to another key. GNU Emacs uses @key{Control,X} @key{z} to stop running.
|
||||
|
||||
@@ -1018,9 +1142,27 @@ Note that functions cannot be started in the background. Functions that are stop
|
||||
|
||||
\section initialization Initialization files
|
||||
|
||||
On startup, `fish` evaluates the files `/usr/share/fish/config.fish` (Or `/usr/local/fish...` if you installed fish in `/usr/local`), `/etc/fish/config.fish` (Or `~/etc/fish/...` if you installed fish in your home directory) and `~/.config/fish/config.fish` (Or any other directory specified by the `$XDG_CONFIG_HOME` variable), in that order.
|
||||
On startup, Fish evaluates a number of configuration files, which can be used to control the behavior of the shell. The location of these configuration variables is controlled by a number of environment variables, and their default or usual location is given below.
|
||||
|
||||
The first file should not be directly edited, the second one is meant for systemwide configuration and the last one is meant for user configuration. If you want to run a command only on starting an interactive shell, use the exit status of the command `status --is-interactive` to determine if the shell is interactive. If you want to run a command only when using a login shell, use `status --is-login` instead.
|
||||
Configuration files are evaluated in the following order:
|
||||
- Configuration shipped with fish, which should not be edited, in `$__fish_datadir/config.fish` (usually `/usr/share/fish/config.fish`).
|
||||
- System-wide configuration files, where administrators can include initialization that should be run for all users on the system - similar to `/etc/profile` for POSIX-style shells - in `$__fish_sysconfdir` (usually `/etc/fish/config.fish`);
|
||||
- Configuration snippets in files ending in `.fish`, in the directories:
|
||||
- `$XDG_CONFIG_HOME/fish/conf.d` (by default, `~/.config/fish/conf.d/`)
|
||||
- `$__fish_sysconfdir/conf.d` (by default, `/etc/fish/conf.d`)
|
||||
- `/usr/share/fish/vendor_conf.d` (set at compile time; by default, `$__fish_datadir/conf.d`)
|
||||
|
||||
If there are multiple files with the same name in these directories, only the first will be executed.
|
||||
|
||||
- User initialization, usually in `~/.config/fish/config.fish` (controlled by the `XDG_CONFIG_HOME` environment variable).
|
||||
|
||||
These paths are controlled by parameters set at build, install, or run time, and may vary from the defaults listed above.
|
||||
|
||||
This wide search may be confusing. If you are unsure where to put your own customisations, use `~/.config/fish/config.fish`.
|
||||
|
||||
These files are all executed on the startup of every shell. If you want to run a command only on starting an interactive shell, use the exit status of the command `status --is-interactive` to determine if the shell is interactive. If you want to run a command only when using a login shell, use `status --is-login` instead. This will speed up the starting of non-interactive or non-login shells.
|
||||
|
||||
If you are developing another program, you may wish to install configuration which is run for all users of the fish shell on a system. This is discouraged; if not carefully written, they may have side-effects or slow the startup of the shell. Additionally, users of other shells will not benefit from the Fish-specific configuration. However, if they are absolutely required, you may install them to the "vendor" configuration directory. As this path may vary from system to system, the `pkgconfig` framework should be used to discover this path with the output of `pkg-config --variable confdir fish`.
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -1028,7 +1170,7 @@ If you want to add the directory `~/linux/bin` to your PATH variable when using
|
||||
|
||||
\fish
|
||||
if status --is-login
|
||||
set PATH $PATH ~/linux/bin
|
||||
set -x PATH $PATH ~/linux/bin
|
||||
end
|
||||
\endfish
|
||||
|
||||
@@ -1058,13 +1200,7 @@ Detected errors include:
|
||||
|
||||
When the cursor is over a parenthesis or a quote, `fish` also highlights its matching quote or parenthesis.
|
||||
|
||||
To customize the syntax highlighting, you can set the environment variables `fish_color_normal`, `fish_color_command`, `fish_color_substitution`, `fish_color_redirection`, `fish_color_end`, `fish_color_error`, `fish_color_param`, `fish_color_comment`, `fish_color_match`, `fish_color_search_match`, `fish_color_cwd`, `fish_pager_color_prefix`, `fish_pager_color_completion`, `fish_pager_color_description`, `fish_pager_color_progress` and `fish_pager_color_secondary`. Usually, the value of these variables will be one of `black`, `red`, `green`, `brown`, `yellow`, `blue`, `magenta`, `purple`, `cyan`, `white` or `normal`, but they can be an array containing any color options for the `set_color` command.
|
||||
|
||||
\fish
|
||||
set fish_color_error black --background=red --bold
|
||||
# Make all commandline errors be written in a black,
|
||||
# bold font, with a red background.
|
||||
\endfish
|
||||
To customize the syntax highlighting, you can set the environment variables listed in the <a href='index.html#variables-color'>Variables for changing highlighting colors</a> section.
|
||||
|
||||
\subsection title Programmable title
|
||||
|
||||
@@ -1088,6 +1224,10 @@ function fish_title
|
||||
end
|
||||
\endfish
|
||||
|
||||
\subsection prompt Programmable prompt
|
||||
|
||||
When fish waits for input, it will display a prompt by evaluating the `fish_prompt` and `fish_right_prompt` functions. The output of the former is displayed on the left and the latter's output on the right side of the terminal. The output of `fish_mode_prompt` will be prepended on the left, though the default function only does this when in <a href="index.html#vi-mode">vi-mode</a>.
|
||||
|
||||
\subsection greeting Configurable greeting
|
||||
|
||||
If a function named `fish_greeting` exists, it will be run when entering interactive mode. Otherwise, if an environment variable named `fish_greeting` exists, it will be printed.
|
||||
@@ -1113,6 +1253,8 @@ function --on-signal WINCH my_signal_handler
|
||||
end
|
||||
\endfish
|
||||
|
||||
Please note that event handlers only become active when a function is loaded, which means you might need to otherwise <a href='commands.html#source'>source</a> or execute a function instead of relying on <a href=#syntax-function-autoloading>autoloading</a>. One approach is to put it into your <a href="index.html#initialization">initialization file</a>.
|
||||
|
||||
For more information on how to define new event handlers, see the documentation for the <a href='commands.html#function'>function</a> command.
|
||||
|
||||
|
||||
@@ -1132,7 +1274,7 @@ If you install fish in your home directory, fish will not work correctly for any
|
||||
|
||||
If you have a question not answered by this documentation, there are several avenues for help:
|
||||
|
||||
-# The official mailing list at <a href='https://lists.sf.net/lists/listinfo/fish-users'>fish-users@lists.sf.net</a>
|
||||
-# The official mailing list at <a href='https://lists.sourceforge.net/lists/listinfo/fish-users'>fish-users@lists.sourceforge.net</a>
|
||||
|
||||
-# The Internet Relay Chat channel, \#fish on `irc.oftc.net`
|
||||
|
||||
|
||||
@@ -115,9 +115,28 @@ The precise terms and conditions for copying, distribution and modification foll
|
||||
----
|
||||
|
||||
|
||||
## License for wcslcat and wcslcpy, and code derived from tmux
|
||||
## License for PCRE2
|
||||
|
||||
`fish` also contains small amounts of code under the OpenBSD license, namely versions of the two functions strlcat and strlcpy, modified for use with wide character strings. This code is copyrighted by Todd C. Miller (1998). It also contains code from [tmux](http://tmux.sourceforge.net), copyrighted by Nicholas Marriott <nicm@users.sourceforge.net> (2007), and made available under an identical license.
|
||||
`fish` contains code from the [PCRE2](http://www.pcre.org) library to support regular expressions. This code, created by Philip Hazel, is distributed under the terms of the BSD license. Copyright © 1997-2015 University of Cambridge.
|
||||
|
||||
The BSD license follows.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
-# Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
-# 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.
|
||||
|
||||
-# Neither the name of the University of Cambridge nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
|
||||
|
||||
----
|
||||
|
||||
|
||||
## License for wcslcpy and code derived from tmux
|
||||
|
||||
`fish` also contains small amounts of code under the OpenBSD license, namely a version of the function strlcpy, modified for use with wide character strings. This code is copyrighted by Todd C. Miller (1998). It also contains code from [tmux](http://tmux.sourceforge.net), copyrighted by Nicholas Marriott <nicm@users.sourceforge.net> (2007), and made available under an identical license.
|
||||
|
||||
The OpenBSD license is included below.
|
||||
|
||||
@@ -129,9 +148,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE
|
||||
----
|
||||
|
||||
|
||||
## License for xdgmime and glibc
|
||||
|
||||
The xdgmime library, written and copyrighted by Red Hat, Inc, is used by the mimedb command, which is a part of fish. It is released under the LGPL, version 2 or later, or under the Academic Free License, version 2. Version 2 of the LGPL license agreement is included below.
|
||||
## License for glibc
|
||||
|
||||
Fish contains code from the glibc library, namely the wcstok function. This code is licensed under the LGPL, version 2 or later. Version 2 of the LPGL license agreement is included below.
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
|
||||
\section math math - Perform mathematics calculations
|
||||
|
||||
\subsection math-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
math EXPRESSION
|
||||
math [-sN] EXPRESSION
|
||||
\endfish
|
||||
|
||||
\subsection math-description Description
|
||||
@@ -12,9 +11,26 @@ math EXPRESSION
|
||||
|
||||
For a description of the syntax supported by math, see the manual for the bc program. Keep in mind that parameter expansion takes place on any expressions before they are evaluated. This can be very useful in order to perform calculations involving shell variables or the output of command substitutions, but it also means that parenthesis have to be escaped.
|
||||
|
||||
The following options are available:
|
||||
|
||||
- `-sN` Sets the scale of the result. `N` must be an integer and defaults to zero. This simply sets bc's `scale` variable to the provided value. Note that you cannot put a space between `-s` and `N`.
|
||||
|
||||
\subsection return-values Return Values
|
||||
|
||||
If invalid options or no expression is provided the return `status` is two. If the expression is invalid the return `status` is three. If bc returns a result of `0` (literally, not `0.0` or similar variants) the return `status` is one otherwise it's zero.
|
||||
|
||||
\subsection math-example Examples
|
||||
|
||||
`math 1+1` outputs 2.
|
||||
|
||||
`math $status-128` outputs the numerical exit status of the last command minus 128.
|
||||
|
||||
`math 10 / 6` outputs `1`.
|
||||
|
||||
`math -s0 10.0 / 6.0` outputs `1`.
|
||||
|
||||
`math -s3 10 / 6` outputs `1.666`.
|
||||
|
||||
\subsection math-cautions Cautions
|
||||
|
||||
Note that the modulo operator (`x % y`) is not well defined for floating point arithmetic. The `bc` command produces a nonsensical result rather than emit an error and fail in that case. It doesn't matter if the arguments are integers; e.g., `10 % 4`. You'll still get an incorrect result. Do not use the `-sN` flag with N greater than zero if you want sensible answers when using the modulo operator.
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
\section mimedb mimedb - lookup file information via the mime database
|
||||
|
||||
\subsection mimedb-synopsis Synopsis
|
||||
\fish{synopsis}
|
||||
mimedb [OPTIONS] FILES...
|
||||
\endfish
|
||||
|
||||
\subsection mimedb-description Description
|
||||
|
||||
`mimedb` queries the MIME type database and the `.desktop` files installed on the system in order to find information on the files listed in `FILES`. The information that `mimedb` can retrieve includes the MIME type for a file, a description of the type, and the default action that can be performed on the file. `mimedb` can also be used to launch the default action for this file.
|
||||
|
||||
The following options are available:
|
||||
|
||||
- `-t`, `--input-file-data` determines the files' type both by their filename and by their contents (default behaviour).
|
||||
|
||||
- `-f`, `--input-filename` determines the files' type by their filename.
|
||||
|
||||
- `-i`, `--input-mime` specifies that the arguments are not files, but MIME types.
|
||||
|
||||
- `-m`, `--output-mime` outputs the MIME type of each file (default behaviour).
|
||||
|
||||
- `-f`, `--output-description` outputs the description of each MIME type.
|
||||
|
||||
- `-a`, `--output-action` outputs the default action of each MIME type.
|
||||
|
||||
- `-l`, `--launch` launches the default action for the specified files.
|
||||
|
||||
- `-v`, `--version` displays the version number and exits.
|
||||
@@ -11,6 +11,7 @@ nextd [ -l | --list ] [POS]
|
||||
|
||||
If the `-l` or `--list` flag is specified, the current directory history is also displayed.
|
||||
|
||||
Note that the `cd` command limits directory history to the 25 most recently visited directories. The history is stored in the `$dirprev` and `$dirnext` variables which this command manipulates.
|
||||
|
||||
\subsection nextd-example Example
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ open FILES...
|
||||
|
||||
\subsection open-description Description
|
||||
|
||||
`open` opens a file in its default application, using the `xdg-open` command if it exists, or else the <a href="commands.html#mimedb">mimedb</a> command.
|
||||
`open` opens a file in its default application, using the appropriate tool for the operating system. On GNU/Linux, this requires the common but optional `xdg-open` utility, from the `xdg-utils` package.
|
||||
|
||||
|
||||
\subsection open-example Example
|
||||
|
||||
@@ -7,12 +7,12 @@ COMMAND1; or COMMAND2
|
||||
|
||||
\subsection or-description Description
|
||||
|
||||
`or` is used to execute a command if the current exit status (as set by the last previous command) is not 0.
|
||||
`or` is used to execute a command if the current exit status (as set by the previous command) is not 0.
|
||||
|
||||
`or` does not change the current exit status.
|
||||
|
||||
The exit status of the last foreground command to exit can always be accessed using the <a href="index.html#variables-status">$status</a> variable.
|
||||
`or` statements may be used as part of the condition in an <a href="#if">`and`</a> or <a href="#while">`while`</a> block. See the documentation
|
||||
for <a href="#if">`if`</a> and <a href="#while">`while`</a> for examples.
|
||||
|
||||
`or` does not change the current exit status. The exit status of the last foreground command to exit can always be accessed using the <a href="index.html#variables-status">$status</a> variable.
|
||||
|
||||
\subsection or-example Example
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ prevd [ -l | --list ] [POS]
|
||||
|
||||
If the `-l` or `--list` flag is specified, the current history is also displayed.
|
||||
|
||||
Note that the `cd` command limits directory history to the 25 most recently visited directories. The history is stored in the `$dirprev` and `$dirnext` variables which this command manipulates.
|
||||
|
||||
\subsection prevd-example Example
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user