2014-02-25 08:28:24 +01:00
|
|
|
/* toxic_strings.c
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
|
|
|
*
|
|
|
|
* This file is part of Toxic.
|
|
|
|
*
|
|
|
|
* Toxic is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Toxic is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
2013-12-10 09:03:45 +01:00
|
|
|
*/
|
|
|
|
|
2014-03-11 00:34:18 +01:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2013-12-10 09:03:45 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "toxic_windows.h"
|
|
|
|
#include "misc_tools.h"
|
2013-12-11 06:10:09 +01:00
|
|
|
#include "toxic_strings.h"
|
2013-12-10 09:03:45 +01:00
|
|
|
|
|
|
|
/* Adds char to buffer at pos */
|
|
|
|
void add_char_to_buf(wchar_t *buf, size_t *pos, size_t *len, wint_t ch)
|
|
|
|
{
|
|
|
|
if (*pos < 0 || *len >= MAX_STR_SIZE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* move all chars including null in front of pos one space forward and insert char in pos */
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = *len; i >= *pos && i >= 0; --i)
|
2014-04-19 23:58:13 +02:00
|
|
|
buf[i + 1] = buf[i];
|
2013-12-10 09:03:45 +01:00
|
|
|
|
|
|
|
buf[(*pos)++] = ch;
|
|
|
|
++(*len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deletes the character before pos */
|
|
|
|
void del_char_buf_bck(wchar_t *buf, size_t *pos, size_t *len)
|
|
|
|
{
|
|
|
|
if (*pos <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* similar to add_char_to_buf but deletes a char */
|
2014-04-19 23:58:13 +02:00
|
|
|
for (i = *pos - 1; i <= *len; ++i)
|
|
|
|
buf[i] = buf[i + 1];
|
2013-12-10 09:03:45 +01:00
|
|
|
|
|
|
|
--(*pos);
|
|
|
|
--(*len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deletes the character at pos */
|
|
|
|
void del_char_buf_frnt(wchar_t *buf, size_t *pos, size_t *len)
|
|
|
|
{
|
|
|
|
if (*pos < 0 || *pos >= *len)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = *pos; i < *len; ++i)
|
2014-04-19 23:58:13 +02:00
|
|
|
buf[i] = buf[i + 1];
|
2013-12-10 09:03:45 +01:00
|
|
|
|
|
|
|
--(*len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deletes the line from beginning to pos */
|
|
|
|
void discard_buf(wchar_t *buf, size_t *pos, size_t *len)
|
|
|
|
{
|
|
|
|
if (*pos <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
int c = 0;
|
|
|
|
|
|
|
|
for (i = *pos; i <= *len; ++i)
|
|
|
|
buf[c++] = buf[i];
|
|
|
|
|
|
|
|
*pos = 0;
|
|
|
|
*len = c - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deletes the line from pos to len */
|
|
|
|
void kill_buf(wchar_t *buf, size_t *pos, size_t *len)
|
|
|
|
{
|
|
|
|
if (*len == *pos)
|
|
|
|
return;
|
|
|
|
|
|
|
|
buf[*pos] = L'\0';
|
|
|
|
*len = *pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* nulls buf and sets pos and len to 0 */
|
|
|
|
void reset_buf(wchar_t *buf, size_t *pos, size_t *len)
|
|
|
|
{
|
|
|
|
buf[0] = L'\0';
|
|
|
|
*pos = 0;
|
|
|
|
*len = 0;
|
|
|
|
}
|
|
|
|
|
2014-06-04 02:35:00 +02:00
|
|
|
/* Removes trailing spaces from buf. */
|
|
|
|
void rm_trailing_spaces_buf(wchar_t *buf, size_t *pos, size_t *len)
|
|
|
|
{
|
|
|
|
if (*len <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buf[*len - 1] != ' ')
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (*pos == *len)
|
|
|
|
--(*pos);
|
|
|
|
|
|
|
|
buf[--(*len)] = L'\0';
|
|
|
|
rm_trailing_spaces_buf(buf, pos, len);
|
|
|
|
}
|
|
|
|
|
2013-12-14 06:36:06 +01:00
|
|
|
#define HIST_PURGE MAX_LINE_HIST / 4
|
|
|
|
|
|
|
|
/* shifts hist items back and makes room for HIST_PURGE new entries */
|
|
|
|
static void shift_hist_back(wchar_t (*hst)[MAX_STR_SIZE], int *hst_tot)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int n = MAX_LINE_HIST - HIST_PURGE;
|
|
|
|
|
|
|
|
for (i = 0; i < n; ++i)
|
2014-04-19 23:58:13 +02:00
|
|
|
wmemcpy(hst[i], hst[i + HIST_PURGE], MAX_STR_SIZE);
|
2013-12-14 06:36:06 +01:00
|
|
|
|
|
|
|
*hst_tot = n;
|
|
|
|
}
|
|
|
|
|
2013-12-11 09:29:31 +01:00
|
|
|
/* adds a line to the ln_history buffer at hst_pos and sets hst_pos to end of history. */
|
2014-04-19 23:58:13 +02:00
|
|
|
void add_line_to_hist(const wchar_t *buf, size_t len, wchar_t (*hst)[MAX_STR_SIZE], int *hst_tot,
|
2013-12-11 09:29:31 +01:00
|
|
|
int *hst_pos)
|
2013-12-11 06:10:09 +01:00
|
|
|
{
|
|
|
|
if (len > MAX_STR_SIZE)
|
|
|
|
return;
|
|
|
|
|
2013-12-14 06:36:06 +01:00
|
|
|
if (*hst_tot >= MAX_LINE_HIST)
|
|
|
|
shift_hist_back(hst, hst_tot);
|
2013-12-11 06:10:09 +01:00
|
|
|
|
2013-12-14 06:36:06 +01:00
|
|
|
++(*hst_tot);
|
2013-12-11 06:10:09 +01:00
|
|
|
*hst_pos = *hst_tot;
|
2013-12-14 06:36:06 +01:00
|
|
|
|
2014-04-19 23:58:13 +02:00
|
|
|
wmemcpy(hst[*hst_tot - 1], buf, len + 1);
|
2013-12-11 06:10:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* copies history item at hst_pos to buf. Sets pos and len to the len of the history item.
|
2014-02-23 20:22:45 +01:00
|
|
|
hst_pos is decremented or incremented depending on key_dir.
|
2014-04-19 23:58:13 +02:00
|
|
|
|
2014-02-23 20:22:45 +01:00
|
|
|
resets buffer if at end of history */
|
2013-12-11 09:29:31 +01:00
|
|
|
void fetch_hist_item(wchar_t *buf, size_t *pos, size_t *len, wchar_t (*hst)[MAX_STR_SIZE],
|
|
|
|
int hst_tot, int *hst_pos, int key_dir)
|
2013-12-11 06:10:09 +01:00
|
|
|
{
|
2014-03-24 12:18:58 +01:00
|
|
|
if (key_dir == MOVE_UP) {
|
2013-12-11 10:49:21 +01:00
|
|
|
if (--(*hst_pos) < 0) {
|
2014-02-26 07:51:06 +01:00
|
|
|
*hst_pos = 0;
|
2013-12-11 10:49:21 +01:00
|
|
|
beep();
|
|
|
|
}
|
2013-12-11 06:10:09 +01:00
|
|
|
} else {
|
2013-12-19 02:18:02 +01:00
|
|
|
if (++(*hst_pos) >= hst_tot) {
|
2014-02-26 07:51:06 +01:00
|
|
|
*hst_pos = hst_tot;
|
2014-02-23 20:22:45 +01:00
|
|
|
reset_buf(buf, pos, len);
|
2013-12-11 10:49:21 +01:00
|
|
|
return;
|
|
|
|
}
|
2013-12-11 06:10:09 +01:00
|
|
|
}
|
|
|
|
|
2013-12-11 09:29:31 +01:00
|
|
|
const wchar_t *hst_line = hst[*hst_pos];
|
2013-12-11 06:10:09 +01:00
|
|
|
size_t h_len = wcslen(hst_line);
|
|
|
|
|
|
|
|
wmemcpy(buf, hst_line, h_len + 1);
|
|
|
|
|
|
|
|
*pos = h_len;
|
|
|
|
*len = h_len;
|
|
|
|
}
|
|
|
|
|
2014-04-19 23:58:13 +02:00
|
|
|
/* looks for the first instance in list that begins with the last entered word in buf according to pos,
|
|
|
|
then fills buf with the complete word. e.g. "Hello jo" would complete the buffer
|
2013-12-10 09:03:45 +01:00
|
|
|
with "Hello john".
|
|
|
|
|
|
|
|
list is a pointer to the list of strings being compared, n_items is the number of items
|
2014-04-19 23:58:13 +02:00
|
|
|
in the list, and size is the size of each item in the list.
|
2013-12-10 09:03:45 +01:00
|
|
|
|
|
|
|
Returns the difference between the old len and new len of buf on success, -1 if error */
|
|
|
|
int complete_line(wchar_t *buf, size_t *pos, size_t *len, const void *list, int n_items, int size)
|
|
|
|
{
|
|
|
|
if (*pos <= 0 || *len <= 0 || *len >= MAX_STR_SIZE)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
const uint8_t *L = (uint8_t *) list;
|
|
|
|
|
|
|
|
uint8_t ubuf[MAX_STR_SIZE];
|
2014-04-19 23:58:13 +02:00
|
|
|
|
2013-12-10 09:03:45 +01:00
|
|
|
/* work with multibyte string copy of buf for simplicity */
|
|
|
|
if (wcs_to_mbs_buf(ubuf, buf, MAX_STR_SIZE) == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* isolate substring from space behind pos to pos */
|
|
|
|
uint8_t tmp[MAX_STR_SIZE];
|
|
|
|
snprintf(tmp, sizeof(tmp), "%s", ubuf);
|
|
|
|
tmp[*pos] = '\0';
|
|
|
|
uint8_t *sub = strrchr(tmp, ' ');
|
2014-06-04 02:35:00 +02:00
|
|
|
int n_endchrs = 1; /* 1 = append space to end of match, 2 = append ": " */
|
2013-12-10 09:03:45 +01:00
|
|
|
|
|
|
|
if (!sub++) {
|
|
|
|
sub = tmp;
|
2014-06-04 02:35:00 +02:00
|
|
|
|
|
|
|
if (sub[0] != '/') /* make sure it's not a command */
|
|
|
|
n_endchrs = 2;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (string_is_empty(sub))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
int s_len = strlen(sub);
|
|
|
|
const uint8_t *match;
|
|
|
|
bool is_match = false;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* look for a match in list */
|
|
|
|
for (i = 0; i < n_items; ++i) {
|
2014-04-19 23:58:13 +02:00
|
|
|
match = &L[i * size];
|
|
|
|
|
2013-12-10 09:03:45 +01:00
|
|
|
if (is_match = strncasecmp(match, sub, s_len) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_match)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* put match in correct spot in buf and append endchars (space or ": ") */
|
2014-06-04 02:35:00 +02:00
|
|
|
const uint8_t *endchrs = n_endchrs == 1 ? " " : ": ";
|
2013-12-10 09:03:45 +01:00
|
|
|
int m_len = strlen(match);
|
2014-06-02 09:19:59 +02:00
|
|
|
int strt = *pos - s_len;
|
2013-12-10 09:03:45 +01:00
|
|
|
int diff = m_len - s_len + n_endchrs;
|
|
|
|
|
|
|
|
if (*len + diff > MAX_STR_SIZE)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
uint8_t tmpend[MAX_STR_SIZE];
|
|
|
|
strcpy(tmpend, &ubuf[*pos]);
|
|
|
|
strcpy(&ubuf[strt], match);
|
2014-04-19 23:58:13 +02:00
|
|
|
strcpy(&ubuf[strt + m_len], endchrs);
|
|
|
|
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
|
2013-12-10 09:03:45 +01:00
|
|
|
|
|
|
|
/* convert to widechar and copy back to original buf */
|
|
|
|
wchar_t newbuf[MAX_STR_SIZE];
|
|
|
|
|
2014-01-23 05:29:28 +01:00
|
|
|
if (mbs_to_wcs_buf(newbuf, ubuf, MAX_STR_SIZE) == -1)
|
2013-12-10 09:03:45 +01:00
|
|
|
return -1;
|
|
|
|
|
2013-12-11 06:10:09 +01:00
|
|
|
wcscpy(buf, newbuf);
|
2013-12-10 09:03:45 +01:00
|
|
|
|
|
|
|
*len += (size_t) diff;
|
|
|
|
*pos += (size_t) diff;
|
|
|
|
|
|
|
|
return diff;
|
|
|
|
}
|