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
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
/* Adds char to line at pos */
|
|
|
|
void add_char_to_buf(ChatContext *ctx, wint_t ch)
|
2013-12-10 09:03:45 +01:00
|
|
|
{
|
2014-06-06 21:27:06 +02:00
|
|
|
if (ctx->pos < 0 || ctx->len >= MAX_STR_SIZE)
|
2013-12-10 09:03:45 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* move all chars including null in front of pos one space forward and insert char in pos */
|
|
|
|
int i;
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
for (i = ctx->len; i >= ctx->pos && i >= 0; --i)
|
|
|
|
ctx->line[i + 1] = ctx->line[i];
|
2013-12-10 09:03:45 +01:00
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
ctx->line[ctx->pos++] = ch;
|
|
|
|
++ctx->len;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Deletes the character before pos */
|
2014-06-06 21:27:06 +02:00
|
|
|
void del_char_buf_bck(ChatContext *ctx)
|
2013-12-10 09:03:45 +01:00
|
|
|
{
|
2014-06-06 21:27:06 +02:00
|
|
|
if (ctx->pos <= 0)
|
2013-12-10 09:03:45 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* similar to add_char_to_buf but deletes a char */
|
2014-06-06 21:27:06 +02:00
|
|
|
for (i = ctx->pos - 1; i <= ctx->len; ++i)
|
|
|
|
ctx->line[i] = ctx->line[i + 1];
|
2013-12-10 09:03:45 +01:00
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
--ctx->pos;
|
|
|
|
--ctx->len;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Deletes the character at pos */
|
2014-06-06 21:27:06 +02:00
|
|
|
void del_char_buf_frnt(ChatContext *ctx)
|
2013-12-10 09:03:45 +01:00
|
|
|
{
|
2014-06-06 21:27:06 +02:00
|
|
|
if (ctx->pos < 0 || ctx->pos >= ctx->len)
|
2013-12-10 09:03:45 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
for (i = ctx->pos; i < ctx->len; ++i)
|
|
|
|
ctx->line[i] = ctx->line[i + 1];
|
2013-12-10 09:03:45 +01:00
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
--ctx->len;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Deletes the line from beginning to pos */
|
2014-06-06 21:27:06 +02:00
|
|
|
void discard_buf(ChatContext *ctx)
|
2013-12-10 09:03:45 +01:00
|
|
|
{
|
2014-06-06 21:27:06 +02:00
|
|
|
if (ctx->pos <= 0)
|
2013-12-10 09:03:45 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
int c = 0;
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
for (i = ctx->pos; i <= ctx->len; ++i)
|
|
|
|
ctx->line[c++] = ctx->line[i];
|
2013-12-10 09:03:45 +01:00
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
ctx->pos = 0;
|
|
|
|
ctx->len = c - 1;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Deletes the line from pos to len */
|
2014-06-06 21:27:06 +02:00
|
|
|
void kill_buf(ChatContext *ctx)
|
2013-12-10 09:03:45 +01:00
|
|
|
{
|
2014-06-06 21:27:06 +02:00
|
|
|
if (ctx->len == ctx->pos)
|
2013-12-10 09:03:45 +01:00
|
|
|
return;
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
ctx->line[ctx->pos] = L'\0';
|
|
|
|
ctx->len = ctx->pos;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
/* nulls line and sets pos and len to 0 */
|
|
|
|
void reset_buf(ChatContext *ctx)
|
2013-12-10 09:03:45 +01:00
|
|
|
{
|
2014-06-06 21:27:06 +02:00
|
|
|
ctx->line[0] = L'\0';
|
|
|
|
ctx->pos = 0;
|
|
|
|
ctx->len = 0;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
/* Removes trailing spaces from line. */
|
|
|
|
void rm_trailing_spaces_buf(ChatContext *ctx)
|
2014-06-04 02:35:00 +02:00
|
|
|
{
|
2014-06-06 21:27:06 +02:00
|
|
|
if (ctx->len <= 0)
|
2014-06-04 02:35:00 +02:00
|
|
|
return;
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
if (ctx->line[ctx->len - 1] != ' ')
|
2014-06-04 02:35:00 +02:00
|
|
|
return;
|
|
|
|
|
2014-06-04 20:41:36 +02:00
|
|
|
int i;
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
for (i = ctx->len - 1; i >= 0; --i) {
|
|
|
|
if (ctx->line[i] != ' ')
|
2014-06-04 20:41:36 +02:00
|
|
|
break;
|
|
|
|
}
|
2014-06-04 02:35:00 +02:00
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
ctx->len = i + 1;
|
2014-06-07 20:36:37 +02:00
|
|
|
ctx->pos = MIN(ctx->pos, ctx->len);
|
2014-06-06 21:27:06 +02:00
|
|
|
ctx->line[ctx->len] = L'\0';
|
2014-06-04 02:35:00 +02:00
|
|
|
}
|
|
|
|
|
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 */
|
2014-06-06 21:27:06 +02:00
|
|
|
static void shift_hist_back(ChatContext *ctx)
|
2013-12-14 06:36:06 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int n = MAX_LINE_HIST - HIST_PURGE;
|
|
|
|
|
|
|
|
for (i = 0; i < n; ++i)
|
2014-06-06 21:27:06 +02:00
|
|
|
wmemcpy(ctx->ln_history[i], ctx->ln_history[i + HIST_PURGE], MAX_STR_SIZE);
|
2013-12-14 06:36:06 +01:00
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
ctx->hst_tot = n;
|
2013-12-14 06:36:06 +01:00
|
|
|
}
|
|
|
|
|
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-06-06 21:27:06 +02:00
|
|
|
void add_line_to_hist(ChatContext *ctx)
|
2013-12-11 06:10:09 +01:00
|
|
|
{
|
2014-06-06 21:27:06 +02:00
|
|
|
if (ctx->len > MAX_STR_SIZE)
|
2013-12-11 06:10:09 +01:00
|
|
|
return;
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
if (ctx->hst_tot >= MAX_LINE_HIST)
|
|
|
|
shift_hist_back(ctx);
|
2013-12-11 06:10:09 +01:00
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
++ctx->hst_tot;
|
|
|
|
ctx->hst_pos = ctx->hst_tot;
|
2013-12-14 06:36:06 +01:00
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
wmemcpy(ctx->ln_history[ctx->hst_tot - 1], ctx->line, ctx->len + 1);
|
2013-12-11 06:10:09 +01:00
|
|
|
}
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
/* copies history item at hst_pos to line. 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-06-06 21:27:06 +02:00
|
|
|
resets line if at end of history */
|
|
|
|
void fetch_hist_item(ChatContext *ctx, int key_dir)
|
2013-12-11 06:10:09 +01:00
|
|
|
{
|
2014-03-24 12:18:58 +01:00
|
|
|
if (key_dir == MOVE_UP) {
|
2014-06-06 21:27:06 +02:00
|
|
|
if (--ctx->hst_pos < 0) {
|
|
|
|
ctx->hst_pos = 0;
|
2013-12-11 10:49:21 +01:00
|
|
|
beep();
|
|
|
|
}
|
2013-12-11 06:10:09 +01:00
|
|
|
} else {
|
2014-06-06 21:27:06 +02:00
|
|
|
if (++ctx->hst_pos >= ctx->hst_tot) {
|
|
|
|
ctx->hst_pos = ctx->hst_tot;
|
|
|
|
reset_buf(ctx);
|
2013-12-11 10:49:21 +01:00
|
|
|
return;
|
|
|
|
}
|
2013-12-11 06:10:09 +01:00
|
|
|
}
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
const wchar_t *hst_line = ctx->ln_history[ctx->hst_pos];
|
2013-12-11 06:10:09 +01:00
|
|
|
size_t h_len = wcslen(hst_line);
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
wmemcpy(ctx->line, hst_line, h_len + 1);
|
|
|
|
ctx->pos = h_len;
|
|
|
|
ctx->len = h_len;
|
2013-12-11 06:10:09 +01:00
|
|
|
}
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
/* looks for the first instance in list that begins with the last entered word in line according to pos,
|
|
|
|
then fills line with the complete word. e.g. "Hello jo" would complete the line
|
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
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
Returns the difference between the old len and new len of line on success, -1 if error */
|
|
|
|
int complete_line(ChatContext *ctx, const void *list, int n_items, int size)
|
2013-12-10 09:03:45 +01:00
|
|
|
{
|
2014-06-06 21:27:06 +02:00
|
|
|
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE)
|
2013-12-10 09:03:45 +01:00
|
|
|
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 */
|
2014-06-06 21:27:06 +02:00
|
|
|
if (wcs_to_mbs_buf(ubuf, ctx->line, MAX_STR_SIZE) == -1)
|
2013-12-10 09:03:45 +01:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* isolate substring from space behind pos to pos */
|
|
|
|
uint8_t tmp[MAX_STR_SIZE];
|
|
|
|
snprintf(tmp, sizeof(tmp), "%s", ubuf);
|
2014-06-06 21:27:06 +02:00
|
|
|
tmp[ctx->pos] = '\0';
|
2013-12-10 09:03:45 +01:00
|
|
|
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-06 21:27:06 +02:00
|
|
|
int strt = ctx->pos - s_len;
|
2013-12-10 09:03:45 +01:00
|
|
|
int diff = m_len - s_len + n_endchrs;
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
if (ctx->len + diff > MAX_STR_SIZE)
|
2013-12-10 09:03:45 +01:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
uint8_t tmpend[MAX_STR_SIZE];
|
2014-06-06 21:27:06 +02:00
|
|
|
strcpy(tmpend, &ubuf[ctx->pos]);
|
2013-12-10 09:03:45 +01:00
|
|
|
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;
|
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
wcscpy(ctx->line, newbuf);
|
2013-12-10 09:03:45 +01:00
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
ctx->len += (size_t) diff;
|
|
|
|
ctx->pos += (size_t) diff;
|
2013-12-10 09:03:45 +01:00
|
|
|
|
|
|
|
return diff;
|
|
|
|
}
|