Compare commits

..

193 Commits

Author SHA1 Message Date
axel
f7b656017f Use the same wording about license in Makefile and main.c.
darcs-hash:20061101144747-ac50b-fac8e3693445a8601f0c71ab191a64dac0ad7a67.gz
2006-11-02 00:47:47 +10:00
axel
7a8ca73376 Add missing include to fix a warning
darcs-hash:20061101105412-ac50b-1ee3d996330ad435954abfc8f827deb3f121adb5.gz
2006-11-01 20:54:12 +10:00
axel
9eb1826961 Update to buildscripts to fix dependency issues caused by new documentation layout
darcs-hash:20061101103112-ac50b-8ee49c3031b7802822c95ffcfee26d10e1870ed1.gz
2006-11-01 20:31:12 +10:00
axel
728a60bd67 Fix beginning/end-of-line input function, add beginning/end-of-buffer functions
darcs-hash:20061031220149-ac50b-6e6b8f523642bead730059dd96ee2d1290283b5e.gz
2006-11-01 08:01:49 +10:00
axel
0099c3c420 Add table of contents to begining of documentation. This involves some restructuring of the documentation files.
darcs-hash:20061031153614-ac50b-7a6e97e30ae759591028227466e76c574b931fd5.gz
2006-11-01 01:36:14 +10:00
axel
885d16fcd6 Fix casing and other minor issues in documentation
darcs-hash:20061031152316-ac50b-e68db9853d6e9461a0c054f1ea290704ccfc0a31.gz
2006-11-01 01:23:16 +10:00
axel
c4a8f4c890 Code beutification in build files
darcs-hash:20061031020656-ac50b-2385bb51d7df624e5691b7659120596600fd1d5d.gz
2006-10-31 12:06:56 +10:00
axel
c098cb5c87 Bump version number
darcs-hash:20061030160357-ac50b-29729cb4ba358e09f9c19e6d6e07e0c2489e14fd.gz
2006-10-31 02:03:57 +10:00
axel
63643ff17f Fix completions for which and type, which where broken by previous script updates
darcs-hash:20061030015221-ac50b-e4a0f2802e7a5dc4a1e594933f25cae00d9ea104.gz
2006-10-30 11:52:21 +10:00
axel
f83575f084 Make sure signals aren't blocked while autoloading, also add a few consistency checks to see that signals aren't blocked in critical places
darcs-hash:20061029210911-ac50b-50bec85c3d59d0332ba44f3ece1a012cdc3e8c4b.gz
2006-10-30 07:09:11 +10:00
axel
a6c00ca0d2 Minor edits
darcs-hash:20061028164448-ac50b-c53d5f235d01db3a11b01996b77411a213dc5303.gz
2006-10-29 02:44:48 +10:00
axel
c5eaefc8b5 Update autoloader to fix concurrency issues when changing loader path in autoloaded function
darcs-hash:20061028164122-ac50b-25f978df9afeb370a06ef7576ef03183034bc057.gz
2006-10-29 02:41:22 +10:00
axel
f16bb285be Documentation updates and clarifications
darcs-hash:20061028163229-ac50b-2b6d3712a97903788520c155326b0e7a193b5eec.gz
2006-10-29 02:32:29 +10:00
axel
09c348bef2 Add a shellscript function 'save'function' for saving the current definition of a function to file
darcs-hash:20061027225004-ac50b-2454152687ff84deec90e3d938a0288e62dc34e6.gz
2006-10-28 08:50:04 +10:00
axel
561ec7d5f5 Change the way the umask is used so that executable bits are ignored on file creation. Thanks to sqweek and Jamessan for explaining the issue.
darcs-hash:20061026151946-ac50b-3a55159343f1fe0a4edf3f077bcec8afd6f131f5.gz
2006-10-27 01:19:46 +10:00
axel
e98a604a21 Minor edits, remove unneeded code, add a few commants, correct spelling, tweak the todo list, etc.
darcs-hash:20061026102253-ac50b-eb42fdab9a9211d68386a563134856a96b870d90.gz
2006-10-26 20:22:53 +10:00
axel
3341fc888c Make the fish manpage in Doxygen and add it to the main fish documentation
darcs-hash:20061026102059-ac50b-2a7956bb4651b5ffe867e7c6eb26a29e2f15ad24.gz
2006-10-26 20:20:59 +10:00
axel
1faf7df371 Move out argument parsing into it's own function
darcs-hash:20061025205443-ac50b-2889624cadb3b92be13da523df32b178c773dbf7.gz
2006-10-26 06:54:43 +10:00
axel
3a128e1484 Use bitset to implement flags for jobs instead of wasting a whole int for every flag
darcs-hash:20061025204759-ac50b-ea07caa30782a1ea02d2cd8aa7cbc94474047a10.gz
2006-10-26 06:47:59 +10:00
axel
cdc52f7bde Add more comments to the history implementation
darcs-hash:20061025204650-ac50b-419d37d9ea68de0deee613524d06882a8e4c908e.gz
2006-10-26 06:46:50 +10:00
axel
e0899addcb Minor cleanups and improved error checking in reader code
darcs-hash:20061025203608-ac50b-213edeb462eaabce849d9cd13ffc30879e810bb8.gz
2006-10-26 06:36:08 +10:00
axel
c627509e59 Make al_pop return null on empty lists instead of crashing
darcs-hash:20061025203433-ac50b-5d3a18d788d6f36dffe1136664f029a500989db9.gz
2006-10-26 06:34:33 +10:00
axel
4502fc74c3 Fix spelling error in init file
darcs-hash:20061025203337-ac50b-576bd81401e332f94ecdff5665ca8da82c63fa8e.gz
2006-10-26 06:33:37 +10:00
axel
3b0ed061cd If the builtin help won't fit on-screen, and it can't be shortened, don't print it
darcs-hash:20061025203225-ac50b-8675f297a8aabea080edf7946d6f136296a6d7bb.gz
2006-10-26 06:32:25 +10:00
axel
dfa73c7cc1 Remove the --key-binding switch for fish
darcs-hash:20061025202836-ac50b-682015e2f5830a85ff520e89b0a951ca9d2913dc.gz
2006-10-26 06:28:36 +10:00
axel
12be24ef47 Update dependency list
darcs-hash:20061025163950-ac50b-161f81c51f5e923bfaf0aa9fda4d74f785e7aff7.gz
2006-10-26 02:39:50 +10:00
axel
c684b7c7c7 Update makefile to not try to delete old config files during install, and instead fail with a relevant error message. Thanks to Jamessan for pointing out the evilness of the old method and suggesting the new method.
darcs-hash:20061025163532-ac50b-ff394c53b8eb0d932894784bc25e086f9c9b65ec.gz
2006-10-26 02:35:32 +10:00
axel
4f22082a5c Do not remove trailing whitespace from function definitions, the may be a part of a function
darcs-hash:20061025122712-ac50b-6d7ab43572f71cafa5fddd65b8350498e2651b41.gz
2006-10-25 22:27:12 +10:00
axel
e3c1363831 Drop switch for saving of functions to file from the function builtin
darcs-hash:20061025105746-ac50b-942e878b01f5e080d7cf1e6414246b68b608b08f.gz
2006-10-25 20:57:46 +10:00
axel
6d413c8dc3 Fix bug where in rare cases calling the exit builtin would cause jobs to not execute even though the call to exit was blocked by running jobs
darcs-hash:20061025101402-ac50b-36456915671513f376a90c4455d1c9256f4a9030.gz
2006-10-25 20:14:02 +10:00
axel
32a49e45c8 Use the _t suffix for typedef:ed structs in complete.c
darcs-hash:20061024110352-ac50b-30768be6a11d9a5935be479fbdb430a42b0a95b9.gz
2006-10-24 21:03:52 +10:00
axel
b37d49a708 Fix bug in sed scripts for generating configuration files from templates. Multiple substitutions on the same line where ignored.
darcs-hash:20061023104315-ac50b-e5e84fb1e33fad98d81efccca0ae5dd57b479c7e.gz
2006-10-23 20:43:15 +10:00
axel
86b7023536 Decrease priority of fishd debug message
darcs-hash:20061022160329-ac50b-5f35fe90f6be184f02fc6514fc6047b25e4f93c3.gz
2006-10-23 02:03:29 +10:00
axel
287ab597ca Remove extra whitespace from warning message on directory transition
darcs-hash:20061022155759-ac50b-e1cd50b1b0d05413ad6e4d6c06a0f005e17d6976.gz
2006-10-23 01:57:59 +10:00
axel
c313f21066 A few more minor code tweaks to fish_pager, including added documentation and removing a few hardcoded constants.
darcs-hash:20061022115026-ac50b-590de2ef2f0cbe474ca4e41fd134e0c46d6877b3.gz
2006-10-22 21:50:26 +10:00
axel
e2dca4273a Add documentation, fix memory leaks and do minor code tweaks in fish_pager
darcs-hash:20061022110414-ac50b-e5ba776e795e0273d819d4eb51d5f60fba967db2.gz
2006-10-22 21:04:14 +10:00
axel
5a7a8003a0 Give search highligting precedence over other highligting types
darcs-hash:20061022094018-ac50b-0f688dc7e756f428c05e6977db6dc9cf9f642475.gz
2006-10-22 19:40:18 +10:00
axel
b83a7cb659 Make automatic history reloading actually work the way it should
darcs-hash:20061022012102-ac50b-e57a0dd2c918a2a8abd0210b9f8a2163ce664b74.gz
2006-10-22 11:21:02 +10:00
axel
da81328d75 Fix warning messages in fish_tests
darcs-hash:20061021225900-ac50b-992edf0914250ae090ef952717ef3a05cb9cfa6e.gz
2006-10-22 08:59:00 +10:00
axel
5ae4306418 Change meaning of ** to match both files and directories
darcs-hash:20061021224429-ac50b-38e46fa533baf9a46d207ab95bfa7af55abbe54a.gz
2006-10-22 08:44:29 +10:00
axel
ed36f30eae Fix crash bug in new history code - fish would segfauls in non-interactive mode on exit
darcs-hash:20061021103035-ac50b-a2a8d96416ff217cc5640f8f27db8dbac2c39b82.gz
2006-10-21 20:30:35 +10:00
axel
7b8ebdadd6 Fix flags for mmap in history, don't unload history items written to disk in order to keep proper ordering
darcs-hash:20061021101609-ac50b-563c0b14b620a6ef4bffe69202e97103b1d75ea5.gz
2006-10-21 20:16:09 +10:00
axel
bb4e166b37 Add some documentation to the new history code, and fix some minor code issues
darcs-hash:20061020230420-ac50b-39a08d68b82481514b0d6c1024a12618bf329d57.gz
2006-10-21 09:04:20 +10:00
axel
9dc1a7d5e9 Rewritten history implementation - uses mmap to save lots of memory and also allows incremental saving. The history is autosaved every five minutes and every five added entries
darcs-hash:20061020223649-ac50b-5e3e2c1e395feec0f5ac457149639f68d52d40f0.gz
2006-10-21 08:36:49 +10:00
axel
79f59e2a2d Decrease number of gettext messages that are buffered to save memory
darcs-hash:20061020223440-ac50b-ad0c0f685bfc851c62c340ee7d97fa1413bc9fca.gz
2006-10-21 08:34:40 +10:00
axel
8285242ff6 Add wrename wrapper around rename function
darcs-hash:20061020223347-ac50b-1735f7e63b87f021ca71c44e5278726d3e8debc3.gz
2006-10-21 08:33:47 +10:00
axel
c0a54955e7 Remove /etc/fish file before creating directory with the same name to avoid clash
darcs-hash:20061019234336-ac50b-569c1b492ab4d1f5f84dc8a4730700264c4e3e10.gz
2006-10-20 09:43:36 +10:00
axel
b2d4e85f17 Make any character except '/' legal in function names
darcs-hash:20061019154747-ac50b-f3ab0df1085b91ec0eadcceddb23f03d5b0247aa.gz
2006-10-20 01:47:47 +10:00
axel
a5868d67f5 Make failed process expansions expand to zero arguments, not to the original string
darcs-hash:20061019154127-ac50b-86975e62d9947819862a98e7b6fff3ff630f26b7.gz
2006-10-20 01:41:27 +10:00
axel
45f1263112 Minor code fixes
darcs-hash:20061019153950-ac50b-9a7d5939ce47cd5f8b7167a97b0e9c62315b7b6e.gz
2006-10-20 01:39:50 +10:00
axel
4683f4c989 Fix a number of bugs found using the warnings generated by earlier patch
darcs-hash:20061019153603-ac50b-4efb1ad1fe2cbe693a921648a0616a3d258d7933.gz
2006-10-20 01:36:03 +10:00
axel
ae16397e1c Fix occasional garbled characters in output of the set builtin
darcs-hash:20061019152418-ac50b-2ef6e93820deb5e272f28f893c51dca642a6b080.gz
2006-10-20 01:24:18 +10:00
axel
2d05b1c1b4 Add compiler warnings for some common incorrect usage of functions, such as forgetting to cast null pointers to variadic functions
darcs-hash:20061019151947-ac50b-4043638a7a830fa80fd918f92365f5afe3ff208a.gz
2006-10-20 01:19:47 +10:00
axel
ea998b03f2 First stab at directory transition. Test with care...
darcs-hash:20061019115023-ac50b-30c3fd51d8af8a616d63dfcac39370d7fe6d144e.gz
2006-10-19 21:50:23 +10:00
axel
52b2525b0e Make the callback for the file autoloader optional, and clarify its use
darcs-hash:20061019114632-ac50b-a0b3e1b3e7f26aa7cd674ade1a4fb2246f978ebc.gz
2006-10-19 21:46:32 +10:00
axel
ff96668151 Minor edits to documentation
darcs-hash:20061019114024-ac50b-e283638e3a34e1d38be58971f31900129230c598.gz
2006-10-19 21:40:24 +10:00
axel
d7576a409a Make history variable contain whole history
darcs-hash:20061019113916-ac50b-7e24780cdd591ae23210f0da2cb80a4cf09ba5c6.gz
2006-10-19 21:39:16 +10:00
axel
f6815629fc Give USER and HOME default values if undefined
darcs-hash:20061019113844-ac50b-def2288d589f479779166ed64903e99c8c8ab71a.gz
2006-10-19 21:38:44 +10:00
axel
8b3bcd2c4c Tweak initial capacity calculations to always be a Mersenne number
darcs-hash:20061018230246-ac50b-3da6ada42423f5bba3f8c3fdb366ce1f352cffde.gz
2006-10-19 09:02:46 +10:00
axel
c7bc31fe50 Fix exceptaionally rare crash bug in hash tables (happens once in every 2^32 hash lookups
darcs-hash:20061018230148-ac50b-4e67ecf1f9aeae8239c40101ae2ad6aa164c31bb.gz
2006-10-19 09:01:48 +10:00
axel
bab168f1d1 Fix yet another universal variable issue with initialization of the read buffer. This may fix fishd bugs reported by Philip Ganchev and Martin Bähr
darcs-hash:20061018164438-ac50b-c586b1ad36249853d613d0137b505377fe890d37.gz
2006-10-19 02:44:38 +10:00
axel
2ab04f4043 Skip command description lookup when no commands where found
darcs-hash:20061018155151-ac50b-5562479da23b89571f91ae1e2ed15e640ef0a094.gz
2006-10-19 01:51:51 +10:00
axel
b32bbb24b9 Fix bug in command description lookup code causing missing descriptions when command is given with a path
darcs-hash:20061018155059-ac50b-40936e573c07deb6b159a16d843f02ed60e79b49.gz
2006-10-19 01:50:59 +10:00
axel
f86f80fcd6 Properly handle character sets in universal variables
darcs-hash:20061017211129-ac50b-6aecd04b74a9122ff0e1b320a2cf48db36dd2194.gz
2006-10-18 07:11:29 +10:00
axel
d563e428e8 Avoid unloading an item currently being loaded by the autoloader
darcs-hash:20061016154022-ac50b-f4b74457a9e3acdcc70076f65dff4c1f00ac379f.gz
2006-10-17 01:40:22 +10:00
axel
5473711a20 Minor code simplifications in the reader and related libraries
darcs-hash:20061016153226-ac50b-830735fadfdf578dfa4c686a2a6cd98df0e50c95.gz
2006-10-17 01:32:26 +10:00
axel
91009ac9aa Fix hang bug when appending to killring
darcs-hash:20061016150017-ac50b-c1f789d9913949ebc44cd9d02af5c3555bdf51bf.gz
2006-10-17 01:00:17 +10:00
axel
49bff53370 Avoid reading before begining of buffer when moving/erasing word, fixes crash bug reported by Martin Bähr and further described by Philip Ganchev.
darcs-hash:20061016143912-ac50b-1deacc00f6c0438e6d760568ef5b1e47e3fe08c4.gz
2006-10-17 00:39:12 +10:00
axel
afcab9f1b3 Minor bugfix in the kill-ring code
darcs-hash:20061012223200-ac50b-6a046a89295f01937a38000ef6d016b7be5c19f1.gz
2006-10-13 08:32:00 +10:00
axel
841fdf3a04 Make kill-word and backward-kill-word accumulate kills in the killring
darcs-hash:20061012193000-ac50b-69f261df78b3957b9cec3d728fe05b8a27267c31.gz
2006-10-13 05:30:00 +10:00
axel
92446bda80 Yet another tweak to the move_word function
darcs-hash:20061012161317-ac50b-3b374e2b6c4c22f82c1cf018bf83298c8216fcb1.gz
2006-10-13 02:13:17 +10:00
axel
a620a1e5ed Update todo-list
darcs-hash:20061012140247-ac50b-ae6b9a26c5979dc7080ff3fea8dad618211227e1.gz
2006-10-13 00:02:47 +10:00
axel
5a8df6cc85 Fix major memory leak in autoloader introduced by recent autounloader patch
darcs-hash:20061012133012-ac50b-d03de17d9df4d41db075b24c2f7e48ad8c0f6417.gz
2006-10-12 23:30:12 +10:00
axel
b70b966f90 Fix the kill-line, backward-kill-line and kill-whole-line commands to work correctly with multiline editing
darcs-hash:20061012132732-ac50b-03fe641cf32ace645c88174528e849ab0d1ecb4b.gz
2006-10-12 23:27:32 +10:00
axel
97f7c2093b Drop warning in parse_util.c
darcs-hash:20061012120859-ac50b-1af2af938cd99630c2ea7b532e6213c26cc4ea6b.gz
2006-10-12 22:08:59 +10:00
axel
8ece4f3ddc Better string hashing function
darcs-hash:20061012010129-ac50b-3c420efe649e892c491d9d9830dda153ca395655.gz
2006-10-12 11:01:29 +10:00
axel
17a13a8eb7 Use the xdg-open command in the open function if it exists
darcs-hash:20061011161749-ac50b-f700489a238dafbd9aec4ef4f2eed731a8622b27.gz
2006-10-12 02:17:49 +10:00
axel
afaf156a42 Fix compilation issue in test suite,. Thanks to Martin Bähr for the report.
darcs-hash:20061010224721-ac50b-0bd07f325c2026d991cf9535941060fadd5869cb.gz
2006-10-11 08:47:21 +10:00
axel
c4f3b5e9ef Unload older autoloaded functions
darcs-hash:20061010224546-ac50b-7c3f38d32d4a413a9c0d8436bb13a5d65235f3a7.gz
2006-10-11 08:45:46 +10:00
axel
f5916358e5 Fix bug in the input buffering of messages to/from fishd causing garbled messages
darcs-hash:20061010222113-ac50b-1b6b01ab781ecbadf11a99b501f19a526ae7a7cf.gz
2006-10-11 08:21:13 +10:00
axel
e3e1b34fec Only show greeting in interactive mode
darcs-hash:20061010173154-ac50b-4831a80be03ed132ca5f709dcc5284d17d828d4e.gz
2006-10-11 03:31:54 +10:00
James Vega
18bb4ca826 Makefile.in: Update clean target to preserve builtin_help.c, user_doc, doc_src/builtin_doc and remove share/fish
darcs-hash:20060920040413-35ec8-2bc89e5dff67e2cab274676df2ca90eb1bb385e9.gz
2006-09-20 14:04:13 +10:00
axel
007e4662e3 Fix bug in contains function
darcs-hash:20061009215133-ac50b-3dc99c245e69c176f334046d9746d533a106cf2a.gz
2006-10-10 07:51:33 +10:00
axel
e11677ef66 Make the greeting message configurable using the fish_greeting variable
darcs-hash:20061009214905-ac50b-cc07bf2b76c5306f96d1bca7fd478d972de25de8.gz
2006-10-10 07:49:05 +10:00
axel
194167da32 New version of the xdg fix. Unlike the previous version, this one should actually work.
darcs-hash:20061009212440-ac50b-10d1cdd7441335d033171f5b71a8a97f8a1d1dfb.gz
2006-10-10 07:24:40 +10:00
axel
dafeac5c40 Fix compilation issues in xdg library caused missing headers. Thanks to Jamessan for the report.
darcs-hash:20061009201230-ac50b-4b5c183fbd88ef45a0ededdc3eea79191951fb5f.gz
2006-10-10 06:12:30 +10:00
axel
effea85984 Apdate address of fish homepage
darcs-hash:20061009152007-ac50b-403f605d46849a3b83192d872c4f6322bf97bb7e.gz
2006-10-10 01:20:07 +10:00
axel
0b34836c79 Update dependency list
darcs-hash:20061009151948-ac50b-89b0c12a9c8763517d85bf3e46f78b7c64846db6.gz
2006-10-10 01:19:48 +10:00
axel
f85ce201ee Do not use INTERNAL_SEPARATOR tokens to separate different parts of an unescaped string when unescape_special is false. This fixes a bug where weird characters would sometimes be printed in completion descriptions
darcs-hash:20061009151913-ac50b-47a9d3274b2399cef6fd0e12a908a606da2c4903.gz
2006-10-10 01:19:13 +10:00
axel
80ac4ddc2b Allow more than one argument to the commandline builtin. The arguments will be joined together using newlines
darcs-hash:20061009141608-ac50b-546c0f5897670bb7e628d6e7c63d687eac261ee1.gz
2006-10-10 00:16:08 +10:00
axel
9a0f712e29 Make the screen repainting code slightly more robust by keeping track of whether clr_eol may be needed to clear 'debris' from e.g. resizes
darcs-hash:20061009132642-ac50b-6162ed86a97771a8da4be2adff3ad6a4f1851616.gz
2006-10-09 23:26:42 +10:00
axel
286e110fb1 Various minor cleanups
darcs-hash:20061009103408-ac50b-a54797b9f89f51a8fc8f13674e8fd2329e989d4c.gz
2006-10-09 20:34:08 +10:00
axel
988a7fddf3 Indent empty lines after a block command correctly. Thanks to Philip Ganchev for the suggestion.
darcs-hash:20061009095931-ac50b-c958a6ec7a130019527e8e06d94af010d55ac3d5.gz
2006-10-09 19:59:31 +10:00
axel
a321505351 Allow escaped newlines within qoutes, expand them to themselves
darcs-hash:20061009012248-ac50b-a403705cfe166c7686a168bc017c50c316c28161.gz
2006-10-09 11:22:48 +10:00
axel
a074cd62bc Be more rigorous with the exit codes set by the parser and builtins
darcs-hash:20061009012102-ac50b-4f28c43dd1ccdcc04d1620a6da05218a99fd7337.gz
2006-10-09 11:21:02 +10:00
axel
7a8b468165 Allow Meta-newline to always insert a newline character
darcs-hash:20061009011529-ac50b-c8e3d77b569bc445e586c95aca01e4433fbff598.gz
2006-10-09 11:15:29 +10:00
axel
770fa771b6 Unknown commands should set the status flag to 127, as in bash and friends
darcs-hash:20061008234650-ac50b-d41e6ec3d0a6088b0addf5721aecf8d98ed866cd.gz
2006-10-09 09:46:50 +10:00
axel
414fa591b8 Make sure that if a syntax error occurs, the parser does not try to evaluate command substitutions in the command
darcs-hash:20061008234458-ac50b-96f9be42b12a9d2d2b61f6700b25c1242e1c385b.gz
2006-10-09 09:44:58 +10:00
axel
941b472b37 Make sure indentation works even if a line begins with whitespace
darcs-hash:20061008232351-ac50b-122ff623a2e428352477aa52afee9a71b40e569e.gz
2006-10-09 09:23:51 +10:00
axel
179f575593 Update history loading/saving to handle multiline editing
darcs-hash:20061008135046-ac50b-e830fe313e23f632b9c645227f41c49c8ce600f4.gz
2006-10-08 23:50:46 +10:00
axel
6400b60bdd Fix a few places where uncasted 0 was used as a null pointer in vararg functions, causing potential crashes on 64-bit platforms
darcs-hash:20061008132759-ac50b-23fe4f70a5143b8b187780403d8d21fb69c3e83f.gz
2006-10-08 23:27:59 +10:00
axel
0e03e872be Fis minor memory leak in screen handling code
darcs-hash:20061008004704-ac50b-3f40073c00f1ebd8e851c49e2df873c423637d0c.gz
2006-10-08 10:47:04 +10:00
axel
e51322ac81 Make it possible to use backslash to stay in multiline mode even when not at the end of the command
darcs-hash:20061007210631-ac50b-cc8513802c247d92c8d4d5f7bcf7a146aab67a1e.gz
2006-10-08 07:06:31 +10:00
axel
1e739166b3 Fix tokenizer bug causing bad highlighting in multiline mode
darcs-hash:20061007210521-ac50b-5cdfc808389c928b932b0e41ef14abd71b537633.gz
2006-10-08 07:05:21 +10:00
axel
560e53fd5f Add autoindentation support
darcs-hash:20061007005625-ac50b-11873654797eb1e98fd17893022bdf995be3e2aa.gz
2006-10-07 10:56:25 +10:00
axel
184d58cd36 Buffer calls to read() in the universal variable code
darcs-hash:20061006184539-ac50b-d8ecc4c45d0caae12cd60e32515a1218b37831d3.gz
2006-10-07 04:45:39 +10:00
axel
bcf3024cf0 Update todo list
darcs-hash:20061005201141-ac50b-5441cefd081ede3d7b02c5955c828ac7c3f132c3.gz
2006-10-06 06:11:41 +10:00
axel
9611a3b205 Color the ellipsis used by line wrapping as comments. Thanks to Philip Ganchev for the suggestion.
darcs-hash:20061005194026-ac50b-2708cfe79f28dbae9febc3fc5fcddb48c1fc8822.gz
2006-10-06 05:40:26 +10:00
axel
8ace1739f5 Add missing newline in error message for popd function. Thanks to Phipip Ganchev.
darcs-hash:20061005064419-ac50b-4770f393ea02761a5f4b4044b456d1b618d6da23.gz
2006-10-05 16:44:19 +10:00
axel
302516a747 Fix bug causing ls function to never color or classify files
darcs-hash:20061004235530-ac50b-815b8576b4d845c4d5929e034177c917fc050cae.gz
2006-10-05 09:55:30 +10:00
axel
ad5a6e0552 Move the code keeping track of file descriptor modification from reader.c to screen.c
darcs-hash:20061004233312-ac50b-9a10ff758375885ae78a5e5c04279c1976a037ea.gz
2006-10-05 09:33:12 +10:00
axel
873fd83307 Drop the optional checking of block type for the end builtin
darcs-hash:20061004233206-ac50b-cf72c879b4b58c8e5ba4e1dff5c2746ca2e8844f.gz
2006-10-05 09:32:06 +10:00
axel
d1078f8582 Detect and handle terminals size changes
darcs-hash:20061004214502-ac50b-aaf5b76a6281c0ba8757e794b0a802793ce92916.gz
2006-10-05 07:45:02 +10:00
axel
0ea668b260 Minor code cleanup
darcs-hash:20061004214204-ac50b-e1529fcedb1665f9871a95eba293a4a3c1150464.gz
2006-10-05 07:42:04 +10:00
axel
91c745e4b5 Add the possibility to set the cursor position using the commandline builtin
darcs-hash:20061004213948-ac50b-3f673edeb01390bb3f280812d90bc8469f2f8ba8.gz
2006-10-05 07:39:48 +10:00
axel
7d73349889 Add the possibility to set the input that the commandline builtin operates on
darcs-hash:20061004184939-ac50b-f2c3e2161a5bf77834a566462ac9942571c9d6ea.gz
2006-10-05 04:49:39 +10:00
axel
53a2c017fe Mangle very long variable values when using the set builtin to print variables and their values
darcs-hash:20061004181901-ac50b-a043695fa8fffe877970a51dd042c4bf623a770c.gz
2006-10-05 04:19:01 +10:00
axel
80ff583400 Use universal variables for fish_function_path and fish_complete_path
darcs-hash:20061004175519-ac50b-2e9dabc9ce1c21ebfcba020db8a8d84ef48433e9.gz
2006-10-05 03:55:19 +10:00
axel
0c7f74c78d Repain prompt after showing completion pager
darcs-hash:20061004102706-ac50b-51d0603c81f3125c01bad0901f8d2b745fc18e4a.gz
2006-10-04 20:27:06 +10:00
axel
13b1ea3f50 Various fixes to make double-wide characters (e.g. asian characters) work with the new multiline editing code
darcs-hash:20061001232136-ac50b-9bd771b382c00b71c5e2ee75df77ba2594b2a738.gz
2006-10-02 09:21:36 +10:00
axel
44ff9956b9 Second cleanup of multiline editing patch. Add code comments, use better variable names, etc..
darcs-hash:20061001212243-ac50b-6cd5abfcf6b7013fd23b27734ca29af27d945ca3.gz
2006-10-02 07:22:43 +10:00
axel
add1fa9208 First cleanup of multiline patch - add support for commands longer than one line and do minor cleanups, including removal of a few unused functions
darcs-hash:20061001205423-ac50b-2819a086fecb1bcd0ab1bc63bae76956f0181f54.gz
2006-10-02 06:54:23 +10:00
axel
8b2059c628 Add function to insert a range of new elements into the middle of an array_list
darcs-hash:20061001201728-ac50b-db2f7bccee53224f50347c8995b2f6496940243d.gz
2006-10-02 06:17:28 +10:00
axel
15724d0798 First stab at multiline editing
darcs-hash:20061001160258-ac50b-1a760913e64b96e30ff321d7fbe4069ca161cdfe.gz
2006-10-02 02:02:58 +10:00
axel
2839f5e567 Minor comment and documentation edits
darcs-hash:20061001155918-ac50b-8b5b4f5dbd8334bac1c0dc77fa18c8f3cfb4a878.gz
2006-10-02 01:59:18 +10:00
axel
67c820cee8 Minor tweaks to code validation for the for builtin (again)
darcs-hash:20061001155734-ac50b-6009b98dfccaf8f8292859f25c4d564c6b622f47.gz
2006-10-02 01:57:34 +10:00
axel
bce4c78d49 Further reduction of malloc calls in the history
darcs-hash:20061001152040-ac50b-085f4b8ce20c4793d5e592f7a213df04208630cb.gz
2006-10-02 01:20:40 +10:00
axel
421ebcc2d7 Be a bit more careful with memory alignemnt in halloc
darcs-hash:20060930121917-ac50b-6292696663684a38844b4c21360274b365e52969.gz
2006-09-30 22:19:17 +10:00
axel
92df4a6d91 Make sure M-d erases last character of word. Thanks to DynWind for the report
darcs-hash:20060929214804-ac50b-ffb19242fcbd594fb72016427704cb51cf9d0a22.gz
2006-09-30 07:48:04 +10:00
axel
22fe8e6a17 Fix bug in the setenv function (values wheren't exported!), thanks to Matrin Bähr for the report.
darcs-hash:20060928165405-ac50b-5ada00cfc08805677e1932c800ee79d68e35a68b.gz
2006-09-29 02:54:05 +10:00
axel
d0f1870735 Add syntax check to see that the for builtin is not given an insufficient number of arguments
darcs-hash:20060926124109-ac50b-b088397933fa7ea539e48fa9fcd461de8295f7ce.gz
2006-09-26 22:41:09 +10:00
axel
b71f5d09b0 Fix occasional off-by-one bug in syntax highlighting causing the character next to the cursor to be unhighlighted instead of the cursor itself
darcs-hash:20060924175723-ac50b-35757e87eb7076c2ecdecaed11c1bb673c571035.gz
2006-09-25 03:57:23 +10:00
axel
eb00ad77fb Make sure isatty docs are built into the main doc file
darcs-hash:20060919175509-ac50b-0174257f46e15d6e931bd8664e8a83ac498707b2.gz
2006-09-20 03:55:09 +10:00
axel
be886bc6df Unly use classifications in ls if stdout is a tty
darcs-hash:20060919165317-ac50b-c7923c7f5900ecc9814756743e6b0345efa382c5.gz
2006-09-20 02:53:17 +10:00
axel
7a5823fd60 Documentation updates from Beni Cherniavsky
darcs-hash:20060919145203-ac50b-bc87b8f5e6a18395e4bc3e364da4a40ad97850e7.gz
2006-09-20 00:52:03 +10:00
axel
81d61c467b Fix bug in for that causes crash on syntax error
darcs-hash:20060919142140-ac50b-48cbbdfd109e2b420d8e36acd5b13696445c0850.gz
2006-09-20 00:21:40 +10:00
axel
e91e3b6593 Minor bugfix in the switch parsing for the status builitn
darcs-hash:20060919142042-ac50b-b532e0308407d101d1f8b328a575a54e8bc46799.gz
2006-09-20 00:20:42 +10:00
axel
1db67a5105 Add completions for the wpa_cli command
darcs-hash:20060918222913-ac50b-9aeac9d1a5ecb4b6915625b07133b66ebab0b2bd.gz
2006-09-19 08:29:13 +10:00
axel
810faacd72 Make sure that syntax validator allows use of 'break' and 'continue' with --help even outside of loops, and make sure 'return' is only used in function definitions.
darcs-hash:20060918001518-ac50b-78977cbd17e4edce8d1b7d4c5426f478d42392af.gz
2006-09-18 10:15:18 +10:00
axel
6be3807cae Fix issue with ^W and other shortcurs sometimes not deleting anything
darcs-hash:20060916230532-ac50b-395d34e2c67d2be3d634638265a98239442fd6cd.gz
2006-09-17 09:05:32 +10:00
axel
4399503f4e Fix a bug in completion insertion code on string with escaped quotes. This bug was reported by David Benbennick.
darcs-hash:20060914151821-ac50b-c6628fc01a90865e0aec6e93b39b77c3877606fc.gz
2006-09-15 01:18:21 +10:00
axel
06b5fdc6e8 Update todo-list. Thanks to MArtin Bähr for the additions.
darcs-hash:20060913212744-ac50b-cb446bcebc04a89c7b065e2d3879b474740a005e.gz
2006-09-14 07:27:44 +10:00
axel
4037219dc0 Make sude completions include /sbin and /usr/sbin in PATH. Thanks to Xavier Douville for the suggestion.
darcs-hash:20060913171310-ac50b-a9e30533bc634f194f73fdee1e042d407f55fcac.gz
2006-09-14 03:13:10 +10:00
axel
1612ec50fb Fix bug in __fish_complete_subcommand, reported by Xavier Douville
darcs-hash:20060912231409-ac50b-c573d798d9d1abc197fcf50f3b52df2e44e1f70e.gz
2006-09-13 09:14:09 +10:00
axel
3bb0163598 Update todo-list again
darcs-hash:20060912221050-ac50b-1c16582591642beba13f83224dc7ef47cb9c5a0a.gz
2006-09-13 08:10:50 +10:00
axel
4d19aa7698 Update todo-list
darcs-hash:20060912215025-ac50b-448068ea065db5d2db4bb68b7e41ef4e986ecc83.gz
2006-09-13 07:50:25 +10:00
axel
f72de8e141 Ugly kludge to fix ugly header output from Doxygen in man-pages
darcs-hash:20060912155058-ac50b-50487271adc31d20a0e07e742a1cbe724068be6d.gz
2006-09-13 01:50:58 +10:00
axel
02eb856e44 Don't syntax highlight the character under the cursor, since that may hide the cursor. Thanks to Matin Bähr and Philip Ganchev for the reports
darcs-hash:20060911143935-ac50b-e1502365aeba0f4d97976f688329cbfc4b9871a4.gz
2006-09-12 00:39:35 +10:00
axel
c550f4eb21 Add completions for xpdf and xmms, written by Vikas Gorur
darcs-hash:20060911141848-ac50b-a541eafba3f0155b207963633262229330c01bea.gz
2006-09-12 00:18:48 +10:00
axel
00c25436d7 Make it possible to save a function when defining it using the -S switch
darcs-hash:20060908141241-ac50b-69a055a1e791e04e2b1208a5c36b9bb22c854c12.gz
2006-09-09 00:12:41 +10:00
axel
6107d63995 Add wmkdir function
darcs-hash:20060908141128-ac50b-9b67d1c5af9f746be18509bad3a0e8988efce29a.gz
2006-09-09 00:11:28 +10:00
axel
eafa0a7169 Bugfix in the wdirname function
darcs-hash:20060908141041-ac50b-8650eea2d071606654cad94553344ed12b4bf609.gz
2006-09-09 00:10:41 +10:00
axel
45d2b89780 Use halloc in history as well as other minor cleanups in history.c
darcs-hash:20060908123455-ac50b-9a3aa6a186fc883621c120cd0964a05ed595f2a4.gz
2006-09-08 22:34:55 +10:00
axel
72d73b7fdd Fix crash bug in cyntax validator when using an illegal command name. Thanks to Martin Bähr for the report.
darcs-hash:20060907201559-ac50b-34fa01bbc40eafddcc64a5111bebd88aab75a8d4.gz
2006-09-08 06:15:59 +10:00
axel
227a5da02c Fix syntax bug caused by new cmdsubs slicing feature. Thanks to Martin Bähr for the report.
darcs-hash:20060907201145-ac50b-8315f1c207883bfbe56db2ec8b3a8b3635e8dc84.gz
2006-09-08 06:11:45 +10:00
axel
e356bdaa8e Optionally add type of block to the end builtin to verify block nesting correctness
darcs-hash:20060905204347-ac50b-d0f87a700e38cdff9787be827b0df90b7f7baba5.gz
2006-09-06 06:43:47 +10:00
axel
697d524687 Clear error buffer before creating new error message to avoid bug causing all previous errors to accumulate
darcs-hash:20060905204020-ac50b-6ecc9e4c57a6b387431cef32c734ca525f05c26c.gz
2006-09-06 06:40:20 +10:00
axel
73f0d0bb48 Fix warning when help function is called with no arguments
darcs-hash:20060904201612-ac50b-63b83a589735021a6afd6be193500b549e3b25dd.gz
2006-09-05 06:16:12 +10:00
axel
200ebe43dc Add math shellscript function, which is a thin wrapper around bc
darcs-hash:20060904160023-ac50b-0d784182ca3930b0987d4338655b8717237e842c.gz
2006-09-05 02:00:23 +10:00
axel
ff2d354ef8 Bump version number
darcs-hash:20060904002509-ac50b-098c9c879257d689a975abd102f9b4d9fc00f592.gz
2006-09-04 10:25:09 +10:00
axel
3bef568955 Fix nagging warning message
darcs-hash:20060903234751-ac50b-c5d7f026323b5cab450e1770be572dcdf3ecc904.gz
2006-09-04 09:47:51 +10:00
axel
9a7be6db08 New status message for fish_pager
darcs-hash:20060903231209-ac50b-b8bad71cb9194a905918534fafec619118d61e21.gz
2006-09-04 09:12:09 +10:00
axel
40e2025327 Minor polish
darcs-hash:20060903230006-ac50b-c55a9272bb1cdb10312b8580c4c2a85654329e30.gz
2006-09-04 09:00:06 +10:00
axel
a819c863eb Skip bug causing autoloader to sometimes use the wrong version of a function. Thanks to Martin Bähr and Mystilleef for the bug reports.
darcs-hash:20060903225839-ac50b-5b1f3d5f0b8c54b999836c3384c22c2a31c31bd0.gz
2006-09-04 08:58:39 +10:00
axel
827c88e4a1 Fix bug where using the return builtin inside an if-block could cause the else-block to get executed
darcs-hash:20060831205320-ac50b-64ecbaa3ed5e32c1a815ba384a6831a8fd5e1b47.gz
2006-09-01 06:53:20 +10:00
axel
e2b7a078f4 Make "$foo\[1]" not be an array slicing. Notice the extra backslash
darcs-hash:20060831155932-ac50b-746462d2147f349f9a799cb4786a0abacd1d3d4a.gz
2006-09-01 01:59:32 +10:00
axel
6de0c4103b Add support for \cx backslash escapes for control sequences, syntax is borrowed from bash
darcs-hash:20060831155813-ac50b-cc93412afc87c1c391c3dbc5e7b8c9175efe01d8.gz
2006-09-01 01:58:13 +10:00
axel
b6e8171f01 Fix minor null pointer bug in the set builtin, fix bug causing the -n switch to be ignored, add missing completions for the -n switch to functions and set builtins, and touch up the documentation for said builtin a bit
darcs-hash:20060831154400-ac50b-dddbee79481e0e0a8da9fc025e8a15c466460a2f.gz
2006-09-01 01:44:00 +10:00
axel
b1439075c6 Updated definiton of move_word, more intuitive behaviour when a token consists only of non-alphanumerics
darcs-hash:20060831004525-ac50b-aa6675809f0f17fa266982374700a8a4ce6b2f5a.gz
2006-08-31 10:45:25 +10:00
axel
7df536023b Fix concurrency bug in autoloader causing memory leak
darcs-hash:20060828162734-ac50b-76c88ba8cc164646dcff16cb899633f1e10392e2.gz
2006-08-29 02:27:34 +10:00
axel
f5f15f9de2 Use dynamically sized buffer for reporting error messages in the parser
darcs-hash:20060828151913-ac50b-02453c13d107f88023b2331bf40daf6d329ac597.gz
2006-08-29 01:19:13 +10:00
axel
0e0a61119f Update english transliteration
darcs-hash:20060828130147-ac50b-2b07adaa3fd63cf0cd2b0122fef45b9aee365e37.gz
2006-08-28 23:01:47 +10:00
axel
6f058c687d Add fallback if SIGWINCH is unavailable
darcs-hash:20060828122515-ac50b-f2b8f1519bbbd62908a6648255bfb20bdce83212.gz
2006-08-28 22:25:15 +10:00
axel
53ea5d60b7 Minor code tweaks, mostly things like indentation, but also a ferw code reorderings
darcs-hash:20060828120244-ac50b-ad4be149ff245b6f799452f9eeff7bcc60af1526.gz
2006-08-28 22:02:44 +10:00
axel
9525f429c6 Dont let fallback implementation of killpg kill group 1
darcs-hash:20060828120122-ac50b-c5e3eb7392654feb378cdfcf11ab102418aa1386.gz
2006-08-28 22:01:22 +10:00
axel
548e379d6a Provide fallback version of getopt_long instead of checking for it's presense every time it is used
darcs-hash:20060828114305-ac50b-f4aad19e936fa42bbe84e51e72aa32445a469527.gz
2006-08-28 21:43:05 +10:00
axel
202d29de88 Restructure the autoloader. This fixes a very weird and rare Heissenbug, probably caused by a compiler bug, but also makes the structure of the code a bit more logical.
darcs-hash:20060828110019-ac50b-7be19eda18eb358163a9a5b7180c6c7d028e546d.gz
2006-08-28 21:00:19 +10:00
axel
23152ae8a6 Remove checks for gettext presense in mimedb.c and set_color.c. If gettext is unavailable, a fallback is provided.
darcs-hash:20060828105806-ac50b-47f092813ed70a03477d66c377edbe24f2aedf40.gz
2006-08-28 20:58:06 +10:00
axel
7310596dab Much more reliable getopt_long test. Idea from Netocrat.
darcs-hash:20060828102949-ac50b-bb55face2f3127018b6c79a72ee71e38f075232a.gz
2006-08-28 20:29:49 +10:00
axel
4afe49d7c6 Redo the -POSIX_C_SOURCE test to only add macros if they are found to fix things. Also add -stdÉ9 to CPPFLAGS if it is added to CFLAGS. Also add more comments, redo indentation and general file cleanup. Written cooperatively by Liljencrantz and Netocrat.
darcs-hash:20060828100334-ac50b-73eed298fdf5a853243413f0f12c235ffa9e787a.gz
2006-08-28 20:03:34 +10:00
axel
d7c3d2acbf Use OK as return value for del_curterm fallback
darcs-hash:20060828100046-ac50b-e52e7181ffb6fa5b1b3162ac3ae0aacc9bf7f5a3.gz
2006-08-28 20:00:46 +10:00
axel
f771fce892 Add a $version variable. Suggested by Martin Bähr
darcs-hash:20060828095840-ac50b-db561647eee1d06785448a4bfc6826eef5aec2b7.gz
2006-08-28 19:58:40 +10:00
axel
6522000bf0 Don't turn of file completion in svn completions if given an unknown subcommand
darcs-hash:20060827144853-ac50b-d09576fd6984eb18b06e0e7b1d8a88aa7b9d1df4.gz
2006-08-28 00:48:53 +10:00
axel
285abcc9bc Do not use the non-standard -i switch for sed
darcs-hash:20060827131554-ac50b-b969c2a56607ff46d028f5c44faabf2842814f0e.gz
2006-08-27 23:15:54 +10:00
axel
b15e8123ca If no completions have been found, use file completion even if command specific completions have disabled file completions. Suggested by MArtin Bähr.
darcs-hash:20060827005740-ac50b-41c3bf2bb91bcfc0122c317bcc2aca2061cd019e.gz
2006-08-27 10:57:40 +10:00
axel
1c86395ed8 Fix bug reportad by Martin Bähr that causes fish fail when using blocks in pipelines in interactive mode.
darcs-hash:20060827005252-ac50b-09c98537b9de72f0d4a2e5a28490b2e38fe321c8.gz
2006-08-27 10:52:52 +10:00
axel
3c8d2a1126 Don't use carriage return on initial painting of the prompt
darcs-hash:20060826022416-ac50b-16746f45142589e7fa83e95b6ee6a2fad98432c4.gz
2006-08-26 12:24:16 +10:00
axel
ed8cd08984 Fix minor memory leak in completion code
darcs-hash:20060826021948-ac50b-6fecba2056e47cb7c4e8499f2a51e1c0c23d0757.gz
2006-08-26 12:19:48 +10:00
axel
69537430ea Fix bug in completion code reported by Martin Bähr, as well as other bug evident in his bug report.
darcs-hash:20060826013722-ac50b-08de084a40af8ba5d708a7cd162087b7afbb7648.gz
2006-08-26 11:37:22 +10:00
axel
0a603a56c6 Minor bugfix for the completions for the complete builtin
darcs-hash:20060825154545-ac50b-eaa8b210ddc6fb6a089deb5c2b19723bd92228f3.gz
2006-08-26 01:45:45 +10:00
axel
046dd82995 Add minor new completion for make command
darcs-hash:20060825154516-ac50b-80284df4f7dd6cd332f2b21f5c9bdc359cc00eca.gz
2006-08-26 01:45:16 +10:00
axel
97c3e231f4 Allow slicing of command substitution output
darcs-hash:20060824133904-ac50b-fbc43cf30d8eb15e50343b786af77f85fb0b8d4e.gz
2006-08-24 23:39:04 +10:00
axel
76b782d576 Do not mix wide and narrow printf calls on stderr in set_color.c
darcs-hash:20060824133828-ac50b-399d9c8d4f6cd7c36ceb2991011d9dae23851d6f.gz
2006-08-24 23:38:28 +10:00
154 changed files with 11115 additions and 7018 deletions

View File

@@ -1,10 +1,9 @@
#
# Copyright (C) 2005 Axel Liljencrantz
# Copyright (C) 2005-2006 Axel Liljencrantz
#
# 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
# of the License, or (at your option) any later version.
# 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
@@ -32,11 +31,19 @@
# hallucinations.
#
#
# Programs
#
CC := @CC@
INSTALL:=@INSTALL@
#
# Installation directories
#
prefix = @prefix@
exec_prefix = @exec_prefix@
datadir = @datadir@
@@ -47,54 +54,87 @@ docdir = @docdir@
localedir = @localedir@
prefix = @prefix@
optbindirs = @optbindirs@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
#
# Various flags
#
MACROS=-DLOCALEDIR=\"$(localedir)\" -DPREFIX=L\"$(prefix)\" -DDATADIR=L\"$(datadir)\" -DSYSCONFDIR=L\"$(sysconfdir)\"
CFLAGS=@CFLAGS@ $(MACROS)
CPPFLAGS=@CPPFLAGS@
CFLAGS=@CFLAGS@ $(MACROS)
CPPFLAGS=@CPPFLAGS@
LDFLAGS= @LIBS@ @LDFLAGS@
#etc files to install
ETC_DIR_INSTALL = etc/fish_interactive.fish
#
# Set to 1 if we have gettext
#
HAVE_GETTEXT=@HAVE_GETTEXT@
#
#Additional .c files used by common.o. These also have a corresponding
#.h file.
#
COMMON_FILES := util.c halloc.c halloc_util.c fallback.c
# All objects that the system needs to build fish, except main.o
FISH_OBJS := function.o builtin.o complete.o env.o exec.o \
expand.o highlight.o history.o kill.o parser.o proc.o reader.o \
sanity.o tokenizer.o wildcard.o wgetopt.o wutil.o input.o \
output.o intern.o env_universal.o env_universal_common.o \
input_common.o event.o signal.o io.o parse_util.o common.o \
#
# All objects that the system needs to build fish, except main.o
#
FISH_OBJS := function.o builtin.o complete.o env.o exec.o expand.o \
highlight.o history.o kill.o parser.o proc.o reader.o sanity.o \
tokenizer.o wildcard.o wgetopt.o wutil.o input.o output.o intern.o \
env_universal.o env_universal_common.o input_common.o event.o \
signal.o io.o parse_util.o common.o screen.o path.o
#
# Additional files used by builtin.o
#
BUILTIN_FILES := builtin_help.c builtin_set.c builtin_commandline.c \
builtin_ulimit.c builtin_complete.c builtin_jobs.c
# All objects that the system needs to build fish_pager
FISH_PAGER_OBJS := fish_pager.o output.o wutil.o \
tokenizer.o input_common.o env_universal.o env_universal_common.o \
common.o
#
# All objects that the system needs to build fish_pager
#
FISH_PAGER_OBJS := fish_pager.o output.o wutil.o tokenizer.o \
input_common.o env_universal.o env_universal_common.o common.o
#
# All objects that the system needs to build fish_tests
#
FISH_TESTS_OBJS := $(FISH_OBJS) fish_tests.o
#
# All objects that the system needs to build fishd
#
FISHD_OBJS := fishd.o env_universal_common.o wutil.o \
doc_src/fishd.o common.o
#
# All objects needed to build mimedb
#
MIME_OBJS := mimedb.o xdgmimealias.o xdgmime.o xdgmimeglob.o \
xdgmimeint.o xdgmimemagic.o xdgmimeparent.o wutil.o common.o
#
# Files containing documentation for builtins.
#
BUILTIN_DOC_SRC := doc_src/source.txt doc_src/and.txt \
doc_src/begin.txt doc_src/bg.txt doc_src/bind.txt \
doc_src/block.txt doc_src/break.txt doc_src/builtin.txt \
@@ -108,41 +148,61 @@ BUILTIN_DOC_SRC := doc_src/source.txt doc_src/and.txt \
doc_src/status.txt doc_src/switch.txt doc_src/ulimit.txt \
doc_src/while.txt
#
# Files generated by running doxygen on the files in $(BUILTIN_DOC_SRC)
#
BUILTIN_DOC_HDR := $(BUILTIN_DOC_SRC:.txt=.doxygen)
HDR_FILES := doc_src/index.hdr doc_src/commands.hdr doc_src/design.hdr doc_src/license.hdr doc_src/faq.hdr
#
# Files containing documentation for external commands.
#
CMD_DOC_SRC := doc_src/contains.txt doc_src/count.txt doc_src/dirh.txt \
doc_src/dirs.txt doc_src/fish_pager.txt doc_src/fishd.txt \
doc_src/help.txt doc_src/mimedb.txt doc_src/nextd.txt \
doc_src/open.txt doc_src/popd.txt doc_src/prevd.txt \
doc_src/psub.txt doc_src/pushd.txt doc_src/set_color.txt \
doc_src/trap.txt doc_src/type.txt doc_src/umask.txt \
doc_src/vared.txt
doc_src/dirs.txt doc_src/fish.txt doc_src/fish_pager.txt \
doc_src/fishd.txt doc_src/help.txt doc_src/isatty.txt \
doc_src/mimedb.txt doc_src/nextd.txt doc_src/open.txt \
doc_src/popd.txt doc_src/prevd.txt doc_src/psub.txt \
doc_src/pushd.txt doc_src/set_color.txt doc_src/trap.txt \
doc_src/type.txt doc_src/umask.txt doc_src/vared.txt
#
# Files generated by running doxygen on the files in $(CMD_DOC_SRC)
#
CMD_DOC_HDR := $(CMD_DOC_SRC:.txt=.doxygen)
#
# Files in the test directory
#
TEST_IN := $(wildcard tests/test*.in)
#
# Files that should be added to the tar archives
#
#
# Files in ./doc_src/
DOC_SRC_DIR_FILES := doc_src/Doxyfile.in doc_src/doc.hdr \
$(BUILTIN_DOC_SRC) $(CMD_DOC_SRC) doc_src/fish.1.in
#
DOC_SRC_DIR_FILES := doc_src/Doxyfile.in doc_src/index.hdr \
doc_src/license.hdr doc_src/faq.hdr doc_src/design.hdr \
$(BUILTIN_DOC_SRC) $(CMD_DOC_SRC)
#
# Files in ./. There is some overlap between the variables in the
# list, so when copying these files, cp will complain that some files
# are specified more than once.
#
# Files in ./
MAIN_DIR_FILES := Doxyfile Doxyfile.user Makefile.in configure \
configure.ac config.h.in install-sh set_color.c count.c \
key_reader.c gen_hdr.sh gen_hdr2.c $(MIME_OBJS:.o=.h) \
@@ -152,68 +212,124 @@ MAIN_DIR_FILES := Doxyfile Doxyfile.user Makefile.in configure \
xsel-0.9.6.tar ChangeLog config.sub config.guess fish_tests.c \
main.c fish_pager.c fishd.c seq.in
#
# Files in ./etc/
ETC_DIR_FILES :=etc/fish.in etc/fish_inputrc \
etc/fish_interactive.fish.in
#
ETC_DIR_FILES :=etc/config.fish.in etc/fish_inputrc
#
# Files in ./share/
SHARE_DIR_FILES :=share/fish.in
#
SHARE_DIR_FILES :=share/config.fish.in share/config_interactive.fish.in
#
# Files in ./tests/
#
TESTS_DIR_FILES := $(TEST_IN) $(TEST_IN:.in=.out) $(TEST_IN:.in=.err) \
$(TEST_IN:.in=.status) tests/test.fish tests/gen_output.fish
#
# Files in ./share/completions/
#
COMPLETIONS_DIR_FILES := $(wildcard share/completions/*.fish)
#
# Files in ./share/functions/
#
FUNCTIONS_DIR_FILES := $(wildcard share/functions/*.fish)
# Programs to build
#
# Programs to install
#
PROGRAMS:=fish set_color @XSEL@ @SEQ_FALLBACK@ mimedb count fish_pager fishd
# Manuals to install
MANUALS:=doc_src/fish.1 @XSEL_MAN_PATH@ \
doc_src/builtin_doc/man/man1/mimedb.1 \
doc_src/builtin_doc/man/man1/set_color.1 \
doc_src/builtin_doc/man/man1/count.1 \
doc_src/builtin_doc/man/man1/fishd.1 \
#
# Manual pagess to install
#
MANUALS:=doc_src/builtin_doc/man/man1/fish.1 @XSEL_MAN_PATH@ \
doc_src/builtin_doc/man/man1/mimedb.1 \
doc_src/builtin_doc/man/man1/set_color.1 \
doc_src/builtin_doc/man/man1/count.1 \
doc_src/builtin_doc/man/man1/fishd.1 \
doc_src/builtin_doc/man/man1/fish_pager.1
#All translation message catalogs
#
# All translation message catalogs
#
TRANSLATIONS_SRC := $(wildcard po/*.po)
TRANSLATIONS := $(TRANSLATIONS_SRC:.po=.gmo)
#Make everything needed for installing fish
all: $(PROGRAMS) user_doc etc/fish share/fish etc/fish_interactive.fish $(TRANSLATIONS)
#
# Make everything needed for installing fish
#
all: $(PROGRAMS) user_doc etc/config.fish share/config.fish share/config_interactive.fish $(TRANSLATIONS)
@echo fish has now been built.
@echo Use \'make install\' to install fish.
.PHONY: all
#
# These dependencies make sure that autoconf and configure are run
# when the source code for the build configuration has changed.
#
configure: configure.ac
./config.status --recheck
Makefile: Makefile.in configure
./config.status
fish.spec: fish.spec.in
./config.status
#
# Build fish with some debug flags specified. This is GCC specific,
# and should only be used when debuging fish.
#
debug:
make fish CFLAGS="@CFLAGS@ $(MACROS) -O0 -Wno-unused -Werror -g"
.PHONY: debug
#
# User documentation, describing the features of the fish shell.
user_doc: doc_src/doc.hdr Doxyfile.user user_doc.head.html
$(MAKE) doc.h # Depend on the source (doc.hdr) and manually make the intermediate as needed
#
user_doc: $(HDR_FILES) Doxyfile.user user_doc.head.html $(CMD_DOC_SRC) $(BUILTIN_DOC_SRC)
$(MAKE) doc.h # Depend on the sources (*.hdr) and manually make the intermediate as needed
doxygen Doxyfile.user
touch user_doc
#
# Source code documentation. Also includes user documentation.
#
doc: *.h *.c doc.h Doxyfile builtin_help.c
doxygen;
#
# PDF version of the source code documentation.
#
doc/refman.pdf: doc
cd doc/latex;
make;
@@ -221,56 +337,100 @@ doc/refman.pdf: doc
cd ../..;
rm -r doc/latex;
#
# This target runs both the low level code tests and the high level script tests.
#
test: $(PROGRAMS) fish_tests
./fish_tests; cd tests; ../fish <test.fish;
.PHONY: test
#
# Build the xsel program, which is maintained in its own tarball
#
xsel-0.9.6:
tar -xf xsel-0.9.6.tar
xsel-0.9.6/xsel: xsel-0.9.6
cd xsel-0.9.6; ./configure; make
#
# commands.hdr collects documentation on all commands, functions and
# builtins
#
doc_src/commands.hdr:$(BUILTIN_DOC_SRC) $(CMD_DOC_SRC)
rm -f commands.tmp;
echo "/** \page commands Commands" >>commands.tmp;
echo "Fish ships with a large number of builtin commands, shellscript functions and external commandss. These are all described below. " >>commands.tmp;
for i in `printf "%s\n" $(BUILTIN_DOC_SRC) $(CMD_DOC_SRC)|sort`; do \
echo "<hr>" >>commands.tmp; \
cat $$i >>commands.tmp; \
echo >>commands.tmp; \
echo >>commands.tmp; \
echo "Back to <a href='index.html#toc-commands'>index</a>". >>commands.tmp; \
done
echo "*/" >>commands.tmp
mv commands.tmp doc_src/commands.hdr
#
# doc.h is a compilation of the various snipptes of text used both for
# the user documentation and for internal help functions into a single
# file that can be parsed dy Doxygen to generate the user
# documentation.
doc.h:$(BUILTIN_DOC_SRC) $(CMD_DOC_SRC) doc_src/doc.hdr
cat doc_src/doc.hdr >doc.h;
echo "/** \page builtins Builtin commands" >>doc.h;
for i in `printf "%s\n" $(BUILTIN_DOC_SRC)|sort`; do \
echo "<hr>" >>doc.h; \
cat $$i >>doc.h; \
done
echo "*/" >>doc.h
echo "/** \page commands External commands" >>doc.h;
echo "\c fish is shipped with commands which do not use any internal parts of the shell, and are therefore not written as builtins, but separate commands." >>doc.h
for i in `printf "%s\n" $(CMD_DOC_SRC)|sort`; do \
echo "<hr>" >>doc.h; \
cat $$i >>doc.h; \
done
echo "*/" >>doc.h
#
doc.h:$(HDR_FILES)
rm -f doc.h
echo "/** \mainpage Fish user documentation" >doc.tmp
echo "\section toc Table of contents" >>doc.tmp
echo '- <a href="index.html" name="toc-index">Fish user documentation</a>' >>doc.tmp
for i in $(HDR_FILES); do\
sed <$$i >>doc.tmp -n \
-e 's,.*\\page *\([^ ]*\) *\(.*\)$$,- <a href="'`basename $$i .hdr`'.html" name="toc-'`basename $$i .hdr`'">\2</a>,p' \
-e 's,.*\\section *\([^ ]*\) *\(.*\)$$, - <a href="'`basename $$i .hdr`'.html#\1" name="toc-'`basename $$i .hdr`'">\2</a>,p' \
# -e 's,.*\\subsection *\([^ ]*\) *\(.*\)$$, - <a href="'`basename $$i .hdr`'.html#\1" name="toc-'`basename $$i .hdr`'">\2</a>,p'; \
done
cat $(HDR_FILES) >>doc.tmp;
mv doc.tmp doc.h
#
# This rule creates complete doxygen headers from each of the various
# snipptes of text used both for the user documentation and for
# internal help functions, that can be parsed to Doxygen to generate
# the internal help function text.
#
%.doxygen:%.txt
echo "/** \page " `basename $*` >$@;
cat $*.txt >>$@;
echo "*/" >>$@
%: %.in Makefile
sed <$@.in >$@ -e "s,@sysconfdir\@,$(sysconfdir)," -e "s,@datadir\@,$(datadir)," -e "s,@docdir\@,$(docdir)," -e "s|@configure_input\@|$@, generated from $@.in by the Makefile. DO NOT MANUALLY EDIT THIS FILE!|" -e "s,@prefix\@,$(prefix)," -e "s,@optbindirs\@,$(optbindirs),"
sed <$@.in >$@ -e "s,@sysconfdir\@,$(sysconfdir),g" -e "s,@datadir\@,$(datadir),g" -e "s,@docdir\@,$(docdir),g" -e "s|@configure_input\@|$@, generated from $@.in by the Makefile. DO NOT MANUALLY EDIT THIS FILE!|g" -e "s,@prefix\@,$(prefix),g" -e "s,@optbindirs\@,$(optbindirs),g"
#-e "s,@\@,$(),"
# Compile translation file
#
# Compile translation files to binary format
#
%.gmo:
if test $(HAVE_GETTEXT) = 1; then \
msgfmt -o $*.gmo $*.po; \
fi
#
# Update existing po file or copy messages.pot
#
%.po:messages.pot
if test $(HAVE_GETTEXT) = 1;then \
if test -f $*.po; then \
@@ -280,7 +440,11 @@ doc.h:$(BUILTIN_DOC_SRC) $(CMD_DOC_SRC) doc_src/doc.hdr
fi; \
fi
#
# Create a template translation object
#
messages.pot: *.c *.h etc/*.in share/fish share/completions/*.fish share/functions/*.fish seq
if test $(HAVE_GETTEXT) = 1;then \
xgettext -k_ -kN_ *.c *.h -o messages.pot; \
@@ -295,6 +459,8 @@ builtin.o: $(BUILTIN_FILES)
common.o: $(COMMON_FILES)
#
# Generate the internal help functions by making doxygen create
# man-pages which are then converted into C code. The convertion path
# looks like this:
@@ -326,6 +492,7 @@ common.o: $(COMMON_FILES)
#
# Which is an awful, clunky and ugly way of producing
# documentation. There ought to be something simpler.
#
doc_src/builtin_doc: $(BUILTIN_DOC_SRC) doc_src/count.txt builtin_help.hdr $(CMD_DOC_SRC)
for i in $(BUILTIN_DOC_SRC) $(CMD_DOC_SRC); do \
@@ -336,7 +503,9 @@ doc_src/builtin_doc: $(BUILTIN_DOC_SRC) doc_src/count.txt builtin_help.hdr $(CMD
done
cd doc_src; doxygen; cd ..;
for i in doc_src/builtin_doc/man/man1/*.1; do \
sed -i -e "s/\(.\)\\.SH/\1/" $$i; \
CMD_NAME=`basename $$i .1`; \
sed -e "s/\(.\)\\.SH/\1/" -e "s/$$CMD_NAME *\\\\- *\"\(.*\)\"/\1/" <$$i >$$i.tmp; \
mv $$i.tmp $$i; \
done
touch doc_src/builtin_doc
@@ -351,11 +520,12 @@ builtin_help.c: doc_src/builtin_doc gen_hdr.sh
done;
echo "}" >>builtin_help.c
#
# Generate help texts for external fish commands, like set_color and
# mimedb. Depends on builtin_help.c to make sure doxygen gets run to
# generate the man files.
# mimedb.
#
%.c : %.doxygen
$(MAKE) gen_hdr2 builtin_help.c # These should really be filed as dependencis for %.c above instead, but that seems to confuse make
echo "// This file was automatically generated, do not edit" >$@
@@ -374,8 +544,10 @@ builtin_help.c: doc_src/builtin_doc gen_hdr.sh
# The build rules for installing/uninstalling fish
#
#
# Check for an incompatible installed fish version, and fail with an
# error if found
#
check-uninstall:
if test -f $(DESTDIR)$(sysconfdir)/fish.d/fish_function.fish -o -f $(DESTDIR)$(sysconfdir)/fish.d/fish_complete.fish; then \
@@ -383,46 +555,70 @@ check-uninstall:
echo ERROR;\
echo;\
echo An older fish installation using an incompatible filesystem hierarchy was detected;\
echo You must uninstall this fish version before installing proceeding;\
echo You must uninstall this fish version before proceeding;\
echo type \'make uninstall-legacy\' to uninstall these files,;\
echo or type \'make force-install\' to force installation.;\
echo The latter may result in a broken installation.;\
echo;\
false;\
fi;
if test -f $(DESTDIR)$(sysconfdir)/fish; then \
echo;\
echo ERROR;\
echo;\
echo An older fish installation using an incompatible filesystem hierarchy was detected;\
echo You must remove the file $(DESTDIR)$(sysconfdir)/fish before proceeding;\
echo type \'make uninstall-legacy\' to uninstall this file,;\
echo or remove it manually using \'rm $(DESTDIR)$(sysconfdir)/fish\'.;\
echo;\
false;\
fi;
.PHONY: check-uninstall
#
# This check makes sure that the install-sh script is executable. The
# darcs repo doesn't preserve the executable bit, so this needs to be
# run after checkout.
#
install-sh:
if test -x install-sh; then true; else chmod 755 install-sh; fi
.PHONY: install-sh
# Try to install after checking for incompatible installed versions
#
# Try to install after checking for incompatible installed versions.
#
install: all install-sh check-uninstall install-force
.PHONY: install
#
# Force installation, even in presense of incompatible previous
# version
# version. This may fail.
#
install-force: all install-translations
$(INSTALL) -m 755 -d $(DESTDIR)$(bindir)
for i in $(PROGRAMS); do\
$(INSTALL) -m 755 $$i $(DESTDIR)$(bindir) ; \
done;
$(INSTALL) -m 755 -d $(DESTDIR)$(sysconfdir)/fish.d
$(INSTALL) -m 755 -d $(DESTDIR)$(sysconfdir)/fish
$(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish
$(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/completions
$(INSTALL) -m 755 -d $(DESTDIR)$(datadir)/fish/functions
$(INSTALL) -m 644 etc/fish $(DESTDIR)$(sysconfdir)/fish
$(INSTALL) -m 644 share/fish $(DESTDIR)$(datadir)/fish
for i in $(ETC_DIR_INSTALL); do \
$(INSTALL) -m 644 $$i $(DESTDIR)$(sysconfdir)/fish.d; \
done;
$(INSTALL) -m 644 etc/config.fish $(DESTDIR)$(sysconfdir)/fish/
$(INSTALL) -m 644 share/config.fish $(DESTDIR)$(datadir)/fish/
$(INSTALL) -m 644 share/config_interactive.fish $(DESTDIR)$(datadir)/fish/
for i in $(COMPLETIONS_DIR_FILES); do \
$(INSTALL) -m 644 $$i $(DESTDIR)$(datadir)/fish/completions/; \
done;
for i in $(FUNCTIONS_DIR_FILES); do \
$(INSTALL) -m 644 $$i $(DESTDIR)$(datadir)/fish/functions/; \
done;
$(INSTALL) -m 644 etc/fish_inputrc $(DESTDIR)$(sysconfdir)/fish_inputrc;
$(INSTALL) -m 644 etc/fish_inputrc $(DESTDIR)$(sysconfdir)/fish/fish_inputrc;
$(INSTALL) -m 755 -d $(DESTDIR)$(docdir)
for i in user_doc/html/* ChangeLog; do \
if test -f $$i; then \
@@ -444,38 +640,42 @@ install-force: all install-translations
.PHONY: install-force
#
# Uninstall this fish version
#
uninstall: uninstall-translations
for i in $(PROGRAMS); do \
-for i in $(PROGRAMS); do \
rm -f $(DESTDIR)$(bindir)/$$i; \
done;
rm -f $(DESTDIR)$(bindir)/xsel
rm -f $(DESTDIR)$(sysconfdir)/fish
rm -f $(DESTDIR)$(sysconfdir)/fish_inputrc
if test -f $(DESTDIR)$(sysconfdir)/fish.d/fish_interactive.fish; then \
rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_interactive.fish; \
fi
if test -d $(DESTDIR)$(datadir)/fish; then \
-rm -f $(DESTDIR)$(bindir)/xsel
-rm -f $(DESTDIR)$(sysconfdir)/fish/config.fish
-rm -f $(DESTDIR)$(sysconfdir)/fish/fish_inputrc
-rmdir $(DESTDIR)$(sysconfdir)/fish
-if test -d $(DESTDIR)$(datadir)/fish; then \
rm -r $(DESTDIR)$(datadir)/fish; \
fi
if test -d $(DESTDIR)$(docdir); then \
-if test -d $(DESTDIR)$(docdir); then \
rm -r $(DESTDIR)$(docdir);\
fi
for i in $(MANUALS); do \
-for i in $(MANUALS); do \
rm -f $(DESTDIR)$(mandir)/man1/`basename $$i`*; \
done;
.PHONY: uninstall
# Uninstall older fish release. This is not the default uninstall
#
# Uninstall an older fish release. This is not the default uninstall
# since there is a slight chance that it removes a file put in place by
# the sysadmin.
# the sysadmin. But if 'make install' detects a file confligt, it
# suggests using this target.
#
uninstall-legacy: uninstall
rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_interactive.fish
rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_complete.fish
rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_function.fish
if test -d $(DESTDIR)$(sysconfdir)/fish.d/completions; then \
-rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_interactive.fish
-rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_complete.fish
-rm -f $(DESTDIR)$(sysconfdir)/fish.d/fish_function.fish
-if test -d $(DESTDIR)$(sysconfdir)/fish.d/completions; then \
for i in $(COMPLETIONS_DIR_FILES); do \
basename=`basename $$i`; \
if test -f $(DESTDIR)$(sysconfdir)/fish.d/completions/$$basename; then \
@@ -483,8 +683,9 @@ uninstall-legacy: uninstall
fi; \
done; \
fi;
rmdir $(DESTDIR)$(sysconfdir)/fish.d/completions; true
rmdir $(DESTDIR)$(sysconfdir)/fish.d; true
-rmdir $(DESTDIR)$(sysconfdir)/fish.d/completions
-rmdir $(DESTDIR)$(sysconfdir)/fish.d
-rm $(DESTDIR)$(sysconfdir)/fish
@echo The previous fish installation has been removed.
.PHONY: uninstall-legacy
@@ -506,41 +707,87 @@ uninstall-translations:
fi
.PHONY: uninstall-translations
#
# The build rules for all the commands
#
#
# Build the fish program.
#
fish: $(FISH_OBJS) main.o
$(CC) $(FISH_OBJS) main.o $(LDFLAGS) -o $@
#
# Build the fish_pager program.
#
fish_pager: $(FISH_PAGER_OBJS)
$(CC) $(FISH_PAGER_OBJS) $(LDFLAGS) -o $@
#
# Build the fishd program.
#
fishd: $(FISHD_OBJS)
$(CC) $(FISHD_OBJS) $(LDFLAGS) -o $@
#
# Build the fish_tests program.
#
fish_tests: $(FISH_TESTS_OBJS)
$(CC) $(FISH_TESTS_OBJS) $(LDFLAGS) -o $@
# mimedb does not need any libraries, so we don't use LDFLAGS here
#
# Build the mimedb program.
#
# mimedb does not need any libraries, so we don't use LDFLAGS here.
#
mimedb: $(MIME_OBJS) doc_src/mimedb.o
$(CC) $(MIME_OBJS) doc_src/mimedb.o $(LDFLAGS) -o $@
# count does not need any libraries, so we don't use LDFLAGS here
#
# Build the count program.
#
# count does not need any libraries, so we don't use LDFLAGS here.
#
count: count.o
$(CC) count.o -o $@
set_color: set_color.o doc_src/set_color.o common.o
$(CC) set_color.o doc_src/set_color.o common.o $(LDFLAGS) -o $@
#
# Build the set_color program
#
set_color: set_color.o doc_src/set_color.o common.o
$(CC) set_color.o doc_src/set_color.o common.o wutil.o $(LDFLAGS) -o $@
#
# Test program for the tokenizer library
#
tokenizer_test: tokenizer.c tokenizer.h wutil.o common.o
$(CC) $(CFLAGS) tokenizer.c wutil.o common.o -D TOKENIZER_TEST $(LDFLAGS) -o $@
#
# Neat little program to show output from terminal
#
key_reader: key_reader.o input_common.o common.o env_universal.o env_universal_common.o wutil.o
$(CC) key_reader.o input_common.o common.o env_universal.o env_universal_common.o wutil.o $(LDFLAGS) -o $@
#
# Update dependencies
#
@@ -549,12 +796,16 @@ depend:
./config.status
.PHONY: depend
#
# Copy all the source files into a new directory and use tar to create
# an archive from it. Simplest way I could think of to make an archive
# witout backups, autogenerated files, etc.
#
# Uses install instead of mkdir so build won't fail if the directory
# exists
#
fish-@PACKAGE_VERSION@.tar: $(DOC_SRC_DIR_FILES) $(MAIN_DIR_FILES) $(ETC_DIR_FILES) $(TEST_DIR_FILES) $(SHARE_DIR_FILES) $(FUNCTIONS_DIR_FILES) $(COMPLETIONS_DIR_FILES) ChangeLog user_doc doc_src/builtin_doc
rm -rf fish-@PACKAGE_VERSION@
$(INSTALL) -d fish-@PACKAGE_VERSION@
@@ -579,9 +830,19 @@ fish-@PACKAGE_VERSION@.tar: $(DOC_SRC_DIR_FILES) $(MAIN_DIR_FILES) $(ETC_DIR_FIL
tar -c fish-@PACKAGE_VERSION@ >fish-@PACKAGE_VERSION@.tar
rm -rf fish-@PACKAGE_VERSION@
#
# Just an alias for fish-@PACKAGE_VERSION@.tar
#
tar: fish-@PACKAGE_VERSION@.tar
.PHONY: tar
#
# Make compressed tar archives
#
fish-@PACKAGE_VERSION@.tar.gz: fish-@PACKAGE_VERSION@.tar
gzip -f --best -c fish-@PACKAGE_VERSION@.tar >fish-@PACKAGE_VERSION@.tar.gz
@@ -591,8 +852,19 @@ fish-@PACKAGE_VERSION@.tar.bz2: fish-@PACKAGE_VERSION@.tar
dist: fish-@PACKAGE_VERSION@.tar.bz2
.PHONY: dist
#
# Build the RPM spec file.
#
fish.spec: fish.spec.in
./config.status
#
# Create .rpm file for the current systems architecture and an
# .src.rpm file.
#
rpm: fish-@PACKAGE_VERSION@.tar.bz2 fish.spec
@if which rpmbuild; then true; else \
echo Could not find the rpmbuild command, needed to build an rpm; \
@@ -607,18 +879,29 @@ rpm: fish-@PACKAGE_VERSION@.tar.bz2 fish.spec
mv /usr/src/redhat/SRPMS/fish*@PACKAGE_VERSION@*.src.rpm .
.PHONY: rpm
#
# Cleanup targets
#
#
# distclean should restore the tree to the state right after extracting a tarball.
#
distclean: clean
rm -f fish.spec doc_src/fish.1 doc_src/Doxyfile
rm -f etc/fish etc/fish_interactive.fish seq
rm -f fish.spec doc_src/Doxyfile
rm -f etc/config.fish share/config_interactive.fish seq share/config.fish
rm -f config.status config.log config.h Makefile
.PHONY: distclean
#
# clean removes everything built by the makefile, but not things that
# are created by the configure script.
#
clean:
rm -f *.o doc.h doc_src/*.doxygen doc_src/*.c builtin_help.c doc_src/*.o
rm -f *.o doc.h doc.tmp doc_src/*.doxygen doc_src/*.c doc_src/*.o doc_src/commands.hdr
rm -f tests/tmp.err tests/tmp.out tests/tmp.status tests/foo.txt
rm -f tokenizer_test fish key_reader set_color gen_hdr2 mimedb
rm -f fishd fish_pager count fish_tests
@@ -626,41 +909,41 @@ clean:
rm -f fish-@PACKAGE_VERSION@.tar.gz
rm -f fish-@PACKAGE_VERSION@.tar.bz2
rm -rf doc;
rm -rf user_doc;
rm -rf doc_src/builtin_doc
rm -rf fish-@PACKAGE_VERSION@
rm -rf xsel-0.9.6/
rm -f $(TRANSLATIONS)
.PHONY: clean
# DO NOT DELETE THIS LINE -- make depend depends on it.
builtin.o: config.h fallback.h util.h wutil.h builtin.h function.h complete.h
builtin.o: proc.h io.h parser.h event.h reader.h env.h common.h wgetopt.h
builtin.o: sanity.h tokenizer.h wildcard.h input_common.h input.h intern.h
builtin.o: signal.h halloc.h halloc_util.h parse_util.h expand.h
builtin.o: signal.h halloc.h halloc_util.h parse_util.h expand.h path.h
builtin.o: builtin_help.c builtin_set.c builtin_commandline.c
builtin.o: builtin_complete.c builtin_ulimit.c builtin_jobs.c
builtin_commandline.o: signal.h config.h fallback.h util.h wutil.h builtin.h
builtin_commandline.o: config.h signal.h fallback.h util.h wutil.h builtin.h
builtin_commandline.o: common.h wgetopt.h reader.h proc.h io.h parser.h
builtin_commandline.o: event.h tokenizer.h input_common.h input.h
builtin_commandline.o: parse_util.h
builtin_complete.o: signal.h config.h fallback.h util.h wutil.h builtin.h
builtin_complete.o: config.h signal.h fallback.h util.h wutil.h builtin.h
builtin_complete.o: common.h complete.h wgetopt.h parser.h proc.h io.h
builtin_complete.o: event.h reader.h
builtin_help.o: config.h util.h common.h halloc_util.h
builtin_jobs.o: config.h fallback.h util.h wutil.h builtin.h proc.h io.h
builtin_jobs.o: parser.h event.h common.h wgetopt.h
builtin_set.o: signal.h config.h fallback.h util.h wutil.h builtin.h env.h
builtin_set.o: config.h signal.h fallback.h util.h wutil.h builtin.h env.h
builtin_set.o: expand.h common.h wgetopt.h proc.h io.h parser.h event.h
builtin_ulimit.o: config.h fallback.h util.h builtin.h common.h wgetopt.h
common.o: config.h fallback.h util.h wutil.h common.h expand.h proc.h io.h
common.o: wildcard.h parser.h event.h util.c halloc.c halloc.h halloc_util.c
common.o: fallback.c
complete.o: signal.h config.h fallback.h util.h tokenizer.h wildcard.h proc.h
complete.o: config.h signal.h fallback.h util.h tokenizer.h wildcard.h proc.h
complete.o: io.h parser.h event.h function.h complete.h builtin.h env.h
complete.o: exec.h expand.h common.h reader.h history.h intern.h parse_util.h
complete.o: halloc.h halloc_util.h wutil.h
complete.o: halloc.h halloc_util.h wutil.h path.h
count.o: config.h
env.o: config.h signal.h fallback.h util.h wutil.h proc.h io.h common.h env.h
env.o: sanity.h expand.h history.h reader.h parser.h event.h env_universal.h
env.o: env_universal_common.h input_common.h complete.h
@@ -668,35 +951,37 @@ env_universal.o: config.h signal.h fallback.h util.h common.h wutil.h
env_universal.o: env_universal_common.h env_universal.h
env_universal_common.o: config.h signal.h fallback.h util.h common.h wutil.h
env_universal_common.o: env_universal_common.h
event.o: signal.h config.h fallback.h util.h wutil.h function.h proc.h io.h
event.o: config.h signal.h fallback.h util.h wutil.h function.h proc.h io.h
event.o: parser.h event.h common.h halloc_util.h
exec.o: signal.h config.h fallback.h util.h common.h wutil.h proc.h io.h
exec.o: config.h signal.h fallback.h util.h common.h wutil.h proc.h io.h
exec.o: exec.h parser.h event.h builtin.h function.h env.h wildcard.h
exec.o: sanity.h expand.h env_universal.h env_universal_common.h halloc.h
exec.o: halloc_util.h parse_util.h
expand.o: signal.h config.h fallback.h util.h common.h wutil.h env.h proc.h
expand.o: config.h signal.h fallback.h util.h common.h wutil.h env.h proc.h
expand.o: io.h parser.h event.h expand.h wildcard.h exec.h tokenizer.h
expand.o: complete.h parse_util.h halloc_util.h
expand.o: complete.h parse_util.h halloc.h halloc_util.h
fallback.o: config.h fallback.h util.h
fishd.o: config.h signal.h fallback.h util.h common.h wutil.h
fishd.o: env_universal_common.h
fishd.o: env_universal_common.h halloc.h halloc_util.h path.h
fish_pager.o: config.h signal.h fallback.h util.h wutil.h common.h complete.h
fish_pager.o: output.h input_common.h env_universal.h env_universal_common.h
fish_pager.o: halloc.h halloc_util.h
fish_tests.o: config.h signal.h fallback.h util.h common.h proc.h io.h
fish_tests.o: reader.h builtin.h function.h complete.h wutil.h env.h expand.h
fish_tests.o: parser.h event.h tokenizer.h output.h exec.h halloc_util.h
function.o: signal.h config.h wutil.h fallback.h util.h function.h proc.h
function.o: config.h signal.h wutil.h fallback.h util.h function.h proc.h
function.o: io.h parser.h event.h common.h intern.h reader.h parse_util.h
function.o: env.h expand.h
halloc.o: config.h fallback.h util.h common.h halloc.h
halloc_util.o: config.h fallback.h util.h common.h halloc.h
highlight.o: signal.h config.h fallback.h util.h wutil.h highlight.h
highlight.o: config.h signal.h fallback.h util.h wutil.h highlight.h
highlight.o: tokenizer.h proc.h io.h parser.h event.h parse_util.h builtin.h
highlight.o: function.h env.h expand.h sanity.h common.h complete.h output.h
highlight.o: halloc.h halloc_util.h
history.o: config.h fallback.h util.h wutil.h history.h common.h reader.h
history.o: env.h sanity.h signal.h
highlight.o: halloc.h halloc_util.h wildcard.h path.h
history2.o: config.h fallback.h util.h wutil.h history.h common.h halloc.h
history2.o: halloc_util.h intern.h path.h
history.o: config.h fallback.h util.h wutil.h history.h common.h halloc.h
history.o: halloc_util.h intern.h path.h signal.h
input.o: config.h signal.h fallback.h util.h wutil.h reader.h proc.h io.h
input.o: common.h sanity.h input_common.h input.h parser.h event.h env.h
input.o: expand.h output.h intern.h
@@ -705,30 +990,36 @@ input_common.o: env_universal.h env_universal_common.h
intern.o: config.h fallback.h util.h wutil.h common.h intern.h
io.o: config.h fallback.h util.h wutil.h exec.h proc.h io.h common.h halloc.h
key_reader.o: config.h fallback.h input_common.h
kill.o: signal.h config.h fallback.h util.h wutil.h kill.h proc.h io.h
kill.o: sanity.h common.h env.h exec.h parser.h event.h halloc.h
kill.o: config.h signal.h fallback.h util.h wutil.h kill.h proc.h io.h
kill.o: sanity.h common.h env.h exec.h halloc.h path.h
main.o: config.h signal.h fallback.h util.h common.h reader.h builtin.h
main.o: function.h complete.h wutil.h env.h sanity.h proc.h io.h parser.h
main.o: event.h expand.h intern.h exec.h output.h halloc_util.h history.h
main.o: event.h expand.h intern.h exec.h output.h halloc.h halloc_util.h
main.o: history.h path.h
mimedb.o: config.h xdgmime.h fallback.h util.h
output.o: config.h signal.h fallback.h util.h wutil.h expand.h common.h
output.o: output.h halloc_util.h highlight.h
parser.o: signal.h config.h fallback.h util.h common.h wutil.h proc.h io.h
parser.o: config.h signal.h fallback.h util.h common.h wutil.h proc.h io.h
parser.o: parser.h event.h tokenizer.h exec.h wildcard.h function.h builtin.h
parser.o: env.h expand.h reader.h sanity.h env_universal.h
parser.o: env_universal_common.h intern.h parse_util.h halloc.h halloc_util.h
parser.o: path.h
parse_util.o: config.h fallback.h util.h wutil.h common.h tokenizer.h
parse_util.o: parse_util.h expand.h intern.h exec.h proc.h io.h env.h
parse_util.o: wildcard.h halloc_util.h
path.o: config.h fallback.h util.h common.h env.h wutil.h halloc.h
path.o: halloc_util.h path.h expand.h
proc.o: config.h signal.h fallback.h util.h wutil.h proc.h io.h common.h
proc.o: reader.h sanity.h env.h parser.h event.h halloc.h halloc_util.h
proc.o: output.h
reader.o: config.h signal.h fallback.h util.h wutil.h highlight.h reader.h
reader.o: proc.h io.h parser.h event.h complete.h history.h common.h sanity.h
reader.o: env.h exec.h expand.h tokenizer.h kill.h input_common.h input.h
reader.o: function.h output.h parse_util.h
sanity.o: signal.h config.h fallback.h util.h common.h sanity.h proc.h io.h
reader.o: function.h output.h screen.h parse_util.h
sanity.o: config.h signal.h fallback.h util.h common.h sanity.h proc.h io.h
sanity.o: history.h reader.h kill.h wutil.h
screen.o: config.h fallback.h common.h util.h wutil.h output.h highlight.h
screen.o: screen.h
set_color.o: config.h fallback.h
signal.o: config.h signal.h common.h util.h fallback.h wutil.h event.h
signal.o: reader.h proc.h io.h

317
builtin.c
View File

@@ -13,7 +13,7 @@
3). Create a file doc_src/NAME.txt, containing the manual for the builtin in Doxygen-format. Check the other builtin manuals for proper syntax.
4). Add an entry to the BUILTIN_DOC_SRC variable of Makefile.in. Note that the entries should be sorted alphabetically!
4). Add an entry to the BUILTIN_DOC_SRC variable of Makefile.in.
5). Add an entry to the manual at the builtin-overview subsection of doc_src/doc.hdr. Note that the entries should be sorted alphabetically!
@@ -65,6 +65,7 @@
#include "halloc_util.h"
#include "parse_util.h"
#include "expand.h"
#include "path.h"
@@ -214,15 +215,17 @@ static void builtin_print_help( wchar_t *cmd, string_buffer_t *b )
if( is_interactive && !builtin_out_redirect && b==sb_err)
{
/* Interactive mode help to screen - only print synopsis if the rest won't fit */
int screen_height, lines;
screen_height = common_get_height();
lines = count_char( str, L'\n' );
if( lines > 2*screen_height/3 )
{
wchar_t *pos;
int cut=0;
/* Find first empty line */
for( pos=str; *pos; pos++ )
@@ -246,9 +249,16 @@ static void builtin_print_help( wchar_t *cmd, string_buffer_t *b )
if( is_empty )
{
*(pos+1)=L'\0';
cut = 1;
break;
}
}
}
if( !cut )
{
*str = 0;
}
}
}
@@ -335,7 +345,7 @@ static int builtin_bind( wchar_t **argv )
long_options[opt_index].name );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
case 'M':
input_set_mode( woptarg );
@@ -348,7 +358,7 @@ static int builtin_bind( wchar_t **argv )
case '?':
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
@@ -430,7 +440,7 @@ static int builtin_block( wchar_t **argv )
long_options[opt_index].name );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
case 'h':
builtin_print_help( argv[0], sb_out );
return 0;
@@ -450,7 +460,7 @@ static int builtin_block( wchar_t **argv )
case '?':
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
@@ -461,13 +471,13 @@ static int builtin_block( wchar_t **argv )
if( scope != UNSET )
{
sb_printf( sb_err, _( L"%ls: Can not specify scope when removing block\n" ), argv[0] );
return 1;
return STATUS_BUILTIN_ERROR;
}
if( !global_event_block )
{
sb_printf( sb_err, _( L"%ls: No blocks defined\n" ), argv[0] );
return 1;
return STATUS_BUILTIN_ERROR;
}
event_block_t *eb = global_event_block;
@@ -571,7 +581,7 @@ static int builtin_builtin( wchar_t **argv )
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
case 'h':
builtin_print_help( argv[0], sb_out );
return 0;
@@ -583,7 +593,7 @@ static int builtin_builtin( wchar_t **argv )
case '?':
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
@@ -660,7 +670,7 @@ static int builtin_generic( wchar_t **argv )
argv[0],
long_options[opt_index].name );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
case 'h':
builtin_print_help( argv[0], sb_out );
@@ -669,19 +679,19 @@ static int builtin_generic( wchar_t **argv )
case '?':
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
}
return 1;
return STATUS_BUILTIN_ERROR;
}
/**
Output a definition of the specified function to the sb_out
Output a definition of the specified function to the specified
stringbuffer. Used by the functions builtin.
*/
static void functions_def( wchar_t *name )
static void functions_def( wchar_t *name, string_buffer_t *out )
{
const wchar_t *desc = function_get_desc( name );
const wchar_t *def = function_get_definition(name);
@@ -697,7 +707,7 @@ static void functions_def( wchar_t *name )
al_init( &ev );
event_get( &search, &ev );
sb_append2( sb_out,
sb_append2( out,
L"function ",
name,
(void *)0);
@@ -706,7 +716,7 @@ static void functions_def( wchar_t *name )
{
wchar_t *esc_desc = escape( desc, 1 );
sb_append2( sb_out, L" --description ", esc_desc, (void *)0 );
sb_append2( out, L" --description ", esc_desc, (void *)0 );
free( esc_desc );
}
@@ -717,22 +727,22 @@ static void functions_def( wchar_t *name )
{
case EVENT_SIGNAL:
{
sb_printf( sb_out, L" --on-signal %ls", sig2wcs( next->param1.signal ) );
sb_printf( out, L" --on-signal %ls", sig2wcs( next->param1.signal ) );
break;
}
case EVENT_VARIABLE:
{
sb_printf( sb_out, L" --on-variable %ls", next->param1.variable );
sb_printf( out, L" --on-variable %ls", next->param1.variable );
break;
}
case EVENT_EXIT:
{
if( next->param1.pid > 0 )
sb_printf( sb_out, L" --on-process-exit %d", next->param1.pid );
sb_printf( out, L" --on-process-exit %d", next->param1.pid );
else
sb_printf( sb_out, L" --on-job-exit %d", -next->param1.pid );
sb_printf( out, L" --on-job-exit %d", -next->param1.pid );
break;
}
@@ -740,7 +750,7 @@ static void functions_def( wchar_t *name )
{
job_t *j = job_get( next->param1.job_id );
if( j )
sb_printf( sb_out, L" --on-job-exit %d", j->pgid );
sb_printf( out, L" --on-job-exit %d", j->pgid );
break;
}
@@ -750,7 +760,7 @@ static void functions_def( wchar_t *name )
al_destroy( &ev );
sb_append2( sb_out,
sb_append2( out,
L"\n\t",
def,
L"\nend\n\n",
@@ -835,7 +845,7 @@ static int builtin_functions( wchar_t **argv )
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
case 'e':
erase=1;
@@ -864,7 +874,7 @@ static int builtin_functions( wchar_t **argv )
case '?':
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
@@ -882,7 +892,7 @@ static int builtin_functions( wchar_t **argv )
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
if( erase )
@@ -903,7 +913,7 @@ static int builtin_functions( wchar_t **argv )
argv[0] );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
func = argv[woptind];
if( !function_exists( func ) )
@@ -915,7 +925,7 @@ static int builtin_functions( wchar_t **argv )
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
function_set_desc( func, desc );
@@ -973,7 +983,7 @@ static int builtin_functions( wchar_t **argv )
for( i=0; i<al_get_count( &names ); i++ )
{
functions_def( (wchar_t *)al_get( &names, i ) );
functions_def( (wchar_t *)al_get( &names, i ), sb_out );
}
al_destroy( &names );
@@ -992,7 +1002,7 @@ static int builtin_functions( wchar_t **argv )
{
if( !query )
{
functions_def( argv[i] );
functions_def( argv[i], sb_out );
}
}
}
@@ -1004,21 +1014,14 @@ static int builtin_functions( wchar_t **argv )
}
/**
Test whether the specified string is a valid name for a keybinding
*/
static int wcsbindingname( wchar_t *str )
typedef struct function_data
{
while( *str )
{
if( (!iswalnum(*str)) && (*str != L'-' ) )
{
return 0;
}
str++;
}
return 1;
wchar_t *name;
wchar_t *description;
array_list_t *events;
}
function_data_t;
/**
@@ -1030,7 +1033,6 @@ static int builtin_function( wchar_t **argv )
int argc = builtin_count_args( argv );
int res=0;
wchar_t *desc=0;
int is_binding=0;
array_list_t *events;
int i;
@@ -1046,10 +1048,6 @@ static int builtin_function( wchar_t **argv )
L"description", required_argument, 0, 'd'
}
,
{
L"key-binding", no_argument, 0, 'b'
}
,
{
L"on-signal", required_argument, 0, 's'
}
@@ -1082,7 +1080,7 @@ static int builtin_function( wchar_t **argv )
int opt = wgetopt_long( argc,
argv,
L"bd:s:j:p:v:h",
L"d:s:j:p:v:h",
long_options,
&opt_index );
if( opt == -1 )
@@ -1097,7 +1095,6 @@ static int builtin_function( wchar_t **argv )
BUILTIN_ERR_UNKNOWN,
argv[0],
long_options[opt_index].name );
builtin_print_help( argv[0], sb_err );
res = 1;
break;
@@ -1106,10 +1103,6 @@ static int builtin_function( wchar_t **argv )
desc=woptarg;
break;
case 'b':
is_binding=1;
break;
case 's':
{
int sig = wcs2sig( woptarg );
@@ -1241,7 +1234,7 @@ static int builtin_function( wchar_t **argv )
return 0;
case '?':
builtin_print_help( argv[0], sb_err );
res = 1;
break;
@@ -1259,7 +1252,7 @@ static int builtin_function( wchar_t **argv )
argc-woptind );
res=1;
}
else if( !(is_binding?wcsbindingname( argv[woptind] ) : !wcsvarname( argv[woptind] ) ))
else if( wcsfuncname( argv[woptind] ) )
{
sb_printf( sb_err,
_( L"%ls: Illegal function name '%ls'\n" ),
@@ -1316,16 +1309,20 @@ static int builtin_function( wchar_t **argv )
}
else
{
current_block->param1.function_name=halloc_wcsdup( current_block, argv[woptind]);
current_block->param2.function_description=desc?halloc_wcsdup( current_block, desc):0;
current_block->param3.function_is_binding = is_binding;
current_block->param4.function_events = events;
function_data_t * d = halloc( current_block, sizeof( function_data_t ));
d->name=halloc_wcsdup( current_block, argv[woptind]);
d->description=desc?halloc_wcsdup( current_block, desc):0;
d->events = events;
for( i=0; i<al_get_count( events ); i++ )
{
event_t *e = (event_t *)al_get( events, i );
e->function_name = current_block->param1.function_name;
e->function_name = d->name;
}
current_block->data = d;
}
current_block->tok_pos = parser_get_pos();
@@ -1383,7 +1380,7 @@ static int builtin_random( wchar_t **argv )
long_options[opt_index].name );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
case 'h':
builtin_print_help( argv[0], sb_out );
@@ -1392,7 +1389,7 @@ static int builtin_random( wchar_t **argv )
case '?':
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
@@ -1412,7 +1409,7 @@ static int builtin_random( wchar_t **argv )
}
lrand48_r( &seed_buffer, &res );
sb_printf( sb_out, L"%d\n", res%32767 );
sb_printf( sb_out, L"%d\n", abs(res%32767) );
break;
}
@@ -1430,7 +1427,7 @@ static int builtin_random( wchar_t **argv )
argv[0],
argv[woptind] );
return 1;
return STATUS_BUILTIN_ERROR;
}
seeded=1;
srand48_r( foo, &seed_buffer);
@@ -1444,7 +1441,7 @@ static int builtin_random( wchar_t **argv )
argv[0],
argc-woptind );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
}
return 0;
@@ -1531,7 +1528,7 @@ static int builtin_read( wchar_t **argv )
long_options[opt_index].name );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
case L'x':
place |= ENV_EXPORT;
@@ -1562,7 +1559,7 @@ static int builtin_read( wchar_t **argv )
case L'?':
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
}
@@ -1576,7 +1573,7 @@ static int builtin_read( wchar_t **argv )
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
if( (place&ENV_LOCAL?1:0) + (place & ENV_GLOBAL?1:0) + (place & ENV_UNIVERSAL?1:0) > 1)
@@ -1587,7 +1584,7 @@ static int builtin_read( wchar_t **argv )
parser_current_line() );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
/*
@@ -1600,7 +1597,7 @@ static int builtin_read( wchar_t **argv )
if( !wcslen( argv[i] ) )
{
sb_printf( sb_err, BUILTIN_ERR_VARNAME_ZERO, argv[0] );
return 1;
return STATUS_BUILTIN_ERROR;
}
for( src=argv[i]; *src; src++ )
@@ -1609,7 +1606,7 @@ static int builtin_read( wchar_t **argv )
{
sb_printf( sb_err, BUILTIN_ERR_VARCHAR, argv[0], *src );
sb_append2(sb_err, parser_current_line(), L"\n", (void *)0 );
return 1;
return STATUS_BUILTIN_ERROR;
}
}
@@ -1815,7 +1812,7 @@ static int builtin_status( wchar_t **argv )
int opt = wgetopt_long( argc,
argv,
L"hjt",
L"hj:t",
long_options,
&opt_index );
if( opt == -1 )
@@ -1832,7 +1829,7 @@ static int builtin_status( wchar_t **argv )
long_options[opt_index].name );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
case 'h':
builtin_print_help( argv[0], sb_out );
@@ -1858,7 +1855,7 @@ static int builtin_status( wchar_t **argv )
case '?':
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
@@ -1986,7 +1983,7 @@ static int builtin_exit( wchar_t **argv )
argv[0],
argv[1] );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
break;
}
@@ -1998,7 +1995,7 @@ static int builtin_exit( wchar_t **argv )
argv[0] );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
}
@@ -2049,7 +2046,7 @@ static int builtin_cd( wchar_t **argv )
else
dir_in = argv[1];
dir = parser_cdpath_get( context, dir_in );
dir = path_get_cdpath( context, dir_in );
if( !dir )
{
@@ -2110,13 +2107,13 @@ static int builtin_source( wchar_t ** argv )
{
sb_printf( sb_err, _( L"%ls: Expected at least one argument, got %d\n" ), argv[0], argc );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
if( wstat(argv[1], &buf) == -1 )
{
builtin_wperror( L"stat" );
return 1;
return STATUS_BUILTIN_ERROR;
}
if( !S_ISREG(buf.st_mode) )
@@ -2124,7 +2121,7 @@ static int builtin_source( wchar_t ** argv )
sb_printf( sb_err, _( L"%ls: '%ls' is not a file\n" ), argv[0], argv[1] );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
if( ( fd = wopen( argv[1], O_RDONLY ) ) == -1 )
{
@@ -2219,8 +2216,8 @@ static int builtin_fg( wchar_t **argv )
*/
for( j=first_job; j; j=j->next )
{
if( j->constructed && (!job_is_completed(j)) &&
( (job_is_stopped(j) || !j->fg) && (j->job_control) ) )
if( job_get_flag( j, JOB_CONSTRUCTED ) && (!job_is_completed(j)) &&
( (job_is_stopped(j) || (!job_get_flag(j, JOB_FOREGROUND)) ) && job_get_flag( j, JOB_CONTROL) ) )
{
break;
}
@@ -2241,9 +2238,20 @@ static int builtin_fg( wchar_t **argv )
since we want to know if this is an ambigous job
specification or if this is an malformed job id
*/
int pid = wcstol( argv[1], 0, 10 );
j = job_get_from_pid( pid );
if( j != 0 )
wchar_t *endptr;
int pid;
int found_job = 0;
errno = 0;
pid = wcstol( argv[1], &endptr, 10 );
if( !( *endptr || errno ) )
{
j = job_get_from_pid( pid );
if( j )
found_job = 1;
}
if( found_job )
{
sb_printf( sb_err,
_( L"%ls: Ambiguous job\n" ),
@@ -2256,6 +2264,7 @@ static int builtin_fg( wchar_t **argv )
argv[0],
argv[1] );
}
builtin_print_help( argv[0], sb_err );
j=0;
@@ -2264,12 +2273,14 @@ static int builtin_fg( wchar_t **argv )
else
{
wchar_t *end;
int pid = abs(wcstol( argv[1], &end, 10 ));
int pid;
errno = 0;
pid = abs(wcstol( argv[1], &end, 10 ));
if( *end )
if( *end || errno )
{
sb_printf( sb_err,
_( L"%ls: Argument '%ls' is not a number\n" ),
BUILTIN_ERR_NOT_NUMBER,
argv[0],
argv[1] );
builtin_print_help( argv[0], sb_err );
@@ -2277,7 +2288,7 @@ static int builtin_fg( wchar_t **argv )
else
{
j = job_get_from_pid( pid );
if( !j || !j->constructed || job_is_completed( j ))
if( !j || !job_get_flag( j, JOB_CONSTRUCTED ) || job_is_completed( j ))
{
sb_printf( sb_err,
_( L"%ls: No suitable job: %d\n" ),
@@ -2286,7 +2297,7 @@ static int builtin_fg( wchar_t **argv )
builtin_print_help( argv[0], sb_err );
j=0;
}
else if( !j->job_control )
else if( !job_get_flag( j, JOB_CONTROL) )
{
sb_printf( sb_err,
_( L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n" ),
@@ -2328,7 +2339,7 @@ static int builtin_fg( wchar_t **argv )
reader_write_title();
make_first( j );
j->fg=1;
job_set_flag( j, JOB_FOREGROUND, 1 );
job_continue( j, job_is_stopped(j) );
}
@@ -2347,9 +2358,9 @@ static int send_to_bg( job_t *j, const wchar_t *name )
L"bg",
name );
builtin_print_help( L"bg", sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
else if( !j->job_control )
else if( !job_get_flag( j, JOB_CONTROL ) )
{
sb_printf( sb_err,
_( L"%ls: Can't put job %d, '%ls' to background because it is not under job control\n" ),
@@ -2357,7 +2368,7 @@ static int send_to_bg( job_t *j, const wchar_t *name )
j->job_id,
j->command );
builtin_print_help( L"bg", sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
else
{
@@ -2367,7 +2378,7 @@ static int send_to_bg( job_t *j, const wchar_t *name )
j->command );
}
make_first( j );
j->fg=0;
job_set_flag( j, JOB_FOREGROUND, 0 );
job_continue( j, job_is_stopped(j) );
return 0;
}
@@ -2385,7 +2396,7 @@ static int builtin_bg( wchar_t **argv )
job_t *j;
for( j=first_job; j; j=j->next )
{
if( job_is_stopped(j) && j->job_control && (!job_is_completed(j)) )
if( job_is_stopped(j) && job_get_flag( j, JOB_CONTROL ) && (!job_is_completed(j)) )
{
break;
}
@@ -2427,15 +2438,15 @@ static int builtin_for( wchar_t **argv )
if( argc < 3)
{
sb_printf( sb_err,
_( L"%ls: Expected at least two arguments, got %d\n"),
argc ,
argv[0] );
BUILTIN_FOR_ERR_COUNT,
argv[0] ,
argc );
builtin_print_help( argv[0], sb_err );
}
else if ( wcsvarname(argv[1]) )
{
sb_printf( sb_err,
_( L"%ls: '%ls' is not a valid variable name\n" ),
BUILTIN_FOR_ERR_NAME,
argv[0],
argv[1] );
builtin_print_help( argv[0], sb_err );
@@ -2494,6 +2505,30 @@ static int builtin_begin( wchar_t **argv )
return proc_get_last_status();
}
/**
Define the function specified by the function_data_t structure.
*/
static void builtin_end_add_function_def( function_data_t *d )
{
/**
Copy the text from the beginning of the function
until the end command and use as the new definition
for the specified function
*/
wchar_t *def = wcsndup( parser_get_buffer()+current_block->tok_pos,
parser_get_job_pos()-current_block->tok_pos );
function_add( d->name,
def,
d->description,
d->events );
free( def );
}
/**
Builtin for ending a block of code, such as a for-loop or an if statement.
@@ -2509,7 +2544,7 @@ static int builtin_end( wchar_t **argv )
argv[0] );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
else
{
@@ -2574,21 +2609,21 @@ static int builtin_end( wchar_t **argv )
case FUNCTION_DEF:
{
/**
Copy the text from the beginning of the function
until the end command and use as the new definition
for the specified function
*/
wchar_t *def = wcsndup( parser_get_buffer()+current_block->tok_pos,
parser_get_job_pos()-current_block->tok_pos );
function_add( current_block->param1.function_name,
def,
current_block->param2.function_description,
current_block->param4.function_events,
current_block->param3.function_is_binding );
function_data_t *d = (function_data_t *)current_block->data;
if( d )
{
builtin_end_add_function_def( d );
}
else
{
debug(0,
_(L"%ls: Missing function definition information. This is a fish bug. If you can reproduce it, please file a bug report to %s."),
argv[0],
PACKAGE_BUGREPORT);
}
free(def);
}
break;
@@ -2619,7 +2654,7 @@ static int builtin_else( wchar_t **argv )
_( L"%ls: Not inside of 'if' block\n" ),
argv[0] );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
else
{
@@ -2654,7 +2689,7 @@ static int builtin_break_continue( wchar_t **argv )
argv[1] );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
@@ -2671,7 +2706,7 @@ static int builtin_break_continue( wchar_t **argv )
_( L"%ls: Not inside of loop\n" ),
argv[0] );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
b = current_block;
@@ -2712,7 +2747,7 @@ static int builtin_return( wchar_t **argv )
argv[0],
argv[1] );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
break;
}
@@ -2721,7 +2756,7 @@ static int builtin_return( wchar_t **argv )
_( L"%ls: Too many arguments\n" ),
argv[0] );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
@@ -2737,23 +2772,24 @@ static int builtin_return( wchar_t **argv )
_( L"%ls: Not inside of function\n" ),
argv[0] );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
b = current_block;
while( ( b->type != FUNCTION_CALL))
{
b->type = FAKE;
b->skip=1;
b = b->outer;
}
b->skip=1;
// proc_set_last_status( status );
return status;
}
/**
Builtin for executing one of several blocks of commands depending on the value of an argument.
Builtin for executing one of several blocks of commands depending
on the value of an argument.
*/
static int builtin_switch( wchar_t **argv )
{
@@ -2778,51 +2814,52 @@ static int builtin_switch( wchar_t **argv )
current_block->skip=1;
current_block->param2.switch_taken=0;
}
return res;
}
/**
Builtin used together with the switch builtin for conditional execution
Builtin used together with the switch builtin for conditional
execution
*/
static int builtin_case( wchar_t **argv )
{
int argc = builtin_count_args( argv );
int i;
wchar_t *unescaped=0;
if( current_block->type != SWITCH )
{
sb_printf( sb_err,
_( L"%ls: 'case' command while not in switch block\n" ),
argv[0] );
builtin_print_help( argv[0], sb_err );
return 1;
return STATUS_BUILTIN_ERROR;
}
current_block->skip = 1;
if( current_block->param2.switch_taken )
{
return 0;
}
for( i=1; i<argc; i++ )
{
free( unescaped );
int match;
unescaped = parse_util_unescape_wildcards( argv[i] );
match = wildcard_match( current_block->param1.switch_value, unescaped );
free( unescaped );
if( wildcard_match( current_block->param1.switch_value, unescaped ) )
if( match )
{
current_block->skip = 0;
current_block->param2.switch_taken = 1;
break;
}
}
free( unescaped );
return 0;
}
@@ -2838,15 +2875,15 @@ static int builtin_case( wchar_t **argv )
const static builtin_data_t builtin_data[]=
{
{
L"exit", &builtin_exit, N_( L"Exit the shell" )
L"exit", &builtin_exit, N_( L"Exit the shell" )
}
,
{
L"block", &builtin_block, N_( L"Temporarily block delivery of events" )
L"block", &builtin_block, N_( L"Temporarily block delivery of events" )
}
,
{
L"builtin", &builtin_builtin, N_( L"Run a builtin command instead of a function" )
L"builtin", &builtin_builtin, N_( L"Run a builtin command instead of a function" )
}
,
{
@@ -3048,6 +3085,8 @@ int builtin_exists( wchar_t *cmd )
*/
static int internal_help( wchar_t *cmd )
{
CHECK( cmd, 0 );
if( wcscmp( cmd, L"for" ) == 0 ||
wcscmp( cmd, L"while" ) == 0 ||
wcscmp( cmd, L"function" ) == 0 ||

View File

@@ -62,11 +62,29 @@ enum
*/
#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 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" )
/**
Stringbuffer used to represent standard output
*/

View File

@@ -52,15 +52,15 @@ enum
}
;
static wchar_t *current_buffer=0;
static int current_cursor_pos = -1;
/**
Returns the current commandline buffer.
*/
static const wchar_t *get_buffer()
static wchar_t *get_buffer()
{
const wchar_t *buff = builtin_complete_get_temporary_buffer();
if( !buff )
buff = reader_get_buffer();
return buff;
return current_buffer;
}
/**
@@ -68,11 +68,7 @@ static const wchar_t *get_buffer()
*/
static int get_cursor_pos()
{
const wchar_t *buff = builtin_complete_get_temporary_buffer();
if( buff )
return wcslen( buff );
else
return reader_get_cursor_pos();
return current_cursor_pos;
}
@@ -210,6 +206,20 @@ static int builtin_commandline( wchar_t **argv )
int function_mode = 0;
int tokenize = 0;
int cursor_mode = 0;
wchar_t *begin, *end;
current_buffer = (wchar_t *)builtin_complete_get_temporary_buffer();
if( current_buffer )
{
current_cursor_pos = wcslen( current_buffer );
}
else
{
current_buffer = reader_get_buffer();
current_cursor_pos = reader_get_cursor_pos();
}
if( !get_buffer() )
{
@@ -272,6 +282,14 @@ static int builtin_commandline( wchar_t **argv )
L"help", no_argument, 0, 'h'
}
,
{
L"input", required_argument, 0, 'I'
}
,
{
L"cursor", no_argument, 0, 'C'
}
,
{
0, 0, 0, 0
}
@@ -282,7 +300,7 @@ static int builtin_commandline( wchar_t **argv )
int opt = wgetopt_long( argc,
argv,
L"aijpctwforh",
L"aijpctwforhI:C",
long_options,
&opt_index );
if( opt == -1 )
@@ -337,6 +355,15 @@ static int builtin_commandline( wchar_t **argv )
tokenize=1;
break;
case 'I':
current_buffer = woptarg;
current_cursor_pos = wcslen( woptarg );
break;
case 'C':
cursor_mode = 1;
break;
case 'h':
builtin_print_help( argv[0], sb_out );
return 0;
@@ -354,16 +381,13 @@ static int builtin_commandline( wchar_t **argv )
/*
Check for invalid switch combinations
*/
if( buffer_part || cut_at_cursor || append_mode || tokenize )
if( buffer_part || cut_at_cursor || append_mode || tokenize || cursor_mode )
{
sb_printf(sb_err,
BUILTIN_ERR_COMBO,
argv[0] );
sb_append2(sb_err,
parser_current_line(),
L"\n",
(void *)0);
builtin_print_help( argv[0], sb_err );
return 1;
}
@@ -374,10 +398,6 @@ static int builtin_commandline( wchar_t **argv )
BUILTIN_ERR_MISSING,
argv[0] );
sb_append2( sb_err,
parser_current_line(),
L"\n",
(void *)0 );
builtin_print_help( argv[0], sb_err );
return 1;
}
@@ -386,7 +406,6 @@ static int builtin_commandline( wchar_t **argv )
wint_t c = input_get_code( argv[i] );
if( c != -1 )
{
// fwprintf( stderr, L"Add function %ls (%d)\n", argv[i], c );
/*
input_unreadch inserts the specified keypress or
readline function at the top of the stack of unused
@@ -396,15 +415,10 @@ static int builtin_commandline( wchar_t **argv )
}
else
{
// fwprintf( stderr, L"BLUR %ls %d\n", argv[i], c );
sb_append2( sb_err,
argv[0],
L": Unknown readline function '",
argv[i],
L"'\n",
parser_current_line(),
L"\n",
(void *)0 );
sb_printf( sb_err,
_(L"%ls: Unknown readline function '%ls'\n"),
argv[0],
argv[i] );
builtin_print_help( argv[0], sb_err );
return 1;
}
@@ -416,7 +430,7 @@ static int builtin_commandline( wchar_t **argv )
/*
Check for invalid switch combinations
*/
if( argc-woptind > 1 )
if( cursor_mode && (argc-woptind > 1) )
{
sb_append2( sb_err,
@@ -427,9 +441,19 @@ static int builtin_commandline( wchar_t **argv )
return 1;
}
if( (buffer_part || tokenize || cut_at_cursor) && cursor_mode )
{
sb_printf( sb_err,
BUILTIN_ERR_COMBO,
argv[0] );
builtin_print_help( argv[0], sb_err );
return 1;
}
if( (tokenize || cut_at_cursor) && (argc-woptind) )
{
sb_printf( sb_err,
BUILTIN_ERR_COMBO2,
argv[0],
@@ -463,14 +487,44 @@ static int builtin_commandline( wchar_t **argv )
{
buffer_part = STRING_MODE;
}
if( cursor_mode )
{
if( argc-woptind )
{
wchar_t *endptr;
int new_pos;
errno = 0;
new_pos = wcstol( argv[woptind], &endptr, 10 );
if( *endptr || errno )
{
sb_printf( sb_err,
BUILTIN_ERR_NOT_NUMBER,
argv[0],
argv[woptind] );
builtin_print_help( argv[0], sb_err );
}
current_buffer = reader_get_buffer();
new_pos = maxi( 0, mini( new_pos, wcslen( current_buffer ) ) );
reader_set_buffer( current_buffer, new_pos );
return 0;
}
else
{
sb_printf( sb_out, L"%d\n", reader_get_cursor_pos() );
return 0;
}
wchar_t *begin, *end;
}
switch( buffer_part )
{
case STRING_MODE:
{
begin = (wchar_t *)get_buffer();
begin = get_buffer();
end = begin+wcslen(begin);
break;
}
@@ -516,7 +570,28 @@ static int builtin_commandline( wchar_t **argv )
case 1:
{
replace_part( begin, end, argv[woptind], append_mode );
break;
break;
}
default:
{
string_buffer_t sb;
int i;
sb_init( &sb );
sb_append( &sb, argv[woptind] );
for( i=woptind+1; i<argc; i++ )
{
sb_append( &sb, L"\n" );
sb_append( &sb, argv[i] );
}
replace_part( begin, end, (wchar_t *)sb.buff, append_mode );
sb_destroy( &sb );
break;
}
}

View File

@@ -489,14 +489,14 @@ static int builtin_complete( wchar_t **argv )
{
if( condition && wcslen( condition ) )
{
if( parser_test( condition, 0, 0 ) )
if( parser_test( condition, 0, 0, 0 ) )
{
sb_printf( sb_err,
L"%ls: Condition '%ls' contained a syntax error\n",
argv[0],
condition );
parser_test( condition, sb_err, argv[0] );
parser_test( condition, 0, sb_err, argv[0] );
res = 1;
}

View File

@@ -276,7 +276,7 @@ static int builtin_jobs( wchar_t **argv )
*/
for( j=first_job; j; j=j->next )
{
if( j->constructed && !job_is_completed(j) )
if( (j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) )
{
builtin_jobs_print( j, mode, !found );
return 0;
@@ -330,7 +330,7 @@ static int builtin_jobs( wchar_t **argv )
/*
Ignore unconstructed jobs, i.e. ourself.
*/
if( j->constructed && !job_is_completed(j) )
if( (j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) )
{
builtin_jobs_print( j, mode, !found );
found = 1;

View File

@@ -318,20 +318,20 @@ static int al_contains_long( array_list_t *list,
*/
static void erase_values(array_list_t *list, array_list_t *indexes)
{
int i;
long i;
array_list_t result;
al_init(&result);
for (i = 0; i < al_get_count(list); i++)
{
if (!al_contains_long(indexes, (long)i + 1))
if (!al_contains_long(indexes, i + 1))
{
al_push(&result, al_get(list, i));
}
else
{
free((void *) al_get(list, i));
free( (void *)al_get(list, i));
}
}
@@ -358,7 +358,7 @@ static void print_variables(int include_values, int esc, int scope)
for( i = 0; i < al_get_count(&names); i++ )
{
wchar_t *key = (wchar_t *)al_get( &names, i );
wchar_t *e_key = esc ? escape(key, 1) : wcsdup(key);
wchar_t *e_key = esc ? escape(key, 0) : wcsdup(key);
sb_append(sb_out, e_key);
@@ -366,9 +366,32 @@ static void print_variables(int include_values, int esc, int scope)
{
wchar_t *value = env_get(key);
wchar_t *e_value;
e_value = esc ? expand_escape_variable(value) : wcsdup(value);
sb_append2(sb_out, L" ", e_value, (void *)0);
free(e_value);
if( value )
{
int shorten = 0;
if( wcslen( value ) > 64 )
{
shorten = 1;
value = wcsndup( value, 60 );
if( !value )
{
DIE_MEM();
}
}
e_value = esc ? expand_escape_variable(value) : wcsdup(value);
sb_append2(sb_out, L" ", e_value, (void *)0);
free(e_value);
if( shorten )
{
sb_append(sb_out, L"\u2026");
free( value );
}
}
}
sb_append(sb_out, L"\n");
@@ -455,6 +478,8 @@ static int builtin_set( wchar_t **argv )
int slice=0;
int i;
wchar_t *bad_char;
/* Parse options to obtain the requested operation and the modifiers */
woptind = 0;
@@ -599,6 +624,13 @@ static int builtin_set( wchar_t **argv )
return retcode;
}
if( list )
{
/* Maybe we should issue an error if there are any other arguments? */
print_variables(0, 0, scope);
return 0;
}
if( woptind == argc )
{
/*
@@ -623,13 +655,6 @@ static int builtin_set( wchar_t **argv )
return retcode;
}
if( list )
{
/* Maybe we should issue an error if there are any other arguments? */
print_variables(0, 0, scope);
return 0;
}
if( !(dest = wcsdup(argv[woptind])))
{
DIE_MEM();
@@ -648,7 +673,15 @@ static int builtin_set( wchar_t **argv )
builtin_print_help( argv[0], sb_err );
return 1;
}
if( (bad_char = wcsvarname( dest ) ) )
{
sb_printf( sb_err, BUILTIN_ERR_VARCHAR, argv[0], *bad_char );
builtin_print_help( argv[0], sb_err );
free( dest );
return 1;
}
if( slice && erase && (scope != ENV_USER) )
{
free( dest );
@@ -676,9 +709,9 @@ static int builtin_set( wchar_t **argv )
al_init(&values);
al_init(&indexes);
al_init(&result);
tokenize_variable_array( env_get(dest), &result );
for( ; woptind<argc; woptind++ )
{
if( !parse_index( &indexes, argv[woptind], dest, al_get_count( &result ) ) )

236
common.c
View File

@@ -296,7 +296,10 @@ char *wcs2str_internal( const wchar_t *in, char *out )
while( in[in_pos] )
{
if( ( in[in_pos] >= ENCODE_DIRECT_BASE) &&
if( in[in_pos] == INTERNAL_SEPARATOR )
{
}
else if( ( in[in_pos] >= ENCODE_DIRECT_BASE) &&
( in[in_pos] < ENCODE_DIRECT_BASE+256) )
{
out[out_pos++] = in[in_pos]- ENCODE_DIRECT_BASE;
@@ -307,7 +310,7 @@ char *wcs2str_internal( const wchar_t *in, char *out )
if( res == (size_t)(-1) )
{
debug( 1, L"Wide character has no narrow representation" );
debug( 1, L"Wide character %d has no narrow representation", in[in_pos] );
memset( &state, 0, sizeof(state) );
}
else
@@ -405,19 +408,25 @@ wchar_t **strv2wcsv( const char **in )
}
wchar_t *wcsvarname( wchar_t *str )
wchar_t *wcsvarname( const wchar_t *str )
{
while( *str )
{
if( (!iswalnum(*str)) && (*str != L'_' ) )
{
return str;
return (wchar_t *)str;
}
str++;
}
return 0;
}
wchar_t *wcsfuncname( const wchar_t *str )
{
return wcschr( str, L'/' );
}
int wcsvarchr( wchar_t chr )
{
return ( (iswalnum(chr)) || (chr == L'_' ));
@@ -813,64 +822,22 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
{
switch( in[++in_pos] )
{
/*
A null character after a backslash is an
error, return null
*/
case L'\0':
{
free(in);
return 0;
}
case L'n':
{
in[out_pos]=L'\n';
break;
}
/*
Numeric escape sequences. No prefix means
octal escape, otherwise hexadecimal.
*/
case L'r':
{
in[out_pos]=L'\r';
break;
}
case L't':
{
in[out_pos]=L'\t';
break;
}
case L'b':
{
in[out_pos]=L'\b';
break;
}
case L'a':
{
in[out_pos]=L'\a';
break;
}
case L'f':
{
in[out_pos]=L'\f';
break;
}
case L'v':
{
in[out_pos]=L'\v';
break;
}
case L'e':
{
in[out_pos]=L'\x1b';
break;
}
case L'u':
case L'U':
case L'x':
case L'X':
case L'0':
case L'1':
case L'2':
@@ -879,6 +846,10 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
case L'5':
case L'6':
case L'7':
case L'u':
case L'U':
case L'x':
case L'X':
{
int i;
long long res=0;
@@ -951,8 +922,107 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
break;
}
/*
\a means bell (alert)
*/
case L'a':
{
in[out_pos]=L'\a';
break;
}
/*
\b means backspace
*/
case L'b':
{
in[out_pos]=L'\b';
break;
}
/*
\cX means control sequence X
*/
case L'c':
{
in_pos++;
if( in[in_pos] >= L'a' &&
in[in_pos] <= (L'a'+32) )
{
in[out_pos]=in[in_pos]-L'a'+1;
}
else if( in[in_pos] >= L'A' &&
in[in_pos] <= (L'A'+32) )
{
in[out_pos]=in[in_pos]-L'A'+1;
}
else
{
free(in);
return 0;
}
break;
}
/*
\e means escape
*/
case L'e':
{
in[out_pos]=L'\x1b';
break;
}
/*
\f means form feed
*/
case L'f':
{
in[out_pos]=L'\f';
break;
}
/*
\n means newline
*/
case L'n':
{
in[out_pos]=L'\n';
break;
}
/*
\r means carriage return
*/
case L'r':
{
in[out_pos]=L'\r';
break;
}
/*
\t means tab
*/
case L't':
{
in[out_pos]=L'\t';
break;
}
/*
\v means vetrical tab
*/
case L'v':
{
in[out_pos]=L'\v';
break;
}
default:
{
if( unescape_special )
in[out_pos++] = INTERNAL_SEPARATOR;
in[out_pos]=in[in_pos];
break;
}
@@ -960,7 +1030,8 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
}
else
{
switch( in[in_pos]){
switch( in[in_pos])
{
case L'~':
{
if( unescape_special && (in_pos == 0) )
@@ -1076,14 +1147,16 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
case L'\'':
{
mode = 1;
in[out_pos] = INTERNAL_SEPARATOR;
if( unescape_special )
in[out_pos] = INTERNAL_SEPARATOR;
break;
}
case L'\"':
{
mode = 2;
in[out_pos] = INTERNAL_SEPARATOR;
if( unescape_special )
in[out_pos] = INTERNAL_SEPARATOR;
break;
}
@@ -1108,6 +1181,7 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
{
case '\\':
case L'\'':
case L'\n':
{
in[out_pos]=in[in_pos];
break;
@@ -1129,7 +1203,8 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
}
if( c == L'\'' )
{
in[out_pos] = INTERNAL_SEPARATOR;
if( unescape_special )
in[out_pos] = INTERNAL_SEPARATOR;
mode = 0;
}
else
@@ -1150,7 +1225,8 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
case '"':
{
mode = 0;
in[out_pos] = INTERNAL_SEPARATOR;
if( unescape_special )
in[out_pos] = INTERNAL_SEPARATOR;
break;
}
@@ -1167,6 +1243,7 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
case '\\':
case L'$':
case '"':
case '\n':
{
in[out_pos]=in[in_pos];
break;
@@ -1486,3 +1563,42 @@ void tokenize_variable_array( const wchar_t *val, array_list_t *out )
}
int create_directory( wchar_t *d )
{
int ok = 0;
struct stat buf;
int stat_res = 0;
while( (stat_res = wstat(d, &buf ) ) != 0 )
{
if( errno != EAGAIN )
break;
}
if( stat_res == 0 )
{
if( S_ISDIR( buf.st_mode ) )
{
ok = 1;
}
}
else
{
if( errno == ENOENT )
{
wchar_t *dir = wcsdup( d );
dir = wdirname( dir );
if( !create_directory( dir ) )
{
if( !wmkdir( d, 0700 ) )
{
ok = 1;
}
}
free(dir);
}
}
return ok?0:-1;
}

View File

@@ -52,7 +52,8 @@ extern struct termios shell_modes;
extern wchar_t ellipsis_char;
/**
The verbosity of fish
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;
@@ -73,28 +74,54 @@ extern wchar_t *program_name;
failiure, the current function is ended at once. The second
parameter is the exit status of the current function on failiure.
*/
#define CHECK( arg, retval ) \
#define CHECK( arg, retval ) \
if( !(arg) ) \
{ \
debug( 1, \
L"function %s called with null value for argument %s. " \
L"This is a bug. " \
L"If you can reproduce it, please send a bug report to %s.", \
_( L"function %s called with null value for argument %s. " \
L"This is a bug. " \
L"If you can reproduce it, please send a bug report to %s." ), \
__func__, \
#arg, \
PACKAGE_BUGREPORT ); \
return retval; \
} \
}
/**
Exit program at once, leaving an error message about running out of memory
*/
#define DIE_MEM() \
#define DIE_MEM() \
{ \
fwprintf( stderr, L"fish: Out of memory on line %d of file %s, shutting down fish\n", __LINE__, __FILE__ ); \
fwprintf( stderr, \
L"fish: Out of memory on line %d of file %s, shutting down fish\n", \
__LINE__, \
__FILE__ ); \
exit(1); \
} \
}
/**
Cause fish to crash. This should only be usd for debugging.
*/
#define CRASH() \
{ \
int *n = 0; \
*n = 1; \
}
/**
Check if signals are blocked
*/
#define CHECK_BLOCK( retval ) \
if( signal_is_blocked() ) \
{ \
debug( 0, \
L"function %s called while blocking signals. " \
L"This is a bug. " \
L"If you can reproduce it, please send a bug report to %s.", \
__func__, \
PACKAGE_BUGREPORT ); \
return retval; \
}
/**
Shorthand for wgettext call
@@ -106,6 +133,7 @@ extern wchar_t *program_name;
*/
#define N_(wstr) wstr
/**
Take an array_list_t containing wide strings and converts them to a
single null-terminated wchar_t **. The array is allocated using
@@ -193,7 +221,7 @@ wchar_t *wcsdupcat( const wchar_t *a, const wchar_t *b );
Returns a newly allocated concatenation of the specified wide
character strings. The last argument must be a null pointer.
*/
wchar_t *wcsdupcat2( const wchar_t *a, ... );
__sentinel wchar_t *wcsdupcat2( const wchar_t *a, ... );
/**
Test if the given string is a valid variable name
@@ -206,7 +234,16 @@ wchar_t *wcsdupcat2( const wchar_t *a, ... );
\return null if this is a valid name, and a pointer to the first invalid character otherwise
*/
wchar_t *wcsvarname( wchar_t *str );
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
*/
wchar_t *wcsfuncname( const wchar_t *str );
/**
Test if the given string is valid in a variable name
@@ -256,7 +293,7 @@ const wchar_t *wsetlocale( int category, const wchar_t *locale );
\return zero is needle is not found, of if needle is null, non-zero otherwise
*/
int contains_str( const wchar_t *needle, ... );
__sentinel int contains_str( const wchar_t *needle, ... );
/**
Call read while blocking the SIGCHLD signal. Should only be called
@@ -358,5 +395,12 @@ void write_screen( const wchar_t *msg, string_buffer_t *buff );
void tokenize_variable_array( const wchar_t *val, array_list_t *out );
/**
Make sure the specified direcotry exists. If no, try to create it.
\return 0 if the directory exists, -1 otherwise.
*/
int create_directory( wchar_t *d );
#endif

View File

@@ -45,6 +45,7 @@
#include "halloc.h"
#include "halloc_util.h"
#include "wutil.h"
#include "path.h"
/*
@@ -194,7 +195,7 @@ typedef struct complete_entry_opt
/** Next option in the linked list */
struct complete_entry_opt *next;
}
complete_entry_opt;
complete_entry_opt_t;
/**
Struct describing a command completion
@@ -209,16 +210,16 @@ typedef struct complete_entry
/** String containing all short option characters */
wchar_t *short_opt_str;
/** Linked list of all options */
complete_entry_opt *first_option;
complete_entry_opt_t *first_option;
/** Next command completion in the linked list */
struct complete_entry *next;
/** True if no other options than the ones supplied are possible */
int authorative;
}
complete_entry;
complete_entry_t;
/** First node in the linked list of all completion entries */
static complete_entry *first_entry=0;
static complete_entry_t *first_entry=0;
/** Hashtable containing all descriptions that describe an executable */
static hash_table_t *suffix_hash=0;
@@ -235,7 +236,7 @@ static hash_table_t *condition_cache=0;
static string_buffer_t *get_desc_buff=0;
static void complete_free_entry( complete_entry *c );
static void complete_free_entry( complete_entry_t *c );
static void clear_hash_entry( void *key, void *data );
@@ -244,7 +245,7 @@ static void clear_hash_entry( void *key, void *data );
*/
static void complete_destroy()
{
complete_entry *i=first_entry, *prev;
complete_entry_t *i=first_entry, *prev;
while( i )
{
@@ -346,9 +347,9 @@ static int condition_test( const wchar_t *condition )
/**
Recursively free all complete_entry_opt structs and their contents
Recursively free all complete_entry_opt_t structs and their contents
*/
static void complete_free_opt_recursive( complete_entry_opt *o )
static void complete_free_opt_recursive( complete_entry_opt_t *o )
{
if( o->next != 0 )
complete_free_opt_recursive( o->next );
@@ -356,9 +357,9 @@ static void complete_free_opt_recursive( complete_entry_opt *o )
}
/**
Free a complete_entry and its contents
Free a complete_entry_t and its contents
*/
static void complete_free_entry( complete_entry *c )
static void complete_free_entry( complete_entry_t *c )
{
// free( c->cmd );
free( c->short_opt_str );
@@ -378,10 +379,10 @@ static void clear_hash_entry( void *key, void *data )
/**
Search for an exactly matching completion entry
*/
static complete_entry *complete_find_exact_entry( const wchar_t *cmd,
static complete_entry_t *complete_find_exact_entry( const wchar_t *cmd,
const int cmd_type )
{
complete_entry *i;
complete_entry_t *i;
for( i=first_entry; i; i=i->next )
{
if( ( wcscmp(cmd, i->cmd)==0) && ( cmd_type == i->cmd_type ))
@@ -403,18 +404,18 @@ void complete_add( const wchar_t *cmd,
const wchar_t *comp,
const wchar_t *desc )
{
complete_entry *c;
complete_entry_opt *opt;
complete_entry_t *c;
complete_entry_opt_t *opt;
CHECK( cmd, );
complete_init();
c = complete_find_exact_entry( cmd, cmd_type );
if( c == 0 )
{
if( !(c = malloc( sizeof(complete_entry) )))
if( !(c = malloc( sizeof(complete_entry_t) )))
{
DIE_MEM();
}
@@ -429,7 +430,7 @@ void complete_add( const wchar_t *cmd,
c->short_opt_str = wcsdup(L"");
}
if( !(opt = malloc( sizeof( complete_entry_opt ) )))
if( !(opt = malloc( sizeof( complete_entry_opt_t ) )))
{
DIE_MEM();
}
@@ -474,7 +475,7 @@ void complete_remove( const wchar_t *cmd,
wchar_t short_opt,
const wchar_t *long_opt )
{
complete_entry *e, *eprev=0, *enext=0;
complete_entry_t *e, *eprev=0, *enext=0;
CHECK( cmd, );
@@ -485,7 +486,7 @@ void complete_remove( const wchar_t *cmd,
if( (cmd_type == e->cmd_type ) &&
( wcscmp( cmd, e->cmd) == 0 ) )
{
complete_entry_opt *o, *oprev=0, *onext=0;
complete_entry_opt_t *o, *oprev=0, *onext=0;
if(( short_opt == 0 ) && (long_opt == 0 ) )
{
@@ -581,14 +582,14 @@ static void parse_cmd_string( void *context,
wchar_t *cmd, *path;
/* Get the path of the command */
path = parser_get_filename( context, str );
path = path_get_path( context, str );
if( path == 0 )
{
/**
Use the empty string as the 'path' for commands that can
not be found.
*/
path = wcsdup(L"");
path = halloc_wcsdup( context, L"");
}
/* Make sure the path is not included in the command */
@@ -610,8 +611,8 @@ int complete_is_valid_option( const wchar_t *str,
const wchar_t *opt,
array_list_t *errors )
{
complete_entry *i;
complete_entry_opt *o;
complete_entry_t *i;
complete_entry_opt_t *o;
wchar_t *cmd, *path;
int found_match = 0;
int authorative = 1;
@@ -815,7 +816,7 @@ int complete_is_valid_option( const wchar_t *str,
str[0] = opt[j];
str[1]=0;
al_push( errors,
wcsdupcat2(_( L"Unknown option: " ), L"'", str, L"'", 0) );
wcsdupcat2(_( L"Unknown option: " ), L"'", str, L"'", (void *)0) );
}
opt_found = 0;
@@ -833,12 +834,12 @@ int complete_is_valid_option( const wchar_t *str,
if( hash_get_count( &gnu_match_hash )==0)
{
al_push( errors,
wcsdupcat2( _(L"Unknown option: "), L"'", opt, L"\'", 0) );
wcsdupcat2( _(L"Unknown option: "), L"'", opt, L"\'", (void *)0) );
}
else
{
al_push( errors,
wcsdupcat2( _(L"Multiple matches for option: "), L"'", opt, L"\'", 0) );
wcsdupcat2( _(L"Multiple matches for option: "), L"'", opt, L"\'", (void *)0) );
}
}
}
@@ -908,24 +909,26 @@ static const wchar_t *complete_get_desc_suffix( const wchar_t *suff_orig )
array_list_t l;
al_init( &l );
exec_subshell( cmd, &l );
free(cmd);
if( al_get_count( &l )>0 )
if( exec_subshell( cmd, &l ) != -1 )
{
wchar_t *ln = (wchar_t *)al_get(&l, 0 );
if( wcscmp( ln, L"unknown" ) != 0 )
if( al_get_count( &l )>0 )
{
desc = wcsdup( ln);
/*
I have decided I prefer to have the description
begin in uppercase and the whole universe will just
have to accept it. Hah!
*/
desc[0]=towupper(desc[0]);
wchar_t *ln = (wchar_t *)al_get(&l, 0 );
if( wcscmp( ln, L"unknown" ) != 0 )
{
desc = wcsdup( ln);
/*
I have decided I prefer to have the description
begin in uppercase and the whole universe will just
have to accept it. Hah!
*/
desc[0]=towupper(desc[0]);
}
}
}
free(cmd);
al_foreach( &l, &free );
al_destroy( &l );
}
@@ -1154,78 +1157,82 @@ static void complete_cmd_desc( const wchar_t *cmd, array_list_t *comp )
systems with a large set of manuals, but it should be ok
since apropos is only called once.
*/
exec_subshell( lookup_cmd, &list );
if( exec_subshell( lookup_cmd, &list ) != -1 )
{
/*
Then discard anything that is not a possible completion and put
the result into a hashtable with the completion as key and the
description as value.
Should be reasonably fast, since no memory allocations are needed.
*/
for( i=0; i<al_get_count( &list); i++ )
{
wchar_t *el = (wchar_t *)al_get( &list, i );
wchar_t *key, *key_end, *val_begin;
key = el+wcslen(cmd);
if( !el )
continue;
key_end = wcschr( el, L'\t' );
if( !key_end )
continue;
*key_end = 0;
val_begin = key_end+1;
/*
And once again I make sure the first character is uppercased
because I like it that way, and I get to decide these
things.
Then discard anything that is not a possible completion and put
the result into a hashtable with the completion as key and the
description as value.
Should be reasonably fast, since no memory allocations are needed.
*/
val_begin[0]=towupper(val_begin[0]);
for( i=0; i<al_get_count( &list); i++ )
{
wchar_t *el = (wchar_t *)al_get( &list, i );
wchar_t *key, *key_end, *val_begin;
hash_put( &lookup, key, val_begin );
}
if( !el )
continue;
/*
Then do a lookup on every completion and if a match is found,
change to the new description.
key = el+wcslen(cmd_start);
key_end = wcschr( el, L'\t' );
This needs to do a reallocation for every description added, but
there shouldn't be that many completions, so it should be ok.
*/
for( i=0; i<al_get_count(comp); i++ )
{
wchar_t *el = (wchar_t *)al_get( comp, i );
wchar_t *cmd_end = wcschr( el,
COMPLETE_SEP );
wchar_t *new_desc;
if( cmd_end )
*cmd_end = 0;
new_desc = (wchar_t *)hash_get( &lookup,
el );
if( new_desc )
{
wchar_t *new_el = wcsdupcat2( el,
COMPLETE_SEP_STR,
new_desc,
0 );
al_set( comp, i, new_el );
free( el );
if( !key_end )
continue;
*key_end = 0;
val_begin = key_end+1;
/*
And once again I make sure the first character is uppercased
because I like it that way, and I get to decide these
things.
*/
val_begin[0]=towupper(val_begin[0]);
hash_put( &lookup, key, val_begin );
}
else
/*
Then do a lookup on every completion and if a match is found,
change to the new description.
This needs to do a reallocation for every description added, but
there shouldn't be that many completions, so it should be ok.
*/
for( i=0; i<al_get_count(comp); i++ )
{
wchar_t *el = (wchar_t *)al_get( comp, i );
wchar_t *cmd_end = wcschr( el,
COMPLETE_SEP );
wchar_t *new_desc;
if( cmd_end )
*cmd_end = COMPLETE_SEP;
*cmd_end = 0;
new_desc = (wchar_t *)hash_get( &lookup,
el );
if( new_desc )
{
wchar_t *new_el = wcsdupcat2( el,
COMPLETE_SEP_STR,
new_desc,
(void *)0 );
al_set( comp, i, new_el );
free( el );
}
else
{
if( cmd_end )
*cmd_end = COMPLETE_SEP;
}
}
}
hash_destroy( &lookup );
al_foreach( &list,
&free );
@@ -1270,9 +1277,11 @@ static void complete_cmd( const wchar_t *cmd,
wchar_t *cdpath = env_get(L"CDPATH");
wchar_t *cdpath_cpy = wcsdup( cdpath?cdpath:L"." );
int prev_count = al_get_count( comp );
if( (wcschr( cmd, L'/') != 0) || (cmd[0] == L'~' ) )
{
array_list_t tmp;
al_init( &tmp );
@@ -1281,47 +1290,57 @@ static void complete_cmd( const wchar_t *cmd,
comp,
ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ) != EXPAND_ERROR )
{
complete_cmd_desc( cmd, comp );
if( al_get_count( comp ) > prev_count )
{
complete_cmd_desc( cmd, comp );
}
}
al_destroy( &tmp );
}
else
{
path = env_get(L"PATH");
path_cpy = wcsdup( path );
for( nxt_path = wcstok( path_cpy, ARRAY_SEP_STR, &state );
nxt_path != 0;
nxt_path = wcstok( 0, ARRAY_SEP_STR, &state) )
if( path )
{
nxt_completion = wcsdupcat2( nxt_path,
(nxt_path[wcslen(nxt_path)-1]==L'/'?L"":L"/"),
cmd,
0 );
if( ! nxt_completion )
continue;
al_init( &tmp );
if( expand_string( 0,
nxt_completion,
&tmp,
ACCEPT_INCOMPLETE |
EXECUTABLES_ONLY ) != EXPAND_ERROR )
path_cpy = wcsdup( path );
for( nxt_path = wcstok( path_cpy, ARRAY_SEP_STR, &state );
nxt_path != 0;
nxt_path = wcstok( 0, ARRAY_SEP_STR, &state) )
{
for( i=0; i<al_get_count(&tmp); i++ )
nxt_completion = wcsdupcat2( nxt_path,
(nxt_path[wcslen(nxt_path)-1]==L'/'?L"":L"/"),
cmd,
(void *)0 );
if( ! nxt_completion )
continue;
al_init( &tmp );
if( expand_string( 0,
nxt_completion,
&tmp,
ACCEPT_INCOMPLETE |
EXECUTABLES_ONLY ) != EXPAND_ERROR )
{
al_push( comp, al_get( &tmp, i ) );
for( i=0; i<al_get_count(&tmp); i++ )
{
al_push( comp, al_get( &tmp, i ) );
}
}
al_destroy( &tmp );
}
free( path_cpy );
if( al_get_count( comp ) > prev_count )
{
complete_cmd_desc( cmd, comp );
}
al_destroy( &tmp );
}
free( path_cpy );
complete_cmd_desc( cmd, comp );
/*
These return the original strings - don't free them
*/
@@ -1335,7 +1354,6 @@ static void complete_cmd( const wchar_t *cmd,
copy_strings_with_prefix( comp, cmd, COMPLETE_BUILTIN_DESC, &builtin_get_desc, &possible_comp );
al_destroy( &possible_comp );
}
/*
@@ -1354,7 +1372,7 @@ static void complete_cmd( const wchar_t *cmd,
wcsdupcat2( nxt_path,
(nxt_path[wcslen(nxt_path)-1]==L'/'?L"":L"/"),
cmd,
0 );
(void *)0 );
if( ! nxt_completion )
{
continue;
@@ -1435,29 +1453,29 @@ static void complete_from_args( const wchar_t *str,
strings should be escaped!
*/
/*
for( i=0; i< al_get_count( &possible_comp ); i++ )
{
wchar_t *next = (wchar_t *)al_get( &possible_comp, i );
wchar_t *next_unescaped;
if( next )
{
next_unescaped = unescape( next, 0 );
if( next_unescaped )
{
al_set( &possible_comp , i, next_unescaped );
}
else
{
al_set( &possible_comp , i, 0 );
debug( 2, L"Could not expand string %ls on line %d of file %s", next, __LINE__, __FILE__ );
}
free( next );
}
else
{
debug( 2, L"Got null string on line %d of file %s", __LINE__, __FILE__ );
}
}
for( i=0; i< al_get_count( &possible_comp ); i++ )
{
wchar_t *next = (wchar_t *)al_get( &possible_comp, i );
wchar_t *next_unescaped;
if( next )
{
next_unescaped = unescape( next, 0 );
if( next_unescaped )
{
al_set( &possible_comp , i, next_unescaped );
}
else
{
al_set( &possible_comp , i, 0 );
debug( 2, L"Could not expand string %ls on line %d of file %s", next, __LINE__, __FILE__ );
}
free( next );
}
else
{
debug( 2, L"Got null string on line %d of file %s", __LINE__, __FILE__ );
}
}
*/
copy_strings_with_prefix( comp_out, str, desc, 0, &possible_comp );
@@ -1469,7 +1487,7 @@ static void complete_from_args( const wchar_t *str,
/**
Match against an old style long option
*/
static int param_match_old( complete_entry_opt *e,
static int param_match_old( complete_entry_opt_t *e,
wchar_t *optstr )
{
return (optstr[0] == L'-') && (wcscmp( e->long_opt, &optstr[1] ) == 0);
@@ -1478,7 +1496,7 @@ static int param_match_old( complete_entry_opt *e,
/**
Match a parameter
*/
static int param_match( complete_entry_opt *e,
static int param_match( complete_entry_opt_t *e,
wchar_t *optstr )
{
if( e->short_opt != L'\0' &&
@@ -1499,7 +1517,7 @@ static int param_match( complete_entry_opt *e,
/**
Test if a string is an option with an argument, like --color=auto or -I/usr/include
*/
static wchar_t *param_match2( complete_entry_opt *e,
static wchar_t *param_match2( complete_entry_opt_t *e,
wchar_t *optstr )
{
if( e->short_opt != L'\0' && e->short_opt == optstr[1] )
@@ -1571,6 +1589,7 @@ static void complete_load_handler( const wchar_t *cmd )
void complete_load( const wchar_t *name, int reload )
{
CHECK( name, );
parse_util_load( name,
L"fish_complete_path",
&complete_load_handler,
@@ -1587,8 +1606,8 @@ static int complete_param( wchar_t *cmd_orig,
wchar_t *str,
array_list_t *comp_out )
{
complete_entry *i;
complete_entry_opt *o;
complete_entry_t *i;
complete_entry_opt_t *o;
array_list_t matches;
wchar_t *cmd, *path;
@@ -1775,7 +1794,7 @@ static void complete_param_expand( wchar_t *str,
int do_file )
{
wchar_t *comp_str;
if( (wcsncmp( str, L"--", 2 )) == 0 && (comp_str = wcschr(str, L'=' ) ) )
{
comp_str++;
@@ -1784,16 +1803,16 @@ static void complete_param_expand( wchar_t *str,
{
comp_str = str;
}
/*
debug( 3,
L"expand_string( \"%ls\", comp_out, EXPAND_SKIP_CMDSUBST | ACCEPT_INCOMPLETE | %ls );",
comp_str,
do_file?L"0":L"EXPAND_SKIP_WILDCARDS" );
*/
expand_string( 0,
wcsdup(comp_str),
comp_out,
EXPAND_SKIP_CMDSUBST | ACCEPT_INCOMPLETE | (do_file?0:EXPAND_SKIP_WILDCARDS) );
if( expand_string( 0,
wcsdup(comp_str),
comp_out,
EXPAND_SKIP_CMDSUBST | ACCEPT_INCOMPLETE | (do_file?0:EXPAND_SKIP_WILDCARDS) ) == EXPAND_ERROR )
{
debug( 3, L"Error while expanding string '%ls'", comp_str );
}
}
/**
@@ -1820,20 +1839,27 @@ static int complete_variable( const wchar_t *var,
if( wcsncmp( var, name, varlen) == 0 )
{
wchar_t *value = expand_escape_variable( env_get( name ));
wchar_t *blarg;
/*
Variable description is 'Variable: VALUE
*/
blarg = wcsdupcat2( &name[varlen], COMPLETE_SEP_STR, COMPLETE_VAR_DESC_VAL, value, 0 );
wchar_t *value_unescaped, *value;
if( blarg )
value_unescaped = env_get( name );
if( value_unescaped )
{
res =1;
al_push( comp, blarg );
}
free( value );
wchar_t *desc;
value = expand_escape_variable( value_unescaped );
/*
Variable description is 'Variable: VALUE
*/
desc = wcsdupcat2( &name[varlen], COMPLETE_SEP_STR, COMPLETE_VAR_DESC_VAL, value, (void *)0 );
if( desc )
{
res =1;
al_push( comp, desc );
}
free( value );
}
}
}
@@ -1953,7 +1979,7 @@ static int try_complete_user( const wchar_t *cmd,
L"/",
COMPLETE_SEP_STR,
COMPLETE_USER_DESC,
0 );
(void *)0 );
if( blarg != 0 )
{
al_push( comp, blarg );
@@ -2130,6 +2156,14 @@ void complete( const wchar_t *cmd,
int do_file;
do_file = complete_param( current_command, prev_token, current_token, comp );
/*
If we have found no command specific completions at
all, fall back to using file completions.
*/
if( !al_get_count( comp ) )
do_file = 1;
complete_param_expand( current_token, comp, do_file );
}
}
@@ -2165,11 +2199,13 @@ static void append_switch( string_buffer_t *out,
void complete_print( string_buffer_t *out )
{
complete_entry *e;
complete_entry_t *e;
CHECK( out, );
for( e = first_entry; e; e=e->next )
{
complete_entry_opt *o;
complete_entry_opt_t *o;
for( o= e->first_option; o; o=o->next )
{
wchar_t *modestr[] =

View File

@@ -1,7 +1,25 @@
# Process this file with autoconf to produce a configure script.
AC_INIT(fish,1.21.11,fish-users@lists.sf.net)
#
# This file is the main build configuration file for fish. It is used
# to determine your systems capabilities, and tries to adapt fish to
# take maximum advantage of the services your system offers.
#
# Process this file using the 'autoconf' command to produce a working
# configure script, which should in turn be executed in order to
# configure the build process.
#
AC_INIT(fish,1.22.0,fish-users@lists.sf.net)
#
# If needed, run autoconf to regenerate the configure file
#
# This makes sure that after running autoconf once to create the first
# version of configure, we never again need to worry about manually
# running autoconf to handle an updates configure.ac.
#
AC_MSG_CHECKING([if autoconf needs to be run])
if test configure -ot configure.ac; then
AC_MSG_RESULT([yes])
@@ -11,38 +29,55 @@ if test configure -ot configure.ac; then
AC_MSG_NOTICE([running autoconf])
if autoconf; then
./configure "$@"
exit
fi
exit
exit 1
else
AC_MSG_ERROR( [cannot find the autoconf program in your path.
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 it and try again.]
)
fi
else
AC_MSG_RESULT([no])
fi
#
# If needed, run autoheader to regenerate config.h.in
#
# This makes sure we never ever have to run autoheader manually. It
# will be run whenever needed automatically.
#
AC_MSG_CHECKING([if autoheader needs to be run])
if test ! -f ./config.h.in -o config.h.in -ot configure.ac; then
AC_MSG_RESULT([yes])
if which autoheader >/dev/null; then
AC_MSG_NOTICE([running autoheader])
autoheader
autoheader || exit 1
else
AC_MSG_ERROR( [cannot find the autoheader program in your path.
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 it and try again.]
)
fi
else
AC_MSG_RESULT([no])
fi
#
# Detect directories which may contain additional headers, libraries
# and commands. This needs to be done early - before Autoconf starts
# to mess with CFLAGS and all the other environemnt variables.
#
# This mostly helps OS X users, since fink usually installs out of
# tree and doesn't update CFLAGS.
#
for i in /usr/pkg /sw /opt /opt/local; do
AC_MSG_CHECKING([for $i/include include directory])
@@ -74,24 +109,57 @@ done
AC_SUBST( optbindirs, $optbindirs )
#
# Tell autoconf to create config.h header
#
AC_CONFIG_HEADERS(config.h)
#
# This adds markup to the code that results in a few extra compile
# time checks on recent GCC versions. It helps stop a few common bugs.
#
AH_BOTTOM([#if __GNUC__ >= 3
#define __warn_unused __attribute__ ((warn_unused_result))
#define __sentinel __attribute__ ((sentinel))
#else
#define __warn_unused
#define __sentinel
#endif])
#
# Set up various programs needed for install
#
AC_PROG_CC
AC_PROG_CPP
AC_PROG_INSTALL
#
# Check for seq command. If missing, make sure fallback shellscript
# implementation is installed
# implementation is installed.
#
AC_CHECK_PROG( SEQ_FALLBACK, seq, [ ], [seq])
#
# Optionally drop xsel command
AC_ARG_WITH( xsel,
AC_HELP_STRING([--without-xsel],
[do not build the xsel program needed for X clipboard integration]),
[xsel=$withval],
[xsel=with_xsel] )
#
AC_ARG_WITH(
xsel,
AC_HELP_STRING(
[--without-xsel],
[do not build the xsel program needed for X clipboard integration]
),
[xsel=$withval],
[xsel=with_xsel]
)
if [[ "$xsel" = "with_xsel" ]]; then
AC_SUBST( XSEL,[xsel-0.9.6/xsel])
@@ -103,38 +171,46 @@ else
AC_SUBST( XSEL_MAN_PATH,[ ])
fi
# These help out with getting better prototypes on some platforms
#
# Test if the compiler accepts the -std=c99 flag. If so, using it
# increases the odds of correct compilation, since we want to use the
# *wprintf functions, which where defined in C99. 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. Finally,
# 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().
# *wprintf functions, which where defined in C99.
#
XCFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -std=c99 -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200112L"
AC_MSG_CHECKING(if -std=c99 -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200112L works)
AC_CACHE_VAL(local_cv_has__std_c99,[
AC_TRY_RUN([
#include <stdlib.h>
#include <stdio.h>
CFLAGS="$CFLAGS -std=c99"
XCPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS -std=c99"
AC_MSG_CHECKING(if -std=c99 works)
AC_CACHE_VAL(
local_cv_has__std_c99,
[
AC_TRY_RUN(
[
#include <stdlib.h>
#include <stdio.h>
int main()
{
return 0;
}
],
local_cv_has__std_c99=yes,
local_cv_has__std_c99=no,
)
]
)
int main() {
return 0;
}],
local_cv_has__std_c99=yes,
local_cv_has__std_c99=no,
)])
AC_MSG_RESULT($local_cv_has__std_c99)
case x$local_cv_has__std_c99 in
xno) CFLAGS="$XCFLAGS" ;;
xno)
CFLAGS="$XCFLAGS"
CPPFLAGS="$XCPPFLAGS" ;;
esac
#
# If we are using gcc, set some flags that increase the odds of the
# compiler producing a working binary...
@@ -144,7 +220,7 @@ if test "$CC" = gcc; then
#
# -fno-optimize-sibling-calls seems to work around a bug where
# sending a SIGWINCH to fish on NetBSD causes fish to exit when
# sending a SIGWINCH to fish on NetBSD 3.0 causes fish to exit when
# compiled with GCC 3.3.3. This is probably either a compiler bug
# or a libc bug, but adding this flag seems to fix things for
# now. Long term, the real problem should be tracked down and
@@ -163,6 +239,7 @@ if test "$CC" = gcc; then
fi
#
# If we are compiling against glibc, set some flags to work around
# some rather stupid attempts to hide prototypes for *wprintf
@@ -171,16 +248,24 @@ fi
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;])],
[
AC_LANG_PROGRAM(
[
#include <stdlib.h>
#ifdef __GLIBC__
#define STATUS 0
#else
#define STATUS 1
#endif
],
[
return STATUS;
]
)
],
[glibc=yes],
[glibc=no] )
[glibc=no]
)
if test "$glibc" = yes; then
AC_MSG_RESULT(yes)
@@ -192,12 +277,13 @@ if test "$glibc" = yes; then
# fallback.h, in order to keep fish working on non-gnu platforms.
#
AC_DEFINE( _GNU_SOURCE, 1, [Macro to enable additional prototypes under Glibc])
AC_DEFINE( _ISOC99_SOURCE, 1, [Macro to enable additional prototypes under Glibc])
CFLAGS="$CFLAGS -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
@@ -207,13 +293,18 @@ fi
# 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*)
@@ -226,7 +317,10 @@ case $target_os in
esac
#
# BSD-specific flags go here
#
AC_MSG_CHECKING([if we are under BSD])
case $target_os in
*bsd*)
@@ -240,10 +334,13 @@ case $target_os in
esac
#
# Set up PREFIX and related preprocessor symbols. Fish needs to know
# where it will be installed. One of the reasons for this is so that
# it can make sure the fish installation directory is in the path
# during startup.
#
if [[ "$prefix" = NONE ]]; then
export prefix=/usr/local
AC_SUBST( prefix, /usr/local)
@@ -252,129 +349,386 @@ else
fi
#
# Set up the directory where the documentation files should be
# installed
#
AC_ARG_VAR( [docdir], [Documentation direcotry] )
if test -z $docdir; then
AC_SUBST(docdir, [$datadir/doc/fish] )
AC_SUBST(docdir, [$datadir/doc/fish] )
else
AC_SUBST(docdir, [$docdir])
AC_SUBST(docdir, [$docdir])
fi
#
# Set up locale directory. This is where the .po files will be
# installed.
#
AC_SUBST( [localedir], [$datadir/locale])
#
# See if Linux procfs is present. This is used to get extra
# information about running processes.
#
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.])
AC_DEFINE(
[HAVE_TRANSLATE_H],
[1],
[Define to 1 if the wgettext function should be used for translating strings.]
)
#
# Check presense of various libraries
#
# Check for presense of various libraries
AC_SEARCH_LIBS( gettext, intl,,)
AC_SEARCH_LIBS( connect, socket, , [AC_MSG_ERROR([Cannot find the socket library, needed to build this package.] )] )
AC_SEARCH_LIBS( nanosleep, rt, , [AC_MSG_ERROR([Cannot find the rt library, needed to build this package.] )] )
AC_SEARCH_LIBS( setupterm, [ncurses curses], , [AC_MSG_ERROR([Could not find a curses implementation, needed to build fish])] )
# Check for presense of various header files
#
# Check presense of various header files
#
AC_CHECK_HEADERS([getopt.h termio.h sys/resource.h term.h ncurses/term.h libintl.h ncurses.h curses.h stropts.h siginfo.h sys/select.h sys/ioctl.h sys/termios.h])
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])])
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.
#
XCFLAGS="$CFLAGS"
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)
CFLAGS="$XCFLAGS $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_TERMIOS_H
/* Neither POSIX, C89 nor C99: a common extension.
* For: TIOCGWINSZ and struct winsize (under at least
* Solaris, NetBSD and (dual-listed) FreeBSD). */
#include <sys/termios.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
/* As above (under at least Linux and FreeBSD). */
#include <sys/ioctl.h>
#endif
],
[
/* Avert high-level optimisation, by making the program's
* return value depend on all tested identifiers. */
int ret = 0;
/* POSIX only: might be unhidden by _POSIX_C_SOURCE. */
struct sigaction sa;
sigset_t ss;
siginfo_t info;
ret += (int)(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 += (int)(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
CFLAGS="$XCFLAGS"
fi
#
# Check for presense of various functions used by fish
#
# Check for presense of various functions
AC_CHECK_FUNCS( gettext wcsdup wcsndup wcslen wcscasecmp wcsncasecmp fwprintf )
AC_CHECK_FUNCS( futimes wcwidth wcswidth getopt_long wcstok fputwc fgetwc )
AC_CHECK_FUNCS( futimes wcwidth wcswidth wcstok fputwc fgetwc )
AC_CHECK_FUNCS( wcstol dcgettext wcslcat wcslcpy lrand48_r killpg)
# The Makefile also needs to know if we have gettext, so it knows if the translations should be installed.
#
# The Makefile also needs to know if we have gettext, so it knows if
# the translations should be installed.
#
AC_CHECK_FUNC( gettext, AC_SUBST( HAVE_GETTEXT, 1 ), AC_SUBST( HAVE_GETTEXT, 0 ) )
#
# Here follows a list of small programs used to test for various
# 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 );])],
[
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] )
[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.])
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 exists
#
# Check if struct winsize and TIOCGWINSZ exist
#
AC_MSG_CHECKING([if struct winsize and TIOCGWINSZ exist])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([
#ifdef HAVE_SYS_TERMIOS_H
#include <sys/termios.h>
#endif
[
AC_LANG_PROGRAM(
[
#ifdef HAVE_SYS_TERMIOS_H
#include <sys/termios.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
],
[
struct winsize termsize = {0};
TIOCGWINSZ;
]
)
],
[
AC_MSG_RESULT(yes);
AC_DEFINE([HAVE_WINSIZE], [1], [Define to 1 if the winsize struct and TIOCGWINSZ macro exist])
],
[
AC_MSG_RESULT(no)
]
)
],
[struct winsize termsize = {0}; TIOCGWINSZ;])],
[AC_MSG_RESULT(yes); AC_DEFINE([HAVE_WINSIZE], [1], [Define to 1 if the winsize struct and TIOCGWINSZ macro exist])],
AC_MSG_RESULT(no))
#
# 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_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([#if HAVE_LIBINTL_H]
[#include <libintl.h>]
[#endif],
[extern int _nl_msg_cat_cntr;]
[int tmp = _nl_msg_cat_cntr; exit(tmp);], have__nl_msg_cat_cntr=yes, have__nl_msg_cat_cntr=no)
AC_TRY_LINK(
[
#if HAVE_LIBINTL_H
#include <libintl.h>
#endif
],
[
extern int _nl_msg_cat_cntr;
int tmp = _nl_msg_cat_cntr;
exit(tmp);
],
have__nl_msg_cat_cntr=yes,
have__nl_msg_cat_cntr=no
)
if test "$have__nl_msg_cat_cntr" = yes; then
AC_MSG_RESULT(yes)
AC_DEFINE([HAVE__NL_MSG_CAT_CNTR], [1],
[Define to 1 if the _nl_msg_cat_cntr symbol is exported.])
AC_DEFINE(
[HAVE__NL_MSG_CAT_CNTR],
[1],
[Define to 1 if the _nl_msg_cat_cntr symbol is exported.]
)
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
@@ -386,7 +740,11 @@ AC_MSG_CHECKING([If del_curterm is broken])
case $target_os in
*bsd*)
AC_MSG_RESULT(yes)
AC_DEFINE([HAVE_BROKEN_DEL_CURTERM],[1],[del_curterm si broken, redefine it to a no-op to avoid a double-free bug])
AC_DEFINE(
[HAVE_BROKEN_DEL_CURTERM],
[1],
[del_curterm is broken, redefine it to a no-op to avoid a double-free bug]
)
;;
*)
AC_MSG_RESULT(no)
@@ -394,8 +752,14 @@ case $target_os in
esac
# Tell the world what we know
AC_CONFIG_FILES([Makefile fish.spec doc_src/fish.1 doc_src/Doxyfile seq])
AC_CONFIG_FILES([Makefile fish.spec doc_src/Doxyfile seq])
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."

View File

@@ -1,5 +1,4 @@
\section and and - Conditionally execute a command
\section and and - conditionally execute a command
\subsection and-synopsis Synopsis
<tt>COMMAND1; and COMMAND2</tt>
@@ -7,7 +6,7 @@
\subsection and-description Description
The \c and builtin is used to execute a command if the current exit
status (as set by the last previous command) is zero
status (as set by the last previous command) is 0.
The and command does not change the current exit status.

View File

@@ -1,8 +1,7 @@
\section begin begin - Start a new block of code
\section begin begin - start a new block of code
\subsection begin-synopsis Synopsis
<tt>begin; [COMMAND;...] end </tt>
<tt>begin; [COMMANDS...;] end</tt>
\subsection begin-description Description

View File

@@ -1,14 +1,21 @@
\section bind bind - Handle key bindings.
\section bind bind - handle key bindings
\subsection bind-synopsis Synopsis
<tt>bind [OPTIONS] [BINDINGS...] </tt>
<tt>bind [OPTIONS] [BINDINGS...]</tt>
The <tt>bind</tt> builtin causes fish to add the readline style bindings specified by <tt>BINDINGS</tt> to the list of key bindings. For more information on specifying keyboard bindings, use <tt>man readline</tt> to access the readline documentation.
The <tt>bind</tt> builtin causes fish to add the readline style bindings specified by BINDINGS to the list of key bindings, as if they appeared in your <tt>~/.fish_inputrc</tt> file.
For more information on the syntax keyboard bindings, use <tt>man
readline</tt> to access the readline documentation. The availiable commands
are listed in the <a href="index.html#editor">Command Line Editor</a> section
of the fish manual - but you may also use any fish command! To write such
commands, see the <a href="#commandline">commandline</a> builtin. It's good
practice to put the code into a <tt><a href="#function">function</a> -b</tt>
and bind to the function name.
\subsection bind-description Description
- <tt>-M MODE</tt> or <tt>--set-mode=MODE</tt> sets the current input mode to MODE.
\subsection bind-example Example
<tt>bind -M vi</tt> changes to the vi input mode

View File

@@ -1,5 +1,4 @@
\section block block - Temporarily block delivery of events
\section block block - temporarily block delivery of events
\subsection block-synopsis Synopsis
<tt>block [OPTIONS...]</tt>
@@ -12,7 +11,8 @@
\subsection block-example Example
<pre>block -g
<pre>
block -g
\#Do something that should not be interrupted
block -e
</pre>

View File

@@ -1,4 +1,3 @@
\section break break - stop the innermost currently evaluated loop
\subsection break-synopsis Synopsis
@@ -9,13 +8,12 @@ The \c break builtin is used to halt a currently running loop, such as a <a href
\subsection break-example Example
The following code searches all .c files for smurfs, and halts at the first occurrence.
<p>
<tt>for i in *.c;
<br>&nbsp;&nbsp;&nbsp;&nbsp;if grep smurf $i;
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo Smurfs are present in $i;
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
<br>&nbsp;&nbsp;&nbsp;&nbsp;end;
<br>end;
</tt>
</p>
<pre>
for i in *.c
if grep smurf $i
echo Smurfs are present in $i
break
end
end
</pre>

View File

@@ -1,4 +1,3 @@
\section builtin builtin - run a builtin command
\subsection builtin-synopsis Synopsis

View File

@@ -1,7 +1,7 @@
\section case case - conditionally execute a block of commands
\subsection case-synopsis Synopsis
<tt>switch VALUE; [case [WILDCARD...]; [COMMANDS...];...] end</tt>
<tt>switch VALUE; [case [WILDCARD...]; [COMMANDS...]; ...] end</tt>
\subsection case-description Description
@@ -32,7 +32,6 @@ forms of parameter expansion have been performed for the case command.
If the variable \$animal contains the name of an animal, the following
code would attempt to classify it:
<p>
<pre>
switch $animal
case cat
@@ -47,7 +46,7 @@ switch $animal
echo I have no idea what a $animal is
end
</pre>
</p>
<p>
If the above code was run with \c \$animal set to \c whale, the output would be \c mammal.
</p>
If the above code was run with \c \$animal set to \c whale, the output
would be \c mammal.

View File

@@ -1,4 +1,4 @@
\section commandline commandline - Set or get the current commandline buffer
\section commandline commandline - set or get the current commandline buffer
\subsection commandline-synopsis Synopsis
<tt>commandline [OPTIONS] [CMD]</tt>
@@ -9,8 +9,22 @@
- \c CMD is the new value of the commandline. If unspecified, the
current value of the commandline is written to standard output.
The following switches change what the commandline builtin does
- \c -C or \c --cursor set or get the current cursor position, not
the contents of the buffer. If no argument is given, the current
cursor position is printed, otherwise the argument is interpreted
as the new cursor position.
- \c -f or \c --function inject readline functions into the
reader. This option can not be combined with any other option. It
will cause any additional arguments to be interpreted as readline
functions, and these functions will be injected into the reader, so
that they will be returned to the reader before any additional
actual keypresses are read.
The following switches change the way \c commandline updates the
commandline
commandline buffer
- \c -a or \c --append do not remove the current commandline, append
the specified string at the end of it
@@ -28,20 +42,12 @@ or updated
- \c -t or \c --current_token select the current token.
The following switch changes the way \c commandline prints the current
commandline
commandline buffer
- \c -c or \c --cut-at-cursor only print selection up until the
current cursor position
- \c -o or \c --tokenize tokenize the selection and print one string-type token per line
Other switches
- \c -f or \c --function inject readline functions into the
reader. This option can not be combined with any other option. It
will cause any additional arguments to be interpreted as readline
functions, and these functions will be injected into the reader, so
that they will be returned to the reader before any additional
actual keypresses are read.
If commandline is called during a call to complete a given string
using <code>complete -C STRING</code>, commandline will consider the

View File

@@ -1,5 +1,4 @@
\section contains contains - Test if a word is present in a list
\section contains contains - test if a word is present in a list
\subsection contains-synopsis Synopsis
<code>contains [OPTIONS] KEY [VALUES...]</code>

View File

@@ -1,20 +1,19 @@
\section continue continue - skip the rest of the current lap of the innermost currently evaluated loop
\subsection continue-synopsis Synopsis
<tt>LOOP_CONSTRUCT; [COMMANDS...] continue; [COMMANDS...] end</tt>
<tt>LOOP_CONSTRUCT; [COMMANDS...;] continue; [COMMANDS...;] end</tt>
\subsection continue-description Description
The \c continue builtin is used to skip the current lap of the innermost currently running loop, such as a <a href="#for">for</a> loop or a <a href="#while">while</a> loop. It is usually added inside of a conditional block such as an <a href="#if">if</a> statement or a <a href="#switch">switch</a> statement.
\subsection continue-example Example
The following code removes all tmp files without smurfs.
<p>
<tt>for i in *.tmp;
<br>&nbsp;&nbsp;&nbsp;&nbsp;if grep smurf $i;
<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;
<br>&nbsp;&nbsp;&nbsp;&nbsp;end;
<br>&nbsp;&nbsp;&nbsp;&nbsp;rm $i;
<br>end;
</tt>
</p>
<pre>
for i in *.tmp
if grep smurf $i
continue
end
rm $i
end
</pre>

View File

@@ -1,5 +1,4 @@
\section count count - Count the number of elements of an array
\section count count - count the number of elements of an array
\subsection count-synopsis Synopsis
<tt>count $VARIABLE</tt>

155
doc_src/design.hdr Normal file
View File

@@ -0,0 +1,155 @@
/** \page design Design document
\section design-overview Overview
This is a description of the design principles that have been used to
design fish. The fish design has three high level goals. These are:
-# Everything that can be done in other shell languages should be
possible to do in fish, though fish may rely on external commands in
doing so.
-# Fish should be user friendly, but not at the expense of expressiveness.
Most tradeoffs between power and ease of use can be avoided with careful design.
-# Whenever possible without breaking the above goals, fish should
follow the Posix syntax.
To achive these high-level goals, the fish design relies on a number
of more specific design principles. These are presented below,
together with a rationale and a few examples for each.
\section ortho The law of orthogonality
The shell language should have a small set of orthogonal features. Any
situation where two features are related but not identical, one of them
should be removed, and the other should be made powerful and general
enough to handle all common use cases of either feature.
Rationale:
Related features make the language larger, which makes it harder to
learn. It also increases the size of the sourcecode, making the
program harder to maintain and update.
Examples:
- Here documents are too similar to using echo inside of a pipeline.
- Subshells, command substitution and process substitution are strongly related. \c fish only supports command substitution, the others can be achived either using a block or the psub shellscript function.
- Having both aliases and functions is confusing, especially since both of them have limitations and problems. \c fish functions have none of the drawbacks of either syntax.
- The many Posix quoting styles are silly, especially \$''.
\section sep The law of minimalism
The shell should only contain features that cannot be implemented in
a reasonable way outside of the shell. A large performance decrease,
as well as some program complexity increase is acceptable in order to
improve separation.
Rationale:
A modular project is easier to maintain since smaller programs are far
easier to understand than larger ones. A modular project is also more
future proof since the modules can be individually
replaced. Modularity also decreases the severity of bugs, since there
is good hope that a bug, even a serious one, in one module, does not
take the whole system down.
Examples:
- Builtin commands should only be created when it cannot be
avoided. \c echo, \c kill, \c printf and \c time are among the commands
that fish does not implement internally since they can be provided as
external commands. Several other commands that are commonly implemented
as builtins and can not be implemented as external commands,
including \c type, \c vared, \c pushd and \c popd are implemented as shellscript
functions in fish.
- Mathematical calculations, regex matching, generating lists of numbers
and many other funtions can easily be done in external programs. They
should not be supported internally by the shell.
The law of minimalism does not imply that a large feature set is
bad. So long as a feature is not part of the shell itself, but a
separate command or at least a shellscript function, bloat is fine.
\section conf Configurability is the root of all evil
Every configuration option in a program is a place where the program
is too stupid to figure out for itself what the user really wants, and
should be considered a failiure of both the program and the programmer
who implemented it.
Rationale:
Different configuration options are a nightmare to maintain, since the
number of potential bugs caused by specific configuration combinations
quickly becomes an issue. Configuration options often imply
assumptions about the code which change when reimplementing the code,
causing issues with backwards compatibility. But mostly, configuration
options should be avoided since they simply should not exist, as the
program should be smart enough to do what is best, or at least a good
enough approximation of it.
Examples:
- Fish allows the user to set various syntax highlighting colors. This is needed because fish does not know what colors the terminal uses by default, which might make some things unreadable. The proper solution would be for text color preferences to be defined centrally by the user for all programs, and for the terminal emulator to send these color properties to fish.
- Fish does not allow you to set the history filename, the number of history entries, different language substyles or any number of other common shell configuration options.
A special note on the evils of configurability is the long list of
very useful features found in some shells, that are not turned on by
default. Both zsh and bash support command specific completions, but
no such completions are shipped with bash by default, and they are
turned of by default in zsh. Other features that zsh support that are
disabled by default include tab-completion of strings containing
wildcards, a sane completion pager and a history file.
\section user The law of user focus
When designing a program, one should first think about how to make a
intuitive and powerful program. Implementation issues should only be
considered once a user interface has been designed.
Rationale:
This design rule is different than the others, since it describes how
one should go about designing new features, not what the features
should be. The problem with focusing on what can be done, and what is
easy to do, is that to much of the implementation is exposed. This
means that the user must know a great deal about the underlying system
to be able to guess how the shell works, it also means that the
language will often be rather low-level.
Examples:
- There should only be one type of input to the shell, lists of commands. Loops, conditionals and variable assignments are all performed through regular commands.
- The differences between builtin commands, shellscript functions and builtin commands should be made as small as possible. Builtins and shellscript functions should have exactly the same types of argument expansion as other commands, should be possible to use in any position in a pipeline, and should support any io redirection.
- Instead of forking when performing command substitution to provide a fake variable scope, all fish commands are performed from the same process, and fish instead supports true scoping
- All blocks end with the \c end builtin
\section disc The law of discoverability
A program should be designed to make its features as
easy as possible to discover for the user.
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 commandline programs is
through manual pages. This requires both that the user starts to use a
different program, and the she/he then remembers the new information
until the next time she/he uses the same program.
Examples:
- Everything should be tab-completable, and every tab completion should have a description
- Every syntax error and error in a builtin command should contain an error message describing what went wrong and a relevant help page. Whenever possible, errors should be flagged red by the syntax highlighter.
- 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, he will know the whole language, and be able to use tab-completion to discover new featues.
*/

View File

@@ -1,4 +1,4 @@
\section dirh dirh
\section dirh dirh - print directory history
\subsection dirh-synopsis Synopsis
<tt>dirh</tt>

View File

@@ -1,4 +1,4 @@
\section dirs dirs
\section dirs dirs - print directory stack
\subsection dirs-synopsis Synopsis
<tt>dirs</tt>

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,13 @@
\section else else - execute command if a condition is not met.
\section else else - execute command if a condition is not met
\subsection else-synopsis Synopsis
<tt>if CONDITION; COMMAND_TRUE [else; COMMAND_FALSE] end;</tt>
<tt>if CONDITION; COMMANDS_TRUE...; [else; COMMANDS_FALSE...;] end</tt>
\subsection else-description Description
<tt>if</tt> will execute the command CONDITION. If the commands exit
status is zero, the command COMMAND_TRUE will execute. If it is
not zero and COMMAND_FALSE is specified, COMMAND_FALSE will be
executed.
<tt>if</tt> will execute the command CONDITION. If the condition's exit
status is 0, the commands COMMANDS_TRUE will execute. If it is not 0 and
<tt>else</tt> is given, COMMANDS_FALSE will be executed. Hint: use
<a href="#begin"><tt>begin; ...; end</tt></a> for complex conditions.
\subsection else-example Example

View File

@@ -1,11 +1,12 @@
\section end end - end a block of commands.
\subsection end-synopsis Synopsis
<pre>for VARNAME in [VALUES...]; COMMANDS; end
if CONDITION; COMMAND_TRUE [else; COMMAND_FALSE] end
while CONDITION; COMMANDS; end
switch VALUE; [case [WILDCARD...]; [COMMANDS...];...] end
<pre>
begin; [COMMANDS...] end
if CONDITION; COMMANDS_TRUE...; [else; COMMANDS_FALSE...;] end
while CONDITION; COMMANDS...; end
for VARNAME in [VALUES...]; COMMANDS...; end
switch VALUE; [case [WILDCARD...]; [COMMANDS...]; ...] end
</pre>
\subsection end-description Description

View File

@@ -1,5 +1,4 @@
\section exec exec - Execute command in current process
\section exec exec - execute command in current process
\subsection exec-synopsis Synopsis
<tt>exec COMMAND [OPTIONS...]</tt>

136
doc_src/faq.hdr Normal file
View File

@@ -0,0 +1,136 @@
/** \page faq Frequently asked questions
- <a href='#faq-cwd-symlink'>Why does cd, pwd and other fish commands always resolve symlinked directories to their canonical path?</a>
- <a href='#faq-cd-autocomplete'>Why does the cd command autocompletion list the subdirectories of my home directory as completions?</a>
- <a href='#faq-cd-implicit'>I accidentally entered a directory path and fish changed directory. What happened?</a>
- <a href='#faq-open'>The open command doesn't work.</a>
- <a href='#faq-default'>How do I make fish my default shell?</a>
- <a href='#faq-titlebar'>I'm seeing weird output before each prompt when using screen. What's wrong?</a>
- <a href='#faq-greeting'>How do I change the greeting message?</a>
<hr>
\section faq-cwd-symlink Why does cd, $PWD and and various fish commands always resolve symlinked directories to their canonical path?
<i>
For example if ~/images is a symlink to ~/Documents/Images, if I write
'cd images', my prompt will say ~/D/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:
Writing <code>cd images; ls ..</code> given the above directory
structure would list the contents of ~/Documents, not of ~, even
though using <code>cd ..</code> changes the current direcotry to ~,
and the prompt, the pwd builtin and many other directory information
sources suggest that the the current directory is ~/images and it's
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.
Another related issue is that many programs that operate on recursive
directory trees, like the find command, silently ignore symlinked
directories. For example, <code>find $PWD -name '*.txt'</code>
silently fails in shells that don't resolve symlinked paths.
<hr>
\section faq-cd-autocomplete Why does the cd command autocompletion list the subdirectories of my home directory as completions?
Because they are completions. In fish, if you specify a relative
directory to the cd command, i.e. any path that does not start with
either './' or '/', the environment variable CDPATH will be examined, and any
directories in this path is used as a base direcotry. To disable this
feature, write <code>set CDPATH .</code> on the commandline.
<hr>
\section faq-cd-implicit I accidentally entered a directory path and fish changed directory. What happened?
If fish is unable to locate a command with a given name, fish will
test if a directory of that name exists. If it does, it is implicitly
assumed that you want to change working directory. For example, the
fastest way to switch to your home directory is to simply type
<code>~</code>.
<hr>
\section faq-open The open command doesn't work.
The open command uses the mimetype database and the .desktop files
used by Gnome and KDE to identify filetypes and default actions. If
at least one of these two desktops are installed, but the open command is
not working, this probably means that the relevant files are installed
in a nonstandard location. Please contact the <a
href='mailto:fish-users@lists.sf.net'>fish mailing list</a>, and
hopefully this can be resolved.
\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:
\section faq-titlebar I'm seeing weird output before each prompt when using screen. What's wrong?
Quick answer:
Run the following command in fish:
<pre>
echo function fish_title;end ~/.config/fish/config.fish
</pre>
Problem solved!
The long answer:
Fish is trying to set the titlebar message of your terminal. While
screen itself supports this feature, your terminal does
not. Unfortuntaly, when the underlying terminal doesn't support
setting the titlebar, screen simply passes through the escape codes
and text to the underlying terminal instead of ignoring them. It is
impossible detect and resolve this problem from inside fish since fish
has no way of knowing what the underlying terminal type is. For now,
the only way to fix this is to unset the titlebar message, as
suggested above.
Note that fish has a default titlebar message, which will be used if
the fish_title function is undefined. So simply unsetting the
fish_title function will not work.
<code>echo /usr/local/bin/fish >>/etc/shells</code>
If you installed a prepackaged version of fish, the package manager
should have already done this for you.
In order to change your default shell, type:
<code>chsh -s /usr/bin/fish</code>
You may need to adjust the above path to e.g. /usr/local/bin/fish.
You will need to log out and back in again for the change to take
effect.
<hr>
\section faq-greeting How do I change the greeting message?
Change the value of the variable fish_greeting. For example, to remove
the greeting use:
<pre>
set fish_greeting
</pre>
*/

18
doc_src/fish.txt Normal file
View File

@@ -0,0 +1,18 @@
\section fish fish - the friendly interactive shell
\subsection fish-synopsis Synopsis
fish [-h] [-v] [-c command] [FILE [ARGUMENTS...]]
\subsection fish-description Description
A commandline shell written mainly with interactive use in mind. The full manual is available <a href='index.html'>in html</a> by using the <a href='#help'>help</a> command from inside fish.
- <code>-c</code> or <code>--command=COMMANDS</code> evaluate the specified commands instead of reading from the commandline
- <code>-d</code> or <code>--debug-level=DEBUG_LEVEL</code> specify the verbosity level of fish. A higher number means higher verbosity. The default level is 1.
- <code>-h</code> or <code>--help</code> display help and exit
- <code>-i</code> or <code>--interactive</code> specify that fish is to run in interactive mode
- <code>-l</code> or <code>--login</code> specify that fish is to run as a login shell
- <code>-n</code> or <code>--no-execute</code> do not execute any commands, only perform syntax checking
- <code>-p</code> or <code>--profile=PROFILE_FILE</code> when fish exits, output timing information on all executed commands to the specified file
- <code>-v</code> or <code>--version</code> display version and exit

View File

@@ -1,5 +1,4 @@
\section fish_pager fish_pager - Internal command used by fish
\section fish_pager fish_pager - internal command used by fish
\subsection fish_pager-description Description

View File

@@ -1,5 +1,4 @@
\section fishd fishd - Universal variable daemon
\section fishd fishd - universal variable daemon
\subsection fishd-synopsis Synopsis
<tt>fishd [(-h|--help|-v|--version)]</tt>
@@ -18,13 +17,14 @@ When no clients are connected, fishd will automatically shut down.
\subsection fishd-files Files
~/.fishd.HOSTNAME permanent storage location for universal variable
data. The data is stored as a set of \c set and \c set_export commands
such as would be parsed by fishd. If an instance of fishd is running
(which is generally the case), manual modifications to ~/.fishd.HOSTNAME
will be lost. Do NOT edit this file manually!
\c ~/.config/fish/fishd.HOSTNAME permanent storage location for universal
variable data. The data is stored as a set of \c set and \c set_export
commands such as would be parsed by fishd. The file must always be
stored in ASCII format. If an instance of fishd is running (which is
generally the case), manual modifications to ~/.fishd.HOSTNAME will be
lost. Do NOT edit this file manually!
/tmp/fishd.socket.USERNAME the socket which fishd uses to communicate
\c /tmp/fishd.socket.USERNAME the socket which fishd uses to communicate
with all clients.
/tmp/fishd.log.USERNAME the fishd log file

View File

@@ -1,13 +1,13 @@
\section for for - perform a set of commands multiple times.
\subsection for-synopsis Synopsis
<tt>for VARNAME in [VALUES...]; [COMMANDS...]; end</tt>
<tt>for VARNAME in [VALUES...]; COMMANDS...; end</tt>
\subsection for-description Description
<tt>for</tt> is a loop construct. It will perform the commands specified
by <tt>COMMANDS</tt> multiple times. Each time the environment variable
specified by <tt>VARNAME</tt> is assigned a new value from <tt>VALUES</tt>.
<tt>for</tt> is a loop construct. It will perform the commands specified by
COMMANDS multiple times. Each time the environment variable specified by
VARNAME is assigned a new value from VALUES. If VALUES is empty, COMMANDS will
not be executed at all.
\subsection for-example Example
@@ -17,7 +17,9 @@ The command
would output:
<pre>foo
<pre>
foo
bar
baz</pre>
baz
</pre>

View File

@@ -5,7 +5,6 @@
\subsection function-description Description
- \c -b or \c --key-binding specifies that the function is a key biding. Key binding functions work exactly like regular functions except that they can not be tab-completed, and may contain the '-' character.
- <code>-d DESCRIPTION</code> or \c --description=DESCRIPTION is a description of what the function does, suitable as a completion description
- <code>-j PID</code> or <code> --on-job-exit PID</code> tells fish to run this function when the job with group id PID exits. Instead of PID, the string 'caller' can be specified. This is only legal when in a command substitution, and will result in the handler being triggered by the exit of the job which created this command substitution.
- <code>-p PID</code> or <code> --on-process-exit PID</code> tells fish to run this function when the fish child process with process id PID exits
@@ -29,7 +28,8 @@ are inserted into the environment <a href="index.html#variables-arrays">variable
\subsection function-example Example
<pre>function ll
<pre>
function ll
ls -l $argv
end
</pre>

View File

@@ -11,7 +11,7 @@ This builtin command is used to print or erase functions.
- <code>-d DESCRIPTION</code> or <code>--description=DESCRIPTION</code> change the description of this function
- <code>-e</code> or <code>--erase</code> causes the specified functions to be erased.
- <code>-h</code> or <code>--help</code> display a help message and exit
- <code>-n</code> or <code>--names</code> list only the names of all defined functions
- <code>-n</code> or <code>--names</code> list only the names of all defined functions, not their definition
- <code>-q</code> or <code>--query</code> test if the specified functions exist. Does not output anything, but the builtins exit status is the number of functions specified that were not defined.
The default behavior of \c functions when called with no arguments,

View File

@@ -1,5 +1,4 @@
\section help help - Display fish documentation
\section help help - display fish documentation
\subsection help-synopsis Synopsis
<tt>help [SECTION]</tt>
@@ -8,8 +7,11 @@
The \c help command is used to display a section of the fish help documentation.
If the BROWSER environment variable is set, it will be used to display
the documentation, otherwise fish will search for a suitable browser.
If the BROWSER environment variable is set, it will be used to display the
documentation, otherwise fish will search for a suitable browser.
Note also that most builtin commands display their help in the terminal when
given the <tt>--help</tt> option.
\subsection help-example Example

View File

@@ -1,13 +1,13 @@
\section if if - Conditionally execute a command
\section if if - conditionally execute a command
\subsection if-synopsis Synopsis
<tt>if CONDITION; COMMAND_TRUE [else; COMMAND_FALSE] end;</tt>
<tt>if CONDITION; COMMANDS_TRUE...; [else; COMMANDS_FALSE...;] end</tt>
\subsection if-description Description
<tt>if</tt> will execute the command CONDITION. If the commands exit
status is zero, the command COMMAND_TRUE will execute. If it is
not zero and COMMAND_FALSE is specified, COMMAND_FALSE will be
executed.
<tt>if</tt> will execute the command CONDITION. If the condition's exit
status is 0, the commands COMMANDS_TRUE will execute. If it is not 0 and
<tt>else</tt> is given, COMMANDS_FALSE will be executed. Hint: use
<a href="#begin"><tt>begin; ...; end</tt></a> for complex conditions.
\subsection if-example Example

1367
doc_src/index.hdr Normal file

File diff suppressed because it is too large Load Diff

12
doc_src/isatty.txt Normal file
View File

@@ -0,0 +1,12 @@
\section isatty isatty - test if the specidied file descriptor is a tty
\subsection isatty-synopsis Synopsis
<tt>isatty [FILE DESCRIPTOR]</tt>
where FILE DESCRIPTOR may be either the number of a file descriptor, or one
of the strings stdin, stdout and stderr.
If the specified file descriptor is a tty, the exit status of the
command is zero, otherwise, it is non-zero.

989
doc_src/license.hdr Normal file
View File

@@ -0,0 +1,989 @@
/** \page license Licenses
Fish Copyright (C) 2005 Axel Liljencrantz. Fish is released under the
GNU General Public License, version 2. The license agreement is
included below.
Fish contains code under the BSD 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. The
license agreement is included below.
The XSel command, written and copyrighted by Conrad Parker, is
distributed together with, and used by fish. It is released under the MIT
license. The license agreement is included below.
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. The license agreement is included below.
Fish contains code from the glibc library, namely the wcstok
function. This code is licensed under the LGPL. The license agreement
is included below.
<HR>
<H2><A NAME="SEC1" HREF="gpl.html#TOC1">GNU GENERAL PUBLIC LICENSE</A></H2>
<P>
Version 2, June 1991
</P>
<PRE>
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
</PRE>
<H2><A NAME="SEC2" HREF="gpl.html#TOC2">Preamble</A></H2>
<P>
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
</P>
<P>
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
</P>
<P>
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
</P>
<P>
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
</P>
<P>
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
</P>
<P>
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
</P>
<P>
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
</P>
<P>
The precise terms and conditions for copying, distribution and
modification follow.
</P>
<H2><A NAME="SEC3" HREF="gpl.html#TOC3">TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</A></H2>
<P>
<STRONG>0.</STRONG>
This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
<P>
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
<P>
<STRONG>1.</STRONG>
You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
<P>
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
<P>
<STRONG>2.</STRONG>
You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
<P>
<DL>
<DT>
<DD>
<STRONG>a)</STRONG>
You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
</DD>
</DT>
</DL>
<P>
<DL>
<DT>
<DD>
<STRONG>b)</STRONG>
You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
</DD>
</DT>
</DL>
<P>
<DL>
<DT>
<DD>
<STRONG>c)</STRONG>
If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
</DD>
</DT>
</DL>
<P>
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
<P>
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
<P>
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
<P>
<STRONG>3.</STRONG>
You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
<!-- we use this doubled UL to get the sub-sections indented, -->
<!-- while making the bullets as unobvious as possible. -->
<DL>
<DT>
<DD>
<STRONG>a)</STRONG>
Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
</DD>
</DT>
</DL>
<P>
<DL>
<DT>
<DD>
<STRONG>b)</STRONG>
Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
</DD>
</DT>
</DL>
<P>
<DL>
<DT>
<DD>
<STRONG>c)</STRONG>
Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
</DD>
</DT>
</DL>
<P>
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
<P>
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
<P>
<STRONG>4.</STRONG>
You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
<P>
<STRONG>5.</STRONG>
You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
<P>
<STRONG>6.</STRONG>
Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
<P>
<STRONG>7.</STRONG>
If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
<P>
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
<P>
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
<P>
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
<P>
<STRONG>8.</STRONG>
If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
<P>
<STRONG>9.</STRONG>
The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
<P>
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
<P>
<STRONG>10.</STRONG>
If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
<P><STRONG>NO WARRANTY</STRONG></P>
<P>
<STRONG>11.</STRONG>
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
<P>
<STRONG>12.</STRONG>
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
<P>
<HR>
<h2>License for wcslcat and wcslcpy</h2>
\c fish also contains small amounts of code under the BSD
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.
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.
<HR>
<h2>License for XSel</h2>
The XSel command, written and copyrighted by Conrad Parker, is
distributed together with \c fish.
It is Copyright (C) 2001 Conrad Parker <conrad@vergenet.net>
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation. No representations are made about the
suitability of this software for any purpose. It is provided "as is"
without express or implied warranty.
<HR>
<H2><A NAME="SEC1" HREF="#TOC1">GNU LESSER GENERAL PUBLIC LICENSE</A></H2>
<P>
Version 2.1, February 1999
<P>
<PRE>
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
</PRE>
<H2><A NAME="SEC2" HREF="#TOC2">Preamble</A></H2>
<P>
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
<P>
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
<P>
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
<P>
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
<P>
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
<P>
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
<P>
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
<P>
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
<P>
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
<P>
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
<P>
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
<P>
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
<P>
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
<P>
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
<P>
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
<P>
<H2><A NAME="SEC3" HREF="#TOC3">TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</A></H2>
<P>
<STRONG>0.</STRONG>
This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
<P>
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
<P>
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
<P>
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
<P>
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
<P>
<STRONG>1.</STRONG>
You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
<P>
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
<P>
<STRONG>2.</STRONG>
You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
<P>
<UL>
<LI><STRONG>a)</STRONG>
The modified work must itself be a software library.
<LI><STRONG>b)</STRONG>
You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
<LI><STRONG>c)</STRONG>
You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
<LI><STRONG>d)</STRONG>
If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
<P>
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
<P>
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
<P>
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
<P>
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
</UL>
<P>
<STRONG>3.</STRONG>
You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
<P>
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
<P>
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
<P>
<STRONG>4.</STRONG>
You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
<P>
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
<P>
<STRONG>5.</STRONG>
A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
<P>
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
<P>
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
<P>
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
<P>
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
<P>
<STRONG>6.</STRONG>
As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
<P>
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
<P>
<UL>
<LI><STRONG>a)</STRONG> Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
<LI><STRONG>b)</STRONG> Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
<LI><STRONG>c)</STRONG> Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
<LI><STRONG>d)</STRONG> If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
<LI><STRONG>e)</STRONG> Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
</UL>
<P>
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
<P>
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
<P>
<STRONG>7.</STRONG> You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
<P>
<UL>
<LI><STRONG>a)</STRONG> Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
<LI><STRONG>b)</STRONG> Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
</UL>
<P>
<STRONG>8.</STRONG> You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
<P>
<STRONG>9.</STRONG>
You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
<P>
<STRONG>10.</STRONG>
Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
<P>
<STRONG>11.</STRONG>
If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
<P>
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
<P>
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
<P>
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
<P>
<STRONG>12.</STRONG>
If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
<P>
<STRONG>13.</STRONG>
The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
<P>
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
<P>
<STRONG>14.</STRONG>
If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
<P>
<STRONG>NO WARRANTY</STRONG>
<P>
<STRONG>15.</STRONG>
BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
<P>
<STRONG>16.</STRONG>
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
<P>
*/

View File

@@ -1,5 +1,4 @@
\section mimedb mimedb - Lookup file information via the mime database
\section mimedb mimedb - lookup file information via the mime database
\subsection mimedb-synopsis Synopsis
<tt>mimedb [OPTIONS] FILES...</tt>

View File

@@ -1,10 +1,10 @@
\section nextd nextd
\section nextd nextd - move forward through directory history
\subsection nextd-synopsis Synopsis
<tt>nextd [-l | --list] [pos]</tt>
\subsection nextd-description Description <tt>nextd</tt> moves
forwards <tt>pos</tt> positions in the history of visited directories;
if the end of the history has been hit, a warning is printed. If the
<code>-l></code> or <code>--list</code> flag is specified, the current
\subsection nextd-description Description
<tt>nextd</tt> moves forwards <tt>pos</tt> positions in the history of visited
directories; if the end of the history has been hit, a warning is printed. If
the <code>-l></code> or <code>--list</code> flag is specified, the current
history is also displayed.

View File

@@ -1,14 +1,12 @@
\section not not - Negate the exit status of a job
\section not not - negate the exit status of a job
\subsection not-synopsis Synopsis
<tt>not COMMAND [OPTIONS...]</tt>
<tt>not COMMAND [OPTIONS...]</tt>
\subsection not-description Description
The \c not builtin is used to negate the exit status of another command.
\subsection not-example Example
The following code reports an error and exits if no file named spoon can be found.

View File

@@ -1,5 +1,4 @@
\section open open - Open file in it's default application
\section open open - open file in it's default application
\subsection open-synopsis Synopsis
<tt>open FILES...</tt>

View File

@@ -1,12 +1,12 @@
\section or or - Conditionally execute a command
\section or or - conditionally execute a command
\subsection or-synopsis Synopsis
<tt>COMMAND1; or COMMAND2</tt>
\subsection or-description Description
The \c or builtin is used to execute a command if the current exit status (as set by the last previous command) is non-zero
The \c or builtin is used to execute a command if the current exit
status (as set by the last previous command) is not 0.
The or command does not change the current exit status.

View File

@@ -1,4 +1,4 @@
\section popd popd
\section popd popd - move through directory stack
\subsection popd-synopsis Synopsis
<tt>popd</tt>

View File

@@ -1,4 +1,4 @@
\section prevd prevd
\section prevd prevd - move backward through direcotry history
\subsection prevd-synopsis Synopsis
<tt>prevd [-l | --list] [pos]</tt>

View File

@@ -1,5 +1,4 @@
\section psub psub - Perform process substitution
\section psub psub - perform process substitution
\subsection psub-synopsis Synopsis
<tt>COMMAND1 (COMMAND2|psub) </tt>

View File

@@ -1,4 +1,4 @@
\section pushd pushd
\section pushd pushd - push directory to directory stack
\subsection pushd-synopsis Synopsis
<tt>pushd [DIRECTORY]</tt>

View File

@@ -1,5 +1,4 @@
\section random random - Generate random number
\section random random - generate random number
\subsection random-synopsis Synopsis
<tt>random [SEED]</tt>

View File

@@ -1,8 +1,7 @@
\section return return - Stop the innermost currently evaluated function
\section return return - stop the innermost currently evaluated function
\subsection return-synopsis Synopsis
<tt>function NAME; [COMMANDS...] return [STATUS]; [COMMANDS...] end</tt>
<tt>function NAME; [COMMANDS...;] return [STATUS]; [COMMANDS...;] end</tt>
\subsection return-description Description
@@ -17,9 +16,11 @@ function.
\subsection return-example Example
The following code is an implementation of the false command as a fish function
<p>
<pre>function false
return 1
end</pre>
</p>
<pre>
function false
return 1
end
</pre>

View File

@@ -1,12 +1,14 @@
\section set set - Handle environment variables.
\section set set - handle environment variables.
\subsection set-synopsis Synopsis
<pre>set [SCOPE_OPTIONS]
<pre>
set [SCOPE_OPTIONS]
set [OPTIONS] VARIABLE_NAME VALUES...
set [OPTIONS] VARIABLE_NAME[INDICES]... VALUES...
set (-q | --query) [SCOPE_OPTIONS] VARIABLE_NAMES...
set (-e | --erase) [SCOPE_OPTIONS] VARIABLE_NAME
set (-e | --erase) [SCOPE_OPTIONS] VARIABLE_NAME[INDICES]... </pre>
set (-e | --erase) [SCOPE_OPTIONS] VARIABLE_NAME[INDICES]...
</pre>
The <code>set</code> builtin causes fish to assign the variable <code>VARIABLE_NAME</code> the values <code>VALUES...</code>.
@@ -15,7 +17,7 @@ The <code>set</code> builtin causes fish to assign the variable <code>VARIABLE_N
- <code>-l</code> or <code>--local</code> forces the specified environment variable to be given a scope that is local to the current block, even if a variable with the given name exists and is non-local
- <code>-g</code> or <code>--global</code> causes the specified environment variable to be given a global scope. Non-global variables disappear when the block they belong to ends
- <code>-U</code> or <code>--universal</code> causes the specified environment variable to be given a universal scope. If this option is supplied, the variable will be shared between all the current users fish instances on the current computer, and will be preserved across restarts of the shell.
- <code>-n</code> or <code>--names</code> List only the names of all defined variables
- <code>-n</code> or <code>--names</code> List only the names of all defined variables, not their value
- <code>-q</code> or <code>--query</code> test if the specified variable names are defined. Does not output anything, but the builtins exit status is the number of variables specified that were not defined.
- <code>-u</code> or <code>--unexport</code> causes the specified environment not to be exported to child processes
- <code>-x</code> or <code>--export</code> causes the specified environment variable to be exported to child processes

View File

@@ -1,5 +1,4 @@
\section set_color set_color - Set the terminal color
\section set_color set_color - set the terminal color
\subsection set_color-synopsis Synopsis
<tt>set_color [-v --version] [-h --help] [-b --background COLOR] [COLOR]</tt>

View File

@@ -1,4 +1,4 @@
\section source . - Evaluate contents of file.
\section source . - evaluate contents of file.
\subsection source-synopsis Synopsis
<tt>. FILENAME</tt>

View File

@@ -1,5 +1,4 @@
\section status status - Display fish runtime information
\section status status - query fish runtime information
\subsection status-synopsis Synopsis
<tt>status [OPTION]</tt>

View File

@@ -1,8 +1,7 @@
\section switch switch - conditionally execute a block of commands
\subsection switch-synopsis Synopsis
<tt>switch VALUE; [case [WILDCARD...]; [COMMANDS...];...] end</tt>
<tt>switch VALUE; [case [WILDCARD...]; [COMMANDS...]; ...] end</tt>
\subsection switch-description Description
@@ -22,12 +21,17 @@ Note that fish does not fall through on case statements. Though the
syntax may look a bit like C switch statements, it behaves more like
the case stamantes of traditional shells.
Also note that command substitutions in a case statement will be
evaluated even if it's body is not taken. This may seem
counterintuitive at first, but it is unavoidable, since it would be
impossible to know if a case command will evaluate to true before all
forms of parameter expansion have been performed for the case command.
\subsection switch-example Example
If the variable \$animal contains the name of an animal, the
following code would attempt to classify it:
If the variable \$animal contains the name of an animal, the following
code would attempt to classify it:
<p>
<pre>
switch $animal
case cat
@@ -42,10 +46,7 @@ switch $animal
echo I have no idea what a $animal is
end
</pre>
</p>
<p>
If the above code was run with \c \$animal set to \c whale, the output
would be \c mammal.
</p>

View File

@@ -1,4 +1,3 @@
\section trap trap - perform an action when the shell receives a signal
\subsection trap-synopsis Synopsis

View File

@@ -1,5 +1,4 @@
\section type type - Indicate how a name would be interpreted if used as a command name
\section type type - indicate how a name would be interpreted if used as a command name
\subsection type-synopsis Synopsis
<tt>type [OPTIONS] name [name ...]</tt>

View File

@@ -1,5 +1,4 @@
\section ulimit ulimit - Set or get the shells resource usage limits
\section ulimit ulimit - set or get the shells resource usage limits
\subsection ulimit-synopsis Synopsis
<tt>ulimit [OPTIONS] [LIMIT]</tt>

View File

@@ -1,5 +1,4 @@
\section umask umask - Set or get the shells resource usage limits
\section umask umask - set or get the shells resource usage limits
\subsection umask-synopsis Synopsis
<code>umask [OPTIONS] [MASK]</code>

View File

@@ -1,5 +1,4 @@
\section vared vared - Interactively edit the value of an environment variable
\section vared vared - interactively edit the value of an environment variable
\subsection vared-synopsis Synopsis
<tt>vared VARIABLE_NAME</tt>

View File

@@ -1,13 +1,19 @@
\section while while - perform a command multiple times
\subsection while-synopsis Synopsis
<tt>while CONDITION; COMMANDS; end</tt>
<tt>while CONDITION; COMMANDS...; end</tt>
\subsection while-synopsis Synopsis
The <tt>while</tt> builtin causes fish to continually execute the command COMMANDS while the command CONDITION returns with status 0.
\subsection while-description Description
The <tt>while</tt> builtin causes fish to continually execute CONDITION and
execute COMMANDS as long as CONDITION returned with status 0. If CONDITION is
false on the first time, COMMANDS will not be executed at all. Hints: use
<a href="#begin"><tt>begin; ...; end</tt></a> for complex conditions; more
complex control can be achieved with <tt>while true</tt> containing a
<a href="#break">break</a>.
\subsection while-example Example
<tt>while test -f foo.txt; echo file exists; sleep 10; end</tt>
causes fish to print the line 'file exists' at 10 second intervals as long as the file foo.txt exists.
causes fish to print the line 'file exists' at 10 second intervals as long as
the file foo.txt exists.

51
env.c
View File

@@ -59,7 +59,7 @@
/**
Command used to start fishd
*/
#define FISHD_CMD L"if which fishd 2>/dev/null >/dev/null; fishd ^/tmp/fishd.log.%s; end"
#define FISHD_CMD L"fishd ^/tmp/fishd.log.%s"
/**
Value denoting a null string
@@ -452,11 +452,34 @@ static void setup_path()
al_destroy( &l );
}
static void env_set_defaults()
{
if( !env_get( L"USER" ) )
{
struct passwd *pw = getpwuid( getuid());
wchar_t *unam = str2wcs( pw->pw_name );
env_set( L"USER", unam, ENV_GLOBAL );
free( unam );
}
if( !env_get( L"HOME" ) )
{
wchar_t *unam = env_get( L"USER" );
char *unam_narrow = wcs2str( unam );
struct passwd *pw = getpwnam( unam_narrow );
wchar_t *dir = str2wcs( pw->pw_dir );
env_set( L"HOME", dir, ENV_GLOBAL );
free( dir );
free( unam_narrow );
}
}
void env_init()
{
char **p;
struct passwd *pw;
wchar_t *uname;
wchar_t *version;
sb_init( &dyn_var );
b_init( &export_buffer );
@@ -468,6 +491,7 @@ void env_init()
hash_put( &env_read_only, L"status", L"" );
hash_put( &env_read_only, L"history", L"" );
hash_put( &env_read_only, L"version", L"" );
hash_put( &env_read_only, L"_", L"" );
hash_put( &env_read_only, L"LINES", L"" );
hash_put( &env_read_only, L"COLUMNS", L"" );
@@ -555,12 +579,23 @@ void env_init()
env_set( L"USER", uname, ENV_GLOBAL | ENV_EXPORT );
free( uname );
}
/*
Set up the version variable
*/
version = str2wcs( PACKAGE_VERSION );
env_set( L"version", version, ENV_GLOBAL );
free( version );
env_universal_init( env_get( L"FISHD_SOCKET_DIR"),
env_get( L"USER" ),
&start_fishd,
&universal_callback );
/*
Set correct defaults for e.g. USER and HOME variables
*/
env_set_defaults();
}
void env_destroy()
@@ -683,7 +718,7 @@ int env_set( const wchar_t *key,
env_universal_set( key, val, export );
is_universal = 1;
}
else
{
@@ -711,6 +746,7 @@ int env_set( const wchar_t *key,
(var_mode & ENV_GLOBAL) )
{
node = ( var_mode & ENV_GLOBAL )?global_env:top;
}
else
{
@@ -936,7 +972,7 @@ wchar_t *env_get( const wchar_t *key )
wchar_t *item;
CHECK( key, 0 );
if( wcscmp( key, L"history" ) == 0 )
{
wchar_t *current;
@@ -951,15 +987,11 @@ wchar_t *env_get( const wchar_t *key )
sb_append( &dyn_var, current );
}
for( i=add_current; i<8; i++ )
for( i=add_current;; i++ )
{
wchar_t *next = history_get( i-add_current );
if( !next )
{
/*
This is not an error - it simply means the user has
a short history
*/
break;
}
@@ -967,6 +999,7 @@ wchar_t *env_get( const wchar_t *key )
sb_append( &dyn_var, ARRAY_SEP_STR );
sb_append( &dyn_var, next );
}
return (wchar_t *)dyn_var.buff;
}
else if( wcscmp( key, L"COLUMNS" )==0 )

7
env.h
View File

@@ -80,8 +80,8 @@ void env_destroy();
*/
int env_set( const wchar_t *key,
const wchar_t *val,
int mode );
const wchar_t *val,
int mode );
/**
@@ -94,7 +94,7 @@ int env_set( const wchar_t *key,
wchar_t *env_get( const wchar_t *key );
/**
Returns 1 if the specified key exists. This can't be reliable done
Returns 1 if the specified key exists. This can't be reliably done
using env_get, since env_get returns null for 0-element arrays
\param key The name of the variable to remove
@@ -129,7 +129,6 @@ char **env_export_arr( int recalc );
/**
Insert all variable names into l. These are not copies of the strings and should not be freed after use.
*/
void env_get_names( array_list_t *l, int flags );

View File

@@ -164,7 +164,6 @@ static void callback( int type, const wchar_t *name, const wchar_t *val )
{
if( type == BARRIER_REPLY )
{
debug( 3, L"Got barrier reply" );
barrier_reply = 1;
}
else
@@ -194,7 +193,7 @@ static void check_connection()
env_universal_server.fd = -1;
env_universal_server.killme=0;
sb_clear( &env_universal_server.input );
env_universal_server.input.used=0;
env_universal_read_all();
}
}
@@ -212,6 +211,7 @@ static void reconnect()
debug( 3, L"Get new fishd connection" );
init = 0;
env_universal_server.buffer_consumed = env_universal_server.buffer_used = 0;
env_universal_server.fd = get_socket(1);
init = 1;
if( env_universal_server.fd >= 0 )
@@ -226,26 +226,21 @@ void env_universal_init( wchar_t * p,
void (*sf)(),
void (*cb)( int type, const wchar_t *name, const wchar_t *val ))
{
debug( 3, L"env_universal_init()" );
path=p;
user=u;
start_fishd=sf;
external_callback = cb;
connection_init( &env_universal_server, -1 );
env_universal_server.fd = -1;
env_universal_server.killme = 0;
env_universal_server.fd = get_socket(1);
memset (&env_universal_server.wstate, '\0', sizeof (mbstate_t));
q_init( &env_universal_server.unsent );
env_universal_common_init( &callback );
sb_init( &env_universal_server.input );
env_universal_read_all();
init = 1;
if( env_universal_server.fd >= 0 )
{
env_universal_barrier();
}
debug( 3, L"end env_universal_init()" );
}
void env_universal_destroy()
@@ -259,17 +254,11 @@ void env_universal_destroy()
{
wperror( L"fcntl" );
}
try_send_all( &env_universal_server );
if( close( env_universal_server.fd ) )
{
wperror( L"close" );
}
try_send_all( &env_universal_server );
}
connection_destroy( &env_universal_server );
env_universal_server.fd =-1;
q_destroy( &env_universal_server.unsent );
sb_destroy( &env_universal_server.input );
env_universal_common_destroy();
init = 0;
}
@@ -283,8 +272,6 @@ int env_universal_read_all()
if( !init)
return 0;
debug( 3, L"env_universal_read_all()" );
if( env_universal_server.fd == -1 )
{
reconnect();
@@ -312,7 +299,6 @@ wchar_t *env_universal_get( const wchar_t *name )
CHECK( name, 0 );
debug( 3, L"env_universal_get( \"%ls\" )", name );
return env_universal_common_get( name );
}
@@ -323,7 +309,6 @@ int env_universal_get_export( const wchar_t *name )
CHECK( name, 0 );
debug( 3, L"env_universal_get_export()" );
return env_universal_common_get_export( name );
}
@@ -367,7 +352,7 @@ void env_universal_barrier()
FD_SET( env_universal_server.fd, &fds );
select( env_universal_server.fd+1, 0, &fds, 0, 0 );
}
/*
Wait for barrier reply
*/

View File

@@ -21,6 +21,7 @@
#include <sys/stat.h>
#include <dirent.h>
#include <wctype.h>
#include <iconv.h>
#include <errno.h>
#include <locale.h>
@@ -69,6 +70,21 @@
*/
#define PARSE_ERR L"Unable to parse universal variable message: '%ls'"
/**
ERROR string for internal buffered reader
*/
#define ENV_UNIVERSAL_ERROR 0x100
/**
EAGAIN string for internal buffered reader
*/
#define ENV_UNIVERSAL_AGAIN 0x101
/**
EOF string for internal buffered reader
*/
#define ENV_UNIVERSAL_EOF 0x102
/**
A variable entry. Stores the value of a variable and whether it
should be exported. Obviously, it needs to be allocated large
@@ -110,9 +126,163 @@ static int get_names_show_exported;
static int get_names_show_unexported;
wchar_t *utf2wcs( const char *in )
{
iconv_t cd=(iconv_t) -1;
int i,j;
wchar_t *out;
char *to_name[]=
{
"wchar_t", "WCHAR_T", "wchar", "WCHAR", 0
}
;
char *from_name[]=
{
"utf-8", "UTF-8", "utf8", "UTF8", 0
}
;
size_t in_len = strlen( in );
size_t out_len = sizeof( wchar_t )*(in_len+1);
size_t nconv;
char *nout;
out = malloc( out_len );
nout = (char *)out;
if( !out )
return 0;
for( i=0; to_name[i]; i++ )
{
for( j=0; from_name[j]; j++ )
{
cd = iconv_open ( to_name[i], from_name[j] );
if( cd != (iconv_t) -1)
{
goto start_conversion;
}
}
}
start_conversion:
if (cd == (iconv_t) -1)
{
/* Something went wrong. */
debug( 0, L"Could not perform utf-8 conversion" );
if(errno != EINVAL)
wperror( L"iconv_open" );
/* Terminate the output string. */
free(out);
return 0;
}
nconv = iconv( cd, (char **)&in, &in_len, &nout, &out_len );
if (nconv == (size_t) -1)
{
debug( 0, L"Error while converting from utf string" );
return 0;
}
*((wchar_t *) nout) = L'\0';
if (iconv_close (cd) != 0)
wperror (L"iconv_close");
return out;
}
char *wcs2utf( const wchar_t *in )
{
iconv_t cd=(iconv_t) -1;
int i,j;
char *char_in = (char *)in;
char *out;
char *from_name[]=
{
"wchar_t", "WCHAR_T", "wchar", "WCHAR", 0
}
;
char *to_name[]=
{
"utf-8", "UTF-8", "utf8", "UTF8", 0
}
;
size_t in_len = wcslen( in );
size_t out_len = sizeof( char )*( (MAX_UTF8_BYTES*in_len)+1);
size_t nconv;
char *nout;
out = malloc( out_len );
nout = (char *)out;
in_len *= sizeof( wchar_t );
if( !out )
return 0;
for( i=0; to_name[i]; i++ )
{
for( j=0; from_name[j]; j++ )
{
cd = iconv_open ( to_name[i], from_name[j] );
if( cd != (iconv_t) -1)
{
goto start_conversion;
}
}
}
start_conversion:
if (cd == (iconv_t) -1)
{
/* Something went wrong. */
debug( 0, L"Could not perform utf-8 conversion" );
if(errno != EINVAL)
wperror( L"iconv_open" );
/* Terminate the output string. */
free(out);
return 0;
}
nconv = iconv( cd, &char_in, &in_len, &nout, &out_len );
if (nconv == (size_t) -1)
{
debug( 0, L"%d %d", in_len, out_len );
debug( 0, L"Error while converting from to string" );
return 0;
}
*nout = '\0';
if (iconv_close (cd) != 0)
wperror (L"iconv_close");
return out;
}
void env_universal_common_init( void (*cb)(int type, const wchar_t *key, const wchar_t *val ) )
{
debug( 3, L"Init env_universal_common" );
callback = cb;
hash_init( &env_universal_var, &hash_wcs_func, &hash_wcs_cmp );
}
@@ -134,69 +304,118 @@ void env_universal_common_destroy()
hash_destroy( &env_universal_var );
}
static int read_byte( connection_t *src )
{
if( src->buffer_consumed >= src->buffer_used )
{
int res;
res = read( src->fd, src->buffer, ENV_UNIVERSAL_BUFFER_SIZE );
// debug(4, L"Read chunk '%.*s'", res, src->buffer );
if( res < 0 )
{
if( errno == EAGAIN ||
errno == EINTR )
{
return ENV_UNIVERSAL_AGAIN;
}
return ENV_UNIVERSAL_ERROR;
}
if( res == 0 )
{
return ENV_UNIVERSAL_EOF;
}
src->buffer_consumed = 0;
src->buffer_used = res;
}
return src->buffer[src->buffer_consumed++];
}
void read_message( connection_t *src )
{
while( 1 )
{
char b;
int read_res = read( src->fd, &b, 1 );
wchar_t res=0;
if( read_res < 0 )
int ib = read_byte( src );
char b;
switch( ib )
{
if( errno != EAGAIN &&
errno != EINTR )
case ENV_UNIVERSAL_AGAIN:
{
return;
}
case ENV_UNIVERSAL_ERROR:
{
debug( 2, L"Read error on fd %d, set killme flag", src->fd );
wperror( L"read" );
if( debug_level > 2 )
wperror( L"read" );
src->killme = 1;
return;
}
return;
}
if( read_res == 0 )
{
src->killme = 1;
debug( 3, L"Fd %d has reached eof, set killme flag", src->fd );
if( src->input.used > 0 )
case ENV_UNIVERSAL_EOF:
{
debug( 1,
L"Universal variable connection closed while reading command. Partial command recieved: '%ls'",
(wchar_t *)src->input.buff );
src->killme = 1;
debug( 3, L"Fd %d has reached eof, set killme flag", src->fd );
if( src->input.used > 0 )
{
char c = 0;
b_append( &src->input, &c, 1 );
debug( 1,
L"Universal variable connection closed while reading command. Partial command recieved: '%s'",
(wchar_t *)src->input.buff );
}
return;
}
return;
}
int sz = mbrtowc( &res, &b, 1, &src->wstate );
b = (char)ib;
if( sz == -1 )
{
debug( 1, L"Error while reading universal variable after '%ls'", (wchar_t *)src->input.buff );
wperror( L"mbrtowc" );
}
else if( sz > 0 )
if( b == '\n' )
{
if( res == L'\n' )
wchar_t *msg;
b = 0;
b_append( &src->input, &b, 1 );
msg = utf2wcs( src->input.buff );
/*
Before calling parse_message, we must empty reset
everything, since the callback function could
potentially call read_message.
*/
src->input.used=0;
if( msg )
{
/*
Before calling parse_message, we must empty reset
everything, since the callback function could
potentially call read_message.
*/
wchar_t *msg = wcsdup( (wchar_t *)src->input.buff );
sb_clear( &src->input );
memset (&src->wstate, '\0', sizeof (mbstate_t));
parse_message( msg, src );
free( msg );
}
else
{
sb_append_char( &src->input, res );
debug( 0, _(L"Could not convert message '%s' to wide character string"), src->input.buff );
}
free( msg );
}
else
{
b_append( &src->input, &b, 1 );
}
}
}
@@ -236,7 +455,7 @@ static int match( const wchar_t *msg, const wchar_t *cmd )
static void parse_message( wchar_t *msg,
connection_t *src )
{
debug( 3, L"parse_message( %ls );", msg );
// debug( 3, L"parse_message( %ls );", msg );
if( msg[0] == L'#' )
return;
@@ -343,7 +562,16 @@ static int try_send( message_t *msg,
L"before write of %d chars to fd %d", strlen(msg->body), fd );
int res = write( fd, msg->body, strlen(msg->body) );
if( res != -1 )
{
debug( 4, L"Wrote message '%s'", msg->body );
}
else
{
debug( 4, L"Failed to write message '%s'", msg->body );
}
if( res == -1 )
{
switch( errno )
@@ -352,10 +580,11 @@ static int try_send( message_t *msg,
return 0;
default:
debug( 1,
debug( 2,
L"Error while sending universal variable message to fd %d. Closing connection",
fd );
wperror( L"write" );
if( debug_level > 2 )
wperror( L"write" );
return -1;
}
@@ -371,9 +600,9 @@ static int try_send( message_t *msg,
void try_send_all( connection_t *c )
{
debug( 3,
/* debug( 3,
L"Send all updates to connection on fd %d",
c->fd );
c->fd );*/
while( !q_empty( &c->unsent) )
{
switch( try_send( (message_t *)q_peek( &c->unsent), c->fd ) )
@@ -383,7 +612,7 @@ void try_send_all( connection_t *c )
break;
case 0:
debug( 1,
debug( 4,
L"Socket full, send rest later" );
return;
@@ -394,6 +623,33 @@ void try_send_all( connection_t *c )
}
}
static wchar_t *full_escape( const wchar_t *in )
{
string_buffer_t out;
sb_init( &out );
for( ; *in; in++ )
{
if( *in < 32 )
{
sb_printf( &out, L"\\x%.2x", *in );
}
else if( *in < 128 )
{
sb_append_char( &out, *in );
}
else if( *in < 65536 )
{
sb_printf( &out, L"\\u%.4x", *in );
}
else
{
sb_printf( &out, L"\\U%.8x", *in );
}
}
return (wchar_t *)out.buff;
}
message_t *create_message( int type,
const wchar_t *key_in,
const wchar_t *val_in )
@@ -402,10 +658,18 @@ message_t *create_message( int type,
char *key=0;
size_t sz;
// debug( 4, L"Crete message of type %d", type );
if( key_in )
{
key = wcs2str(key_in);
if( wcsvarname( key_in ) )
{
debug( 0, L"Illegal variable name: '%ls'", key_in );
return 0;
}
key = wcs2utf(key_in);
if( !key )
{
debug( 0,
@@ -426,11 +690,11 @@ message_t *create_message( int type,
val_in=L"";
}
wchar_t *esc = escape(val_in,1);
wchar_t *esc = full_escape( val_in );
if( !esc )
break;
char *val = wcs2str(esc );
char *val = wcs2utf(esc );
free(esc);
sz = strlen(type==SET?SET_MBS:SET_EXPORT_MBS) + strlen(key) + strlen(val) + 4;
@@ -495,6 +759,9 @@ message_t *create_message( int type,
if( msg )
msg->count=0;
// debug( 4, L"Message body is '%s'", msg->body );
return msg;
}
@@ -572,3 +839,22 @@ void enqueue_all( connection_t *c )
try_send_all( c );
}
void connection_init( connection_t *c, int fd )
{
memset (c, 0, sizeof (connection_t));
c->fd = fd;
b_init( &c->input );
q_init( &c->unsent );
c->buffer_consumed = c->buffer_used = 0;
}
void connection_destroy( connection_t *c)
{
q_destroy( &c->unsent );
b_destroy( &c->input );
if( close( c->fd ) )
{
wperror( L"close" );
}
}

View File

@@ -49,6 +49,11 @@ enum
}
;
/**
The size of the buffer used for reading from the socket
*/
#define ENV_UNIVERSAL_BUFFER_SIZE 1024
/**
This struct represents a connection between a universal variable server/client
*/
@@ -66,16 +71,28 @@ typedef struct connection
Set to one when this connection should be killed
*/
int killme;
/**
The state used for character conversions
*/
mbstate_t wstate;
/**
The input string. Input from the socket goes here. When a
newline is encountered, the buffer is parsed and cleared.
*/
string_buffer_t input;
buffer_t input;
/**
The read buffer.
*/
char buffer[ENV_UNIVERSAL_BUFFER_SIZE];
/**
Number of bytes that have already been consumed.
*/
int buffer_consumed;
/**
Number of bytes that have been read into the buffer.
*/
int buffer_used;
/**
Link to the next connection
*/
@@ -147,5 +164,8 @@ int env_universal_common_get_export( const wchar_t *name );
*/
void enqueue_all( connection_t *c );
void connection_init( connection_t *c, int fd );
void connection_destroy( connection_t *c);
#endif

View File

@@ -3,13 +3,6 @@
#
# @configure_input@
#
# Set default search paths for completions and shellscript functions
#
set -g fish_function_path ~/.fish.d/functions @sysconfdir@/fish.d/functions @datadir@/fish/functions
set -g fish_complete_path ~/.fish.d/completions @sysconfdir@/fish.d/completions @datadir@/fish/completions
#
# Set default field separators
#
@@ -66,6 +59,8 @@ end
# Load additional initialization files
#
for i in fish.d/*.fish
. $i
end
if test -d include
for i in include/*.fish
. $i
end
end

View File

@@ -1,110 +0,0 @@
#
# Initializations that should only be performed when in interactive mode
#
# @configure_input@
if not status --is-interactive
exit
end
#
# Print a greeting
#
printf (_ 'Welcome to fish, the friendly interactive shell\n')
printf (_ 'Type %shelp%s for instructions on how to use fish\n') (set_color green) (set_color normal)
#
# Set exit message
#
function fish_on_exit -d (_ "Commands to execute when fish exits") --on-process %self
printf (_ "Good bye\n")
end
#
# Set INPUTRC to something nice
#
# We override INPUTRC if already set, since it may be set by a shell
# other than fish, which may use a different file. The new value should
# be exported, since the fish inputrc file plays nice with other files
# by including them when found.
# Give priority to the default file installed with fish in
# @sysconfdir@/fish_inputrc.
#
for i in ~/.fish_inputrc @sysconfdir@/fish_inputrc ~/.inputrc /etc/inputrc
if test -f $i
set -xg INPUTRC $i
break
end
end
#
# Set various defaults using these throwaway functions
#
function set_default -d "Set an universal variable, unless it has already been set"
if not set -q $argv[1]
set -U -- $argv
end
if not set -q $argv[1]
set -g -- $argv
end
end
function set_exported_default -d "Set an exported universal variable, unless it has already been set"
if not set -q $argv[1]
set -Ux -- $argv
end
if not set -q $argv[1]
set -gx -- $argv
end
end
# Regular syntax highlighting colors
set_default fish_color_normal normal
set_default fish_color_command green
set_default fish_color_redirection normal
set_default fish_color_comment red
set_default fish_color_error red --bold
set_default fish_color_escape cyan
set_default fish_color_operator cyan
set_default fish_color_quote brown
set_default fish_color_valid_path --underline
set_default fish_color_cwd green
# Background color for matching quotes and parenthesis
set_default fish_color_match cyan
# Background color for search matches
set_default fish_color_search_match purple
# Pager colors
set_default fish_pager_color_prefix cyan
set_default fish_pager_color_completion normal
set_default fish_pager_color_description normal
set_default fish_pager_color_progress cyan
#
# Directory history colors
#
set_default fish_color_history_current cyan
#
# Setup the CDPATH variable
#
set_default CDPATH . ~
#
# Remove temporary functions for setting default variable values
#
functions -e set_exported_default
functions -e set_default

146
exec.c
View File

@@ -69,6 +69,10 @@ pid_t getpgid( pid_t pid );
*/
#define FORK_ERROR _( L"Could not create child process - exiting" )
/**
Base open mode to pass to calls to open
*/
#define BASE_MASK 0666
/**
List of all pipes used by internal pipes. These must be closed in
@@ -272,7 +276,7 @@ static int handle_child_io( io_data_t *io, int exit_on_error )
case IO_FILE:
{
if( (tmp=wopen( io->param1.filename,
io->param2.flags, 0777 ) )==-1 )
io->param2.flags, BASE_MASK ) )==-1 )
{
debug( 1,
FILE_ERROR,
@@ -441,7 +445,9 @@ static void launch_process( process_t *p )
{
// debug( 1, L"exec '%ls'", p->argv[0] );
execve (wcs2str(p->actual_cmd), wcsv2strv( (const wchar_t **) p->argv), env_export_arr( 0 ) );
execve ( wcs2str(p->actual_cmd),
wcsv2strv( (const wchar_t **) p->argv),
env_export_arr( 0 ) );
debug( 0,
_( L"Failed to execute process '%ls'" ),
p->actual_cmd );
@@ -525,7 +531,7 @@ static io_data_t *io_transmogrify( io_data_t * in )
{
int fd;
if( (fd=wopen( in->param1.filename, in->param2.flags, 0777 ) )==-1 )
if( (fd=wopen( in->param1.filename, in->param2.flags, BASE_MASK ) )==-1 )
{
debug( 1,
FILE_ERROR,
@@ -576,7 +582,7 @@ static void internal_exec_helper( const wchar_t *def,
*/
if( io && !io_internal )
{
proc_set_last_status( 1 );
proc_set_last_status( STATUS_EXEC_FAIL );
return;
}
@@ -607,23 +613,23 @@ static int set_child_group( job_t *j, process_t *p, int print_errors )
{
int res = 0;
if( j->job_control )
if( job_get_flag( j, JOB_CONTROL ) )
{
int new_pgid=0;
if (!j->pgid)
{
new_pgid=1;
j->pgid = p->pid;
}
if( setpgid (p->pid, j->pgid) )
{
{
if( getpgid( p->pid) != j->pgid && print_errors )
{
debug( 1,
_( L"Could not send process %d from group %d to group %d" ),
p->pid,
_( L"Could not send process %d, '%ls' in job %d, '%ls' from group %d to group %d" ),
p->pid,
p->argv[0],
j->job_id,
j->command,
getpgid( p->pid),
j->pgid );
wperror( L"setpgid" );
@@ -636,7 +642,7 @@ static int set_child_group( job_t *j, process_t *p, int print_errors )
j->pgid = getpid();
}
if( j->terminal && j->fg )
if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
{
if( tcsetpgrp (0, j->pgid) && print_errors )
{
@@ -671,13 +677,16 @@ void exec( job_t *j )
*/
int exec_error=0;
int needs_keepalive = 0;
process_t keepalive;
CHECK( j, );
CHECK_BLOCK();
if( no_exec )
return;
sigemptyset( &chldset );
sigaddset( &chldset, SIGCHLD );
@@ -729,7 +738,7 @@ void exec( job_t *j )
}
else
{
j->constructed=1;
job_set_flag( j, JOB_CONSTRUCTED, 1 );
j->first_process->completed=1;
return;
}
@@ -753,6 +762,53 @@ void exec( job_t *j )
j->io = io_add( j->io, &pipe_write );
signal_block();
/*
See if we need to create a group keepalive process. This is a
process that we create to make sure that the process group
doesn't die accidentally, and is needed when a block/function is
inside a pipeline.
*/
if( job_get_flag( j, JOB_CONTROL ) )
{
for( p=j->first_process; p; p = p->next )
{
if( (p->type == INTERNAL_BLOCK ) ||
(p->type == INTERNAL_FUNCTION ) )
{
if( p->next )
{
needs_keepalive = 1;
break;
}
}
}
}
if( needs_keepalive )
{
keepalive.pid = fork();
if( keepalive.pid == 0 )
{
keepalive.pid = getpid();
set_child_group( j, &keepalive, 1 );
pause();
exit(0);
}
else if( keepalive.pid < 0 )
{
/* The fork failed. */
debug( 0, FORK_ERROR );
wperror (L"fork");
exit (1);
}
else
{
set_child_group( j, &keepalive, 0 );
}
}
/*
This loop loops over every process_t in the job, starting it as
@@ -761,7 +817,7 @@ void exec( job_t *j )
The loop also has to handle pipelining between the jobs.
*/
for( p=j->first_process; p; p = p->next )
{
mypipe[1]=-1;
@@ -816,18 +872,27 @@ void exec( job_t *j )
{
case INTERNAL_FUNCTION:
{
const wchar_t * orig_def;
wchar_t * def=0;
signal_unblock();
orig_def = function_get_definition( p->argv[0] );
signal_block();
wchar_t * def = halloc_register( j, wcsdup( function_get_definition( p->argv[0] )));
if( orig_def )
{
def = halloc_register( j, wcsdup(orig_def) );
}
if( def == 0 )
{
debug( 0, _( L"Unknown function '%ls'" ), p->argv[0] );
break;
}
parser_push_block( FUNCTION_CALL );
current_block->param2.function_call_process = p;
current_block->param1.function_name = halloc_register( current_block, wcsdup( p->argv[0] ) );
current_block->param1.function_call_name = halloc_register( current_block, wcsdup( p->argv[0] ) );
parse_util_set_argv( p->argv+1 );
@@ -889,7 +954,7 @@ void exec( job_t *j )
case IO_FILE:
{
builtin_stdin=wopen( in->param1.filename,
in->param2.flags, 0777 );
in->param2.flags, BASE_MASK );
if( builtin_stdin == -1 )
{
debug( 1,
@@ -939,8 +1004,8 @@ void exec( job_t *j )
builtin_out_redirect = has_fd( j->io, 1 );
builtin_err_redirect = has_fd( j->io, 2 );
fg = j->fg;
j->fg = 0;
fg = job_get_flag( j, JOB_FOREGROUND );
job_set_flag( j, JOB_FOREGROUND, 0 );
signal_unblock();
@@ -953,7 +1018,7 @@ void exec( job_t *j )
false during builtin execution so as not to confuse
some job-handling builtins.
*/
j->fg = fg;
job_set_flag( j, JOB_FOREGROUND, fg );
}
if( close_stdin )
@@ -989,7 +1054,7 @@ void exec( job_t *j )
*/
if( p->next == 0 )
{
proc_set_last_status( j->negate?(status?0:1):status);
proc_set_last_status( job_get_flag( j, JOB_NEGATE )?(!status):status);
}
p->completed = 1;
break;
@@ -1039,7 +1104,7 @@ void exec( job_t *j )
{
if( p->next == 0 )
{
proc_set_last_status( j->negate?(status?0:1):status);
proc_set_last_status( job_get_flag( j, JOB_NEGATE )?(!status):status);
}
p->completed = 1;
}
@@ -1130,7 +1195,7 @@ void exec( job_t *j )
{
debug( 3, L"Set status of %ls to %d using short circut", j->command, p->status );
proc_set_last_status( j->negate?(p->status?0:1):p->status );
proc_set_last_status( job_get_flag( j, JOB_NEGATE )?(!p->status):p->status );
}
break;
@@ -1190,7 +1255,7 @@ void exec( job_t *j )
p->pid = getpid();
setup_child_process( j, p );
launch_process( p );
/*
launch_process _never_ returns...
*/
@@ -1246,6 +1311,15 @@ void exec( job_t *j )
}
}
/*
The keepalive process is no longer needed, so we terminate it
with extreme prejudice
*/
if( needs_keepalive )
{
kill( keepalive.pid, SIGKILL );
}
signal_unblock();
debug( 3, L"Job is constructed" );
@@ -1255,9 +1329,9 @@ void exec( job_t *j )
for( tmp = block_io; tmp; tmp=tmp->next )
j->io = io_remove( j->io, tmp );
j->constructed = 1;
job_set_flag( j, JOB_CONSTRUCTED, 1 );
if( !j->fg )
if( !job_get_flag( j, JOB_FOREGROUND ) )
{
proc_last_bg_pid = j->pgid;
}
@@ -1283,7 +1357,7 @@ int exec_subshell( const wchar_t *cmd,
debug( 1,
_( L"Sent null command to subshell. This is a fish bug. If it can be reproduced, please send a bug report to %s." ),
PACKAGE_BUGREPORT );
return 0;
return -1;
}
is_subshell=1;
@@ -1291,11 +1365,17 @@ int exec_subshell( const wchar_t *cmd,
prev_status = proc_get_last_status();
eval( cmd, io_buffer, SUBST );
if( eval( cmd, io_buffer, SUBST ) )
{
status = -1;
}
else
{
status = proc_get_last_status();
}
io_buffer_read( io_buffer );
status = proc_get_last_status();
proc_set_last_status( prev_status );
is_subshell = prev_subshell;

4
exec.h
View File

@@ -51,8 +51,8 @@ void exec( job_t *j );
\return the status of the last job to exit, or -1 if en error was encountered.
*/
int exec_subshell( const wchar_t *cmd,
array_list_t *l );
__warn_unused int exec_subshell( const wchar_t *cmd,
array_list_t *l );
/**

199
expand.c
View File

@@ -44,6 +44,7 @@ parameter expansion.
#include "complete.h"
#include "parse_util.h"
#include "halloc.h"
#include "halloc_util.h"
/**
@@ -654,8 +655,8 @@ static int expand_pid( wchar_t *in,
free( in );
else
{
*in = L'%';
al_push( out, in );
free(in);
return 0;
}
}
else
@@ -743,6 +744,55 @@ void expand_variable_error( const wchar_t *token, int token_pos, int error_pos )
}
static int parse_slice( wchar_t *in, wchar_t **end_ptr, array_list_t *idx )
{
wchar_t *end;
int pos = 1;
// debug( 0, L"parse_slice on '%ls'", in );
while( 1 )
{
long tmp;
while( iswspace(in[pos]) || (in[pos]==INTERNAL_SEPARATOR))
pos++;
if( in[pos] == L']' )
{
pos++;
break;
}
errno=0;
tmp = wcstol( &in[pos], &end, 10 );
if( ( errno ) || ( end == &in[pos] ) )
{
return 1;
}
// debug( 0, L"Push idx %d", tmp );
al_push_long( idx, tmp );
pos = end-in;
}
if( end_ptr )
{
// debug( 0, L"Remainder is '%ls', slice def was %d characters long", in+pos, pos );
*end_ptr = in+pos;
}
// debug( 0, L"ok, done" );
return 0;
}
/**
Expand all environment variables in the string *ptr.
@@ -841,44 +891,22 @@ static int expand_variables( wchar_t *in, array_list_t *out, int last_idx )
int all_vars=1;
array_list_t var_item_list;
al_init( &var_item_list );
if( in[stop_pos] == L'[' )
{
wchar_t *end;
all_vars = 0;
stop_pos++;
while( 1 )
wchar_t *slice_end;
all_vars=0;
if( parse_slice( &in[stop_pos], &slice_end, var_idx_list ) )
{
long tmp;
while( iswspace(in[stop_pos]) || (in[stop_pos]==INTERNAL_SEPARATOR))
stop_pos++;
if( in[stop_pos] == L']' )
{
stop_pos++;
break;
}
errno=0;
tmp = wcstol( &in[stop_pos], &end, 10 );
if( ( errno ) || ( end == &in[stop_pos] ) )
{
error( SYNTAX_ERROR,
-1,
L"Expected integer or \']\'" );
is_ok = 0;
break;
}
al_push_long( var_idx_list, tmp );
stop_pos = end-in;
}
}
error( SYNTAX_ERROR,
-1,
L"Invalid index value" );
is_ok = 0;
}
stop_pos = (slice_end-in);
}
if( is_ok )
{
tokenize_variable_array( var_val, &var_item_list );
@@ -1189,16 +1217,20 @@ static int expand_brackets( wchar_t *in, int flags, array_list_t *out )
static int expand_cmdsubst( wchar_t *in, array_list_t *out )
{
wchar_t *paran_begin=0, *paran_end=0;
int len1, len2;
int len1;
wchar_t prev=0;
wchar_t *subcmd;
array_list_t sub_res, tail_expand;
array_list_t *sub_res, *tail_expand;
int i, j;
const wchar_t *item_begin;
wchar_t *tail_begin = 0;
void *context;
CHECK( in, 0 );
CHECK( out, 0 );
switch( parse_util_locate_cmdsubst(in,
&paran_begin,
&paran_end,
@@ -1217,38 +1249,97 @@ static int expand_cmdsubst( wchar_t *in, array_list_t *out )
break;
}
context = halloc( 0, 0 );
len1 = (paran_begin-in);
len2 = wcslen(paran_end)-1;
prev=0;
item_begin = paran_begin+1;
al_init( &sub_res );
if( !(subcmd = malloc( sizeof(wchar_t)*(paran_end-paran_begin) )))
sub_res = al_halloc( context );
if( !(subcmd = halloc( context, sizeof(wchar_t)*(paran_end-paran_begin) )))
{
al_destroy( &sub_res );
halloc_free( context );
return 0;
}
wcslcpy( subcmd, paran_begin+1, paran_end-paran_begin );
subcmd[ paran_end-paran_begin-1]=0;
exec_subshell( subcmd, &sub_res);
if( exec_subshell( subcmd, sub_res) == -1 )
{
halloc_free( context );
error( CMDSUBST_ERROR, -1, L"Unknown error while evaulating command substitution" );
return 0;
}
al_init( &tail_expand );
expand_cmdsubst( wcsdup(paran_end+1), &tail_expand );
tail_begin = paran_end + 1;
if( *tail_begin == L'[' )
{
array_list_t *slice_idx = al_halloc( context );
wchar_t *slice_end;
if( parse_slice( tail_begin, &slice_end, slice_idx ) )
{
halloc_free( context );
error( SYNTAX_ERROR, -1, L"Invalid index value" );
return 0;
}
else
{
array_list_t *sub_res2 = al_halloc( context );
tail_begin = slice_end;
for( i=0; i<al_get_count( slice_idx ); i++ )
{
long idx = al_get_long( slice_idx, i );
if( idx < 0 )
{
idx = al_get_count( sub_res ) + idx + 1;
}
if( idx < 1 || idx > al_get_count( sub_res ) )
{
halloc_free( context );
error( SYNTAX_ERROR, -1, L"Invalid index value" );
return 0;
}
idx = idx-1;
al_push( sub_res2, al_get( sub_res, idx ) );
// debug( 0, L"Pushing item '%ls' with index %d onto sliced result", al_get( sub_res, idx ), idx );
al_set( sub_res, idx, 0 );
}
al_foreach( sub_res, &free );
sub_res = sub_res2;
}
}
for( i=0; i<al_get_count( &sub_res ); i++ )
tail_expand = al_halloc( context );
/*
Recursively call ourselves to expand any remaining command
substitutions. The result of this recursive call usiung the tail
of the string is inserted into the tail_expand array list
*/
expand_cmdsubst( wcsdup(tail_begin), tail_expand );
/*
Combine the result of the current command substitution with the
result of the recursive tail expansion
*/
for( i=0; i<al_get_count( sub_res ); i++ )
{
wchar_t *sub_item, *sub_item2;
sub_item = (wchar_t *)al_get( &sub_res, i );
sub_item = (wchar_t *)al_get( sub_res, i );
sub_item2 = escape( sub_item, 1 );
free(sub_item);
int item_len = wcslen( sub_item2 );
for( j=0; j<al_get_count( &tail_expand ); j++ )
for( j=0; j<al_get_count( tail_expand ); j++ )
{
string_buffer_t whole_item;
wchar_t *tail_item = (wchar_t *)al_get( &tail_expand, j );
wchar_t *tail_item = (wchar_t *)al_get( tail_expand, j );
sb_init( &whole_item );
@@ -1265,12 +1356,8 @@ static int expand_cmdsubst( wchar_t *in, array_list_t *out )
}
free(in);
al_destroy( &sub_res );
al_foreach( &tail_expand, &free );
al_destroy( &tail_expand );
free( subcmd );
al_foreach( tail_expand, &free );
halloc_free( context );
return 1;
}

View File

@@ -139,7 +139,7 @@ enum
\param out The list to which the result will be appended.
\return One of EXPAND_OK, EXPAND_ERROR, EXPAND_WILDCARD_MATCH and EXPAND_WILDCARD_NO_MATCH. EXPAND_WILDCARD_NO_MATCH and EXPAND_WILDCARD_MATCH are normal exit conditions used only on strings containing wildcards to tell if the wildcard produced any matches.
*/
int expand_string( void *context, wchar_t *in, array_list_t *out, int flag );
__warn_unused int expand_string( void *context, wchar_t *in, array_list_t *out, int flag );
/**
expand_one is identical to expand_string, except it will fail if in

View File

@@ -1072,7 +1072,22 @@ int _nl_msg_cat_cntr=0;
#ifndef HAVE_KILLPG
int killpg( int pgr, int sig )
{
assert( pgr > 0 );
assert( pgr > 1 );
return kill( -pgr, sig );
}
#endif
#ifndef HAVE_WORKING_GETOPT_LONG
int getopt_long( int argc,
char * const argv[],
const char *optstring,
const struct option *longopts,
int *longindex )
{
return getopt( argc, argv, optstring );
}
#endif

View File

@@ -9,6 +9,8 @@
#include <wchar.h>
#include <limits.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#ifndef WCHAR_MAX
/**
@@ -47,6 +49,10 @@ typedef char tputs_arg_t;
#define SIGIO SIGUSR1
#endif
#ifndef SIGWINCH
#define SIGWINCH SIGUSR2
#endif
#ifndef HAVE_WINSIZE
struct winsize
{
@@ -304,7 +310,7 @@ size_t wcslcpy( wchar_t *dst, const wchar_t *src, size_t siz );
/**
BSD del_curterm seems to do a double-free. We redefine it as a no-op
*/
#define del_curterm(oterm) 1
#define del_curterm(oterm) OK
#endif
#ifndef HAVE_LRAND48_R
@@ -385,5 +391,37 @@ extern int _nl_msg_cat_cntr;
int killpg( int pgr, int sig );
#endif
#ifndef HAVE_WORKING_GETOPT_LONG
struct option
{
const char *name;
int has_arg;
int *flag;
int val;
}
;
#ifndef no_argument
#define no_argument 0
#endif
#ifndef required_argument
#define required_argument 1
#endif
#ifndef optional_argument
#define optional_argument 2
#endif
int getopt_long(int argc,
char * const argv[],
const char *optstring,
const struct option *longopts,
int *longindex);
#endif
#endif

View File

@@ -6,9 +6,9 @@ Release: 0%{?dist}
License: GPL
Group: System Environment/Shells
URL: http://roo.no-ip.org/fish/
URL: http://www.fishshell.org
Source0: http://roo.no-ip.org/%{name}/files/%{version}/%{name}-%{version}.tar.bz2
Source0: http://www.fishshell.org/files/%{version}/%{name}-%{version}.tar.bz2
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: ncurses-devel gettext groff
@@ -133,14 +133,14 @@ fi
%attr(0755,root,root) %_bindir/count
# Configuration files
%config %_sysconfdir/fish
%config %_sysconfdir/fish_inputrc
%dir %_sysconfdir/fish.d
%config %_sysconfdir/fish.d/fish_*.fish
%config %_sysconfdir/fish/config.fish
%config %_sysconfdir/fish/fish_inputrc
%dir %_sysconfdir/fish
# Non-configuration initialization files
%dir %_datadir/fish
%_datadir/fish/fish
%_datadir/fish/config.fish
%_datadir/fish/config_interactive.fish
# Program specific tab-completions
%dir %_datadir/fish/completions
@@ -155,6 +155,9 @@ fi
%changelog
* Sat Oct 14 2006 Axel Liljencrantz<axel@liljencrantz.se> 1.22.0-0
- Update names of various configuration files
* Fri Aug 4 2006 Axel Liljencrantz<axel@liljencrantz.se> 1.21.10-4
- Add better translation finding code from fedora spec to main spec. Thank you to Michael Schwendt.
- Add missing dependency libXext-devel.

View File

@@ -74,6 +74,33 @@ enum
}
;
enum
{
/*
Returnd by the pager if no more displaying is needed
*/
PAGER_DONE,
/*
Returned by the pager if the completions would not fit in the specified number of columns
*/
PAGER_RETRY,
/*
Returned by the pager if the terminal changes size
*/
PAGER_RESIZE
}
;
/**
The minimum number of columns the terminal may have for fish_pager to not refuse showing the completions
*/
#define PAGER_MIN_WIDTH 16
/**
The maximum number of columns of completion to attempt to fit onto the screen
*/
#define PAGER_MAX_COLS 6
/**
This struct should be continually updated by signals as the term
resizes, and as such always contain the correct current size.
@@ -81,11 +108,23 @@ enum
static struct winsize termsize;
/**
The termios modes the terminal had when the program started. These
should be restored on exit
*/
static struct termios saved_modes;
static struct termios pager_modes;
/**
This flag is set to 1 of we have sent the enter_ca_mode terminfo
sequence to save the previous terminal contents.
*/
static int is_ca_mode = 0;
/**
This buffer_t is used to buffer the output of the pager to improve
screen redraw performance bu cutting down the number of write()
calls to only one.
*/
static buffer_t *pager_buffer;
/**
@@ -101,7 +140,13 @@ static wchar_t *hightlight_var[] =
}
;
/**
This string_buffer_t contains the text that should be sent back to the calling program
*/
static string_buffer_t out_buff;
/**
This is the file to which the output text should be sent. It is really a pipe.
*/
static FILE *out_file;
/**
@@ -136,6 +181,10 @@ typedef struct
}
comp_t;
/**
This function translates from a highlight code to a specific color
by check invironement variables
*/
static int get_color( int highlight )
{
wchar_t *val;
@@ -160,6 +209,12 @@ static int get_color( int highlight )
return output_color_code( val );
}
/**
This function calculates the minimum width for each completion
entry in the specified array_list. This width depends on the
terminal size, so this function should be called when the terminal
changes size.
*/
static void recalc_width( array_list_t *l, const wchar_t *prefix )
{
int i;
@@ -173,6 +228,10 @@ static void recalc_width( array_list_t *l, const wchar_t *prefix )
}
/**
Test if the specified character sequence has been entered on the
keyboard
*/
static int try_sequence( char *seq )
{
int j, k;
@@ -196,6 +255,9 @@ static int try_sequence( char *seq )
return 0;
}
/**
Read a character from keyboard
*/
static wint_t readch()
{
struct mapping
@@ -255,26 +317,39 @@ static wint_t readch()
return input_common_readch(0);
}
/**
Write specified character to the output buffer \c pager_buffer
*/
static int pager_buffered_writer( char c)
{
b_append( pager_buffer, &c, 1 );
return 0;
}
/**
Flush \c pager_buffer to stdout
*/
static void pager_flush()
{
write( 1, pager_buffer->buff, pager_buffer->used );
pager_buffer->used = 0;
}
/**
Print the specified string, but use at most the specified amount of
space. If the whole string can't be fitted, ellipsize it.
\param str the string to print
\param max the maximum space that may be used for printing
\param has_more if this flag is true, this is not the entire string, and the string should be ellisiszed even if the string fits but takes up the whole space.
*/
static int print_max( const wchar_t *str, int max, int has_more )
{
int i;
int written = 0;
for( i=0; str[i]; i++ )
{
if( written + wcwidth(str[i]) > max )
break;
if( ( written + wcwidth(str[i]) == max) && (has_more || str[i+1]) )
@@ -290,6 +365,9 @@ static int print_max( const wchar_t *str, int max, int has_more )
return written;
}
/**
Print the specified item using at the specified amount of space
*/
static void completion_print_item( const wchar_t *prefix, comp_t *c, int width )
{
int comp_width=0, desc_width=0;
@@ -423,7 +501,7 @@ static void completion_print( int cols,
\param is_quoted whether the completions should be quoted
\param l the list of completions
\return zero if the specified number of columns do not fit, no-zero otherwise
\return one of PAGER_RETRY, PAGER_DONE and PAGER_RESIZE
*/
static int completion_try_print( int cols,
@@ -434,11 +512,11 @@ static int completion_try_print( int cols,
/*
The calculated preferred width of each column
*/
int pref_width[32];
int pref_width[PAGER_MAX_COLS];
/*
The calculated minimum width of each column
*/
int min_width[32];
int min_width[PAGER_MAX_COLS];
/*
If the list can be printed with this width, width will contain the width of each column
*/
@@ -454,13 +532,13 @@ static int completion_try_print( int cols,
int pref_tot_width=0;
int min_tot_width = 0;
int res=0;
int res=PAGER_RETRY;
/*
Skip completions on tiny terminals
*/
if( termsize.ws_col < 16 )
return 1;
if( termsize.ws_col < PAGER_MIN_WIDTH )
return PAGER_DONE;
memset( pref_width, 0, sizeof(pref_width) );
memset( min_width, 0, sizeof(min_width) );
@@ -545,11 +623,9 @@ static int completion_try_print( int cols,
}
}
// return cols==1;
if( print )
{
res=1;
res=PAGER_DONE;
if( rows < termsize.ws_row )
{
/* List fits on screen. Print it and leave */
@@ -583,15 +659,19 @@ static int completion_try_print( int cols,
*/
while(do_loop)
{
wchar_t msg[10];
int percent = 100*pos/(rows-termsize.ws_row+1);
string_buffer_t msg;
sb_init( &msg );
set_color( FISH_COLOR_BLACK,
get_color(HIGHLIGHT_PAGER_PROGRESS) );
swprintf( msg, 12,
L" %ls(%d%%) \r",
percent==100?L"":(percent >=10?L" ": L" "),
percent );
writestr(msg);
sb_printf( &msg,
_(L" %d to %d of %d \r"),
pos,
pos+termsize.ws_row-1,
rows );
writestr((wchar_t *)msg.buff);
sb_destroy( &msg );
set_color( FISH_COLOR_NORMAL, FISH_COLOR_NORMAL );
pager_flush();
int c = readch();
@@ -689,7 +769,7 @@ static int completion_try_print( int cols,
case R_NULL:
{
do_loop=0;
res=2;
res=PAGER_RESIZE;
break;
}
@@ -878,15 +958,28 @@ static void handle_winch( int sig )
}
}
/**
The callback function that the keyboard reading function calls when
an interrupt occurs. This makes sure that R_NULL is returned at
once when an interrupt has occured.
*/
static int interrupt_handler()
{
return R_NULL;
}
/**
Initialize various subsystems. This also closes stdin and replaces
it with a copy of stderr, so the reading of completion strings must
be done before init is called.
*/
static void init()
{
struct sigaction act;
static struct termios pager_modes;
program_name = L"fish_pager";
wsetlocale( LC_ALL, L"" );
@@ -903,21 +996,21 @@ static void init()
{
if( dup2( 2, 1 ) == -1 )
{
debug( 0, L"Could not set up output file descriptors for pager" );
debug( 0, _(L"Could not set up output file descriptors for pager") );
exit( 1 );
}
if( dup2( in, 0 ) == -1 )
{
debug( 0, L"Could not set up input file descriptors for pager %d", in );
debug( 0, _(L"Could not set up input file descriptors for pager %d"), in );
exit( 1 );
}
}
else
{
debug( 0, L"Could not open tty for pager" );
{
debug( 0, _(L"Could not open tty for pager") );
exit( 1 );
}
}
out_file = fdopen( out, "w" );
/**
@@ -925,13 +1018,12 @@ static void init()
*/
sb_init( &out_buff );
halloc_util_init();
env_universal_init( 0, 0, 0, 0);
input_common_init( &interrupt_handler );
output_set_writer( &pager_buffered_writer );
pager_buffer = halloc( global_context, sizeof( buffer_t ) );
halloc_register_function( global_context, (void (*)(void *))&b_destroy, pager_buffer );
sigemptyset( & act.sa_mask );
act.sa_flags=0;
act.sa_handler=SIG_DFL;
@@ -944,7 +1036,7 @@ static void init()
}
handle_winch( 0 ); /* Set handler for window change events */
tcgetattr(0,&pager_modes); /* get the current terminal modes */
memcpy( &saved_modes,
&pager_modes,
@@ -966,17 +1058,21 @@ static void init()
if( setupterm( 0, STDOUT_FILENO, 0) == ERR )
{
debug( 0, L"Could not set up terminal" );
debug( 0, _(L"Could not set up terminal") );
exit(1);
}
}
void destroy()
/**
Free memory used by various subsystems.
*/
static void destroy()
{
env_universal_destroy();
input_common_destroy();
halloc_util_destroy();
wutil_destroy();
if( del_curterm( cur_term ) == ERR )
{
debug( 0, _(L"Error while closing terminfo") );
@@ -986,43 +1082,58 @@ void destroy()
fclose( out_file );
}
#define BUFSIZE 1024
void read_array( FILE* file, array_list_t *comp )
/**
Read lines of input from the specified file, unescape them and
insert them into the specified list.
*/
static void read_array( FILE* file, array_list_t *comp )
{
char buffer[BUFSIZE];
buffer_t buffer;
int c;
int i;
char cc;
wchar_t *wcs, *unescaped;
b_init( &buffer );
while( !feof( file ) )
{
i = 0;
while( i < BUFSIZE-1 )
buffer.used=0;
while( 1 )
{
c = getc( file );
if( c == EOF )
{
return;
break;
}
if( c == '\n' )
{
break;
}
cc=c;
buffer[ i++ ] = c;
b_append( &buffer, &cc, 1 );
}
buffer[ i ] = '\0';
wcs = str2wcs( buffer );
if( wcs )
if( buffer.used )
{
unescaped = unescape( wcs, 0 );
al_push( comp, unescaped );
free( wcs );
cc=0;
b_append( &buffer, &cc, 1 );
wcs = str2wcs( buffer.buff );
if( wcs )
{
unescaped = unescape( wcs, 0 );
al_push( comp, unescaped );
free( wcs );
}
}
}
b_destroy( &buffer );
}
int main( int argc, char **argv )
@@ -1031,19 +1142,26 @@ int main( int argc, char **argv )
int is_quoted=0;
array_list_t *comp;
wchar_t *prefix;
/*
This initialization is made early, so that the other init code
can use global_context for memory managment
*/
halloc_util_init();
if( argc < 3 )
{
debug( 0, L"Insufficient arguments" );
debug( 0, _(L"Insufficient arguments") );
}
else
{
comp = al_halloc( global_context );
prefix = str2wcs( argv[2] );
is_quoted = strcmp( "1", argv[1] )==0;
is_quoted = 0;
debug( 3, L"prefix is '%ls'", prefix );
// debug( 3, L"prefix is '%ls'", prefix );
if( argc > 3 )
{
@@ -1061,28 +1179,44 @@ int main( int argc, char **argv )
read_array( stdin, comp );
}
init();
mangle_descriptions( comp );
if( wcscmp( prefix, L"-" ) == 0 )
join_completions( comp );
join_completions( comp );
mangle_completions( comp, prefix );
for( i = 6; i>0; i-- )
/**
Try to print the completions. Start by trying to print the
list in PAGER_MAX_COLS columns, if the completions won't
fit, reduce the number of columns by one. Printing a single
column never fails.
*/
for( i = PAGER_MAX_COLS; i>0; i-- )
{
switch( completion_try_print( i, prefix, is_quoted, comp ) )
{
case 0:
case PAGER_RETRY:
break;
case 1:
case PAGER_DONE:
i=0;
break;
case 2:
i=7;
case PAGER_RESIZE:
/*
This means we got a resize event, so we start
over from the beginning. Since it the screen got
bigger, we might be able to fit all completions
on-screen.
*/
i=PAGER_MAX_COLS+1;
break;
}
}
}
free(prefix );

View File

@@ -88,14 +88,6 @@ static void err( wchar_t *blah, ... )
wprintf( L"\n" );
}
/**
Print ok message
*/
static void ok()
{
wprintf( L"OK\n" );
}
/**
Compare two pointers
*/
@@ -120,7 +112,7 @@ static void pq_test( int elements )
for( i=0; i<elements; i++ )
{
int foo = rand() % 100;
long foo = rand() % 100;
// printf( "Adding %d\n", foo );
pq_put( &q, (void *)foo );
count[foo]++;
@@ -130,7 +122,7 @@ static void pq_test( int elements )
for( i=0; i<elements; i++ )
{
int pos = (int)pq_get( &q );
long pos = (long)pq_get( &q );
count[ pos ]--;
if( pos > prev )
err( L"Wrong order of elements in priority_queue_t" );
@@ -201,7 +193,7 @@ static int hash_func( void *data )
/* srand( (int)data );
return rand();
*/
int foo = (int)data;
int foo = (int)(long)data;
return 127*((foo^0xefc7e214)) ^(foo<<11);
}
@@ -217,9 +209,9 @@ static int compare_func( void *key1, void *key2 )
/**
Hashtable test
*/
static int hash_test( int elements )
static int hash_test( long elements )
{
int i;
long i;
int res=1;
hash_table_t h;
@@ -228,17 +220,17 @@ static int hash_test( int elements )
for( i=1; i< elements+1; i++ )
{
hash_put( &h, (void*)i, (void*)100-i );
hash_put( &h, (void*)i, (void*)100l-i );
}
for( i=1; i< elements+1; i++ )
{
if( (int)hash_get( &h, (void*)i ) != (100-i) )
if( (long)hash_get( &h, (void*)i ) != (100l-i) )
{
err( L"Key %d gave data %d, expected data %d",
i,
(int)hash_get( &h, (void*)i ),
100-i );
(long)hash_get( &h, (void*)i ),
100l-i );
res = 0;
break;
@@ -271,7 +263,7 @@ static int hash_test( int elements )
for( i=1; i<elements+1; i++ )
{
if( hash_contains( &h, (void*)i) != (i+1)%2 )
if( hash_contains( &h, (void*)i) != (i+1l)%2l )
{
if( i%2 )
err( L"Key %d remains, should be deleted",
@@ -484,43 +476,43 @@ static void test_parser()
say( L"Testing null input to parser" );
if( !parser_test( 0, 0, 0 ) )
if( !parser_test( 0, 0, 0, 0 ) )
{
err( L"Null input to parser_test undetected" );
}
say( L"Testing block nesting" );
if( !parser_test( L"if; end", 0, 0 ) )
if( !parser_test( L"if; end", 0, 0, 0 ) )
{
err( L"Incomplete if statement undetected" );
}
if( !parser_test( L"if test; echo", 0, 0 ) )
if( !parser_test( L"if test; echo", 0, 0, 0 ) )
{
err( L"Missing end undetected" );
}
if( !parser_test( L"if test; end; end", 0, 0 ) )
if( !parser_test( L"if test; end; end", 0, 0, 0 ) )
{
err( L"Unbalanced end undetected" );
}
say( L"Testing detection of invalid use of builtin commands" );
if( !parser_test( L"case foo", 0, 0 ) )
if( !parser_test( L"case foo", 0, 0, 0 ) )
{
err( L"'case' command outside of block context undetected" );
}
if( !parser_test( L"switch ggg; if true; case foo;end;end", 0, 0 ) )
if( !parser_test( L"switch ggg; if true; case foo;end;end", 0, 0, 0 ) )
{
err( L"'case' command outside of switch block context undetected" );
}
if( !parser_test( L"else", 0, 0 ) )
if( !parser_test( L"else", 0, 0, 0 ) )
{
err( L"'else' command outside of conditional block context undetected" );
}
if( !parser_test( L"break", 0, 0 ) )
if( !parser_test( L"break", 0, 0, 0 ) )
{
err( L"'break' command outside of loop block context undetected" );
}
if( !parser_test( L"exec ls|less", 0, 0 ) || !parser_test( L"echo|return", 0, 0 ))
if( !parser_test( L"exec ls|less", 0, 0, 0 ) || !parser_test( L"echo|return", 0, 0, 0 ))
{
err( L"Invalid pipe command undetected" );
}
@@ -553,7 +545,11 @@ static int expand_test( const wchar_t *in, int flags, ... )
wchar_t *arg;
al_init( &out );
expand_string( 0, wcsdup(in), &out, flags);
if( expand_string( 0, wcsdup(in), &out, flags) )
{
}
va_start( va, flags );

156
fishd.c
View File

@@ -17,10 +17,12 @@ set_export KEY:VALUE
These commands update the value of a variable. The only difference
between the two is that <tt>set_export</tt>-variables should be
exported to children of the process using them. The variable value may
be escaped using C-style backslash escapes. In fact, this is required
for newline characters, which would otherwise be interpreted as end of
command.
exported to children of the process using them. When sending messages,
all values below 32 or above 127 must be escaped using C-style
backslash escapes. This means that the over the wire protocol is
ASCII. However, any conforming reader must also accept non-ascii
characters and interpret them as UTF-8. Lines containing invalid UTF-8
escape sequences must be ignored entirely.
<pre>erase KEY
</pre>
@@ -68,6 +70,9 @@ time the original barrier request was sent have been received.
#include "common.h"
#include "wutil.h"
#include "env_universal_common.h"
#include "halloc.h"
#include "halloc_util.h"
#include "path.h"
/**
Maximum length of socket filename
@@ -98,7 +103,7 @@ time the original barrier request was sent have been received.
/**
The name of the save file. The hostname is appended to this.
*/
#define FILE ".fishd."
#define FILE "fishd."
/**
Maximum length of hostname. Longer hostnames are truncated
@@ -386,23 +391,108 @@ static void daemonize()
}
/**
Get environment variable value. The resulting string needs to be free'd.
*/
static wchar_t *fishd_env_get( wchar_t *key )
{
char *nres, *nkey;
wchar_t *res;
nkey = wcs2str( key );
nres = getenv( nkey );
free( nkey );
if( nres )
{
return str2wcs( nres );
}
else
{
res = env_universal_common_get( key );
if( res )
res = wcsdup( res );
return env_universal_common_get( key );
}
}
/**
Get the configuration directory. The resulting string needs to be
free'd. This is mostly the same code as path_get_config(), but had
to be rewritten to avoid dragging in additional library
dependencies.
*/
static wchar_t *fishd_get_config()
{
wchar_t *xdg_dir, *home;
int done = 0;
wchar_t *res = 0;
xdg_dir = fishd_env_get( L"XDG_CONFIG_HOME" );
if( xdg_dir )
{
res = wcsdupcat( xdg_dir, L"/fish" );
if( !create_directory( res ) )
{
done = 1;
}
else
{
free( res );
}
free( xdg_dir );
}
else
{
home = fishd_env_get( L"HOME" );
if( home )
{
res = wcsdupcat( home, L"/.config/fish" );
if( !create_directory( res ) )
{
done = 1;
}
else
{
free( res );
}
free( home );
}
}
if( done )
{
return res;
}
else
{
debug( 0, _(L"Unable to create a configuration directory for fish. Your personal settings will not be saved. Please set the $XDG_CONFIG_HOME variable to a directory where the current user has write access." ));
return 0;
}
}
/**
Load or save all variables
*/
void load_or_save( int save)
static void load_or_save( int save)
{
struct passwd *pw;
char *name;
char *dir = getenv( "HOME" );
wchar_t *wdir = fishd_get_config();
char *dir;
char hostname[HOSTNAME_LEN];
connection_t c;
int fd;
if( !dir )
if( !wdir )
{
pw = getpwuid( getuid() );
dir = pw->pw_dir;
return;
}
dir = wcs2str( wdir );
free( wdir );
gethostname( hostname, HOSTNAME_LEN );
name = malloc( strlen(dir)+ strlen(FILE)+ strlen(hostname) + 2 );
@@ -410,15 +500,19 @@ void load_or_save( int save)
strcat( name, "/" );
strcat( name, FILE );
strcat( name, hostname );
free( dir );
debug( 4, L"Open file for %s: '%s'",
save?"saving":"loading",
name );
c.fd = open( name, save?(O_CREAT | O_TRUNC | O_WRONLY):O_RDONLY, 0600);
fd = open( name, save?(O_CREAT | O_TRUNC | O_WRONLY):O_RDONLY, 0600);
free( name );
if( c.fd == -1 )
if( fd == -1 )
{
debug( 1, L"Could not open load/save file. No previous saves?" );
wperror( L"open" );
@@ -426,9 +520,7 @@ void load_or_save( int save)
}
debug( 4, L"File open on fd %d", c.fd );
sb_init( &c.input );
memset (&c.wstate, '\0', sizeof (mbstate_t));
q_init( &c.unsent );
connection_init( &c, fd );
if( save )
{
@@ -439,9 +531,7 @@ void load_or_save( int save)
else
read_message( &c );
q_destroy( &c.unsent );
sb_destroy( &c.input );
close( c.fd );
connection_destroy( &c );
}
/**
@@ -485,6 +575,8 @@ int main( int argc, char ** argv )
int update_count=0;
fd_set read_fd, write_fd;
halloc_util_init();
program_name=L"fishd";
wsetlocale( LC_ALL, L"" );
@@ -494,7 +586,6 @@ int main( int argc, char ** argv )
*/
while( 1 )
{
#ifdef HAVE_GETOPT_LONG
static struct option
long_options[] =
{
@@ -520,11 +611,6 @@ int main( int argc, char ** argv )
long_options,
&opt_index );
#else
int opt = getopt( argc,
argv,
GETOPT_STRING );
#endif
if( opt == -1 )
break;
@@ -553,7 +639,7 @@ int main( int argc, char ** argv )
connection_t *c;
int res;
t=sizeof( remote );
t = sizeof( remote );
FD_ZERO( &read_fd );
FD_ZERO( &write_fd );
@@ -611,12 +697,8 @@ int main( int argc, char ** argv )
else
{
connection_t *new = malloc( sizeof(connection_t));
new->fd = child_socket;
connection_init( new, child_socket );
new->next = conn;
q_init( &new->unsent );
new->killme=0;
sb_init( &new->input );
memset (&new->wstate, '\0', sizeof (mbstate_t));
send( new->fd, GREETING, strlen(GREETING), MSG_DONTWAIT );
enqueue_all( new );
conn=new;
@@ -660,9 +742,6 @@ int main( int argc, char ** argv )
{
debug( 4, L"Close connection %d", c->fd );
close(c->fd );
sb_destroy( &c->input );
while( !q_empty( &c->unsent ) )
{
message_t *msg = (message_t *)q_get( &c->unsent );
@@ -671,7 +750,7 @@ int main( int argc, char ** argv )
free( msg );
}
q_destroy( &c->unsent );
connection_destroy( c );
if( prev )
{
prev->next=c->next;
@@ -692,13 +771,16 @@ int main( int argc, char ** argv )
c=c->next;
}
}
if( !conn )
{
debug( 0, L"No more clients. Quitting" );
save();
env_universal_common_destroy();
exit(0);
c=c->next;
break;
}
}
halloc_util_destroy();
}

View File

@@ -44,10 +44,6 @@ typedef struct
Line where definition started
*/
int definition_offset;
/**
Flag for specifying functions which are actually key bindings
*/
int is_binding;
/**
Flag for specifying that this function was automatically loaded
@@ -169,8 +165,7 @@ void function_destroy()
void function_add( const wchar_t *name,
const wchar_t *val,
const wchar_t *desc,
array_list_t *events,
int is_binding )
array_list_t *events )
{
int i;
wchar_t *cmd_end;
@@ -186,13 +181,8 @@ void function_add( const wchar_t *name,
d->cmd = wcsdup( val );
cmd_end = d->cmd + wcslen(d->cmd)-1;
while( (cmd_end>d->cmd) && wcschr( L"\n\r\t ", *cmd_end ) )
{
*cmd_end-- = 0;
}
d->desc = desc?wcsdup( desc ):0;
d->is_binding = is_binding;
d->definition_file = intern(reader_current_filename());
d->is_autoload = is_autoload;
@@ -319,9 +309,7 @@ static void get_names_internal( void *key,
void *aux )
{
wchar_t *name = (wchar_t *)key;
function_data_t *f = (function_data_t *)val;
if( name[0] != L'_' && !f->is_binding && !al_contains_str( (array_list_t *)aux, name ) )
if( name[0] != L'_' && !al_contains_str( (array_list_t *)aux, name ) )
{
al_push( (array_list_t *)aux, name );
}
@@ -365,7 +353,6 @@ const wchar_t *function_get_definition_file( const wchar_t *argv )
CHECK( argv, 0 );
load( argv );
data = (function_data_t *)hash_get( &function, argv );
if( data == 0 )
return 0;
@@ -380,7 +367,6 @@ int function_get_definition_offset( const wchar_t *argv )
CHECK( argv, -1 );
load( argv );
data = (function_data_t *)hash_get( &function, argv );
if( data == 0 )
return -1;

View File

@@ -27,8 +27,7 @@ void function_destroy();
void function_add( const wchar_t *name,
const wchar_t *val,
const wchar_t *desc,
array_list_t *events,
int is_binding );
array_list_t *events );
/**
Remove the function with the specified name.

View File

@@ -24,9 +24,12 @@
#define HALLOC_BLOCK_SIZE 128
/**
Maximum size of trailing halloc space to refuse to discard
Maximum size of trailing halloc space to refuse to discard. This is
set to be larger on 64-bit platforms, since we don't want to get
'stuck' with an unusably small slice of memory, and what is
unusably small often depends on pointer size.
*/
#define HALLOC_SCRAP_SIZE 16
#define HALLOC_SCRAP_SIZE (4*sizeof(void *))
#ifdef HALLOC_DEBUG
/**
@@ -71,24 +74,32 @@ typedef struct halloc
/**
Amount of free space in the scratch area
*/
size_t scratch_free;
#if __STDC_VERSION__ < 199901L
/**
The actual data. MAde to be of type long long to make sure memory alignment is in order.
*/
long long data[1]; // Waste one byte on non-C99 compilers... :-(
#else
long long data[];
#endif
ssize_t scratch_free;
}
halloc_t;
static void *align_ptr( void *in )
{
unsigned long step = maxi(sizeof(double),sizeof(void *));
unsigned long inc = step-1;
unsigned long long_in = (long)in;
unsigned long long_out = ((long_in+inc)/step)*step;
return (void *)long_out;
}
static size_t align_sz( size_t in )
{
size_t step = maxi(sizeof(double),sizeof(void *));
size_t inc = step-1;
return ((in+inc)/step)*step;
}
/**
Get the offset of the halloc structure before a data block
*/
static halloc_t *halloc_from_data( void *data )
{
return (halloc_t *)(((char *)data) - sizeof( halloc_t ) );
return (halloc_t *)(((char *)data) - align_sz(sizeof( halloc_t ) ));
}
/**
@@ -104,7 +115,7 @@ static void late_free( void *data)
statistics, like number of allocations and number of internal calls
to malloc.
*/
static void woot()
static void halloc_report()
{
if( getpid() == pid )
{
@@ -115,25 +126,40 @@ static void woot()
}
#endif
void *halloc( void *context, size_t size )
{
halloc_t *me, *parent;
if( context )
{
void *res;
void *aligned;
#ifdef HALLOC_DEBUG
if( !child_count )
{
pid = getpid();
atexit( woot );
atexit( &halloc_report );
}
child_count++;
child_size += size;
#endif
parent = halloc_from_data( context );
/*
Align memory address
*/
aligned = align_ptr( parent->scratch );
parent->scratch_free -= (aligned-parent->scratch);
if( parent->scratch_free < 0 )
parent->scratch_free=0;
parent->scratch = aligned;
if( size <= parent->scratch_free )
{
res = parent->scratch;
@@ -169,18 +195,18 @@ void *halloc( void *context, size_t size )
}
else
{
me = (halloc_t *)calloc( 1, sizeof(halloc_t) + size + HALLOC_BLOCK_SIZE );
me = (halloc_t *)calloc( 1, align_sz(sizeof(halloc_t)) + align_sz(size) + HALLOC_BLOCK_SIZE );
if( !me )
return 0;
#ifdef HALLOC_DEBUG
parent_count++;
#endif
me->scratch = ((char *)me) + sizeof(halloc_t) + size;
me->scratch = ((char *)me) + align_sz(sizeof(halloc_t)) + align_sz(size);
me->scratch_free = HALLOC_BLOCK_SIZE;
al_init( &me->children );
return &me->data;
return ((char *)me) + align_sz(sizeof(halloc_t));
}
}

View File

@@ -11,7 +11,8 @@
/**
Allocate new memory using specified parent memory context. Context
_must_ be either 0 or the result of a previous call to halloc.
_must_ be either 0 or the result of a previous call to halloc. The
resulting memory is set to zero.
If \c context is null, the resulting block is a root block, and
must be freed with a call to halloc_free().

View File

@@ -33,6 +33,7 @@
#include "halloc.h"
#include "halloc_util.h"
#include "wildcard.h"
#include "path.h"
/**
Number of elements in the highlight_var array
@@ -559,8 +560,7 @@ void highlight_shell( wchar_t * buff,
{
int last_type = tok_last_type( &tok );
int prev_argc=0;
switch( last_type )
{
case TOK_STRING:
@@ -589,7 +589,7 @@ void highlight_shell( wchar_t * buff,
EXPAND_SKIP_CMDSUBST );
if( dir )
{
if( !parser_cdpath_get( context, dir ) )
if( !path_get_cdpath( context, dir ) )
{
color[ tok_get_pos( &tok ) ] = HIGHLIGHT_ERROR;
}
@@ -624,7 +624,7 @@ void highlight_shell( wchar_t * buff,
int is_subcommand = 0;
int mark = tok_get_pos( &tok );
color[ tok_get_pos( &tok ) ] = HIGHLIGHT_COMMAND;
if( parser_is_subcommand( cmd ) )
{
tok_next( &tok );
@@ -672,13 +672,13 @@ void highlight_shell( wchar_t * buff,
/*
Check if this is a regular command
*/
is_cmd |= !!(tmp=parser_get_filename( context, cmd ));
is_cmd |= !!(tmp=path_get_path( context, cmd ));
/*
Could not find the command. Maybe it is
a path for a implicit cd command.
*/
is_cmd |= !!(tmp=parser_cdpath_get( context, cmd ));
is_cmd |= !!(tmp=path_get_cdpath( context, cmd ));
if( is_cmd )
{
@@ -687,7 +687,7 @@ void highlight_shell( wchar_t * buff,
else
{
if( error )
al_push( error, wcsdupcat2 ( L"Unknown command \'", cmd, L"\'", 0 ));
al_push( error, wcsdupcat2 ( L"Unknown command \'", cmd, L"\'", (void *)0 ));
color[ tok_get_pos( &tok ) ] = (HIGHLIGHT_ERROR);
}
had_cmd = 1;
@@ -761,7 +761,7 @@ void highlight_shell( wchar_t * buff,
{
color[ tok_get_pos( &tok ) ] = HIGHLIGHT_ERROR;
if( error )
al_push( error, wcsdupcat2( L"Directory \'", dir, L"\' does not exist", 0 ) );
al_push( error, wcsdupcat2( L"Directory \'", dir, L"\' does not exist", (void *)0 ) );
}
}
@@ -777,7 +777,7 @@ void highlight_shell( wchar_t * buff,
{
color[ tok_get_pos( &tok ) ] = HIGHLIGHT_ERROR;
if( error )
al_push( error, wcsdupcat2( L"File \'", target, L"\' does not exist", 0 ) );
al_push( error, wcsdupcat2( L"File \'", target, L"\' does not exist", (void *)0 ) );
}
}
}

1392
history.c

File diff suppressed because it is too large Load Diff

View File

@@ -43,7 +43,7 @@ wchar_t *history_get( int idx );
void history_first();
/**
Make current point to last history item
Make current point to last history item
*/
void history_reset();
@@ -61,7 +61,7 @@ const wchar_t *history_next_match( const wchar_t *str);
of the history.
*/
void history_set_mode( wchar_t *name );
void history_set_mode( const wchar_t *name );
/**

45
input.c
View File

@@ -123,14 +123,17 @@ static const wchar_t *name_arr[] =
L"kill-word",
L"backward-kill-word",
L"dump-functions",
L"clear-screen",
L"winch",
L"exit",
L"history-token-search-backward",
L"history-token-search-forward",
L"self-insert",
L"null",
L"eof",
L"vi-arg-digit"
L"vi-arg-digit",
L"execute",
L"beginning-of-buffer",
L"end-of-buffer"
}
;
@@ -200,14 +203,17 @@ static const wchar_t code_arr[] =
R_KILL_WORD,
R_BACKWARD_KILL_WORD,
R_DUMP_FUNCTIONS,
R_CLEAR_SCREEN,
R_WINCH,
R_EXIT,
R_HISTORY_TOKEN_SEARCH_BACKWARD,
R_HISTORY_TOKEN_SEARCH_FORWARD,
R_SELF_INSERT,
R_NULL,
R_EOF,
R_VI_ARG_DIGIT
R_VI_ARG_DIGIT,
R_EXECUTE,
R_BEGINNING_OF_BUFFER,
R_END_OF_BUFFER,
}
;
@@ -1222,6 +1228,14 @@ static void add_common_bindings()
*/
for( i=0; i<3; i++ )
{
add_mapping( name[i], L"\n", L"Execute contents of commandline", L"execute" );
/*
This will make Meta-newline insert a newline, since
self-insert ignored the escape character unless it is the
only character of the sequence.
*/
add_mapping( name[i], L"\e\n", L"Meta-newline", L"self-insert" );
/*
We need alternative keybidnings for arrowkeys, since
terminfo sometimes specifies a different sequence than what
@@ -1287,6 +1301,7 @@ static void add_common_bindings()
add_escaped_mapping( name[i], (L"\\C-y"), L"Control-y", L"yank" );
add_mapping( name[i], L"", L"Any key", L"self-insert" );
}
}
/**
@@ -1310,6 +1325,8 @@ static void add_emacs_bindings()
add_escaped_mapping( L"emacs", (L"\ed"), L"Alt-d", L"forward-kill-word" );
add_terminfo_mapping( L"emacs", (key_ppage), L"Page Up", L"beginning-of-history" );
add_terminfo_mapping( L"emacs", (key_npage), L"Page Down", L"end-of-history" );
add_escaped_mapping( L"emacs", (L"\e<"), L"Alt-<", L"beginning-of-buffer" );
add_escaped_mapping( L"emacs", (L"\e>"), L"Alt->", L"end-of-buffer" );
}
/**
@@ -1390,7 +1407,7 @@ static int interrupt_handler()
/*
Tell the reader an event occured
*/
if( reader_interupted() )
if( reader_interrupted() )
{
/*
Return 3, i.e. the character read by a Control-C.
@@ -1398,7 +1415,7 @@ static int interrupt_handler()
return 3;
}
return 0;
return R_WINCH;
}
int input_init()
@@ -1411,7 +1428,7 @@ int input_init()
is_init = 1;
input_common_init( &interrupt_handler );
if( setupterm( 0, STDOUT_FILENO, 0) == ERR )
{
debug( 0, _( L"Could not set up terminal" ) );
@@ -1509,6 +1526,7 @@ static wint_t input_exec_binding( mapping *m, const wchar_t *seq )
{
switch( code )
{
case R_DUMP_FUNCTIONS:
{
for( i=0; i<repeat_count; i++ )
@@ -1519,10 +1537,17 @@ static wint_t input_exec_binding( mapping *m, const wchar_t *seq )
case R_SELF_INSERT:
{
int idx = 0;
if( seq[0] == L'\e' && seq[1] )
{
idx = 1;
}
for( i=1; i<repeat_count; i++ )
input_unreadch( seq[0] );
input_unreadch( seq[idx] );
repeat_count = 1;
return seq[0];
return seq[idx];
}
case R_VI_ARG_DIGIT:
@@ -1654,7 +1679,7 @@ wint_t input_readch()
/*
Clear the interrupted flag
*/
reader_interupted();
reader_interrupted();
/*
Search for sequence in various mapping tables

View File

@@ -39,13 +39,16 @@ enum
R_KILL_WORD,
R_BACKWARD_KILL_WORD,
R_DUMP_FUNCTIONS,
R_CLEAR_SCREEN,
R_WINCH,
R_EXIT,
R_HISTORY_TOKEN_SEARCH_BACKWARD,
R_HISTORY_TOKEN_SEARCH_FORWARD,
R_SELF_INSERT,
R_VI_ARG_DIGIT,
R_VI_DELETE_TO
R_VI_DELETE_TO,
R_EXECUTE,
R_BEGINNING_OF_BUFFER,
R_END_OF_BUFFER
}
;

View File

@@ -186,7 +186,7 @@ wchar_t input_common_readch( int timed )
int sz;
if( (b == R_NULL) || (b == R_EOF) )
if( (b >= R_NULL) && (b < R_NULL + 1000) )
return b;
bb=b;

143
kill.c
View File

@@ -29,8 +29,8 @@
#include "common.h"
#include "env.h"
#include "exec.h"
#include "parser.h"
#include "halloc.h"
#include "path.h"
/**
Maximum entries in killring
@@ -50,7 +50,7 @@ static wchar_t *cut_buffer=0;
static int has_xsel()
{
void *context = halloc(0, 0);
wchar_t *path = parser_get_filename( context, L"xsel" );
wchar_t *path = path_get_path( context, L"xsel" );
int res = !!path;
halloc_free( context );
return res;
@@ -96,8 +96,14 @@ void kill_add( wchar_t *str )
if( (disp = env_get( L"DISPLAY" )) )
{
wchar_t *escaped_str = escape( str, 1 );
wchar_t *cmd = wcsdupcat2(L"echo ", escaped_str, L"|xsel -b",0);
exec_subshell( cmd, 0 );
wchar_t *cmd = wcsdupcat2(L"echo ", escaped_str, L"|xsel -b",(void *)0);
if( exec_subshell( cmd, 0 ) == -1 )
{
/*
Do nothing on failiure
*/
}
free( cut_buffer );
free( cmd );
@@ -105,6 +111,65 @@ void kill_add( wchar_t *str )
}
}
/**
Remove the specified node from the circular list
*/
static void kill_remove_node( ll_node_t *n )
{
if( n->prev == n )
{
kill_last=kill_current = 0;
}
else
{
ll_node_t *nxt = n->prev;
while( nxt->prev != n )
{
nxt=nxt->prev;
}
nxt->prev = n->prev;
if( kill_last == n )
{
kill_last = n->prev;
}
kill_current=kill_last;
free( n->data );
free( n );
}
}
/**
Remove first match for specified string from circular list
*/
static void kill_remove( wchar_t *s )
{
ll_node_t *n, *next=0;
if( !kill_last )
{
return;
}
for( n=kill_last;
n!=kill_last || next == 0 ;
n=n->prev )
{
if( wcscmp( (wchar_t *)n->data, s ) == 0 )
{
kill_remove_node( n );
break;
}
next = n;
}
}
void kill_replace( wchar_t *old, wchar_t *new )
{
kill_remove( old );
kill_add( new );
}
wchar_t *kill_yank_rotate()
{
@@ -133,49 +198,51 @@ static void kill_check_x_buffer()
wchar_t *new_cut_buffer=0;
array_list_t list;
al_init( &list );
exec_subshell( cmd, &list );
for( i=0; i<al_get_count( &list ); i++ )
if( exec_subshell( cmd, &list ) != -1 )
{
wchar_t *next_line = escape( (wchar_t *)al_get( &list, i ), 0 );
if( i==0 )
for( i=0; i<al_get_count( &list ); i++ )
{
new_cut_buffer = next_line;
}
else
{
wchar_t *old = new_cut_buffer;
new_cut_buffer= wcsdupcat2( new_cut_buffer, L"\\n", next_line, 0 );
free( old );
free( next_line );
}
}
if( new_cut_buffer )
{
/*
The buffer is inserted with backslash escapes,
since we don't really like tabs, newlines,
etc. anyway.
*/
if( cut_buffer != 0 )
{
if( wcscmp( new_cut_buffer, cut_buffer ) == 0 )
wchar_t *next_line = escape( (wchar_t *)al_get( &list, i ), 0 );
if( i==0 )
{
free( new_cut_buffer );
new_cut_buffer = 0;
new_cut_buffer = next_line;
}
else
{
free( cut_buffer );
cut_buffer = 0;
wchar_t *old = new_cut_buffer;
new_cut_buffer= wcsdupcat2( new_cut_buffer, L"\\n", next_line, (void *)0 );
free( old );
free( next_line );
}
}
if( cut_buffer == 0 )
if( new_cut_buffer )
{
cut_buffer = new_cut_buffer;
kill_add_internal( cut_buffer );
/*
The buffer is inserted with backslash escapes,
since we don't really like tabs, newlines,
etc. anyway.
*/
if( cut_buffer != 0 )
{
if( wcscmp( new_cut_buffer, cut_buffer ) == 0 )
{
free( new_cut_buffer );
new_cut_buffer = 0;
}
else
{
free( cut_buffer );
cut_buffer = 0;
}
}
if( cut_buffer == 0 )
{
cut_buffer = new_cut_buffer;
kill_add_internal( cut_buffer );
}
}
}

6
kill.h
View File

@@ -9,6 +9,12 @@
#include <wchar.h>
/**
Replace the specified string in the killring
*/
void kill_replace( wchar_t *old, wchar_t *new );
/**
Add a string to the top of the killring
*/

94
main.c
View File

@@ -1,9 +1,9 @@
/*
Copyright (C) 2005 Axel Liljencrantz
Copyright (C) 2005-2006 Axel Liljencrantz
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.
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
@@ -58,9 +58,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "exec.h"
#include "event.h"
#include "output.h"
#include "halloc.h"
#include "halloc_util.h"
#include "history.h"
#include "path.h"
/**
The string describing the single-character options accepted by the main fish binary
@@ -75,23 +76,42 @@ static int read_init()
char cwd[4096];
wchar_t *wcwd;
wchar_t *config_dir;
wchar_t *config_dir_escaped;
void *context;
string_buffer_t *eval_buff;
if( !getcwd( cwd, 4096 ) )
{
wperror( L"getcwd" );
return 0;
}
eval( L"builtin cd " DATADIR L"/fish 2>/dev/null; and builtin . fish 2>/dev/null", 0, TOP );
eval( L"builtin cd " SYSCONFDIR L" 2>/dev/null; and builtin . fish 2>/dev/null", 0, TOP );
eval( L"builtin cd 2>/dev/null; and builtin . .fish 2>/dev/null", 0, TOP );
eval( L"builtin cd " DATADIR L"/fish 2>/dev/null; and builtin . config.fish 2>/dev/null", 0, TOP );
eval( L"builtin cd " SYSCONFDIR L"/fish 2>/dev/null; and builtin . config.fish 2>/dev/null", 0, TOP );
/*
We need to get the configuration directory before we can source the user configuration file
*/
context = halloc( 0, 0 );
eval_buff = sb_halloc( context );
config_dir = path_get_config( context );
config_dir_escaped = escape( config_dir, 1 );
sb_printf( eval_buff, L"builtin cd %ls 2>/dev/null; and builtin . config.fish 2>/dev/null", config_dir_escaped );
eval( (wchar_t *)eval_buff->buff, 0, TOP );
halloc_free( context );
free( config_dir_escaped );
if( chdir( cwd ) == -1 )
{
/*
If we can't change back to previos directory, we'll stay in
If we can't change back to previos directory, we go to
~. Should be a sane default behavior.
*/
eval( L"builtin cd", 0, TOP );
}
wcwd = str2wcs( cwd );
if( wcwd )
{
@@ -102,28 +122,15 @@ static int read_init()
return 1;
}
/**
Calls a bunch of init functions, parses the init files and then
parses commands from stdin or files, depending on arguments
*/
int main( int argc, char **argv )
static int fish_parse_opt( int argc, char **argv, char **cmd_ptr )
{
int res=1;
int force_interactive=0;
int my_optind;
int force_interactive=0;
char *cmd=0;
halloc_util_init();
wsetlocale( LC_ALL, L"" );
is_interactive_session=1;
program_name=L"fish";
while( 1 )
{
#ifdef HAVE_GETOPT_LONG
static struct option
long_options[] =
{
@@ -173,11 +180,6 @@ int main( int argc, char **argv )
long_options,
&opt_index );
#else
int opt = getopt( argc,
argv,
GETOPT_STRING );
#endif
if( opt == -1 )
break;
@@ -190,7 +192,7 @@ int main( int argc, char **argv )
case 'c':
{
cmd = optarg;
*cmd_ptr = optarg;
is_interactive_session = 0;
break;
}
@@ -213,7 +215,7 @@ int main( int argc, char **argv )
case 'h':
{
cmd = "help";
*cmd_ptr = "help";
break;
}
@@ -252,7 +254,7 @@ int main( int argc, char **argv )
case '?':
{
return 1;
exit( 1 );
}
}
@@ -262,11 +264,34 @@ int main( int argc, char **argv )
is_login |= (strcmp( argv[0], "-fish") == 0);
is_interactive_session &= (cmd == 0);
is_interactive_session &= (*cmd_ptr == 0);
is_interactive_session &= (my_optind == argc);
is_interactive_session &= isatty(STDIN_FILENO);
is_interactive_session |= force_interactive;
return my_optind;
}
/**
Calls a bunch of init functions, parses the init files and then
parses commands from stdin or files, depending on arguments
*/
int main( int argc, char **argv )
{
int res=1;
char *cmd=0;
int my_optind=0;
halloc_util_init();
wsetlocale( LC_ALL, L"" );
is_interactive_session=1;
program_name=L"fish";
my_optind = fish_parse_opt( argc, argv, &cmd );
/*
No-exec is prohibited when in interactive mode
*/
@@ -287,6 +312,7 @@ int main( int argc, char **argv )
reader_init();
history_init();
if( read_init() )
{
if( cmd != 0 )

View File

@@ -135,14 +135,10 @@ static int launch_len=0;
*/
static int launch_pos=0;
#if HAVE_GETTEXT
/**
gettext alias
*/
#define _(string) gettext(string)
#else
#define _(string) (string)
#endif
/**
Dynamically generated function, made from the documentation in doc_src.
@@ -1145,10 +1141,8 @@ static void clear_entry( void *key, void *val )
static void locale_init()
{
setlocale( LC_ALL, "" );
#if HAVE_GETTEXT
bindtextdomain( PACKAGE_NAME, LOCALEDIR );
textdomain( PACKAGE_NAME );
#endif
}
@@ -1174,7 +1168,6 @@ int main (int argc, char *argv[])
*/
while( 1 )
{
#ifdef HAVE_GETOPT_LONG
static struct option
long_options[] =
{
@@ -1228,11 +1221,6 @@ int main (int argc, char *argv[])
long_options,
&opt_index );
#else
int opt = getopt( argc,
argv,
GETOPT_STRING );
#endif
if( opt == -1 )
break;

View File

@@ -135,6 +135,11 @@ void output_set_writer( int (*writer)(char) )
out = writer;
}
int (*output_get_writer())(char)
{
return out;
}
void set_color( int c, int c2 )
{
@@ -336,34 +341,6 @@ void set_color( int c, int c2 )
}
/**
perm_left_cursor and parm_right_cursor don't seem to be properly
emulated by many terminal emulators, so we only use plain
curor_left, curor_right...
*/
void move_cursor( int steps )
{
int i;
if( !steps )
return;
if( steps < 0 ){
for( i=0; i>steps; i--)
{
writembs(cursor_left);
}
}
else
{
for( i=0; i<steps; i++)
{
writembs(cursor_right);
}
}
}
/**
Default output method, simply calls write() on stdout
*/
@@ -553,25 +530,6 @@ int write_escaped_str( const wchar_t *str, int max_len )
}
int writespace( int c )
{
if( repeat_char && strlen(repeat_char) )
{
writembs( tparm( repeat_char, ' ', c ) );
}
else
{
int i;
for( i=0; i<c; i++ )
{
out( ' ' );
}
}
return 0;
}
int output_color_code( const wchar_t *val )
{
int j, i, color=FISH_COLOR_NORMAL;

View File

@@ -82,7 +82,7 @@ void set_color( int c, int c2 );
int writembs( char *str );
/**
Write a wide character to fd 1.
Write a wide character using the output method specified using output_set_writer().
*/
int writech( wint_t ch );
@@ -102,23 +102,11 @@ void writestr_ellipsis( const wchar_t *str, int max_width );
*/
int write_escaped_str( const wchar_t *str, int max_len );
/**
parm_ich seems to often be undefined, so we use this
workalike. Writes the specified number of spaces.
*/
int writespace( int c );
/**
Return the internal color code representing the specified color
*/
int output_color_code( const wchar_t *val );
/**
perm_left_cursor and parm_right_cursor don't seem to be defined
very often so we use cursor_left and cursor_right as a fallback.
*/
void move_cursor( int steps );
/**
This is for writing process notification messages. Has to write to
stdout, so clr_eol and such functions will work correctly. Not an
@@ -134,5 +122,9 @@ int writeb( tputs_arg_t b );
*/
void output_set_writer( int (*writer)(char) );
//typedef int (*func_ptr_t)(char);
int (*output_get_writer())(char) ;
#endif

View File

@@ -2,6 +2,10 @@
Various mostly unrelated utility functions related to parsing,
loading and evaluating fish code.
This library can be seen as a 'toolbox' for functions that are
used in many places in fish and that are somehow related to
parsing the code.
*/
#include "config.h"
@@ -29,10 +33,22 @@
#include "intern.h"
#include "exec.h"
#include "env.h"
#include "signal.h"
#include "wildcard.h"
#include "halloc_util.h"
/**
Maximum number of autoloaded items opf a specific type to keep in
memory at a time.
*/
#define AUTOLOAD_MAX 10
/**
Minimum time, in seconds, before an autoloaded item will be
unloaded
*/
#define AUTOLOAD_MIN_AGE 60
/**
A structure representing the autoload state for a specific variable, e.g. fish_complete_path
*/
@@ -479,8 +495,18 @@ static void clear_hash_value( void *key, void *data, void *aux )
if( aux )
{
wchar_t *name = (wchar_t *)key;
time_t *time = (time_t *)data;
void (*handler)(const wchar_t *)= (void (*)(const wchar_t *))aux;
handler( name );
/*
If time[0] is 0, that means the file really doesn't exist,
it's simply been checked before. We should not unload it.
*/
if( time[0] && handler )
{
// debug( 0, L"Unloading function %ls", name );
handler( name );
}
}
free( (void *)data );
@@ -527,14 +553,8 @@ static void parse_util_destroy()
void parse_util_load_reset( const wchar_t *path_var_name,
void (*on_load)(const wchar_t *cmd) )
{
wchar_t *path_var;
CHECK( path_var_name, );
path_var = env_get( path_var_name );
if( !path_var )
return;
if( all_loaded )
{
void *key, *data;
@@ -580,34 +600,111 @@ int parse_util_unload( const wchar_t *cmd,
return !!val;
}
static void parse_util_autounload( const wchar_t *path_var_name,
const wchar_t *skip,
void (*on_load)(const wchar_t *cmd) )
{
autoload_t *loaded;
int loaded_count=0;
if( !all_loaded )
{
return;
}
loaded = (autoload_t *)hash_get( all_loaded, path_var_name );
if( !loaded )
{
return;
}
if( hash_get_count( &loaded->load_time ) >= AUTOLOAD_MAX )
{
time_t oldest_access = time(0) - AUTOLOAD_MIN_AGE;
wchar_t *oldest_item=0;
int i;
array_list_t key;
al_init( &key );
hash_get_keys( &loaded->load_time, &key );
for( i=0; i<al_get_count( &key ); i++ )
{
wchar_t *item = (wchar_t *)al_get( &key, i );
time_t *tm = hash_get( &loaded->load_time, item );
if( wcscmp( item, skip ) == 0 )
{
continue;
}
if( !tm[0] )
continue;
if( hash_get( &loaded->is_loading, item ) )
{
continue;
}
loaded_count++;
if( tm[1] < oldest_access )
{
oldest_access = tm[1];
oldest_item = item;
}
}
al_destroy( &key );
if( oldest_item && loaded_count > AUTOLOAD_MAX)
{
parse_util_unload( oldest_item, path_var_name, on_load );
}
}
}
static int parse_util_load_internal( const wchar_t *cmd,
void (*on_load)(const wchar_t *cmd),
int reload,
autoload_t *loaded,
array_list_t *path_list );
int parse_util_load( const wchar_t *cmd,
const wchar_t *path_var_name,
void (*on_load)(const wchar_t *cmd),
int reload )
{
static array_list_t *path_list=0;
static string_buffer_t *path=0;
array_list_t *path_list=0;
int i;
time_t *tm;
int reloaded = 0;
autoload_t *loaded;
wchar_t *path_var;
int res;
int c, c2;
CHECK( path_var_name, 0 );
CHECK( cmd, 0 );
CHECK_BLOCK( 0 );
// debug( 0, L"Autoload %ls in %ls", cmd, path_var_name );
parse_util_autounload( path_var_name, cmd, on_load );
path_var = env_get( path_var_name );
/*
Do we know where to look
Do we know where to look?
*/
if( !path_var )
{
// debug( 0, L"Path null" );
return 0;
}
/**
Init if this is the first time we try to autoload anything
*/
if( !all_loaded )
{
all_loaded = malloc( sizeof( hash_table_t ) );
@@ -623,12 +720,6 @@ int parse_util_load( const wchar_t *cmd,
if( loaded )
{
if( hash_get( &loaded->is_loading, cmd ) )
{
debug( 0, _(L"Could not autoload item %ls, it is already being autoloaded. This is a circular dependency in the autoloading scripts, please remove it."), cmd );
return 1;
}
/*
Check if the lookup path has changed. If so, drop all loaded
files and start from scratch.
@@ -639,33 +730,102 @@ int parse_util_load( const wchar_t *cmd,
reload = parse_util_load( cmd, path_var_name, on_load, reload );
return reload;
}
/**
Warn and fail on infinite recursion
*/
if( hash_get( &loaded->is_loading, cmd ) )
{
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 );
return 1;
}
}
else
{
/*
We have never tried to autoload using this name before, set up initial data
We have never tried to autoload using this path name before,
set up initial data
*/
loaded = malloc( sizeof( autoload_t ) );
// debug( 0, L"Create brand new autoload_t for %ls->%ls", path_var_name, path_var );
loaded = malloc( sizeof( autoload_t ) );
if( !loaded )
{
DIE_MEM();
}
hash_init( &loaded->load_time, &hash_wcs_func, &hash_wcs_cmp );
hash_put( all_loaded, wcsdup(path_var_name), loaded );
hash_init( &loaded->is_loading, &hash_wcs_func, &hash_wcs_cmp );
loaded->old_path = wcsdup( path_var );
}
hash_put( &loaded->is_loading, cmd, cmd );
path_list = al_new( global_context);
tokenize_variable_array( path_var, path_list );
c = al_get_count( path_list );
hash_put( &loaded->is_loading, cmd, cmd );
/*
Do the actual work in the internal helper function
*/
res = parse_util_load_internal( cmd, on_load, reload, loaded, path_list );
autoload_t *loaded2 = (autoload_t *)hash_get( all_loaded, path_var_name );
if( loaded2 == loaded )
{
/**
Cleanup
*/
hash_remove( &loaded->is_loading, cmd, 0, 0 );
}
c2 = al_get_count( path_list );
al_foreach( path_list, &free );
al_destroy( path_list );
free( path_list );
/**
Make sure we didn't 'drop' something
*/
assert( c == c2 );
return res;
}
/**
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.
*/
static int parse_util_load_internal( const wchar_t *cmd,
void (*on_load)(const wchar_t *cmd),
int reload,
autoload_t *loaded,
array_list_t *path_list )
{
static string_buffer_t *path=0;
time_t *tm;
int i;
int reloaded = 0;
/*
Get modification time of file
*/
tm = (time_t *)hash_get( &loaded->load_time, cmd );
/*
Did we just check this?
*/
@@ -673,7 +833,6 @@ int parse_util_load( const wchar_t *cmd,
{
if(time(0)-tm[1]<=1)
{
hash_remove( &loaded->is_loading, cmd, 0, 0 );
return 0;
}
}
@@ -683,20 +842,14 @@ int parse_util_load( const wchar_t *cmd,
*/
if( !reload && tm )
{
hash_remove( &loaded->is_loading, cmd, 0, 0 );
return 0;
}
if( !path_list )
path_list = al_halloc( global_context);
if( !path )
path = sb_halloc( global_context );
else
sb_clear( path );
tokenize_variable_array( path_var, path_list );
/*
Iterate over path searching for suitable completion files
*/
@@ -706,6 +859,7 @@ int parse_util_load( const wchar_t *cmd,
wchar_t *next = (wchar_t *)al_get( path_list, i );
sb_clear( path );
sb_append2( path, next, L"/", cmd, L".fish", (void *)0 );
if( (wstat( (wchar_t *)path->buff, &buf )== 0) &&
(waccess( (wchar_t *)path->buff, R_OK ) == 0) )
{
@@ -713,6 +867,7 @@ int parse_util_load( const wchar_t *cmd,
{
wchar_t *esc = escape( (wchar_t *)path->buff, 1 );
wchar_t *src_cmd = wcsdupcat( L". ", esc );
free( esc );
if( !tm )
{
@@ -727,19 +882,33 @@ int parse_util_load( const wchar_t *cmd,
intern( cmd ),
tm );
free( esc );
if( on_load )
on_load(cmd );
/*
Source the completion file for the specified completion
*/
exec_subshell( src_cmd, 0 );
if( exec_subshell( src_cmd, 0 ) == -1 )
{
/*
Do nothing on failiure
*/
}
free(src_cmd);
reloaded = 1;
break;
}
else if( tm )
{
/*
If we are rechecking an autoload file, and it hasn't
changed, update the 'last check' timestamp.
*/
tm[1] = time(0);
}
break;
}
}
@@ -759,10 +928,6 @@ int parse_util_load( const wchar_t *cmd,
hash_put( &loaded->load_time, intern( cmd ), tm );
}
al_foreach( path_list, &free );
al_truncate( path_list, 0 );
hash_remove( &loaded->is_loading, cmd, 0, 0 );
return reloaded;
}

View File

@@ -98,14 +98,16 @@ int parse_util_lineno( const wchar_t *str, int len );
not load it multiple times unless it's 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 path_var_name the environment variable giving the search path
\param on_load a callback function to run if a suitable file is found, which has not already been run
\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 parse_util_load( const wchar_t *cmd,
const wchar_t *path_var_name,
void (*on_load)(const wchar_t *cmd),
void (*on_unload)(const wchar_t *cmd),
int reload );
/**
@@ -114,11 +116,10 @@ int parse_util_load( const wchar_t *cmd,
reset.
\param path_var_name the environment variable giving the search path
\param on_load the callback function to use when a file is reloaded
\param on_load the callback function to call if the file has been previously loaded
\param on_unload a callback function which will be called before (re)loading a file, may be used to unload the previous file.
*/
void parse_util_load_reset( const wchar_t *path_var_name,
void (*on_load)(const wchar_t *cmd) );
void (*on_unload)(const wchar_t *cmd) );
/**
Tell the autoloader that the specified file, in the specified path,
@@ -126,11 +127,12 @@ void parse_util_load_reset( const wchar_t *path_var_name,
\param cmd the filename to search for. The suffix '.fish' is always added to this name
\param path_var_name the environment variable giving the search path
\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 parse_util_unload( const wchar_t *cmd,
const wchar_t *path_var_name,
void (*on_load)(const wchar_t *cmd) );
void (*on_unload)(const wchar_t *cmd) );
/**
Set the argv environment variable to the specified null-terminated

747
parser.c

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,9 @@
#include "parser.h"
#include "event.h"
#define PARSER_TEST_ERROR 1
#define PARSER_TEST_INCOMPLETE 2
/**
event_block_t represents a block on events of the specified type
*/
@@ -54,6 +57,11 @@ typedef struct block
The job that is currently evaluated in the specified block.
*/
job_t *job;
/**
Block type-specific data
*/
void *data;
/**
First block type specific variable
@@ -62,11 +70,11 @@ typedef struct block
{
int while_state; /**< True if the loop condition has not yet been evaluated*/
wchar_t *for_variable; /**< Name of the variable to loop over */
int if_state; /**< The state of the if block */
int if_state; /**< The state of the if block, can be one of IF_STATE_UNTESTED, IF_STATE_FALSE, IF_STATE_TRUE */
wchar_t *switch_value; /**< The value to test in a switch block */
wchar_t *function_name; /**< The name of the function to define or the function called*/
const wchar_t *source_dest; /**< The name of the file to source*/
event_t *event; /**<The event that triggered this block */
wchar_t *function_call_name;
} param1;
/**
@@ -76,25 +84,9 @@ typedef struct block
{
array_list_t for_vars; /**< List of values for a for block */
int switch_taken; /**< Whether a switch match has already been found */
wchar_t *function_description; /**< The description of the function to define */
process_t *function_call_process; /**< The process representing this function call */
} param2;
/**
Third block type specific variable
*/
union
{
int function_is_binding; /**< Whether a function is a keybinding */
} param3;
/**
Fourth block type specific variable
*/
union
{
array_list_t *function_events;
} param4;
/**
Name of file that created this block
@@ -196,15 +188,6 @@ extern event_block_t *global_event_block;
*/
extern io_data_t *block_io;
/**
Finds the full path of an executable in a newly allocated string.
\param cmd The name of the executable.
\param context the halloc context to use for memory allocations
\return 0 if the command can not be found, the path of the command otherwise.
*/
wchar_t *parser_get_filename( void *context, const wchar_t *cmd );
/**
Evaluate the expressions contained in cmd.
@@ -313,11 +296,17 @@ const wchar_t *parser_get_block_desc( int block );
/**
Test if the specified string can be parsed, or if more bytes need
to be read first. The result has the first bit set if the string
contains errors, and the second bit is set if the string contains
an unclosed block.
to be read first. The result will have the PARSER_TEST_ERROR bit
set if there is a syntax error in the code, and the
PARSER_TEST_INCOMPLETE bit set if the code contains unclosed
blocks.
\param buff the text buffer to test
\param block_level if non-null, the block nesting level will be filled out into this array
\param out if non-null, any errors in the command will be filled out into this buffer
\param prefix the prefix string to prepend to each error message written to the \c out buffer
*/
int parser_test( const wchar_t * buff, string_buffer_t *out, const wchar_t *prefix );
int parser_test( const wchar_t * buff, int *block_level, string_buffer_t *out, const wchar_t *prefix );
/**
Test if the specified string can be parsed as an argument list,
@@ -327,15 +316,6 @@ int parser_test( const wchar_t * buff, string_buffer_t *out, const wchar_t *pref
*/
int parser_test_args( const wchar_t * buff, string_buffer_t *out, const wchar_t *prefix );
/**
Returns the full path of the specified directory. If the \c in is a
full path to an existing directory, a copy of the string is
returned. If \c in is a directory relative to one of the
directories i the CDPATH, the full path is returned. If no
directory can be found, 0 is returned.
*/
wchar_t *parser_cdpath_get( void *context, wchar_t *in );
/**
Tell the parser that the specified function may not be run if not
inside of a conditional block. This is to remove some possibilities
@@ -377,5 +357,8 @@ const wchar_t *parser_current_filename();
*/
void parser_stack_trace( block_t *b, string_buffer_t *buff);
int parser_get_block_type( const wchar_t *cmd );
const wchar_t *parser_get_block_command( int type );
#endif

Some files were not shown because too many files have changed in this diff Show More