Advertisement
Guest User

More readline bindings for ioquake3

a guest
Jul 3rd, 2010
129
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 38.44 KB | None | 0 0
  1. diff --git a/code/client/cl_keys.c b/code/client/cl_keys.c
  2. index 0f72795..5568a7b 100644
  3. --- a/code/client/cl_keys.c
  4. +++ b/code/client/cl_keys.c
  5. @@ -33,6 +33,9 @@ int           nextHistoryLine;        // the last line in the history buffer, not masked
  6.  int            historyLine;    // the line being displayed from history buffer
  7.                             // will be <= nextHistoryLine
  8.  
  9. +// For now, only support 1 kill ring.
  10. +killring_t killRing;
  11. +
  12.  field_t        g_consoleField;
  13.  field_t        chatField;
  14.  qboolean   chat_team;
  15. @@ -394,7 +397,80 @@ void Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor,
  16.  
  17.  /*
  18.  ================
  19. +Add_Kill_Ring_Entry
  20. +
  21. +This isn't a kill ring as much as a kill buffer currently.
  22. +It adds the last kill to a buffer so the user can yank it later.
  23. +The killring buffer is guaranteed to be NUL terminated if it is used.
  24. +================
  25. +*/
  26. +static void Add_Kill_Ring_Entry(const char *s, int start, int end)
  27. +{
  28. +   int num_elements = end - start + 1;
  29. +
  30. +   // MAX_EDIT_LINE - 1 is also an invalid index because we need room for the NUL
  31. +   if (start > end || start < 0 || end < 0 || end >= MAX_EDIT_LINE - 1) {
  32. +       return;
  33. +   }
  34. +
  35. +   // copy line to history buffer.  This is always NUL terminated.
  36. +   memmove(killRing.buffer, s + start, num_elements);
  37. +   killRing.length = num_elements;
  38. +
  39. +   // Minimum is 1 and max is MAX_EDIT_LINE - 1.
  40. +   killRing.buffer[num_elements] = '\0';
  41. +}
  42. +
  43. +/*
  44. +================
  45. +Use_Kill_Ring_Entry
  46. +
  47. +This uses the last (currently only) kill from the buffer and inserts it.
  48. +It will NUL terminate the resulting string and stays within the bounds of the buffer.
  49. +It silently truncates as needed.
  50. +================
  51. +*/
  52. +static void Use_Kill_Ring_Entry(field_t *edit)
  53. +{
  54. +   size_t len;
  55. +   size_t num_bytes;
  56. +   int copied = 0;
  57. +   char cache[MAX_EDIT_LINE];
  58. +
  59. +   // MAX_EDIT_LINE - 1 is an invalid index because we need room for the NUL
  60. +   if (edit->cursor < 0 || edit->cursor >= MAX_EDIT_LINE - 1) {
  61. +       return;
  62. +   }
  63. +
  64. +   // Save the current buffer after the cursor.  Any space left after the
  65. +   // kill buffer will use this data.
  66. +   memmove(cache, edit->buffer, sizeof(cache));
  67. +
  68. +   // num_bytes uses MAX_EDIT_LINE without -1 because strlcpy handles size-1 and
  69. +   // edit->cursor without + 1 because we're overwriting edit->cursor's position.
  70. +   num_bytes = MAX_EDIT_LINE - edit->cursor;
  71. +
  72. +   // Copy the contents of the kill buffer that fit
  73. +   if ((len = Q_strlcpy(edit->buffer + edit->cursor, killRing.buffer, num_bytes)) >= num_bytes) {
  74. +       // Truncated
  75. +       copied = edit->cursor + num_bytes;
  76. +   } else {
  77. +       copied = edit->cursor + len;
  78. +   }
  79. +
  80. +   // Concatenate the left over parts that fit
  81. +   if ((len = Q_strlcat(edit->buffer + edit->cursor, cache + edit->cursor, num_bytes)) >= num_bytes) {
  82. +       /* Silently handle truncation? */
  83. +   }
  84. +
  85. +   edit->cursor = copied;
  86. +}
  87. +
  88. +/*
  89. +================
  90.  Field_Paste
  91. +
  92. +Pastes the clipboard data for platforms that define Sys_GetClipboardData().
  93.  ================
  94.  */
  95.  void Field_Paste( field_t *edit ) {
  96. @@ -417,6 +493,553 @@ void Field_Paste( field_t *edit ) {
  97.  }
  98.  
  99.  /*
  100. +==================
  101. +Field_Kill_Text
  102. +
  103. +This kills text spanning the start to end indices.  It shifts the results
  104. +left and fills in any left over areas with NULs.
  105. +
  106. +Example using mark which isn't available yet in this code.  It is in GNU Emacs.
  107. +Treat the mark as the starting spot and the cursor as the end.
  108. +
  109. +Unlike Emacs, this includes the last element in the selection.  This is because
  110. +the cursor here is referring to an actual element in the array.  In Emacs, it
  111. +refers to the position between characters.
  112. +
  113. +            m------------------- mark
  114. +                   v------------ cursor
  115. +orig$ ls /etc/X11/xorg.conf
  116. +
  117. +            v------------------- cursor
  118. +orig$ ls /etrg.conf
  119. +==================
  120. +*/
  121. +static void Field_Kill_Text( field_t *edit, int start, int end ) {
  122. +   int num_moved;
  123. +
  124. +   // If the user sent it in the wrong order, swap them.
  125. +   if (start > end) {
  126. +       int old = start;
  127. +       start = end;
  128. +       end = old;
  129. +   }
  130. +
  131. +   // MAX_EDIT_LINE - 1 is invalid because that's for the NUL.
  132. +   if (start < 0 || end < 0 || end >= MAX_EDIT_LINE - 1) {
  133. +       return;
  134. +   }
  135. +
  136. +   // Add this text to the kill ring so we can yank it out later.
  137. +   Add_Kill_Ring_Entry(edit->buffer, start, end);
  138. +
  139. +   // MAX_EDIT_LINE - 1 is the last index of the array.  It must be a NUL.
  140. +   // Therefore, MAX_EDIT_LINE - 2 is the last array element that has user data.
  141. +   // With the check above, end will be at most the index before the NUL.
  142. +   num_moved = MAX_EDIT_LINE - 2 - end;
  143. +   memmove(edit->buffer + start, edit->buffer + end + 1, num_moved);
  144. +
  145. +   // num_moved is not zero indexed so this will be 1 beyond what we moved.
  146. +   memset(edit->buffer + start + num_moved, 0, MAX_EDIT_LINE - start - num_moved);
  147. +
  148. +   edit->cursor = start;
  149. +}
  150. +
  151. +/*
  152. +==================
  153. +Field_Kill
  154. +
  155. +Kills the line from the current cursor position to the end of the line.
  156. +
  157. +It should kill the entire line if it is at the beginning.  It should not do
  158. +anything if it is at the end of the line.
  159. +
  160. +Example from bash (GNU Readline):
  161. +
  162. +               v---------------- cursor
  163. +orig$ ls /etc/X11/xorg.conf
  164. +
  165. +               v---------------- cursor
  166. +modi$ ls /etc/X
  167. +
  168. +      v------------------------- cursor
  169. +orig$ ls /etc/X11/xorg.conf
  170. +
  171. +      v------------------------- cursor
  172. +modi$
  173. +
  174. +                           v---- cursor
  175. +orig$ ls /etc/X11/xorg.conf
  176. +
  177. +                           v---- cursor
  178. +modi$ ls /etc/X11/xorg.conf
  179. +==================
  180. +*/
  181. +static void Field_Kill_Line( field_t *edit ) {
  182. +   size_t len;
  183. +   if (edit->cursor < 0) {
  184. +       return;
  185. +   }
  186. +
  187. +   // Use strlen rather than until the end of the buffer because
  188. +   // we save the killed region in a buffer.
  189. +   len = strlen(edit->buffer + edit->cursor);
  190. +
  191. +   if (len > 0) {
  192. +       Field_Kill_Text(edit, edit->cursor, edit->cursor + len - 1);
  193. +   }
  194. +}
  195. +
  196. +/*
  197. +==================
  198. +Field_Backward_Kill_Line
  199. +
  200. +This is called unix-line-discard in GNU Readline.
  201. +It kills from the start of the line until the current position (moving everything backwards).
  202. +
  203. +Example from bash (GNU Readline):
  204. +
  205. +               v---------------- cursor
  206. +orig$ ls /etc/X11/xorg.conf
  207. +
  208. +      v------------------------- cursor
  209. +modi$ 11/xorg.conf
  210. +
  211. +                           v---- cursor
  212. +orig$ ls /etc/X11/xorg.conf
  213. +
  214. +      v------------------------- cursor
  215. +modi$
  216. +==================
  217. +*/
  218. +static void Field_Backward_Kill_Line( field_t *edit ) {
  219. +   Add_Kill_Ring_Entry(edit->buffer, 0, edit->cursor - 1);
  220. +
  221. +   memmove(edit->buffer, edit->buffer + edit->cursor, MAX_EDIT_LINE - edit->cursor);
  222. +   memset(edit->buffer + MAX_EDIT_LINE - edit->cursor, 0, MAX_EDIT_LINE - (MAX_EDIT_LINE - edit->cursor));
  223. +
  224. +   edit->cursor = 0;
  225. +   edit->scroll = 0;
  226. +}
  227. +
  228. +/*
  229. +==================
  230. +Field_Backward_Word
  231. +
  232. +Emacs defines a word to be a letter/digit but I think that's confusing to
  233. +non-Emacs users so I'm using space/non-space.
  234. +
  235. +This doesn't match GNU Readline so this shows how it should work
  236. +
  237. +If the cursor is on a space, it moves to the beginning of the first word behind it.
  238. +Otherwise, it positions the cursor at the beginning of the current word.
  239. +
  240. +Example:
  241. +
  242. +               v------------------ cursor
  243. +orig$ ls /etc/X11/xorg.conf
  244. +
  245. +         v------------------------ cursor
  246. +modi$ ls /etc/X11/xorg.conf
  247. +
  248. +
  249. +This shows how it will skip the current word if it's on the first character of it already.
  250. +It would behave the same way if the cursor was on top of whitespace.
  251. +
  252. +             v-------------------- cursor
  253. +orig$ ls -la /etc/X11/xorg.conf
  254. +
  255. +         v------------------------ cursor
  256. +modi$ ls -la /etc/X11/xorg.conf
  257. +
  258. +
  259. +                               v-- cursor
  260. +orig$ ls -la /etc/X11/xorg.conf
  261. +
  262. +             v-------------------- cursor
  263. +modi$ ls -la /etc/X11/xorg.conf
  264. +
  265. +
  266. +      v--------------------------- cursor
  267. +orig$ ls -la /etc/X11/xorg.conf
  268. +
  269. +      v--------------------------- cursor
  270. +modi$ ls -la /etc/X11/xorg.conf
  271. +==================
  272. +*/
  273. +static void Field_Backward_Word( field_t *edit) {
  274. +   int index;
  275. +   int saw_char = 0;
  276. +
  277. +   if (edit->cursor <= 0) {
  278. +       return;
  279. +   }
  280. +
  281. +   for (index = edit->cursor - 1; index > 0; index--) {
  282. +       if (isspace(edit->buffer[index])) {
  283. +           if (saw_char) {
  284. +               // The last char was the end of a word.  Go back.
  285. +               index++;
  286. +               break;
  287. +           }
  288. +       } else {
  289. +           saw_char = 1;
  290. +       }
  291. +   }
  292. +
  293. +   edit->cursor = index;
  294. +}
  295. +
  296. +/*
  297. +==================
  298. +Field_Forward_Word
  299. +
  300. +Emacs defines a word to be a letter/digit but I think that's confusing to
  301. +non-Emacs users so I'm using space/non-space.
  302. +
  303. +This doesn't match GNU Readline so this shows how it should work
  304. +
  305. +If the cursor is on a space, it moves to the beginning of the next word.
  306. +Otherwise, it positions the cursor after the end of the current word.
  307. +
  308. +Example:
  309. +
  310. +When it is on the last word, it will advance to the end of it.
  311. +
  312. +               v------------------ cursor
  313. +orig$ ls /etc/X11/xorg.conf
  314. +
  315. +                          v------- cursor
  316. +orig$ ls /etc/X11/xorg.conf
  317. +
  318. +
  319. +This shows how it will skip the current word if it's on the first character of it already.
  320. +It would behave the same way if the cursor was on top of whitespace.
  321. +
  322. +          v----------------------- cursor
  323. +orig$ ls -la /etc/X11/xorg.conf
  324. +
  325. +            v--------------------- cursor
  326. +modi$ ls -la /etc/X11/xorg.conf
  327. +
  328. +
  329. +This shows how it will skip the current word if it's on the first character of it already.
  330. +It would behave the same way if the cursor was on top of whitespace.
  331. +
  332. +           v---------------------- cursor
  333. +orig$ ls -la /etc/X11/xorg.conf
  334. +
  335. +             v-------------------- cursor
  336. +modi$ ls -la /etc/X11/xorg.conf
  337. +==================
  338. +*/
  339. +static void Field_Forward_Word( field_t *edit ) {
  340. +   int index;
  341. +   int saw_space = 0;
  342. +   int len = strlen( edit->buffer );
  343. +
  344. +   if (edit->cursor >= len - 1) {
  345. +       return;
  346. +   }
  347. +
  348. +   for (index = edit->cursor + 1; index < len - 1; index++) {
  349. +       if (isspace(edit->buffer[index])) {
  350. +           saw_space = 1;
  351. +
  352. +       } else {
  353. +           if (saw_space) {
  354. +               break;
  355. +           }
  356. +       }
  357. +   }
  358. +
  359. +   edit->cursor = index;
  360. +}
  361. +
  362. +/*
  363. +==================
  364. +Field_Uppercase_Word
  365. +
  366. +If the cursor is on a space, it moves to the beginning of the first word ahead.
  367. +Otherwise, it positions the cursor at the beginning of the current word.
  368. +
  369. +                          v------- cursor
  370. +orig$ ls -la /etc/X11/xorg.conf
  371. +
  372. +                               v-- cursor
  373. +modi$ ls -la /etc/X11/xorg.CONF
  374. +
  375. +            v--------------------- cursor
  376. +orig$ ls -la /etc/X11/xorg.conf
  377. +
  378. +                               v-- cursor
  379. +modi$ ls -la /ETC/X11/XORG.CONF
  380. +==================
  381. +*/
  382. +static void Field_Uppercase_Word( field_t *edit ) {
  383. +   int index;
  384. +   int saw_nonspace = 0;
  385. +   int len = strlen( edit->buffer );
  386. +
  387. +   if (edit->cursor >= len - 1) {
  388. +       return;
  389. +   }
  390. +
  391. +   for (index = edit->cursor; index < len; index++) {
  392. +       if (isspace(edit->buffer[index])) {
  393. +           if (saw_nonspace) {
  394. +               break;
  395. +           }
  396. +       } else {
  397. +           edit->buffer[index] = (char)toupper((unsigned char)edit->buffer[index]);
  398. +           saw_nonspace = 1;
  399. +       }
  400. +   }
  401. +
  402. +   edit->cursor = index;
  403. +}
  404. +
  405. +/*
  406. +==================
  407. +Field_Lowercase_Word
  408. +
  409. +If the cursor is on a space, it moves to the beginning of the first word behind it.
  410. +Otherwise, it positions the cursor at the beginning of the current word.
  411. +
  412. +                          v------- cursor
  413. +orig$ ls -la /etc/X11/xorg.CONF
  414. +
  415. +                               v-- cursor
  416. +modi$ ls -la /etc/X11/xorg.conf
  417. +
  418. +            v--------------------- cursor
  419. +orig$ ls -la /ETC/X11/XORG.CONF
  420. +
  421. +                               v-- cursor
  422. +modi$ ls -la /etc/x11/xorg.conf
  423. +==================
  424. +*/
  425. +static void Field_Lowercase_Word( field_t *edit ) {
  426. +   int index;
  427. +   int saw_nonspace = 0;
  428. +   int len = strlen( edit->buffer );
  429. +
  430. +   if (edit->cursor >= len - 1) {
  431. +       return;
  432. +   }
  433. +
  434. +   for (index = edit->cursor; index < len; index++) {
  435. +       if (isspace(edit->buffer[index])) {
  436. +           if (saw_nonspace) {
  437. +               break;
  438. +           }
  439. +
  440. +       } else {
  441. +           edit->buffer[index] = (char)tolower((unsigned char)edit->buffer[index]);
  442. +           saw_nonspace = 1;
  443. +       }
  444. +   }
  445. +
  446. +   edit->cursor = index;
  447. +}
  448. +
  449. +/*
  450. +==================
  451. +Field_Capitalize_Word
  452. +
  453. +If the cursor is on a space, it moves to the beginning of the first word behind it.
  454. +Otherwise, it positions the cursor at the beginning of the current word.
  455. +
  456. +                          v------- cursor
  457. +orig$ ls -la /etc/X11/xorg.CONF
  458. +
  459. +                               v-- cursor
  460. +modi$ ls -la /etc/X11/xorg.Conf
  461. +
  462. +               v------------------ cursor
  463. +orig$ ls -la /ETC/X11/XORG.CONF
  464. +
  465. +                               v-- cursor
  466. +modi$ ls -la /ETc/x11/xorg.conf
  467. +==================
  468. +*/
  469. +static void Field_Capitalize_Word( field_t *edit ) {
  470. +   int index;
  471. +   int saw_nonspace = 0;
  472. +   int len = strlen( edit->buffer );
  473. +
  474. +   if (edit->cursor >= len - 1) {
  475. +       return;
  476. +   }
  477. +
  478. +   for (index = edit->cursor; index < len; index++) {
  479. +       if (isspace(edit->buffer[index])) {
  480. +           if (saw_nonspace) {
  481. +               break;
  482. +           }
  483. +
  484. +       } else {
  485. +           if (saw_nonspace == 0) {
  486. +               edit->buffer[index] = (char)toupper((unsigned char)edit->buffer[index]);
  487. +           } else {
  488. +               edit->buffer[index] = (char)tolower((unsigned char)edit->buffer[index]);
  489. +           }
  490. +           saw_nonspace = 1;
  491. +       }
  492. +   }
  493. +
  494. +   edit->cursor = index;
  495. +}
  496. +
  497. +/*
  498. +==================
  499. +Field_Backward_Kill_Word
  500. +
  501. +Emacs defines a word to be a letter/digit but I think that's confusing to
  502. +non-Emacs users so I'm using space/non-space.
  503. +
  504. +                          v------- cursor
  505. +orig$ ls -la /etc/X11/xorg.CONF
  506. +
  507. +             v-------------------- cursor
  508. +modi$ ls -la CONF
  509. +
  510. +               v------------------ cursor
  511. +orig$ ls -la /E
  512. +
  513. +             v-------------------- cursor
  514. +modi$ ls -la TC/X11/XORG.CONF
  515. +==================
  516. +*/
  517. +static void Field_Backward_Kill_Word( field_t *edit) {
  518. +   int saw_nonspace = 0;
  519. +   int previous_index = edit->cursor;
  520. +   int index = 0;
  521. +
  522. +   if (edit->cursor <= 0) {
  523. +       return;
  524. +   }
  525. +
  526. +   for (index = edit->cursor - 1; index > 0; index--) {
  527. +       if (isspace(edit->buffer[index])) {
  528. +           if (saw_nonspace) {
  529. +               index++;
  530. +               break;
  531. +           }
  532. +       } else {
  533. +           saw_nonspace = 1;
  534. +       }
  535. +   }
  536. +
  537. +   Field_Kill_Text(edit, index, previous_index);
  538. +}
  539. +
  540. +/*
  541. +==================
  542. +Field_Kill_Word
  543. +
  544. +Emacs defines a word to be a letter/digit but I think that's confusing to
  545. +non-Emacs users so I'm using space/non-space.
  546. +
  547. +                          v------- cursor
  548. +orig$ ls -la /etc/X11/xorg.CONF
  549. +
  550. +                           v------ cursor
  551. +modi$ ls -la /etc/X11/xorg.
  552. +
  553. +               v------------------ cursor
  554. +orig$ ls -la /ETC/X11/XORG.CONF
  555. +
  556. +               v------------------ cursor
  557. +modi$ ls -la /E
  558. +==================
  559. +*/
  560. +static void Field_Kill_Word( field_t *edit ) {
  561. +   int saw_nonspace = 0;
  562. +   int previous_index = edit->cursor;
  563. +   int index;
  564. +   int len = strlen( edit->buffer );
  565. +
  566. +   if (edit->cursor >= len - 1) {
  567. +       return;
  568. +   }
  569. +
  570. +   for (index = edit->cursor; index < len; index++) {
  571. +       if (isspace(edit->buffer[index])) {
  572. +           if (saw_nonspace) {
  573. +               index--;
  574. +               break;
  575. +           }
  576. +       } else {
  577. +           saw_nonspace = 1;
  578. +       }
  579. +   }
  580. +
  581. +   Field_Kill_Text(edit, previous_index, index);
  582. +}
  583. +
  584. +/*
  585. +==================
  586. +Field_Kill_Word
  587. +
  588. +Emacs defines a word to be a letter/digit but I think that's confusing to
  589. +non-Emacs users so I'm using space/non-space.
  590. +
  591. +                          v------- cursor
  592. +orig$ ls -la /etc/X11/xorg.conf
  593. +
  594. +                           v------ cursor
  595. +modi$ ls -la /etc/X11/xorgc.onf
  596. +
  597. +      v--------------------------- cursor
  598. +orig$ ls -la /etc/X11/xorg.conf
  599. +
  600. +      v--------------------------- cursor
  601. +modi$ ls -la /etc/X11/xorg.conf
  602. +
  603. +                             v---- cursor
  604. +orig$ ls -la /etc/X11/xorg.conf
  605. +
  606. +                              v--- cursor
  607. +modi$ ls -la /etc/X11/xorg.cofn
  608. +
  609. +                              v---- cursor
  610. +orig$ ls -la /etc/X11/xorg.cofn
  611. +
  612. +                              v--- cursor
  613. +modi$ ls -la /etc/X11/xorg.conf
  614. +==================
  615. +*/
  616. +static void Field_Transpose_Chars( field_t *edit ) {
  617. +   int len;
  618. +   char cache_val;
  619. +
  620. +   if ( edit->cursor <= 0 ) {
  621. +       return;
  622. +   }
  623. +
  624. +   // If we're at the end of the line, pretend that we're on the 2nd to last.
  625. +   len = strlen( edit->buffer );
  626. +   if (edit->cursor == len) {
  627. +       edit->cursor--;
  628. +       if ( edit->cursor < edit->scroll )
  629. +       {
  630. +           edit->scroll--;
  631. +       }
  632. +   }
  633. +
  634. +   cache_val = edit->buffer[edit->cursor - 1];
  635. +   edit->buffer[edit->cursor - 1] = edit->buffer[edit->cursor];
  636. +   edit->buffer[edit->cursor] = cache_val;
  637. +
  638. +   if (edit->cursor < len) {
  639. +       edit->cursor++;
  640. +   }
  641. +   if ( edit->cursor >= edit->widthInChars ) {
  642. +       edit->scroll++;
  643. +   }
  644. +}
  645. +
  646. +/*
  647.  =================
  648.  Field_KeyDownEvent
  649.  
  650. @@ -440,21 +1063,36 @@ void Field_KeyDownEvent( field_t *edit, int key ) {
  651.  
  652.     switch ( key ) {
  653.         case K_DEL:
  654. -           if ( edit->cursor < len ) {
  655. -               memmove( edit->buffer + edit->cursor,
  656. -                   edit->buffer + edit->cursor + 1, len - edit->cursor );
  657. +           if (keys[K_CTRL].down) {
  658. +               Field_Backward_Kill_Word( edit );
  659. +
  660. +           } else {
  661. +               if ( edit->cursor < len ) {
  662. +                   memmove( edit->buffer + edit->cursor,
  663. +                        edit->buffer + edit->cursor + 1, len - edit->cursor );
  664. +               }
  665.             }
  666.             break;
  667.  
  668.         case K_RIGHTARROW:
  669. -           if ( edit->cursor < len ) {
  670. -               edit->cursor++;
  671. +           if (keys[K_CTRL].down) {
  672. +               Field_Forward_Word(edit);
  673. +
  674. +           } else {
  675. +               if ( edit->cursor < len ) {
  676. +                   edit->cursor++;
  677. +               }
  678.             }
  679.             break;
  680.  
  681.         case K_LEFTARROW:
  682. -           if ( edit->cursor > 0 ) {
  683. -               edit->cursor--;
  684. +           if (keys[K_CTRL].down) {
  685. +               Field_Backward_Word(edit);
  686. +
  687. +           } else {
  688. +               if ( edit->cursor > 0 ) {
  689. +                   edit->cursor--;
  690. +               }
  691.             }
  692.             break;
  693.  
  694. @@ -490,18 +1128,57 @@ Field_CharEvent
  695.  void Field_CharEvent( field_t *edit, int ch ) {
  696.     int     len;
  697.  
  698. -   if ( ch == 'v' - 'a' + 1 ) {    // ctrl-v is paste
  699. +   if ( ch == 'v' - 'a' + 1 ) {    // ctrl-v is clipboard paste
  700.         Field_Paste( edit );
  701.         return;
  702.     }
  703.  
  704. +   if ( ch == 'y' - 'a' + 1 ) {    // ctrl-y is yank (kill ring)
  705. +       Use_Kill_Ring_Entry( edit );
  706. +       return;
  707. +   }
  708. +
  709.     if ( ch == 'c' - 'a' + 1 ) {    // ctrl-c clears the field
  710.         Field_Clear( edit );
  711.         return;
  712.     }
  713.  
  714. +   // kill goes from the current position to the end of the line
  715. +   // Unlike Emacs/Readline, this does not add it to the kill region (yet).
  716. +   if ( ch == 'k' - 'a' + 1 ) {    // ctrl-k clears from here to EOL
  717. +       Field_Kill_Line( edit );
  718. +       return;
  719. +   }
  720. +
  721. +   if ( ch == 'u' - 'a' + 1 ) {
  722. +       Field_Backward_Kill_Line( edit );
  723. +       return;
  724. +   }
  725. +
  726.     len = strlen( edit->buffer );
  727.  
  728. +   if ( ch == 'd' - 'a' + 1 ) {    // ctrl+d is delete
  729. +       if ( edit->cursor < len ) {
  730. +           memmove( edit->buffer + edit->cursor,
  731. +                edit->buffer + edit->cursor + 1, len - edit->cursor );
  732. +       }
  733. +       return;
  734. +   }
  735. +
  736. +   if ( ch == 'f' - 'a' + 1 ) {    // ctrl-f is move forward 1 char
  737. +       if ( edit->cursor < len ) {
  738. +           edit->cursor++;
  739. +       }
  740. +       return;
  741. +   }
  742. +
  743. +   if ( ch == 'b' - 'a' + 1 ) {    // ctrl-b is move backwards 1 char
  744. +       if ( edit->cursor > 0 ) {
  745. +           edit->cursor--;
  746. +       }
  747. +       return;
  748. +   }
  749. +
  750.     if ( ch == 'h' - 'a' + 1 )  {   // ctrl-h is backspace
  751.         if ( edit->cursor > 0 ) {
  752.             memmove( edit->buffer + edit->cursor - 1,
  753. @@ -515,6 +1192,14 @@ void Field_CharEvent( field_t *edit, int ch ) {
  754.         return;
  755.     }
  756.  
  757. +   // This handles the transpose similar to GNU Readline and not GNU Emacs.
  758. +   // At the beginning of the line, it does nothing.  At the end of the line,
  759. +   // it will transpose the last 2 chars without moving the cursor.
  760. +   if ( ch == 't' - 'a' + 1 ) {    // ctrl-t is transpose chars
  761. +       Field_Transpose_Chars( edit );
  762. +       return;
  763. +   }
  764. +
  765.     if ( ch == 'a' - 'a' + 1 ) {    // ctrl-a is home
  766.         edit->cursor = 0;
  767.         edit->scroll = 0;
  768. @@ -527,6 +1212,65 @@ void Field_CharEvent( field_t *edit, int ch ) {
  769.         return;
  770.     }
  771.  
  772. +   if ( ch == 'w' - 'a' + 1 ) {
  773. +       Field_Backward_Kill_Word( edit );
  774. +       return;
  775. +   }
  776. +
  777. +   // Treat ALT as Meta
  778. +   if (keys[K_ALT].down) {
  779. +       int found = 1;
  780. +
  781. +       switch (ch) {
  782. +       case 'f':
  783. +           Field_Forward_Word( edit );
  784. +           break;
  785. +
  786. +       case 'b':
  787. +           Field_Backward_Word( edit );
  788. +           break;
  789. +
  790. +       case 'd':
  791. +           Field_Kill_Word( edit );
  792. +           break;
  793. +
  794. +       case 'u':
  795. +           /* uppercase-word */
  796. +           Field_Uppercase_Word( edit );
  797. +           break;
  798. +
  799. +       case 'l':
  800. +           /* downcase-word */
  801. +           Field_Lowercase_Word( edit );
  802. +           break;
  803. +
  804. +       case 'c':
  805. +           /* capitalize word */
  806. +           Field_Capitalize_Word( edit );
  807. +           break;
  808. +
  809. +       case 'y':
  810. +           /* rotate then yank */
  811. +           /* There's only one buffer currently so this isn't implemented */
  812. +           break;
  813. +
  814. +       default:
  815. +           found = 0;
  816. +       }
  817. +
  818. +       if (found) {
  819. +           if ( edit->cursor >= edit->widthInChars ) {
  820. +               edit->scroll++;
  821. +           }
  822. +
  823. +           if ( edit->cursor == len + 1) {
  824. +               edit->buffer[edit->cursor] = 0;
  825. +           }
  826. +
  827. +           return;
  828. +       }
  829. +   }
  830. +
  831.     //
  832.     // ignore any other non printable chars
  833.     //
  834. @@ -634,6 +1378,8 @@ void Console_Key (int key) {
  835.         return;
  836.     }
  837.  
  838. +   // XXX Need M-< and M-> for first and last history, respectively
  839. +
  840.     // command history (ctrl-p ctrl-n for unix style)
  841.  
  842.     if ( (key == K_MWHEELUP && keys[K_SHIFT].down) || ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
  843. diff --git a/code/client/keys.h b/code/client/keys.h
  844. index 0168468..4479736 100644
  845. --- a/code/client/keys.h
  846. +++ b/code/client/keys.h
  847. @@ -39,6 +39,9 @@ void Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor,
  848.  #define        COMMAND_HISTORY     32
  849.  extern field_t historyEditLines[COMMAND_HISTORY];
  850.  
  851. +// Only 1 for now
  852. +extern killring_t killRing;
  853. +
  854.  extern field_t g_consoleField;
  855.  extern field_t chatField;
  856.  extern int             anykeydown;
  857. diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c
  858. index 550d100..2809e6b 100644
  859. --- a/code/qcommon/q_shared.c
  860. +++ b/code/qcommon/q_shared.c
  861. @@ -683,24 +683,88 @@ int Q_isalpha( int c )
  862.     return ( 0 );
  863.  }
  864.  
  865. -char* Q_strrchr( const char* string, int c )
  866. +/*      $OpenBSD: index.c,v 1.5 2005/08/08 08:05:37 espie Exp $ */
  867. +/*-
  868. + * Copyright (c) 1990 The Regents of the University of California.
  869. + * All rights reserved.
  870. + *
  871. + * Redistribution and use in source and binary forms, with or without
  872. + * modification, are permitted provided that the following conditions
  873. + * are met:
  874. + * 1. Redistributions of source code must retain the above copyright
  875. + *    notice, this list of conditions and the following disclaimer.
  876. + * 2. Redistributions in binary form must reproduce the above copyright
  877. + *    notice, this list of conditions and the following disclaimer in the
  878. + *    documentation and/or other materials provided with the distribution.
  879. + * 3. Neither the name of the University nor the names of its contributors
  880. + *    may be used to endorse or promote products derived from this software
  881. + *    without specific prior written permission.
  882. + *
  883. + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  884. + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  885. + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  886. + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  887. + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  888. + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  889. + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  890. + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  891. + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  892. + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  893. + * SUCH DAMAGE.
  894. + */
  895. +char *
  896. +Q_strchr(const char *p, int ch)
  897.  {
  898. -   char cc = c;
  899. -   char *s;
  900. -   char *sp=(char *)0;
  901. -
  902. -   s = (char*)string;
  903. +        for (;; ++p) {
  904. +                if (*p == ch)
  905. +                        return((char *)p);
  906. +                if (!*p)
  907. +                        return((char *)NULL);
  908. +        }
  909. +        /* NOTREACHED */
  910. +}
  911.  
  912. -   while (*s)
  913. -   {
  914. -       if (*s == cc)
  915. -           sp = s;
  916. -       s++;
  917. -   }
  918. -   if (cc == 0)
  919. -       sp = s;
  920. +/*      $OpenBSD: rindex.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
  921. +/*
  922. + * Copyright (c) 1988 Regents of the University of California.
  923. + * All rights reserved.
  924. + *
  925. + * Redistribution and use in source and binary forms, with or without
  926. + * modification, are permitted provided that the following conditions
  927. + * are met:
  928. + * 1. Redistributions of source code must retain the above copyright
  929. + *    notice, this list of conditions and the following disclaimer.
  930. + * 2. Redistributions in binary form must reproduce the above copyright
  931. + *    notice, this list of conditions and the following disclaimer in the
  932. + *    documentation and/or other materials provided with the distribution.
  933. + * 3. Neither the name of the University nor the names of its contributors
  934. + *    may be used to endorse or promote products derived from this software
  935. + *    without specific prior written permission.
  936. + *
  937. + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  938. + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  939. + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  940. + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  941. + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  942. + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  943. + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  944. + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  945. + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  946. + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  947. + * SUCH DAMAGE.
  948. + */
  949. +char *
  950. +Q_strrchr(const char *p, int ch)
  951. +{
  952. +        char *save;
  953.  
  954. -   return sp;
  955. +        for (save = NULL;; ++p) {
  956. +                if (*p == ch)
  957. +                        save = (char *)p;
  958. +                if (!*p)
  959. +                        return(save);
  960. +        }
  961. +        /* NOTREACHED */
  962.  }
  963.  
  964.  qboolean Q_isanumber( const char *s )
  965. @@ -730,13 +794,13 @@ qboolean Q_isintegral( float f )
  966.  =============
  967.  Q_strncpyz
  968.  
  969. -Safe strncpy that ensures a trailing zero
  970. +Safe strncpy that ensures a trailing zero.  This now uses Q_strlcpy().
  971.  =============
  972.  */
  973.  void Q_strncpyz( char *dest, const char *src, int destsize ) {
  974. -  if ( !dest ) {
  975. -    Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
  976. -  }
  977. +   if ( !dest ) {
  978. +       Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
  979. +   }
  980.     if ( !src ) {
  981.         Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
  982.     }
  983. @@ -744,8 +808,9 @@ void Q_strncpyz( char *dest, const char *src, int destsize ) {
  984.         Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
  985.     }
  986.  
  987. -   strncpy( dest, src, destsize-1 );
  988. -  dest[destsize-1] = 0;
  989. +   if (Q_strlcpy(dest, src, destsize) >= destsize) {
  990. +       // XXX Handle truncation?
  991. +   }
  992.  }
  993.                  
  994.  int Q_stricmpn (const char *s1, const char *s2, int n) {
  995. @@ -758,8 +823,7 @@ int Q_stricmpn (const char *s1, const char *s2, int n) {
  996.               return -1;
  997.          }
  998.          else if ( s2==NULL )
  999. -          return 1;
  1000. -
  1001. +         return 1;
  1002.  
  1003.    
  1004.     do {
  1005. @@ -786,6 +850,7 @@ int Q_stricmpn (const char *s1, const char *s2, int n) {
  1006.     return 0;       // strings are equal
  1007.  }
  1008.  
  1009. +
  1010.  int Q_strncmp (const char *s1, const char *s2, int n) {
  1011.     int     c1, c2;
  1012.    
  1013. @@ -805,8 +870,9 @@ int Q_strncmp (const char *s1, const char *s2, int n) {
  1014.     return 0;       // strings are equal
  1015.  }
  1016.  
  1017. +// This now uses the OpenBSD version
  1018.  int Q_stricmp (const char *s1, const char *s2) {
  1019. -   return (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1;
  1020. +   return (s1 && s2) ? Q_stricmpn(s1, s2, 99999) : -1;
  1021.  }
  1022.  
  1023.  
  1024. @@ -832,50 +898,225 @@ char *Q_strupr( char *s1 ) {
  1025.      return s1;
  1026.  }
  1027.  
  1028. +/* $OpenBSD: strcasestr.c,v 1.3 2006/03/31 05:34:55 deraadt Exp $  */
  1029. +/* $NetBSD: strcasestr.c,v 1.2 2005/02/09 21:35:47 kleink Exp $    */
  1030. +/*-
  1031. + * Copyright (c) 1990, 1993
  1032. + * The Regents of the University of California.  All rights reserved.
  1033. + *
  1034. + * This code is derived from software contributed to Berkeley by
  1035. + * Chris Torek.
  1036. + *
  1037. + * Redistribution and use in source and binary forms, with or without
  1038. + * modification, are permitted provided that the following conditions
  1039. + * are met:
  1040. + * 1. Redistributions of source code must retain the above copyright
  1041. + *    notice, this list of conditions and the following disclaimer.
  1042. + * 2. Redistributions in binary form must reproduce the above copyright
  1043. + *    notice, this list of conditions and the following disclaimer in the
  1044. + *    documentation and/or other materials provided with the distribution.
  1045. + * 3. Neither the name of the University nor the names of its contributors
  1046. + *    may be used to endorse or promote products derived from this software
  1047. + *    without specific prior written permission.
  1048. + *
  1049. + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  1050. + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  1051. + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  1052. + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  1053. + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  1054. + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  1055. + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  1056. + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  1057. + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  1058. + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  1059. + * SUCH DAMAGE.
  1060. + */
  1061. +/*
  1062. + * Find the first occurrence of find in s, ignore case.
  1063. + */
  1064. +char *
  1065. +Q_strcasestr(const char *s, const char *find)
  1066. +{
  1067. +   char c, sc;
  1068. +   size_t len;
  1069. +
  1070. +   if ((c = *find++) != 0) {
  1071. +       c = (char)tolower((unsigned char)c);
  1072. +       len = strlen(find);
  1073. +       do {
  1074. +           do {
  1075. +               if ((sc = *s++) == 0)
  1076. +                   return (NULL);
  1077. +           } while ((char)tolower((unsigned char)sc) != c);
  1078. +       } while (Q_stricmpn(s, find, len) != 0);
  1079. +       s--;
  1080. +   }
  1081. +   return ((char *)s);
  1082. +}
  1083. +
  1084. +/* Alias for existing code */
  1085. +const char *
  1086. +Q_stristr(const char *s, const char *find)
  1087. +{
  1088. +   return Q_strcasestr(s, find);
  1089. +}
  1090. +
  1091. +/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $  */
  1092. +/*
  1093. + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
  1094. + *
  1095. + * Permission to use, copy, modify, and distribute this software for any
  1096. + * purpose with or without fee is hereby granted, provided that the above
  1097. + * copyright notice and this permission notice appear in all copies.
  1098. + *
  1099. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  1100. + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  1101. + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  1102. + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  1103. + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  1104. + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  1105. + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  1106. + */
  1107. +/*
  1108. + * Appends src to string dst of size siz (unlike strncat, siz is the
  1109. + * full size of dst, not space left).  At most siz-1 characters
  1110. + * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
  1111. + * Returns strlen(src) + MIN(siz, strlen(initial dst)).
  1112. + * If retval >= siz, truncation occurred.
  1113. + */
  1114. +size_t
  1115. +Q_strlcat(char *dst, const char *src, size_t siz)
  1116. +{
  1117. +   char *d = dst;
  1118. +   const char *s = src;
  1119. +   size_t n = siz;
  1120. +   size_t dlen;
  1121. +
  1122. +   if (! dst) {
  1123. +       Com_Error( ERR_FATAL, "Q_strlcat: NULL dest" );
  1124. +   }
  1125. +   if ( !src ) {
  1126. +       Com_Error( ERR_FATAL, "Q_strlcat: NULL src" );
  1127. +   }
  1128. +   if ( siz < 1) {
  1129. +       Com_Error(ERR_FATAL, "Q_strlcat: siz < 1" );
  1130. +   }
  1131. +
  1132. +   /* Find the end of dst and adjust bytes left but don't go past end */
  1133. +   while (n-- != 0 && *d != '\0')
  1134. +       d++;
  1135. +   dlen = d - dst;
  1136. +   n = siz - dlen;
  1137. +
  1138. +   if (n == 0)
  1139. +       return(dlen + strlen(s));
  1140. +   while (*s != '\0') {
  1141. +       if (n != 1) {
  1142. +           *d++ = *s;
  1143. +           n--;
  1144. +       }
  1145. +       s++;
  1146. +   }
  1147. +   *d = '\0';
  1148.  
  1149. -// never goes past bounds or leaves without a terminating 0
  1150. -void Q_strcat( char *dest, int size, const char *src ) {
  1151. -   int     l1;
  1152. +   return(dlen + (s - src));   /* count does not include NUL */
  1153. +}
  1154.  
  1155. -   l1 = strlen( dest );
  1156. -   if ( l1 >= size ) {
  1157. +/* For legacy code, provide the Q_strcat interface to Q_strlcat() */
  1158. +void Q_strcat(char *dst, int siz, const char *src)
  1159. +{
  1160. +   size_t l1 = strlen( dst );
  1161. +   if ( l1 >= siz ) {
  1162.         Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
  1163.     }
  1164. -   Q_strncpyz( dest + l1, src, size - l1 );
  1165. +
  1166. +   Q_strlcat(dst, src, siz);
  1167.  }
  1168.  
  1169. +/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $    */
  1170.  /*
  1171. -* Find the first occurrence of find in s.
  1172. -*/
  1173. -const char *Q_stristr( const char *s, const char *find)
  1174. + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
  1175. + *
  1176. + * Permission to use, copy, modify, and distribute this software for any
  1177. + * purpose with or without fee is hereby granted, provided that the above
  1178. + * copyright notice and this permission notice appear in all copies.
  1179. + *
  1180. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  1181. + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  1182. + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  1183. + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  1184. + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  1185. + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  1186. + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  1187. + */
  1188. +/*
  1189. + * Copy src to string dst of size siz.  At most siz-1 characters
  1190. + * will be copied.  Always NUL terminates (unless siz == 0).
  1191. + * Returns strlen(src); if retval >= siz, truncation occurred.
  1192. + */
  1193. +size_t
  1194. +Q_strlcpy(char *dst, const char *src, size_t siz)
  1195.  {
  1196. -  char c, sc;
  1197. -  size_t len;
  1198. -
  1199. -  if ((c = *find++) != 0)
  1200. -  {
  1201. -    if (c >= 'a' && c <= 'z')
  1202. -    {
  1203. -      c -= ('a' - 'A');
  1204. -    }
  1205. -    len = strlen(find);
  1206. -    do
  1207. -    {
  1208. -      do
  1209. -      {
  1210. -        if ((sc = *s++) == 0)
  1211. -          return NULL;
  1212. -        if (sc >= 'a' && sc <= 'z')
  1213. -        {
  1214. -          sc -= ('a' - 'A');
  1215. -        }
  1216. -      } while (sc != c);
  1217. -    } while (Q_stricmpn(s, find, len) != 0);
  1218. -    s--;
  1219. -  }
  1220. -  return s;
  1221. +   char *d = dst;
  1222. +   const char *s = src;
  1223. +   size_t n = siz;
  1224. +
  1225. +   // Mimic the error cheking from the previous Q_strcpynz
  1226. +   if (! dst) {
  1227. +       Com_Error( ERR_FATAL, "Q_strlcpy: NULL dest" );
  1228. +   }
  1229. +   if ( !src ) {
  1230. +       Com_Error( ERR_FATAL, "Q_strlcpy: NULL src" );
  1231. +   }
  1232. +   if ( siz < 1) {
  1233. +       Com_Error(ERR_FATAL, "Q_strlcpy: siz < 1" );
  1234. +   }
  1235. +
  1236. +   /* Copy as many bytes as will fit */
  1237. +   if (n != 0) {
  1238. +       while (--n != 0) {
  1239. +           if ((*d++ = *s++) == '\0')
  1240. +               break;
  1241. +       }
  1242. +   }
  1243. +
  1244. +   /* Not enough room in dst, add NUL and traverse rest of src */
  1245. +   if (n == 0) {
  1246. +       if (siz != 0)
  1247. +           *d = '\0';      /* NUL-terminate dst */
  1248. +       while (*s++)
  1249. +           ;
  1250. +   }
  1251. +
  1252. +   return(s - src - 1);    /* count does not include NUL */
  1253.  }
  1254.  
  1255. +/* $OpenBSD: strnlen.c,v 1.3 2010/06/02 12:58:12 millert Exp $ */
  1256. +/*
  1257. + * Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
  1258. + *
  1259. + * Permission to use, copy, modify, and distribute this software for any
  1260. + * purpose with or without fee is hereby granted, provided that the above
  1261. + * copyright notice and this permission notice appear in all copies.
  1262. + *
  1263. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  1264. + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  1265. + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  1266. + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  1267. + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  1268. + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  1269. + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  1270. + */
  1271. +size_t
  1272. +Q_strnlen(const char *str, size_t maxlen)
  1273. +{
  1274. +   const char *cp;
  1275. +
  1276. +   for (cp = str; maxlen != 0 && *cp != '\0'; cp++, maxlen--)
  1277. +       ;
  1278. +
  1279. +   return (size_t)(cp - str);
  1280. +}
  1281.  
  1282.  int Q_PrintStrlen( const char *string ) {
  1283.     int         len;
  1284. diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h
  1285. index 6942a62..7c9274c 100644
  1286. --- a/code/qcommon/q_shared.h
  1287. +++ b/code/qcommon/q_shared.h
  1288. @@ -26,6 +26,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  1289.  // q_shared.h -- included first by ALL program modules.
  1290.  // A user mod should never modify this file
  1291.  
  1292. +/* extern __inline is a GNU C extension */
  1293. +#ifdef __GNUC__
  1294. +#  if defined(__GNUC_STDC_INLINE__)
  1295. +#    define    __CTYPE_INLINE  extern __inline __attribute__((__gnu_inline__))
  1296. +#  else
  1297. +#    define    __CTYPE_INLINE  extern __inline
  1298. +#  endif
  1299. +#else
  1300. +#  define  __CTYPE_INLINE
  1301. +#endif
  1302. +
  1303.  #ifdef STANDALONE
  1304.    #define PRODUCT_NAME         "iofoo3"
  1305.    #define BASEGAME         "foobar"
  1306. @@ -701,6 +712,7 @@ int Q_isprint( int c );
  1307.  int Q_islower( int c );
  1308.  int Q_isupper( int c );
  1309.  int Q_isalpha( int c );
  1310. +
  1311.  qboolean Q_isanumber( const char *s );
  1312.  qboolean Q_isintegral( float f );
  1313.  
  1314. @@ -710,13 +722,21 @@ int       Q_strncmp (const char *s1, const char *s2, int n);
  1315.  int        Q_stricmpn (const char *s1, const char *s2, int n);
  1316.  char   *Q_strlwr( char *s1 );
  1317.  char   *Q_strupr( char *s1 );
  1318. -char   *Q_strrchr( const char* string, int c );
  1319.  const char *Q_stristr( const char *s, const char *find);
  1320.  
  1321. -// buffer size safe library replacements
  1322. +// buffer size safe library replacements (uses strlcpy and strlcat)
  1323.  void   Q_strncpyz( char *dest, const char *src, int destsize );
  1324.  void   Q_strcat( char *dest, int size, const char *src );
  1325.  
  1326. +// OpenBSD implementations
  1327. +char *Q_strchr(const char *p, int ch);
  1328. +char *Q_strrchr(const char *p, int ch);
  1329. +char *Q_strcasestr(const char *s, const char *find);
  1330. +int Q_strncasecmp(const char *s1, const char *s2, size_t n);
  1331. +size_t Q_strnlen(const char *str, size_t maxlen);
  1332. +size_t Q_strlcat(char *dst, const char *src, size_t siz);
  1333. +size_t Q_strlcpy(char *dst, const char *src, size_t siz);
  1334. +
  1335.  // strlen that discounts Quake color sequences
  1336.  int Q_PrintStrlen( const char *string );
  1337.  // removes color sequences from string
  1338. @@ -1298,5 +1318,4 @@ typedef enum _flag_status {
  1339.  #define CDKEY_LEN 16
  1340.  #define CDCHKSUM_LEN 2
  1341.  
  1342. -
  1343.  #endif // __Q_SHARED_H
  1344. diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h
  1345. index c6a61e2..7e409f9 100644
  1346. --- a/code/qcommon/qcommon.h
  1347. +++ b/code/qcommon/qcommon.h
  1348. @@ -729,6 +729,11 @@ typedef struct {
  1349.     char    buffer[MAX_EDIT_LINE];
  1350.  } field_t;
  1351.  
  1352. +typedef struct {
  1353. +   int length;
  1354. +   char    buffer[MAX_EDIT_LINE];
  1355. +} killring_t;
  1356. +
  1357.  void Field_Clear( field_t *edit );
  1358.  void Field_AutoComplete( field_t *edit );
  1359.  void Field_CompleteKeyname( void );
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement