home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume35 / zsh / part12 < prev    next >
Text File  |  1993-02-20  |  56KB  |  2,403 lines

  1. Newsgroups: comp.sources.misc
  2. From: zsh-list@cs.uow.edu.au (The Zsh Mailing List)
  3. Subject: v35i062:  zsh - The Z Shell, version 2.3.1, Part12/22
  4. Message-ID: <1993Feb20.212458.28891@sparky.imd.sterling.com>
  5. X-Md4-Signature: 0cd86aecea33fc29076b177ff3ea416b
  6. Date: Sat, 20 Feb 1993 21:24:58 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: zsh-list@cs.uow.edu.au (The Zsh Mailing List)
  10. Posting-number: Volume 35, Issue 62
  11. Archive-name: zsh/part12
  12. Environment: UNIX
  13. Supersedes: zsh2.2: Volume 29, Issue 97-113
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then feed it
  17. # into a shell via "sh file" or similar.  To overwrite existing files,
  18. # type "sh file -c".
  19. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  20. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  21. # Contents:  help/zle src/utils.c
  22. # Wrapped by mattson@odin on Sat Feb  6 14:41:53 1993
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 12 (of 22)."'
  26. if test -f 'help/zle' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'help/zle'\"
  28. else
  29.   echo shar: Extracting \"'help/zle'\" \(19344 characters\)
  30.   sed "s/^X//" >'help/zle' <<'END_OF_FILE'
  31. X     bindkey -mevd
  32. X     bindkey -r in-string ...
  33. X     bindkey [ -a ] in-string [ command ] ...
  34. X     bindkey -s [ -a ] in-string out-string ...
  35. X          If one of the -e, -v, or -d options is given, reset the
  36. X          keymaps  for  emacs mode, vi mode, or the default mode,
  37. X          respectively; if the -m option is also given, allow the
  38. X          use  of  a meta key.  If the -r option is given, remove
  39. X          any binding for each in-string.  If the  -s  option  is
  40. X          not  specified, bind each in-string to a specified com-
  41. X          mand.  If no command is specified, print the binding of
  42. X          in-string if it is bound, or return a nonzero exit code
  43. X          if it is not bound.  If the  -s  option  is  specified,
  44. X          bind each in-string to each specified out-string.  When
  45. X          in-string is typed, out-string will be pushed back  and
  46. X          treated  as input to the line editor.  If the -a option
  47. X          is specified, bind the in-strings  in  the  alternative
  48. X          keymap  instead  of  the standard one.  The alternative
  49. X          keymap is used in vi command mode.
  50. X
  51. X          For either in-string or out-string, control  characters
  52. X          may  be specified in the form ^X, and the backslash may
  53. X          be used  to  introduce  one  of  the  following  escape
  54. X          sequences:
  55. X               \a   bell character
  56. X               \n   linefeed (newline)
  57. X               \b   backspace
  58. X               \t   horizontal tab
  59. X               \v   vertical tab
  60. X               \f   form feed
  61. X               \r   carriage return
  62. X               \e   escape
  63. X               \nnn character code in octal
  64. X               \M-xxx
  65. X                    character or escape sequence  with  meta  bit
  66. X                    set
  67. X
  68. X          In all other cases, \ escapes the following  character.
  69. X          Delete is written as `^?'.
  70. X
  71. X     vi-backward-blank-word (unbound) (B)
  72. X          Move backward one word, where a word is  defined  as  a
  73. X          series of non-blank characters.
  74. X
  75. X     backward-char (^B ESC-[D) ()
  76. X          Move backward one character.
  77. X
  78. X     vi-backward-char () (h)
  79. X          Move backward one character, without changing lines.
  80. X
  81. X     backward-word (ESC-B ESC-b) (unbound)
  82. X          Move to the beginning of the previous word.
  83. X
  84. X     emacs-backward-word
  85. X          Move to the beginning of the previous word.
  86. X
  87. X     vi-backward-word (unbound) (b)
  88. X          Move to the beginning of the previous word, vi-style.
  89. X
  90. X     beginning-of-line (^A) (0)
  91. X          Move to the beginning of the line.  If already  at  the
  92. X          beginning  of  the  line,  move to the beginning of the
  93. X          previous line, if any.
  94. X
  95. X     vi-beginning-of-line
  96. X          Move to the beginning of  the  line,  without  changing
  97. X          lines.
  98. X
  99. X     end-of-line (^E)
  100. X          Move to the end of the line.  If already at the end  of
  101. X          the line, move to the end of the next line, if any.
  102. X
  103. X     vi-end-of-line (unbound) ($)
  104. X          Move to the end of the line.
  105. X
  106. X     vi-forward-blank-word (unbound) (W)
  107. X          Move forward one word, where a word  is  defined  as  a
  108. X          series of non-blank characters.
  109. X
  110. X     vi-forward-blank-word-end (unbound) (E)
  111. X          Move to the end of the current word, or, if at the  end
  112. X          of the current word, to the end of the next word, where
  113. X          a word is defined as a series of non-blank characters.
  114. X
  115. X     forward-char (^F ESC-[C)
  116. X          Move forward one character.
  117. X
  118. X     vi-forward-char (unbound) (space l)
  119. X          Move forward one character.
  120. X
  121. X     vi-find-next-char (^X^F) (f)
  122. X          Read a character from the keyboard,  and  move  to  the
  123. X          next occurrence of it in the line.
  124. X
  125. X     vi-find-next-char-skip (unbound) (t)
  126. X          Read a character from the keyboard,  and  move  to  the
  127. X          position  just  before the next occurrence of it in the
  128. X          line.
  129. X
  130. X     vi-find-prev-char (unbound) (F)
  131. X          Read a character from the keyboard,  and  move  to  the
  132. X          previous occurrence of it in the line.
  133. X
  134. X     vi-find-prev-char-skip (unbound) (T)
  135. X          Read a character from the keyboard,  and  move  to  the
  136. X          position  just  after  the previous occurrence of it in
  137. X          the line.
  138. X
  139. X     vi-first-non-blank (unbound) (^)
  140. X          Move to the first non-blank character in the line.
  141. X
  142. X     vi-forward-word (unbound) (w)
  143. X          Move forward one word, vi-style.
  144. X
  145. X     forward-word (ESC-F ESC-f) (unbound)
  146. X          Move to the beginning of the next word.   The  editor's
  147. X          idea  of a word is specified with the WORDCHARS parame-
  148. X          ter.
  149. X
  150. X     emacs-forward-word
  151. X          Move to the end of the next word.
  152. X
  153. X     vi-forward-word-end (unbound) (e)
  154. X          Move to the end of the next word.
  155. X
  156. X     vi-goto-column (ESC-|) (|)
  157. X          Move to the column specified by the numeric argument.
  158. X
  159. X     vi-goto-mark (unbound) (`)
  160. X          Move to the specified mark.
  161. X
  162. X     vi-goto-mark-line (unbound) (')
  163. X          Move to beginning of the line containing the  specified
  164. X          mark.
  165. X
  166. X     vi-repeat-find (unbound) (;)
  167. X          Repeat the last vi-find command.
  168. X
  169. X     vi-rev-repeat-find (unbound) (,)
  170. X          Repeat the last vi-find command in the opposite  direc-
  171. X          tion.
  172. X
  173. X     beginning-of-buffer-or-history (ESC-<)
  174. X          Move to the beginning of  the  buffer,  or  if  already
  175. X          there, move to the first event in the history list.
  176. X
  177. X     beginning-of-line-hist
  178. X          Move to the beginning of the line.  If already  at  the
  179. X          beginning  of  the buffer, move to the previous history
  180. X          line.
  181. X
  182. X     beginning-of-history
  183. X          Move to the first event in the history list.
  184. X
  185. X     down-line-or-history (^N ESC-[B) (+ j)
  186. X          Move down a line in the buffer, or if  already  at  the
  187. X          bottom  line,  move  to  the  next event in the history
  188. X          list.
  189. X
  190. X     down-history (unbound) (^N)
  191. X          Move to the next event in the history list.
  192. X
  193. X     end-of-buffer-or-history (ESC->)
  194. X          Move to the end of the buffer,  or  if  already  there,
  195. X          move to the last event in the history list.
  196. X
  197. X     end-of-line-hist
  198. X          Move to the end of the line.  If already at the end  of
  199. X          the buffer, move to the next history line.
  200. X
  201. X     end-of-history
  202. X          Move to the last event in the history list.
  203. X
  204. X     vi-fetch-history (unbound) (G)
  205. X          Fetch the history line specified by the  numeric  argu-
  206. X          ment.
  207. X
  208. X     history-incremental-search-backward (^R ^Xr)
  209. X          Search backward incrementally for a  specified  string.
  210. X          The  string  may begin with `^' to anchor the search to
  211. X          the beginning of the line.
  212. X
  213. X     history-incremental-search-forward (^Xs)
  214. X          Search forward incrementally for  a  specified  string.
  215. X          The  string  may begin with `^' to anchor the search to
  216. X          the beginning of the line.
  217. X
  218. X     history-search-backward (ESC-P ESC-p) (K)
  219. X          Search backward in the history  for  a  line  beginning
  220. X          with the first word in the buffer.
  221. X
  222. X     vi-history-search-backward (unbound) (/)
  223. X          Search backward in the history for a specified  string.
  224. X          The  string  may begin with `^' to anchor the search to
  225. X          the beginning of the line.
  226. X
  227. X     history-search-forward (ESC-N ESC-n) (J)
  228. X          Search forward in the history for a line beginning with
  229. X          the first word in the buffer.
  230. X
  231. X     vi-history-search-forward (unbound) (?)
  232. X          Search forward in the history for a  specified  string.
  233. X          The  string  may begin with `^' to anchor the search to
  234. X          the beginning of the line.
  235. X
  236. X     infer-next-history (^X^N)
  237. X          Search in the history list  for  a  line  matching  the
  238. X          current one and fetch the event following it.
  239. X
  240. X     insert-last-word (ESC-_ ESC-.)
  241. X          Insert the last word from the previous history event at
  242. X          the cursor position.
  243. X
  244. X     vi-repeat-search (unbound) (n)
  245. X          Repeat the last vi history search.
  246. X
  247. X     vi-rev-repeat-search (unbound) (N)
  248. X          Repeat the last vi history search, but in reverse.
  249. X
  250. X     toggle-literal-history (ESC-R ESC-r)
  251. X          Toggle  between  literal  and  lexical  history.    The
  252. X          default is lexical history unless the HISTLIT option is
  253. X          set.
  254. X
  255. X     up-line-or-history (^P ESC-[A) (- k)
  256. X          Move up a line in the buffer, or if already at the  top
  257. X          line, move to the previous event in the history list.
  258. X
  259. X     up-history (unbound) (^P)
  260. X          Move to the previous event in the history list.
  261. X
  262. X     vi-add-eol (unbound) (A)
  263. X          Move to the end of the line and enter insert mode.
  264. X
  265. X     vi-add-next (unbound) (a)
  266. X          Move forward one character and enter insert mode.
  267. X
  268. X     backward-delete-char (^H ^?) (^?)
  269. X          Delete the character behind the cursor.
  270. X
  271. X     vi-backward-delete-char (unbound) (X)
  272. X          Delete the character behind the cursor, without  chang-
  273. X          ing lines.
  274. X
  275. X     backward-delete-word
  276. X          Delete the word behind the cursor.
  277. X
  278. X     backward-kill-line
  279. X          Kill from the beginning of the line to the cursor posi-
  280. X          tion.
  281. X
  282. X     backward-kill-word (^W ESC-^H ESC-^?)
  283. X          Kill the word behind the cursor.
  284. X
  285. X     vi-backward-kill-word (unbound) (^W)
  286. X          Kill the word behind the cursor.
  287. X
  288. X     capitalize-word (ESC-C ESC-c)
  289. X          Capitalize the current word and move past it.
  290. X
  291. X     vi-change (unbound) (c)
  292. X          Read a movement command from  the  keyboard,  and  kill
  293. X          from  the  cursor position to the endpoint of the move-
  294. X          ment.  Then enter insert mode.  If the command  is  vi-
  295. X          change, kill the current line.
  296. X
  297. X     vi-change-eol (unbound) (C)
  298. X          Kill to the end of the line and enter insert mode.
  299. X
  300. X     vi-change-whole-line (unbound) (S s)
  301. X          Kill the current line and enter insert mode.
  302. X
  303. X     copy-region-as-kill (ESC-W ESC-w)
  304. X          Copy the area from the cursor to the mark to  the  kill
  305. X          buffer.
  306. X
  307. X     copy-prev-word (ESC-^_)
  308. X          Duplicate the word behind the cursor.
  309. X
  310. X     vi-delete (unbound) (d)
  311. X          Read a movement command from  the  keyboard,  and  kill
  312. X          from  the  cursor position to the endpoint of the move-
  313. X          ment.  If the command is vi-delete,  kill  the  current
  314. X          line.
  315. X
  316. X     delete-char (unbound) (x)
  317. X          Delete the character under the cursor.
  318. X
  319. X     vi-delete-char (unbound) (x)
  320. X          Delete the character under the cursor.
  321. X
  322. X     delete-word (ESC-D ESC-d)
  323. X          Delete the current word.
  324. X
  325. X     down-case-word (ESC-L ESC-l)
  326. X          Convert the current word to all lowercase and move past
  327. X          it.
  328. X
  329. X     kill-word
  330. X          Kill the current word.
  331. X
  332. X     gosmacs-transpose-chars
  333. X          Exchange the two characters behind the cursor.
  334. X
  335. X     vi-indent (unbound) (>)
  336. X          Indent a number of lines.
  337. X
  338. X     vi-insert (unbound) (i)
  339. X          Enter insert mode.
  340. X
  341. X     vi-insert-bol (unbound) (I)
  342. X          Move to the beginning of  the  line  and  enter  insert
  343. X          mode.
  344. X
  345. X     vi-join (^X^J)
  346. X          Join the current line with the next one.
  347. X
  348. X     kill-line (^K) (D)
  349. X          Kill from the cursor to the end of the line.
  350. X
  351. X     kill-region
  352. X          Kill from the cursor to the mark.
  353. X
  354. X     kill-buffer (^X^U) (^U)
  355. X          Kill the entire buffer.
  356. X
  357. X     kill-whole-line (^U) (unbound)
  358. X          Kill the current line.
  359. X
  360. X     vi-match-bracket (^X^B) (%)
  361. X          Move to the bracket character (one of {},  (),  or  [])
  362. X          that matches the one under the cursor.
  363. X
  364. X     vi-open-line-above (unbound) (O)
  365. X          Open a line above the cursor and enter insert mode.
  366. X
  367. X     vi-open-line-below (unbound) (o)
  368. X          Open a line below the cursor and enter insert mode.
  369. X
  370. X     vi-oper-swap-case
  371. X          Read a movement command from the keyboard, and swap the
  372. X          case  of all characters from the cursor position to the
  373. X          endpoint of the movement.  If the movement  command  is
  374. X          vi-oper-swap-case,  swap  the case of all characters on
  375. X          the current line.
  376. X
  377. X     overwrite-mode (^X^O)
  378. X          Toggle between overwrite mode and insert mode.
  379. X
  380. X     vi-put-after (unbound) (p)
  381. X          Insert the contents of the kill buffer after  the  cur-
  382. X          sor.
  383. X
  384. X     quoted-insert (^V)
  385. X          Insert  the  next  character  typed  into  the   buffer
  386. X          literally.
  387. X
  388. X     quote-line (ESC-')
  389. X          Quote the current line; that is, put a '  character  at
  390. X          the beginning and the end, and convert all ' characters
  391. X          to '\''.
  392. X
  393. X     quote-region (ESC-")
  394. X          Quote the region from the cursor to the mark.
  395. X
  396. X     vi-replace (unbound) (R)
  397. X          Enter overwrite mode.
  398. X
  399. X     vi-repeat-change (unbound) (.)
  400. X          Repeat the last vi mode text modification.
  401. X
  402. X     vi-replace-chars (unbound) (r)
  403. X          Replace the character under the cursor with a character
  404. X          read from the keyboard.
  405. X
  406. X     self-insert (printable characters)
  407. X          Put a character in the buffer at the cursor position.
  408. X
  409. X     self-insert-unmeta (ESC-^I ESC-^J ESC-^M)
  410. X          Put a character in the buffer after stripping the  meta
  411. X          bit and converting ^M to ^J.
  412. X
  413. X     vi-substitute (unbound) (s)
  414. X          Substitute the next character(s).
  415. X
  416. X     vi-swap-case (unbound) (~)
  417. X          Swap the case of the character  under  the  cursor  and
  418. X          move past it.
  419. X
  420. X     transpose-chars (^T)
  421. X          Exchange the two characters to the left of  the  cursor
  422. X          if  at  end  of line, else exchange the character under
  423. X          the cursor with the character to the left.
  424. X
  425. X     transpose-words (ESC-T ESC-t)
  426. X          Exchange the current word with the one before it.
  427. X
  428. X     vi-unindent (unbound) (<)
  429. X          Unindent a number of lines.
  430. X
  431. X     up-case-word (ESC-U ESC-u)
  432. X          Convert the current word to all caps and move past it.
  433. X
  434. X     yank (^Y) (P)
  435. X          Insert the contents of the kill buffer  at  the  cursor
  436. X          position.
  437. X
  438. X     yank-pop (ESC-y) (unbound)
  439. X          Remove the text just yanked, rotate the kill-ring,  and
  440. X          yank  the  new top.  Only works following yank or yank-
  441. X          pop.
  442. X
  443. X     vi-yank (unbound) (y)
  444. X          Read a movement command from the keyboard, and copy the
  445. X          region  from the cursor position to the endpoint of the
  446. X          movement into the kill buffer.  If the command  is  vi-
  447. X          yank, copy the current line.
  448. X
  449. X     vi-yank-eol (unbound) (Y)
  450. X          Copy the region from the cursor position to the end  of
  451. X          the line into the kill buffer.
  452. X
  453. X     digit-argument (ESC-0..ESC-9) (0-9)
  454. X          Start a new numeric argument, or  add  to  the  current
  455. X          one.
  456. X
  457. X     universal-argument
  458. X          Multiply the argument of the next command by 4.
  459. X
  460. X     accept-and-menu-complete
  461. X          In a menu completion,  insert  the  current  completion
  462. X          into  the buffer, and advance to the next possible com-
  463. X          pletion.
  464. X
  465. X     complete-word (unbound) (\)
  466. X          Attempt completion on the current word.
  467. X
  468. X     delete-char-or-list (^D)
  469. X          Delete the character under the cursor.  If  the  cursor
  470. X          is  at  the  end of the line, list possible completions
  471. X          for the current word.
  472. X
  473. X     execute-named-cmd (ESC-x)
  474. X          Read the name of a editor command and execute it.
  475. X
  476. X     execute-last-named-cmd (ESC-z)
  477. X          Redo the last function executed with execute-named-cmd.
  478. X
  479. X     expand-cmd-path
  480. X          Expand the current command to its full pathname.
  481. X
  482. X     expand-or-complete (TAB) (TAB ^X)
  483. X          Attempt shell expansion on the current word.   If  that
  484. X          fails, attempt completion.
  485. X
  486. X     expand-history (ESC-space ESC-!)
  487. X          Perform history expansion on the edit buffer.
  488. X
  489. X     expand-word (^X*)
  490. X          Attempt shell expansion on the current word.
  491. X
  492. X     list-choices (ESC-^D) (^D =)
  493. X          List possible completions for the current word.
  494. X
  495. X     list-expand (^Xg ^XG) (^G)
  496. X          List the expansion of the current word.
  497. X
  498. X     magic-space
  499. X          Perform history expansion and insert a space  into  the
  500. X          buffer.  This is intended to be bound to space.
  501. X
  502. X     menu-complete
  503. X          Like complete-word,  except  that  menu  completion  is
  504. X          used.  See the MENU_COMPLETE option below.
  505. X
  506. X     menu-expand-or-complete
  507. X          Like expand-or-complete, except that menu completion is
  508. X          used.
  509. X
  510. X     reverse-menu-complete
  511. X          See the MENU_COMPLETE option below.
  512. X
  513. X     accept-and-hold (ESC-A ESC-a)
  514. X          Push the contents of the buffer on the buffer stack and
  515. X          execute it.
  516. X
  517. X     accept-and-infer-next-history
  518. X          Execute the contents of the buffer.   Then  search  the
  519. X          history  list  for  a line matching the current one and
  520. X          push the event following onto the buffer stack.
  521. X
  522. X     accept-line (^J ^M)
  523. X          Execute the contents of the buffer.
  524. X
  525. X     accept-line-and-down-history (^O)
  526. X          Execute the current line, and  push  the  next  history
  527. X          event on the the buffer stack.
  528. X
  529. X     vi-cmd-mode (^X^V) (^[)
  530. X          Enter command mode; that is, use the alternate  keymap.
  531. X          Yes, this is bound by default in emacs mode.
  532. X
  533. X     vi-caps-lock-panic (unbound) (H K)
  534. X          Hang until any lowercase key is pressed.  This  is  for
  535. X          vi  users  without the mental capacity to keep track of
  536. X          their caps lock key (like the author).
  537. X
  538. X     clear-screen (^L ESC-^L)
  539. X          Clear the screen and redraw the prompt.
  540. X
  541. X     exchange-point-and-mark (^X^X)
  542. X          Exchange the cursor position with the position  of  the
  543. X          mark.
  544. X
  545. X     get-line (ESC-G ESC-g)
  546. X          Pop the top line off the buffer stack and insert it  at
  547. X          the cursor position.
  548. X
  549. X     pound-insert (unbound) (#)
  550. X          If there is no # character  at  the  beginning  of  the
  551. X          current line, add one.  If there is one, remove it.  In
  552. X          either   case,   accept   the   current   line.     The
  553. X          INTERACTIVE_COMMENTS  option  must  be  set for this to
  554. X          have any usefulness.
  555. X
  556. X     push-line (^Q ESC-Q ESC-q)
  557. X          Push the current buffer onto the buffer stack and clear
  558. X          the buffer.  Next time the editor starts up, the buffer
  559. X          will be popped off the top  of  the  buffer  stack  and
  560. X          loaded into the editing buffer.
  561. X
  562. X     redisplay (unbound) (^R)
  563. X          Redisplays the edit buffer.
  564. X
  565. X     run-help (ESC-H ESC-h)
  566. X          Push the buffer onto the buffer stack, and execute  the
  567. X          command  "run-help  cmd", where cmd is the current com-
  568. X          mand.  run-help is normally aliased to man.
  569. X
  570. X     send-break (^C)
  571. X          Abort the parsing of the current line.
  572. X
  573. X     vi-set-buffer (unbound) (")
  574. X          Specify a buffer to be used in the following command.
  575. X
  576. X     vi-set-mark (unbound) (m)
  577. X          Set the specified mark at the cursor position.
  578. X
  579. X     set-mark-command (^@)
  580. X          Set the mark at the cursor position.
  581. X
  582. X     spell-word (ESC-$ ESC-S ESC-s)
  583. X          Attempt spelling correction on the current word.
  584. X
  585. X     undefined-key
  586. X          Beep.
  587. X
  588. X     undo (^_ ^X^U) (u)
  589. X          Incrementally undo the last text modification.
  590. X
  591. X     which-command (ESC-?)
  592. X          Push the buffer onto the buffer stack, and execute  the
  593. X          command  "which-command  cmd", where cmd is the current
  594. X          command.  which-command is normally aliased to whence.
  595. END_OF_FILE
  596.   if test 19344 -ne `wc -c <'help/zle'`; then
  597.     echo shar: \"'help/zle'\" unpacked with wrong size!
  598.   fi
  599.   # end of 'help/zle'
  600. fi
  601. if test -f 'src/utils.c' -a "${1}" != "-c" ; then 
  602.   echo shar: Will not clobber existing file \"'src/utils.c'\"
  603. else
  604.   echo shar: Extracting \"'src/utils.c'\" \(32015 characters\)
  605.   sed "s/^X//" >'src/utils.c' <<'END_OF_FILE'
  606. X/*
  607. X *
  608. X * utils.c - miscellaneous utilities
  609. X *
  610. X * This file is part of zsh, the Z shell.
  611. X *
  612. X * This software is Copyright 1992 by Paul Falstad
  613. X *
  614. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  615. X * use this software as long as: there is no monetary profit gained
  616. X * specifically from the use or reproduction of this software, it is not
  617. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  618. X * included prominently in any copy made. 
  619. X *
  620. X * The author make no claims as to the fitness or correctness of this software
  621. X * for any use whatsoever, and it is provided as is. Any use of this software
  622. X * is at the user's own risk. 
  623. X *
  624. X */
  625. X
  626. X#include "zsh.h"
  627. X#include <pwd.h>
  628. X#include <errno.h>
  629. X#include <fcntl.h>
  630. X
  631. X/* source a file */
  632. X
  633. Xint source(s) /**/
  634. Xchar *s;
  635. X{
  636. Xint fd,cj = thisjob;
  637. Xint oldlineno = lineno,oldshst;
  638. XFILE *obshin = bshin;
  639. X
  640. X    fd = SHIN;
  641. X    lineno = 0;
  642. X    oldshst = opts[SHINSTDIN];
  643. X    opts[SHINSTDIN] = OPT_UNSET;
  644. X    if ((SHIN = movefd(open(s,O_RDONLY))) == -1)
  645. X        {
  646. X        SHIN = fd;
  647. X        thisjob = cj;
  648. X        opts[SHINSTDIN] = oldshst;
  649. X        return 1;
  650. X        }
  651. X    bshin = fdopen(SHIN,"r");
  652. X    loop(0);
  653. X    fclose(bshin);
  654. X    bshin = obshin;
  655. X    opts[SHINSTDIN] = oldshst;
  656. X    SHIN = fd;
  657. X    thisjob = cj;
  658. X    errflag = 0;
  659. X    retflag = 0;
  660. X    lineno = oldlineno;
  661. X    return 0;
  662. X}
  663. X
  664. X/* try to source a file in the home directory */
  665. X
  666. Xvoid sourcehome(s) /**/
  667. Xchar *s;
  668. X{
  669. Xchar buf[MAXPATHLEN];
  670. Xchar *h;
  671. X
  672. X    if (!(h = getsparam("ZDOTDIR")))
  673. X        h = home;
  674. X    sprintf(buf,"%s/%s",h,s);
  675. X    (void) source(buf);
  676. X}
  677. X
  678. X/* print an error */
  679. X
  680. Xvoid zerrnam(cmd,fmt,str,num) /**/
  681. Xchar *cmd; char *fmt; char *str;int num;
  682. X{
  683. X    if (cmd)
  684. X        {
  685. X        if (errflag || noerrs)
  686. X            return;
  687. X        errflag = 1;
  688. X        trashzle();
  689. X        if (isset(SHINSTDIN))
  690. X            fprintf(stderr,"%s: ",cmd);
  691. X        else
  692. X            fprintf(stderr,"%s: %s: ",argzero,cmd);
  693. X        }
  694. X    while (*fmt)
  695. X        if (*fmt == '%')
  696. X            {
  697. X            fmt++;
  698. X            switch(*fmt++)
  699. X                {
  700. X                case 's':
  701. X                    while (*str)
  702. X                        niceputc(*str++,stderr);
  703. X                    break;
  704. X                case 'l':
  705. X                    while (num--)
  706. X                        niceputc(*str++,stderr);
  707. X                    break;
  708. X                case 'd':
  709. X                    fprintf(stderr,"%d",num);
  710. X                    break;
  711. X                case '%':
  712. X                    putc('%',stderr);
  713. X                    break;
  714. X                case 'c':
  715. X                    niceputc(num,stderr);
  716. X                    break;
  717. X                case 'e':
  718. X                    if (num == EINTR)
  719. X                        {
  720. X                        fputs("interrupt\n",stderr);
  721. X                        errflag = 1;
  722. X                        return;
  723. X                        }
  724. X                    if (num == EIO)
  725. X                        fputs(sys_errlist[num],stderr);
  726. X                    else
  727. X                        {
  728. X                        fputc(tulower(sys_errlist[num][0]),stderr);
  729. X                        fputs(sys_errlist[num]+1,stderr);
  730. X                        }
  731. X                    break;
  732. X                }
  733. X            }
  734. X        else
  735. X            putc(*fmt++,stderr);
  736. X    if (unset(SHINSTDIN) && lineno)
  737. X        fprintf(stderr," [%ld]\n",lineno);
  738. X    else
  739. X        putc('\n',stderr);
  740. X    fflush(stderr);
  741. X}
  742. X
  743. Xvoid zerr(fmt,str,num) /**/
  744. Xchar *fmt; char *str;int num;
  745. X{
  746. X    if (errflag || noerrs)
  747. X        return;
  748. X    errflag = 1;
  749. X    trashzle();
  750. X    fprintf(stderr,"%s: ",(isset(SHINSTDIN)) ? "zsh" : argzero);
  751. X    zerrnam(NULL,fmt,str,num);
  752. X}
  753. X
  754. Xvoid niceputc(c,f) /**/
  755. Xint c;FILE *f;
  756. X{
  757. X    if (itok(c))
  758. X        {
  759. X        if (c >= Pound && c <= Comma)
  760. X            putc(ztokens[c-Pound],f);
  761. X        return;
  762. X        }
  763. X    c &= 0xff;
  764. X    if (isprint(c))
  765. X        putc(c,f);
  766. X    else if (c == '\n')
  767. X        {
  768. X        putc('\\',f);
  769. X        putc('n',f);
  770. X        }
  771. X    else
  772. X        {
  773. X        putc('^',f);
  774. X        putc(c|'@',f);
  775. X        }
  776. X}
  777. X
  778. X/* enable ^C interrupts */
  779. X
  780. Xvoid intr() /**/
  781. X{
  782. X#ifdef SV_INTERRUPT
  783. Xstatic struct sigvec vec = { handler,sigmask(SIGINT),SV_INTERRUPT };
  784. X
  785. X    if (interact)
  786. X        sigvec(SIGINT,&vec,NULL);
  787. X#else
  788. X    if (interact)
  789. X        signal(SIGINT,handler);
  790. X#endif
  791. X}
  792. X
  793. Xvoid noholdintr() /**/
  794. X{
  795. X    intr();
  796. X}
  797. X
  798. Xvoid holdintr() /**/
  799. X{
  800. X#ifdef SV_INTERRUPT
  801. Xstatic struct sigvec vec = { handler,sigmask(SIGINT),0 };
  802. X
  803. X    if (interact) sigvec(SIGINT,&vec,NULL);
  804. X#else
  805. X    if (interact) signal(SIGINT,SIG_IGN);
  806. X#endif
  807. X}
  808. X
  809. X/* get a symlink-free pathname for s relative to PWD */
  810. X
  811. Xchar *findpwd(s) /**/
  812. Xchar *s;
  813. X{
  814. Xchar *t;
  815. X
  816. X    if (*s == '/')
  817. X        return xsymlink(s);
  818. X    s = tricat((pwd[1]) ? pwd : "","/",s);
  819. X    t = xsymlink(s);
  820. X    free(s);
  821. X    return t;
  822. X}
  823. X
  824. Xstatic char xbuf[MAXPATHLEN];
  825. X
  826. X#if 0
  827. Xchar *fixpwd(s) /**/
  828. Xchar *s;
  829. X{
  830. Xstruct stat sbuf,tbuf;
  831. Xchar *t;
  832. X
  833. X    strcpy(xbuf,"");
  834. X    if (*s == '/')
  835. X        t = ztrdup(s);
  836. X    else
  837. X        t = tricat((pwd[1]) ? pwd : "","/",s);
  838. X    (void) xsymlinks(t+1,0); 
  839. X    free(t);
  840. X    if (!*xbuf)
  841. X        strcpy(xbuf,"/");
  842. X    if (stat(xbuf,&sbuf) == 0 && stat(".",&tbuf) == 0)
  843. X        if (!(sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino))
  844. X            chdir(xbuf);
  845. X    return ztrdup(xbuf);
  846. X}
  847. X#endif
  848. X
  849. Xint ispwd(s) /**/
  850. Xchar *s;
  851. X{
  852. Xstruct stat sbuf,tbuf;
  853. X
  854. X    if (stat(s,&sbuf) == 0 && stat(".",&tbuf) == 0)
  855. X        if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino)
  856. X            return 1;
  857. X    return 0;
  858. X}
  859. X
  860. X/* expand symlinks in s, and remove other weird things */
  861. X
  862. Xchar *xsymlink(s) /**/
  863. Xchar *s;
  864. X{
  865. X    if (unset(CHASELINKS))
  866. X        return ztrdup(s);
  867. X    if (*s != '/')
  868. X        return NULL;
  869. X    strcpy(xbuf,"");
  870. X    if (xsymlinks(s+1,1))
  871. X        return ztrdup(s);
  872. X    if (!*xbuf)
  873. X        return ztrdup("/");
  874. X    return ztrdup(xbuf);
  875. X}
  876. X
  877. Xchar **slashsplit(s) /**/
  878. Xchar *s;
  879. X{
  880. Xchar *t,**r,**q;
  881. Xint t0;
  882. X
  883. X    if (!*s)
  884. X        return (char **) zcalloc(sizeof(char **));
  885. X    for (t = s, t0 = 0; *t; t++)
  886. X        if (*t == '/')
  887. X            t0++;
  888. X    q  = r = (char **) zalloc(sizeof(char **)*(t0+2));
  889. X    while (t = strchr(s,'/'))
  890. X        {
  891. X        *t = '\0';
  892. X        *q++ = ztrdup(s);
  893. X        *t = '/';
  894. X        while (*t == '/')
  895. X            t++;
  896. X        if (!*t)
  897. X            {
  898. X            *q = NULL;
  899. X            return r;
  900. X            }
  901. X        s = t;
  902. X        }
  903. X    *q++ = ztrdup(s);
  904. X    *q = NULL;
  905. X    return r;
  906. X}
  907. X
  908. Xint islink(s) /**/
  909. Xchar *s;
  910. X{
  911. X    return readlink(s,NULL,0) == 0;
  912. X}
  913. X
  914. X/* expands symlinks and .. or . expressions */
  915. X/* if flag = 0, only expand .. and . expressions */
  916. X
  917. Xint xsymlinks(s,flag) /**/
  918. Xchar *s;int flag;
  919. X{
  920. Xchar **pp,**opp;
  921. Xchar xbuf2[MAXPATHLEN],xbuf3[MAXPATHLEN];
  922. Xint t0;
  923. X
  924. X    opp = pp = slashsplit(s);
  925. X    for (; *pp; pp++)
  926. X        {
  927. X        if (!strcmp(*pp,"."))
  928. X            {
  929. X            free(*pp);
  930. X            continue;
  931. X            }
  932. X        if (!strcmp(*pp,".."))
  933. X            {
  934. X            char *p;
  935. X
  936. X            free(*pp);
  937. X            if (!strcmp(xbuf,"/"))
  938. X                continue;
  939. X            p = xbuf+strlen(xbuf);
  940. X            while (*--p != '/');
  941. X            *p = '\0';
  942. X            continue;
  943. X            }
  944. X        if (unset(CHASELINKS))
  945. X            {
  946. X            strcat(xbuf,"/");
  947. X            strcat(xbuf,*pp);
  948. X            free(*pp);
  949. X            continue;
  950. X            }
  951. X        sprintf(xbuf2,"%s/%s",xbuf,*pp);
  952. X        t0 = readlink(xbuf2,xbuf3,MAXPATHLEN);
  953. X        if (t0 == -1 || !flag)
  954. X            {
  955. X            strcat(xbuf,"/");
  956. X            strcat(xbuf,*pp);
  957. X            free(*pp);
  958. X            }
  959. X        else
  960. X            {
  961. X            xbuf3[t0] = '\0'; /* STUPID */
  962. X            if (*xbuf3 == '/')
  963. X                {
  964. X                strcpy(xbuf,"");
  965. X                if (xsymlinks(xbuf3+1,flag))
  966. X                    return 1;
  967. X                }
  968. X            else
  969. X                if (xsymlinks(xbuf3,flag))
  970. X                    return 1;
  971. X            free(*pp);
  972. X            }
  973. X        }
  974. X    free(opp);
  975. X    return 0;
  976. X}
  977. X
  978. X/* print a directory */
  979. X
  980. Xvoid fprintdir(s, f) /**/
  981. Xchar *s; FILE *f;
  982. X{
  983. Xint t0;
  984. X
  985. X    t0 = finddir(s);
  986. X    if (t0 == -1)
  987. X        {
  988. X        fputs(s,f);
  989. X        }
  990. X    else
  991. X        {
  992. X        putc('~', f);
  993. X        fputs(usernames[t0],f);
  994. X        fputs(s+strlen(userdirs[t0]),f);
  995. X        }
  996. X}
  997. X
  998. Xvoid printdir(s) /**/
  999. Xchar *s;
  1000. X{
  1001. X    fprintdir(s, stdout);
  1002. X}
  1003. X
  1004. Xvoid printdircr(s) /**/
  1005. Xchar *s;
  1006. X{
  1007. X    fprintdir(s, stdout);
  1008. X    putchar('\n');
  1009. X}
  1010. X
  1011. X/* see if a path has a named directory as its prefix */
  1012. X/* Modified by Carl Edman, cedman@golem.ps.uci.edu.
  1013. X   Exhaustive search is more expensive, but binary search just doesn't
  1014. X   handle all the cases for directory prefixes very well.
  1015. X   Caching improves performance */
  1016. X
  1017. Xint finddir(s) /**/
  1018. Xchar *s;
  1019. X{
  1020. Xint t0,t1 = -1;
  1021. Xint bestlen = -1,len,bestnlen = -1,nlen;
  1022. Xint hash;
  1023. Xstatic int cdir = -1,cval = -1;
  1024. X
  1025. X    if (!s) /* Invalidate directory cache table */
  1026. X        {
  1027. X        cval = -1;
  1028. X        return -1;
  1029. X        }
  1030. X    if (!userdirsz) return -1;
  1031. X
  1032. X    hash = hasher(s);
  1033. X
  1034. X    if (cval != -1 && cval == hash) return cdir;
  1035. X
  1036. X    for(t0 = 0; t0 < userdirsz; t0++)
  1037. X        if (userdirs[t0] && !dircmp(userdirs[t0],s))
  1038. X        {
  1039. X        len = strlen(userdirs[t0]);
  1040. X        nlen = strlen(usernames[t0]);
  1041. X        if ((len > bestlen) || ((len == bestlen) && (nlen < bestnlen)))
  1042. X            {
  1043. X            t1 = t0;
  1044. X            bestlen = len;
  1045. X            bestnlen = nlen;
  1046. X            }
  1047. X        }
  1048. X    cval = hash;
  1049. X    cdir = t1;
  1050. X    return t1;
  1051. X}
  1052. X
  1053. X/* add a named directory */
  1054. X
  1055. Xvoid adduserdir(s,t) /**/
  1056. Xchar *s;char *t;
  1057. X{
  1058. Xint t0,t1;
  1059. X
  1060. X    if (!interact || ((t0 = finddir(t)) != -1 && !strcmp(s,usernames[t0])))
  1061. X        return;
  1062. X    if (!strcmp(t,"/"))
  1063. X        return;
  1064. X    if ((t0 = finddir(t)) != -1 && !strcmp(s,usernames[t0]))
  1065. X        return;
  1066. X    finddir(0); /* Invalidate directory cache table */
  1067. X    if (userdirsz == userdirct)
  1068. X        {
  1069. X        userdirsz *= 2;
  1070. X        userdirs = (char **) realloc((char *) userdirs,
  1071. X            sizeof(char **)*userdirsz);
  1072. X        usernames = (char **) realloc((char *) usernames,
  1073. X            sizeof(char **)*userdirsz);
  1074. X        for (t0 = userdirct; t0 != userdirsz; t0++)
  1075. X            userdirs[t0] = usernames[t0] = NULL;
  1076. X        }
  1077. X    for (t0 = 0; t0 != userdirct; t0++)
  1078. X        if (strcmp(userdirs[t0],t) > 0)
  1079. X            break;
  1080. X    for (t1 = userdirct-1; t1 >= t0; t1--)
  1081. X        {
  1082. X        userdirs[t1+1] = userdirs[t1];
  1083. X        usernames[t1+1] = usernames[t1];
  1084. X        }
  1085. X    userdirs[t0] = ztrdup(t);
  1086. X    usernames[t0] = ztrdup(s);
  1087. X    userdirct++;
  1088. X}
  1089. X
  1090. Xint dircmp(s,t) /**/
  1091. Xchar *s;char *t;
  1092. X{
  1093. X    for (; *s && *t; s++,t++)
  1094. X        if (*s != *t)
  1095. X            return *s-*t;
  1096. X    if (!*s && (!*t || *t == '/'))
  1097. X        return 0;
  1098. X    return *s-*t;
  1099. X}
  1100. X
  1101. Xint ddifftime(t1,t2) /**/
  1102. Xtime_t t1;time_t t2;
  1103. X{
  1104. X    return ((long) t2-(long) t1);
  1105. X}
  1106. X
  1107. X/* see if jobs need printing */
  1108. X
  1109. Xvoid scanjobs() /**/
  1110. X{
  1111. Xint t0;
  1112. X
  1113. X    for (t0 = 1; t0 != MAXJOB; t0++)
  1114. X        if (jobtab[t0].stat & STAT_CHANGED)
  1115. X            printjob(jobtab+t0,0);
  1116. X}
  1117. X
  1118. X/* do pre-prompt stuff */
  1119. X
  1120. Xvoid preprompt() /**/
  1121. X{
  1122. Xint diff;
  1123. XList list;
  1124. Xstruct schedcmd *sch,*schl;
  1125. X
  1126. X    if (unset(NOTIFY))
  1127. X        scanjobs();
  1128. X    if (errflag)
  1129. X        return;
  1130. X    if (list = getshfunc("precmd")) doshfuncnoval(list,NULL,0);
  1131. X    if (errflag)
  1132. X        return;
  1133. X    if (period && (time(NULL) > lastperiod+period) &&
  1134. X            (list = getshfunc("periodic"))) {
  1135. X        doshfuncnoval(list,NULL,0);
  1136. X        lastperiod = time(NULL);
  1137. X    }
  1138. X    if (errflag)
  1139. X        return;
  1140. X    if (watch)
  1141. X        {
  1142. X        diff = (int) ddifftime(lastwatch,time(NULL));
  1143. X        if (diff > logcheck)
  1144. X            {
  1145. X            dowatch();
  1146. X            lastwatch = time(NULL);
  1147. X            }
  1148. X        }
  1149. X    if (errflag)
  1150. X        return;
  1151. X    diff = (int) ddifftime(lastmailcheck,time(NULL));
  1152. X    if (diff > mailcheck)
  1153. X        {
  1154. X        if (mailpath && *mailpath)
  1155. X            checkmailpath(mailpath);
  1156. X        else if (mailfile)
  1157. X            {
  1158. X            char *x[2];
  1159. X
  1160. X            x[0] = mailfile;
  1161. X            x[1] = NULL;
  1162. X            checkmailpath(x);
  1163. X            }
  1164. X        lastmailcheck = time(NULL);
  1165. X        }
  1166. X    for (schl = (struct schedcmd *) &schedcmds, sch = schedcmds; sch;
  1167. X            sch = (schl = sch)->next)
  1168. X        {
  1169. X        if (sch->time < time(NULL))
  1170. X            {
  1171. X            execstring(sch->cmd);
  1172. X            schl->next = sch->next;
  1173. X            free(sch->cmd);
  1174. X            free(sch);
  1175. X            }
  1176. X        if (errflag)
  1177. X            return;
  1178. X        }
  1179. X}
  1180. X
  1181. Xint arrlen(s) /**/
  1182. Xchar **s;
  1183. X{
  1184. Xint t0;
  1185. X
  1186. X    for (t0 = 0; *s; s++,t0++);
  1187. X    return t0;
  1188. X}
  1189. X
  1190. Xvoid checkmailpath(s) /**/
  1191. Xchar **s;
  1192. X{
  1193. Xstruct stat st;
  1194. Xchar *v,*u,c;
  1195. X
  1196. X    while (*s)
  1197. X        {
  1198. X        for (v = *s; *v && *v != '?'; v++);
  1199. X        c = *v;
  1200. X        *v = '\0';
  1201. X        if (c != '?')
  1202. X            u = NULL;
  1203. X        else
  1204. X            u = v+1;
  1205. X        if (stat(*s,&st) == -1)
  1206. X            {
  1207. X            if (errno != ENOENT)
  1208. X                zerr("%e: %s",*s,errno);
  1209. X            }
  1210. X        else if (S_ISDIR(st.st_mode))
  1211. X            {
  1212. X            Lklist l;
  1213. X            DIR *lock = opendir(*s);
  1214. X            char buf[MAXPATHLEN*2],**arr,**ap;
  1215. X            struct direct *de;
  1216. X            int ct = 1;
  1217. X
  1218. X            if (lock)
  1219. X                {
  1220. X                pushheap();
  1221. X                heapalloc();
  1222. X                l = newlist();
  1223. X                readdir(lock); readdir(lock);
  1224. X                while (de = readdir(lock))
  1225. X                    {
  1226. X                    if (errflag)
  1227. X                        break;
  1228. X                    if (u)
  1229. X                        sprintf(buf,"%s/%s?%s",*s,de->d_name,u);
  1230. X                    else
  1231. X                        sprintf(buf,"%s/%s",*s,de->d_name);
  1232. X                    addnode(l,strdup(buf));
  1233. X                    ct++;
  1234. X                    }
  1235. X                closedir(lock);
  1236. X                ap = arr = (char **) alloc(ct*sizeof(char *));
  1237. X                while (*ap++ = ugetnode(l));
  1238. X                checkmailpath(arr);
  1239. X                popheap();
  1240. X                }
  1241. X            }
  1242. X        else
  1243. X            {
  1244. X            if (st.st_size && st.st_atime <= st.st_mtime &&
  1245. X                    st.st_mtime > lastmailcheck)
  1246. X                if (!u)
  1247. X                    {
  1248. X                    fprintf(stderr,"You have new mail.\n");
  1249. X                    fflush(stderr);
  1250. X                    }
  1251. X                else
  1252. X                    {
  1253. X                    char *z = u;
  1254. X
  1255. X                    while (*z)
  1256. X                        if (*z == '$' && z[1] == '_')
  1257. X                            {
  1258. X                            fprintf(stderr,"%s",*s);
  1259. X                            z += 2;
  1260. X                            }
  1261. X                        else
  1262. X                            fputc(*z++,stderr);
  1263. X                    fputc('\n',stderr);
  1264. X                    fflush(stderr);
  1265. X                    }
  1266. X            if (isset(MAILWARNING) && st.st_atime > st.st_mtime &&
  1267. X                    st.st_atime > lastmailcheck && st.st_size)
  1268. X                {
  1269. X                fprintf(stderr,"The mail in %s has been read.\n",*s);
  1270. X                fflush(stderr);
  1271. X                }
  1272. X            }
  1273. X        *v = c;
  1274. X        s++;
  1275. X        }
  1276. X}
  1277. X
  1278. Xvoid saveoldfuncs(x,y) /**/
  1279. Xchar *x;Cmdnam y;
  1280. X{
  1281. XCmdnam cc;
  1282. X
  1283. X    if (y->type == SHFUNC || y->type == DISABLED)
  1284. X        {
  1285. X        cc = (Cmdnam) zcalloc(sizeof *cc);
  1286. X        *cc = *y;
  1287. X        y->u.list = NULL;
  1288. X        addhnode(ztrdup(x),cc,cmdnamtab,freecmdnam);
  1289. X        }
  1290. X}
  1291. X
  1292. X/* create command hashtable */
  1293. X
  1294. Xvoid newcmdnamtab() /**/
  1295. X{
  1296. XHashtab oldcnt;
  1297. X
  1298. X    oldcnt = cmdnamtab;
  1299. X    permalloc();
  1300. X    cmdnamtab = newhtable(101);
  1301. X    addbuiltins();
  1302. X    if (oldcnt) {
  1303. X        listhtable(oldcnt,(HFunc) saveoldfuncs);
  1304. X        freehtab(oldcnt,freecmdnam);
  1305. X    }
  1306. X    lastalloc();
  1307. X    pathchecked = path;
  1308. X}
  1309. X
  1310. Xvoid freecmdnam(a) /**/
  1311. Xvptr a;
  1312. X{
  1313. Xstruct cmdnam *c = (struct cmdnam *) a;
  1314. X
  1315. X    if (c->type == SHFUNC) {
  1316. X        if (c->u.list)
  1317. X            freestruct(c->u.list);
  1318. X    } else if (c->type != BUILTIN && c->type != DISABLED)
  1319. X        free(c->u.nam);
  1320. X    free(c);
  1321. X}
  1322. X
  1323. Xvoid freecompctl(a) /**/
  1324. Xvptr a;
  1325. X{
  1326. XCompctl cc = (Compctl) a;
  1327. X
  1328. X    free(cc);
  1329. X}
  1330. X
  1331. Xvoid freestr(a) /**/
  1332. Xvptr a;
  1333. X{
  1334. X    free(a);
  1335. X}
  1336. X
  1337. Xvoid freeanode(a) /**/
  1338. Xvptr a;
  1339. X{
  1340. Xstruct alias *c = (struct alias *) a;
  1341. X
  1342. X    free(c->text);
  1343. X    free(c);
  1344. X}
  1345. X
  1346. Xvoid freepm(a) /**/
  1347. Xvptr a;
  1348. X{
  1349. Xstruct param *pm = (Param) a;
  1350. X
  1351. X    free(pm);
  1352. X}
  1353. X
  1354. Xvoid restoretty() /**/
  1355. X{
  1356. X    settyinfo(&shttyinfo);
  1357. X}
  1358. X
  1359. Xvoid gettyinfo(ti) /**/
  1360. Xstruct ttyinfo *ti;
  1361. X{
  1362. X    if (SHTTY != -1)
  1363. X        {
  1364. X#ifdef TERMIOS
  1365. X#ifdef HAS_TCCRAP
  1366. X        if (tcgetattr(SHTTY,&ti->tio) == -1)
  1367. X#else
  1368. X        if (ioctl(SHTTY,TCGETS,&ti->tio) == -1)
  1369. X#endif
  1370. X            zerr("bad tcgets: %e",NULL,errno);
  1371. X#else
  1372. X#ifdef TERMIO
  1373. X        ioctl(SHTTY,TCGETA,&ti->tio);
  1374. X#else
  1375. X        ioctl(SHTTY,TIOCGETP,&ti->sgttyb);
  1376. X        ioctl(SHTTY,TIOCLGET,&ti->lmodes);
  1377. X        ioctl(SHTTY,TIOCGETC,&ti->tchars);
  1378. X        ioctl(SHTTY,TIOCGLTC,&ti->ltchars);
  1379. X#endif
  1380. X#endif
  1381. X#ifdef TIOCGWINSZ
  1382. X        if (ioctl(SHTTY,TIOCGWINSZ,&ti->winsize) == -1)
  1383. X        /*    zerr("bad tiocgwinsz: %e",NULL,errno)*/;
  1384. X#endif
  1385. X        }
  1386. X}
  1387. X
  1388. Xvoid settyinfo(ti) /**/
  1389. Xstruct ttyinfo *ti;
  1390. X{
  1391. X    if (SHTTY != -1)
  1392. X        {
  1393. X#ifdef TERMIOS
  1394. X#ifdef HAS_TCCRAP
  1395. X#ifndef TCSADRAIN
  1396. X#define TCSADRAIN 1   /* XXX Princeton's include files are screwed up */
  1397. X#endif
  1398. X        if (tcsetattr(SHTTY, TCSADRAIN, &ti->tio) == -1)
  1399. X#else
  1400. X        if (ioctl(SHTTY,TCSETS,&ti->tio) == -1)
  1401. X#endif
  1402. X        /*    zerr("settyinfo: %e",NULL,errno)*/;
  1403. X#else
  1404. X#ifdef TERMIO
  1405. X        ioctl(SHTTY,TCSETA,&ti->tio);
  1406. X#else
  1407. X        ioctl(SHTTY,TIOCSETN,&ti->sgttyb);
  1408. X        ioctl(SHTTY,TIOCLSET,&ti->lmodes);
  1409. X        ioctl(SHTTY,TIOCSETC,&ti->tchars);
  1410. X        ioctl(SHTTY,TIOCSLTC,&ti->ltchars);
  1411. X#endif
  1412. X#endif
  1413. X#ifdef TIOCGWINSZ
  1414. X        signal(SIGWINCH,SIG_IGN);
  1415. X        if (ioctl(SHTTY,TIOCSWINSZ,&ti->winsize) == -1)
  1416. X        /*    zerr("settyinfo: %e",NULL,errno)*/;
  1417. X        signal(SIGWINCH,handler);
  1418. X#endif
  1419. X        }
  1420. X}
  1421. X
  1422. X#define SANEKEY(X) \
  1423. X    if (ti->X == -1 && savedttyinfo.X != -1) ti->X = savedttyinfo.X;
  1424. X
  1425. Xvoid sanetty(ti) /**/
  1426. Xstruct ttyinfo *ti;
  1427. X{
  1428. Xint t0;
  1429. X
  1430. X#ifdef TIO
  1431. X    ti->tio.c_lflag |= ICANON|ECHO;
  1432. X#ifdef FLUSHO
  1433. X    ti->tio.c_lflag &= ~FLUSHO;
  1434. X#endif
  1435. X    for (t0 = 0; t0 !=
  1436. X#ifdef NCCS
  1437. X    NCCS
  1438. X#else
  1439. X    NCC
  1440. X#endif
  1441. X    ; t0++)
  1442. X        if (ti->tio.c_cc[t0] == VDISABLEVAL &&
  1443. X                savedttyinfo.tio.c_cc[t0] != VDISABLEVAL)
  1444. X            ti->tio.c_cc[t0] = savedttyinfo.tio.c_cc[t0];
  1445. X#else
  1446. X    ti->sgttyb.sg_flags = (ti->sgttyb.sg_flags & ~CBREAK) | ECHO;
  1447. X    ti->lmodes &= ~LFLUSHO;
  1448. X    SANEKEY(tchars.t_quitc);
  1449. X    SANEKEY(tchars.t_startc);
  1450. X    SANEKEY(tchars.t_stopc);
  1451. X    SANEKEY(ltchars.t_suspc);
  1452. X    SANEKEY(ltchars.t_dsuspc);
  1453. X    SANEKEY(ltchars.t_lnextc);
  1454. X    SANEKEY(ltchars.t_flushc);
  1455. X#endif
  1456. X}
  1457. X
  1458. Xvoid adjustwinsize() /**/
  1459. X{
  1460. X#ifdef TIOCGWINSZ
  1461. X    ioctl(SHTTY,TIOCGWINSZ,&shttyinfo.winsize);
  1462. X    if (!(columns = shttyinfo.winsize.ws_col)) columns = 80;
  1463. X    lines = shttyinfo.winsize.ws_row;
  1464. X    setintenv("COLUMNS",columns);
  1465. X    setintenv("LINES",lines);
  1466. X    if (zleactive) refresh();
  1467. X#endif
  1468. X}
  1469. X
  1470. Xint zyztem(s,t) /**/
  1471. Xchar *s;char *t;
  1472. X{
  1473. Xint cj = thisjob;
  1474. X
  1475. X    s = tricat(s," ",t);
  1476. X    execstring(s);    /* Depends on recursion condom in execute() */
  1477. X    free(s);
  1478. X    thisjob = cj;
  1479. X    return lastval;
  1480. X}
  1481. X
  1482. X#ifndef WAITPID
  1483. X
  1484. X/* fork a process and wait for it to complete without confusing
  1485. X    the SIGCHLD handler */
  1486. X
  1487. Xint waitfork() /**/
  1488. X{
  1489. Xint pipes[2];
  1490. Xchar x;
  1491. X
  1492. X    pipe(pipes);
  1493. X    if (!fork())
  1494. X        {
  1495. X        close(pipes[0]);
  1496. X        signal(SIGCHLD,SIG_DFL);
  1497. X        if (!fork())
  1498. X            return 0;
  1499. X        wait(NULL);
  1500. X        _exit(0);
  1501. X        }
  1502. X    close(pipes[1]);
  1503. X    read(pipes[0],&x,1);
  1504. X    close(pipes[0]);
  1505. X    return 1;
  1506. X}
  1507. X
  1508. X#endif
  1509. X
  1510. X/* move a fd to a place >= 10 */
  1511. X
  1512. Xint movefd(fd) /**/
  1513. Xint fd;
  1514. X{
  1515. Xint fe;
  1516. X
  1517. X    if (fd == -1)
  1518. X        return fd;
  1519. X#ifdef F_DUPFD
  1520. X    fe = fcntl(fd,F_DUPFD,10);
  1521. X#else
  1522. X    if ((fe = dup(fd)) < 10)
  1523. X        fe = movefd(fe);
  1524. X#endif
  1525. X    close(fd);
  1526. X    return fe;
  1527. X}
  1528. X
  1529. X/* move fd x to y */
  1530. X
  1531. Xvoid redup(x,y) /**/
  1532. Xint x;int y;
  1533. X{
  1534. X    if (x != y)
  1535. X        {
  1536. X        dup2(x,y);
  1537. X        close(x);
  1538. X        }
  1539. X}
  1540. X
  1541. Xvoid settrap(t0,l) /**/
  1542. Xint t0;List l;
  1543. X{
  1544. XCmd c;
  1545. X
  1546. X    if (l)
  1547. X        {
  1548. X        c = l->left->left->left;
  1549. X        if (c->type == SIMPLE && empty(c->args) && empty(c->redir)
  1550. X                && empty(c->vars) && !c->flags)
  1551. X            l = NULL;
  1552. X        }
  1553. X    if (t0 == -1)
  1554. X        return;
  1555. X    if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN
  1556. X            || t0 == SIGPIPE))
  1557. X        {
  1558. X        zerr("can't trap SIG%s in interactive shells",sigs[t0-1],0);
  1559. X        return;
  1560. X        }
  1561. X    if (!l)
  1562. X        {
  1563. X        sigtrapped[t0] = 2;
  1564. X        if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD &&
  1565. X#ifdef SIGWINCH
  1566. X            t0 != SIGWINCH &&
  1567. X#endif
  1568. X            t0 != SIGHUP) signal(t0,SIG_IGN);
  1569. X        }
  1570. X    else
  1571. X        {
  1572. X        if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD &&
  1573. X#ifdef SIGWINCH
  1574. X            t0 != SIGWINCH &&
  1575. X#endif
  1576. X            t0 != SIGHUP) signal(t0,handler);
  1577. X        sigtrapped[t0] = 1;
  1578. X        permalloc();
  1579. X        sigfuncs[t0] = (List) dupstruct(l);
  1580. X        heapalloc();
  1581. X        }
  1582. X}
  1583. X
  1584. Xvoid unsettrap(t0) /**/
  1585. Xint t0;
  1586. X{
  1587. X    if (t0 == -1)
  1588. X        return;
  1589. X    if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN
  1590. X            || t0 == SIGPIPE)) {
  1591. X        return;
  1592. X    }
  1593. X    sigtrapped[t0] = 0;
  1594. X    if (t0 == SIGINT) intr();
  1595. X    else if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD &&
  1596. X#ifdef SIGWINCH
  1597. X        t0 != SIGWINCH &&
  1598. X#endif
  1599. X        t0 != SIGHUP) signal(t0,SIG_DFL);
  1600. X    if (sigfuncs[t0]) freestruct(sigfuncs[t0]);
  1601. X}
  1602. X
  1603. Xvoid dotrap(sig) /**/
  1604. Xint sig;
  1605. X{
  1606. Xint sav,savval;
  1607. X
  1608. X    sav = sigtrapped[sig];
  1609. X    savval = lastval;
  1610. X    if (sav == 2)
  1611. X        return;
  1612. X    sigtrapped[sig] = 2;
  1613. X    if (sigfuncs[sig]) {
  1614. X        lexsave();
  1615. X        doshfuncnoval(sigfuncs[sig],NULL,0);
  1616. X        lexrestore();
  1617. X    }
  1618. X    if (sigtrapped[sig])
  1619. X        sigtrapped[sig] = sav;
  1620. X    lastval = savval;
  1621. X}
  1622. X
  1623. X/* copy len chars from t into s, and null terminate */
  1624. X
  1625. Xvoid ztrncpy(s,t,len) /**/
  1626. Xchar *s;char *t;int len;
  1627. X{
  1628. X    while (len--) *s++ = *t++;
  1629. X    *s = '\0';
  1630. X}
  1631. X
  1632. X/* copy t into *s and update s */
  1633. X
  1634. Xvoid strucpy(s,t) /**/
  1635. Xchar **s;char *t;
  1636. X{
  1637. Xchar *u = *s;
  1638. X
  1639. X    while (*u++ = *t++);
  1640. X    *s = u-1;
  1641. X}
  1642. X
  1643. Xvoid struncpy(s,t,n) /**/
  1644. Xchar **s;char *t;int n;
  1645. X{
  1646. Xchar *u = *s;
  1647. X
  1648. X    while (n--)
  1649. X        *u++ = *t++;
  1650. X    *s = u;
  1651. X    *u = '\0';
  1652. X}
  1653. X
  1654. Xint checkrmall(s) /**/
  1655. Xchar *s;
  1656. X{
  1657. X    fflush(stdin);
  1658. X    if (*s == '/')
  1659. X        fprintf(stderr,"zsh: sure you want to delete all the files in %s? ",s);
  1660. X    else
  1661. X        fprintf(stderr,"zsh: sure you want to delete all the files in %s/%s? ",
  1662. X            (pwd[1]) ? pwd : "",s);
  1663. X    fflush(stderr);
  1664. X    feep();
  1665. X    return (getquery() == 'y');
  1666. X}
  1667. X
  1668. Xint getquery() /**/
  1669. X{
  1670. Xchar c;
  1671. Xlong val;
  1672. X
  1673. X    setcbreak();
  1674. X#ifdef FIONREAD
  1675. X    ioctl(SHTTY,FIONREAD,&val);
  1676. X    if (val) { unsetcbreak(); write(2,"n\n",2); return 'n'; }
  1677. X#endif
  1678. X    if (read(SHTTY,&c,1) == 1)
  1679. X        if (c == 'y' || c == 'Y' || c == '\t') c = 'y';
  1680. X    unsetcbreak();
  1681. X    if (c != '\n')
  1682. X        write(2,"\n",1);
  1683. X    return (int) c;
  1684. X}
  1685. X
  1686. Xstatic int d;
  1687. Xstatic char *guess,*best;
  1688. X
  1689. Xvoid spscannodis(s,cn) /**/
  1690. Xchar *s;char *cn;
  1691. X{
  1692. X    if (((Cmdnam) cn)->type != DISABLED)
  1693. X        spscan(s,NULL);
  1694. X}
  1695. X
  1696. Xvoid spscan(s,junk) /**/
  1697. Xchar *s;char *junk;
  1698. X{
  1699. Xint nd;
  1700. X
  1701. X    nd = spdist(s,guess,strlen(guess)/4+1);
  1702. X    if (nd <= d) {
  1703. X        best = s;
  1704. X        d = nd;
  1705. X    }
  1706. X}
  1707. X
  1708. X/* spellcheck a word */
  1709. X/* fix s and s2 ; if s2 is non-null, fix the history list too */
  1710. X
  1711. Xvoid spckword(s,s2,tptr,cmd,ask) /**/
  1712. Xchar **s;char **s2;char **tptr;int cmd;int ask;
  1713. X{
  1714. Xchar *t,*u;
  1715. Xchar firstchar;
  1716. Xint x;
  1717. Xint pram = 0;
  1718. X
  1719. X    if (**s == '-' || **s == '%')
  1720. X        return;
  1721. X    if (!strcmp(*s,"in"))
  1722. X        return;
  1723. X    if (!(*s)[0] || !(*s)[1]) return;
  1724. X    if (gethnode(*s,cmdnamtab) || gethnode(*s,aliastab)) return;
  1725. X    t = *s;
  1726. X    if (*t == Tilde || *t == Equals || *t == String) t++;
  1727. X    for (; *t; t++) if (itok(*t)) return;
  1728. X    best = NULL;
  1729. X    for (t = *s; *t; t++) if (*t == '/') break;
  1730. X    if (**s == String) {
  1731. X        if (*t) return;
  1732. X        pram = 1;
  1733. X        guess = *s+1;
  1734. X        d = 100;
  1735. X        listhtable(paramtab,spscan);
  1736. X    } else {
  1737. X        if ((u = spname(guess = *s)) != *s)
  1738. X            best = u;
  1739. X        if (!*t && !cmd) {
  1740. X            if (access(*s,F_OK) == 0) return;
  1741. X            if (hashcmd(*s,pathchecked)) return;
  1742. X            guess = *s;
  1743. X            d = 100;
  1744. X            listhtable(aliastab,spscan);
  1745. X            listhtable(cmdnamtab,spscan);
  1746. X        }
  1747. X    }
  1748. X    if (errflag) return;
  1749. X    if (best && strlen(best) > 1 && strcmp(best,guess)) {
  1750. X        if (ask) {
  1751. X            char *pp;
  1752. X            int junk;
  1753. X
  1754. X            rstring = best; Rstring = guess;
  1755. X            firstchar = *guess;
  1756. X            if (*guess == Tilde) *guess = '~';
  1757. X            else if (*guess == String) *guess = '$';
  1758. X            else if (*guess == Equals) *guess = '=';
  1759. X            pp = putprompt(sprompt,&junk,1);
  1760. X            *guess = firstchar;
  1761. X            fprintf(stderr,"%s",pp);
  1762. X            fflush(stderr);
  1763. X            feep();
  1764. X            x = getquery();
  1765. X        } else
  1766. X            x = 'y';
  1767. X        if (x == 'y') {
  1768. X            if (!pram) {
  1769. X                *s = strdup(best);
  1770. X            } else {
  1771. X                *s = alloc(strlen(best)+2);
  1772. X                strcpy(*s+1,best);
  1773. X                **s = String;
  1774. X            }
  1775. X            if (s2) {
  1776. X                if (*tptr && !strcmp(hlastw,*s2) && hlastw < hptr) {
  1777. X                    char *z;
  1778. X                    hptr = hlastw;
  1779. X                    if (pram) hwaddc('$');
  1780. X                    for (z = best; *z; z++) hwaddc(*z);
  1781. X                    hwaddc(HISTSPACE);
  1782. X                    *tptr = hptr-1;
  1783. X                    **tptr = '\0';
  1784. X                }
  1785. X                *s2 = strdup(best);
  1786. X            }
  1787. X        } else if (x == 'a') {
  1788. X            histdone |= HISTFLAG_NOEXEC;
  1789. X        } else if (x == 'e') {
  1790. X            histdone |= HISTFLAG_NOEXEC|HISTFLAG_RECALL;
  1791. X        }
  1792. X    }
  1793. X}
  1794. X
  1795. Xint ztrftime(buf,bufsize,fmt,tm) /**/
  1796. Xchar *buf;int bufsize;char *fmt;struct tm *tm;
  1797. X{
  1798. Xstatic char *astr[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
  1799. Xstatic char *estr[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
  1800. X    "Aug","Sep","Oct","Nov","Dec"};
  1801. Xstatic char *lstr[] = {"12"," 1"," 2"," 3"," 4"," 5"," 6"," 7"," 8"," 9",
  1802. X    "10","11"};
  1803. Xchar tmp[3];
  1804. X#ifdef HAS_STRFTIME
  1805. Xchar *origbuf = buf;
  1806. X#endif
  1807. X
  1808. X    tmp[0] = '%'; tmp[2] = '\0';
  1809. X    while (*fmt)
  1810. X        if (*fmt == '%')
  1811. X            {
  1812. X            fmt++;
  1813. X            switch(*fmt++)
  1814. X                {
  1815. X                case 'a':
  1816. X                    strucpy(&buf,astr[tm->tm_wday]);
  1817. X                    break;
  1818. X                case 'b':
  1819. X                    strucpy(&buf,estr[tm->tm_mon]);
  1820. X                    break;
  1821. X                case 'd':
  1822. X                    *buf++ = '0'+tm->tm_mday/10;
  1823. X                    *buf++ = '0'+tm->tm_mday%10;
  1824. X                    break;
  1825. X                case 'e':
  1826. X                    if (tm->tm_mday > 9)
  1827. X                        *buf++ = '0'+tm->tm_mday/10;
  1828. X                    *buf++ = '0'+tm->tm_mday%10;
  1829. X                    break;
  1830. X                case 'k':
  1831. X                    if (tm->tm_hour > 9)
  1832. X                        *buf++ = '0'+tm->tm_hour/10;
  1833. X                    *buf++ = '0'+tm->tm_hour%10;
  1834. X                    break;
  1835. X                case 'l':
  1836. X                    strucpy(&buf,lstr[tm->tm_hour%12]);
  1837. X                    break;
  1838. X                case 'm':
  1839. X                    *buf++ = '0'+(tm->tm_mon+1)/10;
  1840. X                    *buf++ = '0'+(tm->tm_mon+1)%10;
  1841. X                    break;
  1842. X                case 'M':
  1843. X                    *buf++ = '0'+tm->tm_min/10;
  1844. X                    *buf++ = '0'+tm->tm_min%10;
  1845. X                    break;
  1846. X                case 'p':
  1847. X                    *buf++ = (tm->tm_hour > 11) ? 'p' : 'a';
  1848. X                    *buf++ = 'm';
  1849. X                    break;
  1850. X                case 'S':
  1851. X                    *buf++ = '0'+tm->tm_sec/10;
  1852. X                    *buf++ = '0'+tm->tm_sec%10;
  1853. X                    break;
  1854. X                case 'y':
  1855. X                    *buf++ = '0'+tm->tm_year/10;
  1856. X                    *buf++ = '0'+tm->tm_year%10;
  1857. X                    break;
  1858. X                default:
  1859. X#ifdef HAS_STRFTIME
  1860. X                    *buf = '\0';
  1861. X                    tmp[1] = fmt[-1];
  1862. X                    strftime(buf,bufsize-strlen(origbuf),tmp,tm);
  1863. X                    buf += strlen(buf);
  1864. X#else
  1865. X                    *buf++ = '%';
  1866. X                    *buf++ = fmt[-1];
  1867. X#endif
  1868. X                    break;
  1869. X                }
  1870. X            }
  1871. X        else
  1872. X            *buf++ = *fmt++;
  1873. X    *buf = '\0';
  1874. X    return 0;
  1875. X}
  1876. X
  1877. Xchar *join(arr,delim) /**/
  1878. Xchar **arr;int delim;
  1879. X{
  1880. Xint len = 0;
  1881. Xchar **s,*ret,*ptr;
  1882. Xstatic char *lastmem = NULL;
  1883. X
  1884. X    for (s = arr; *s; s++)
  1885. X        len += strlen(*s)+1;
  1886. X    if (!len) return "";
  1887. X    if (lastmem) free(lastmem);
  1888. X    lastmem = ptr = ret = zalloc(len);
  1889. X    for (s = arr; *s; s++) {
  1890. X        strucpy(&ptr,*s);
  1891. X        *ptr++ = delim;
  1892. X    }
  1893. X    ptr[-1] = '\0';
  1894. X    return ret;
  1895. X}
  1896. X
  1897. Xchar *spacejoin(s) /**/
  1898. Xchar **s;
  1899. X{
  1900. X    return join(s,*ifs);
  1901. X}
  1902. X
  1903. Xchar *colonjoin(s) /**/
  1904. Xchar **s;
  1905. X{
  1906. X    return join(s,':');
  1907. X}
  1908. X
  1909. Xchar **colonsplit(s) /**/
  1910. Xchar *s;
  1911. X{
  1912. Xint ct;
  1913. Xchar *t,**ret,**ptr;
  1914. X
  1915. X    for (t = s, ct = 0; *t; t++) if (*t == ':') ct++;
  1916. X    ptr = ret = (char **) zalloc(sizeof(char **)*(ct+2));
  1917. X    t = s;
  1918. X    do {
  1919. X        for (s = t; *t && *t != ':'; t++);
  1920. X        *ptr = zalloc((t-s)+1);
  1921. X        ztrncpy(*ptr++,s,t-s);
  1922. X    }
  1923. X    while (*t++);
  1924. X    *ptr = NULL;
  1925. X    return ret;
  1926. X}
  1927. X
  1928. Xchar **spacesplit(s) /**/
  1929. Xchar *s;
  1930. X{
  1931. Xint ct;
  1932. Xchar *t,**ret,**ptr;
  1933. X
  1934. X    for (t = s, ct = 0; *t; t++)
  1935. X        if (isep(*t)) ct++;
  1936. X    ptr = ret = (char **) zalloc(sizeof(char **)*(ct+2));
  1937. X    t = s;
  1938. X    do {
  1939. X        for (s = t; *t && !isep(*t); t++);
  1940. X        *ptr = zalloc((t-s)+1);
  1941. X        ztrncpy(*ptr++,s,t-s);
  1942. X    } while (*t++);
  1943. X    *ptr = NULL;
  1944. X    return ret;
  1945. X}
  1946. X
  1947. XList getshfunc(nam) /**/
  1948. Xchar *nam;
  1949. X{
  1950. XCmdnam x = (Cmdnam) gethnode(nam,cmdnamtab);
  1951. X
  1952. X    return (x && x->type == SHFUNC) ? x->u.list : NULL;
  1953. X}
  1954. X
  1955. X/* allocate a tree element */
  1956. X
  1957. Xvptr allocnode(type) /**/
  1958. Xint type;
  1959. X{
  1960. Xint t0;
  1961. Xstruct node *n = (struct node *) alloc(sizeof *n);
  1962. Xstatic int typetab[N_COUNT][4] = {
  1963. X    {NT_NODE,NT_NODE,0,0},
  1964. X    {NT_NODE,NT_NODE,0,0},
  1965. X    {NT_NODE,NT_NODE,0,0},
  1966. X    {NT_STR|NT_LIST,NT_NODE,NT_NODE|NT_LIST,NT_NODE|NT_LIST},
  1967. X    {NT_STR,0,0,0},
  1968. X    {NT_NODE,NT_NODE,0,0},
  1969. X    {NT_STR,NT_NODE,0,0},
  1970. X    {NT_NODE,NT_STR,NT_NODE,0},
  1971. X    {NT_NODE,NT_NODE,NT_NODE,0},
  1972. X    {NT_NODE,NT_NODE,0,0},
  1973. X    {NT_STR,NT_STR,NT_STR|NT_LIST,0}
  1974. X    };
  1975. X
  1976. X    n->type = type;
  1977. X    for (t0 = 0; t0 != 4; t0++)
  1978. X        n->types[t0] = typetab[type][t0];
  1979. X    return (vptr) n;
  1980. X}
  1981. X
  1982. X/* duplicate a syntax tree */
  1983. X
  1984. Xvptr dupstruct(a) /**/
  1985. Xvptr a;
  1986. X{
  1987. Xstruct node *n = a,*m;
  1988. Xint t0;
  1989. X
  1990. X    if (!a) return NULL;
  1991. X    m = alloc(sizeof *m);
  1992. X    *m = *n;
  1993. X    for (t0 = 0; t0 != 4; t0++)
  1994. X        if (m->ptrs[t0])
  1995. X            switch(m->types[t0])
  1996. X                {
  1997. X                case NT_NODE: m->ptrs[t0] = dupstruct(m->ptrs[t0]); break;
  1998. X                case NT_STR: m->ptrs[t0] =
  1999. X                    (useheap) ? strdup(m->ptrs[t0]) : ztrdup(m->ptrs[t0]); break;
  2000. X                case NT_LIST|NT_NODE:
  2001. X                    m->ptrs[t0] = duplist(m->ptrs[t0],dupstruct); break;
  2002. X                case NT_LIST|NT_STR:
  2003. X                    m->ptrs[t0] = duplist(m->ptrs[t0],(VFunc)
  2004. X                        ((useheap) ? strdup : ztrdup));
  2005. X                    break;
  2006. X                }
  2007. X    return (vptr) m;
  2008. X}
  2009. X
  2010. X/* free a syntax tree */
  2011. X
  2012. Xvoid freestruct(a) /**/
  2013. Xvptr a;
  2014. X{
  2015. Xstruct node *n = (struct node *) a;
  2016. Xint t0;
  2017. X
  2018. X    for (t0 = 0; t0 != 4; t0++)
  2019. X        if (n->ptrs[t0])
  2020. X            switch(n->types[t0])
  2021. X                {
  2022. X                case NT_NODE: freestruct(n->ptrs[t0]); break;
  2023. X                case NT_STR: free(n->ptrs[t0]); break;
  2024. X                case NT_LIST|NT_STR: freetable(n->ptrs[t0],freestr); break;
  2025. X                case NT_LIST|NT_NODE: freetable(n->ptrs[t0],freestruct); break;
  2026. X                }
  2027. X    free(n);
  2028. X}
  2029. X
  2030. XLklist duplist(l,func) /**/
  2031. XLklist l;VFunc func;
  2032. X{
  2033. XLklist ret;
  2034. XLknode node;
  2035. X
  2036. X    ret = newlist();
  2037. X    for (node = firstnode(l); node; incnode(node))
  2038. X        addnode(ret,func(getdata(node)));
  2039. X    return ret;
  2040. X}
  2041. X
  2042. Xchar **mkarray(s) /**/
  2043. Xchar *s;
  2044. X{
  2045. Xchar **t = (char **) zalloc((s) ? (2*sizeof s) : (sizeof s));
  2046. X
  2047. X    if (*t = s) t[1] = NULL;
  2048. X    return t;
  2049. X}
  2050. X
  2051. Xvoid feep() /**/
  2052. X{
  2053. X    if (unset(NOBEEP))
  2054. X        write(2,"\07",1);
  2055. X}
  2056. X
  2057. Xvoid freearray(s) /**/
  2058. Xchar **s;
  2059. X{
  2060. Xchar **t = s;
  2061. X
  2062. X    while (*s)
  2063. X        free(*s++);
  2064. X    free(t);
  2065. X}
  2066. X
  2067. Xint equalsplit(s,t) /**/
  2068. Xchar *s;char **t;
  2069. X{
  2070. X    for (; *s && *s != '='; s++);
  2071. X    if (*s == '=')
  2072. X        {
  2073. X        *s++ = '\0';
  2074. X        *t = s;
  2075. X        return 1;
  2076. X        }
  2077. X    return 0;
  2078. X}
  2079. X
  2080. X/* see if the right side of a list is trivial */
  2081. X
  2082. Xvoid simplifyright(l) /**/
  2083. XList l;
  2084. X{
  2085. XCmd c;
  2086. X
  2087. X    if (!l->right)
  2088. X        return;
  2089. X    if (l->right->right || l->right->left->right ||
  2090. X            l->right->left->flags || l->right->left->left->right ||
  2091. X             l->left->flags)
  2092. X        return;
  2093. X    c = l->left->left->left;
  2094. X    if (c->type != SIMPLE || full(c->args) || full(c->redir)
  2095. X            || full(c->vars))
  2096. X        return;
  2097. X    l->right = NULL;
  2098. X    return;
  2099. X}
  2100. X
  2101. X/* initialize the ztypes table */
  2102. X
  2103. Xvoid inittyptab() /**/
  2104. X{
  2105. Xint t0;
  2106. Xchar *s;
  2107. X
  2108. X    for (t0 = 0; t0 != 256; t0++)
  2109. X        typtab[t0] = 0;
  2110. X    for (t0 = 0; t0 != 32; t0++)
  2111. X        typtab[t0] = typtab[t0+128] = ICNTRL;
  2112. X    typtab[127] = ICNTRL;
  2113. X    for (t0 = '0'; t0 <= '9'; t0++)
  2114. X        typtab[t0] = IDIGIT|IALNUM|IWORD|IIDENT|IUSER;
  2115. X    for (t0 = 'a'; t0 <= 'z'; t0++)
  2116. X        typtab[t0] = typtab[t0-'a'+'A'] = IALPHA|IALNUM|IIDENT|IUSER|IWORD;
  2117. X    for (t0 = 0240; t0 != 0400; t0++)
  2118. X        typtab[t0] = IALPHA|IALNUM|IIDENT|IUSER|IWORD;
  2119. X    typtab['_'] = IIDENT|IUSER;
  2120. X    typtab['-'] = IUSER;
  2121. X    typtab[' '] |= IBLANK|INBLANK;
  2122. X    typtab['\t'] |= IBLANK|INBLANK;
  2123. X    typtab['\n'] |= INBLANK;
  2124. X    for (t0 = (int) STOUC(ALPOP); t0 <= (int) STOUC(Nularg);
  2125. X            t0++)
  2126. X        typtab[t0] |= ITOK;
  2127. X    for (s = ifs; *s; s++)
  2128. X        typtab[(int) (unsigned char) *s] |= ISEP;
  2129. X    for (s = wordchars; *s; s++)
  2130. X        typtab[(int) (unsigned char) *s] |= IWORD;
  2131. X    for (s = SPECCHARS; *s; s++)
  2132. X        typtab[(int) (unsigned char) *s] |= ISPECIAL;
  2133. X}
  2134. X
  2135. Xchar **arrdup(s) /**/
  2136. Xchar **s;
  2137. X{
  2138. Xchar **x,**y;
  2139. X
  2140. X    y = x = (char **) ncalloc(sizeof(char *)*(arrlen(s)+1));
  2141. X    while (*x++ = strdup(*s++));
  2142. X    return y;
  2143. X}
  2144. X
  2145. X/* next few functions stolen (with changes) from Kernighan & Pike */
  2146. X/* "The UNIX Programming Environment" (w/o permission) */
  2147. X
  2148. Xchar *spname (oldname) /**/
  2149. Xchar *oldname;
  2150. X{
  2151. X    char *p,guess[MAXPATHLEN+1],best[MAXPATHLEN+1];
  2152. X    static char newname[MAXPATHLEN+1];
  2153. X    char *new = newname, *old;
  2154. X
  2155. X    if (itok(*oldname)) {
  2156. X        singsub(&oldname);
  2157. X        if (!oldname) return NULL;
  2158. X    }
  2159. X    if (access(oldname,F_OK) == 0) return NULL;
  2160. X    old = oldname;
  2161. X    for (;;) {
  2162. X        while (*old == '/') *new++ = *old++;
  2163. X        *new = '\0';
  2164. X        if (*old == '\0') return newname;
  2165. X        p = guess;
  2166. X        for (; *old != '/' && *old != '\0'; old++)
  2167. X            if (p < guess+MAXPATHLEN) *p++ = *old;
  2168. X        *p = '\0';
  2169. X        if (mindist(newname,guess,best) >= 3) return NULL;
  2170. X        for (p = best; *new = *p++; ) new++;
  2171. X    }
  2172. X}
  2173. X
  2174. Xint mindist(dir,guess,best) /**/
  2175. Xchar *dir;char *guess;char *best;
  2176. X{
  2177. X    int d,nd;
  2178. X    DIR *dd;
  2179. X    struct direct *de;
  2180. X    char buf[MAXPATHLEN];
  2181. X
  2182. X    if (dir[0] == '\0')
  2183. X        dir = ".";
  2184. X    d = 100;
  2185. X    sprintf(buf,"%s/%s",dir,guess);
  2186. X    if (access(buf,F_OK) == 0) { strcpy(best,guess); return 0; }
  2187. X    if (!(dd = opendir(dir))) return d;
  2188. X    while (de = readdir(dd)) {
  2189. X        nd = spdist(de->d_name,guess,strlen(guess)/4+1);
  2190. X        if (nd <= d) {
  2191. X            strcpy(best,de->d_name);
  2192. X            d = nd;
  2193. X            if (d == 0) break;
  2194. X        }
  2195. X    }
  2196. X    closedir(dd);
  2197. X    return d;
  2198. X}
  2199. X
  2200. Xint spdist(s,t,thresh) /**/
  2201. Xchar *s;char *t;int thresh;
  2202. X{
  2203. Xchar *p,*q;
  2204. Xchar *keymap =
  2205. X"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
  2206. X\t1234567890-=\t\
  2207. X\tqwertyuiop[]\t\
  2208. X\tasdfghjkl;'\n\t\
  2209. X\tzxcvbnm,./\t\t\t\
  2210. X\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
  2211. X\t!@#$%^&*()_+\t\
  2212. X\tQWERTYUIOP{}\t\
  2213. X\tASDFGHJKL:\"\n\t\
  2214. X\tZXCVBNM<>?\n\n\t\
  2215. X\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
  2216. X
  2217. X    if (!strcmp(s,t))
  2218. X        return 0;
  2219. X    /* any number of upper/lower mistakes allowed (dist = 1) */
  2220. X    for (p = s, q = t; *p && tulower(*p) == tulower(*q); p++,q++);
  2221. X    if (!*p && !*q)
  2222. X        return 1;
  2223. X    if (!thresh)
  2224. X        return 200;
  2225. X    for (p = s, q = t; *p && *q; p++,q++)
  2226. X        if (*p == *q) continue;    /* don't consider "aa" transposed, ash */
  2227. X        else if (p[1] == q[0] && q[1] == p[0])  /* transpositions */
  2228. X            return spdist(p+2,q+2,thresh-1)+1;
  2229. X        else if (p[1] == q[0])    /* missing letter */
  2230. X            return spdist(p+1,q+0,thresh-1)+2;
  2231. X        else if (p[0] == q[1])    /* missing letter */
  2232. X            return spdist(p+0,q+1,thresh-1)+2;
  2233. X        else if (*p != *q)
  2234. X            break;
  2235. X    if ((!*p && strlen(q) == 1) || (!*q && strlen(p) == 1))
  2236. X        return 2;
  2237. X    for (p = s, q = t; *p && *q; p++,q++)
  2238. X        if (p[0] != q[0] && p[1] == q[1])
  2239. X            {
  2240. X            int t0;
  2241. X            char *z;
  2242. X
  2243. X            /* mistyped letter */
  2244. X
  2245. X            if (!(z = strchr(keymap,p[0])) || *z == '\n' || *z == '\t')
  2246. X                return spdist(p+1,q+1,thresh-1)+1;
  2247. X            t0 = z-keymap;
  2248. X            if (*q == keymap[t0-15] || *q == keymap[t0-14] ||
  2249. X                    *q == keymap[t0-13] ||
  2250. X                    *q == keymap[t0-1] || *q == keymap[t0+1] ||
  2251. X                    *q == keymap[t0+13] || *q == keymap[t0+14] ||
  2252. X                    *q == keymap[t0+15])
  2253. X                return spdist(p+1,q+1,thresh-1)+2;
  2254. X            return 200;
  2255. X            }
  2256. X        else if (*p != *q)
  2257. X            break;
  2258. X    return 200;
  2259. X}
  2260. X
  2261. Xchar *zgetenv(s) /**/
  2262. Xchar *s;
  2263. X{
  2264. Xchar **av,*p,*q;
  2265. X
  2266. X    for (av = environ; *av; av++)
  2267. X        {
  2268. X        for (p = *av, q = s; *p && *p != '=' && *q && *p == *q; p++,q++);
  2269. X        if (*p == '=' && !*q)
  2270. X            return p+1;
  2271. X        }
  2272. X    return NULL;
  2273. X}
  2274. X
  2275. Xint tulower(c) /**/
  2276. Xint c;
  2277. X{
  2278. X    c &= 0xff;
  2279. X    return (isupper(c) ? tolower(c) : c);
  2280. X}
  2281. X
  2282. Xint tuupper(c) /**/
  2283. Xint c;
  2284. X{
  2285. X    c &= 0xff;
  2286. X    return (islower(c) ? toupper(c) : c);
  2287. X}
  2288. X
  2289. X#ifdef SYSV
  2290. X#include <sys/utsname.h>
  2291. X
  2292. Xint gethostname(nameptr, maxlength)
  2293. Xchar *nameptr;
  2294. Xint maxlength;
  2295. X{
  2296. Xstruct utsname name;
  2297. Xint result;
  2298. X
  2299. X    result = uname(&name);
  2300. X    if (result >= 0) {
  2301. X        strncpy(nameptr,name.nodename,maxlength);
  2302. X        return 0;
  2303. X    } else return -1;
  2304. X}
  2305. X#endif
  2306. X
  2307. X/* set cbreak mode, or the equivalent */
  2308. X
  2309. Xvoid setcbreak() /**/
  2310. X{
  2311. Xstruct ttyinfo ti;
  2312. X
  2313. X    ti = shttyinfo;
  2314. X#ifdef TIO
  2315. X    ti.tio.c_lflag &= ~ICANON;
  2316. X    ti.tio.c_cc[VMIN] = 1;
  2317. X    ti.tio.c_cc[VTIME] = 0;
  2318. X#else
  2319. X    ti.sgttyb.sg_flags |= CBREAK;
  2320. X#endif
  2321. X    settyinfo(&ti);
  2322. X}
  2323. X
  2324. Xint getlineleng() /**/
  2325. X{
  2326. Xint z;
  2327. X
  2328. X#ifdef TIOCSWINSZ
  2329. X    z = shttyinfo.winsize.ws_col;
  2330. X    return (z) ? z : 80;
  2331. X#else
  2332. X    return 80;
  2333. X#endif
  2334. X}
  2335. X
  2336. Xvoid unsetcbreak() /**/
  2337. X{
  2338. X    settyinfo(&shttyinfo);
  2339. X}
  2340. X
  2341. X/* give the tty to some process */
  2342. X
  2343. Xvoid attachtty(pgrp) /**/
  2344. Xlong pgrp;
  2345. X{
  2346. Xstatic int ep = 0;
  2347. X
  2348. X    if (jobbing) {
  2349. X#ifdef HAS_TCSETPGRP
  2350. X        if (SHTTY != -1 && tcsetpgrp(SHTTY,pgrp) == -1 && !ep)
  2351. X#else
  2352. X        int arg = pgrp;
  2353. X        if (SHTTY != -1 && ioctl(SHTTY,TIOCSPGRP,&arg) == -1 && !ep)
  2354. X#endif
  2355. X            {
  2356. X            zerr("can't set tty pgrp: %e",NULL,errno);
  2357. X            fflush(stderr);
  2358. X            opts[MONITOR] = OPT_UNSET;
  2359. X            ep =1;
  2360. X            errflag = 0;
  2361. X            }
  2362. X    }
  2363. X}
  2364. X
  2365. X/* get the tty pgrp */
  2366. X
  2367. Xlong gettygrp() /**/
  2368. X{
  2369. Xint arg;
  2370. X
  2371. X    if (SHTTY == -1) return -1;
  2372. X#ifdef HAS_TCSETPGRP
  2373. X    arg = tcgetpgrp(SHTTY);
  2374. X#else
  2375. X    ioctl(SHTTY,TIOCGPGRP,&arg);
  2376. X#endif
  2377. X    return arg;
  2378. X}
  2379. END_OF_FILE
  2380.   if test 32015 -ne `wc -c <'src/utils.c'`; then
  2381.     echo shar: \"'src/utils.c'\" unpacked with wrong size!
  2382.   fi
  2383.   # end of 'src/utils.c'
  2384. fi
  2385. echo shar: End of archive 12 \(of 22\).
  2386. cp /dev/null ark12isdone
  2387. MISSING=""
  2388. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
  2389.     if test ! -f ark${I}isdone ; then
  2390.     MISSING="${MISSING} ${I}"
  2391.     fi
  2392. done
  2393. if test "${MISSING}" = "" ; then
  2394.     echo You have unpacked all 22 archives.
  2395.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2396. else
  2397.     echo You still must unpack the following archives:
  2398.     echo "        " ${MISSING}
  2399. fi
  2400. exit 0
  2401.  
  2402. exit 0 # Just in case...
  2403.