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
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2014-06-21 23:55:01 +02:00
|
|
|
#include <wchar.h>
|
2013-12-10 09:03:45 +01:00
|
|
|
|
2014-06-12 00:06:55 +02:00
|
|
|
#include "toxic.h"
|
|
|
|
#include "windows.h"
|
2013-12-10 09:03:45 +01:00
|
|
|
#include "misc_tools.h"
|
2013-12-11 06:10:09 +01:00
|
|
|
#include "toxic_strings.h"
|
2014-07-27 01:49:59 +02:00
|
|
|
#include "notify.h"
|
2013-12-10 09:03:45 +01:00
|
|
|
|
2014-07-14 20:32:38 +02:00
|
|
|
/* Adds char to line at pos. Return 0 on success, -1 if line buffer is full */
|
|
|
|
int add_char_to_buf(ChatContext *ctx, wint_t ch)
|
2013-12-10 09:03:45 +01:00
|
|
|
{
|
2014-07-14 20:32:38 +02:00
|
|
|
if (ctx->len >= MAX_STR_SIZE - 1)
|
|
|
|
return -1;
|
2013-12-10 09:03:45 +01:00
|
|
|
|
2014-06-21 23:55:01 +02:00
|
|
|
wmemmove(&ctx->line[ctx->pos + 1], &ctx->line[ctx->pos], ctx->len - ctx->pos);
|
2014-06-06 21:27:06 +02:00
|
|
|
ctx->line[ctx->pos++] = ch;
|
2014-06-21 23:55:01 +02:00
|
|
|
ctx->line[++ctx->len] = L'\0';
|
2014-07-14 20:32:38 +02:00
|
|
|
|
|
|
|
return 0;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
2014-07-14 20:32:38 +02:00
|
|
|
/* Deletes the character before pos. Return 0 on success, -1 if nothing to delete */
|
|
|
|
int del_char_buf_bck(ChatContext *ctx)
|
2013-12-10 09:03:45 +01:00
|
|
|
{
|
2014-07-14 20:32:38 +02:00
|
|
|
if (ctx->pos <= 0)
|
|
|
|
return -1;
|
2013-12-10 09:03:45 +01:00
|
|
|
|
2014-06-21 23:55:01 +02:00
|
|
|
wmemmove(&ctx->line[ctx->pos - 1], &ctx->line[ctx->pos], ctx->len - ctx->pos);
|
2014-06-06 21:27:06 +02:00
|
|
|
--ctx->pos;
|
2014-06-21 23:55:01 +02:00
|
|
|
ctx->line[--ctx->len] = L'\0';
|
2014-07-14 20:32:38 +02:00
|
|
|
|
|
|
|
return 0;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
2014-07-14 20:32:38 +02:00
|
|
|
/* Deletes the character at pos. Return 0 on success, -1 if nothing to delete. */
|
|
|
|
int del_char_buf_frnt(ChatContext *ctx)
|
2013-12-10 09:03:45 +01:00
|
|
|
{
|
2014-06-22 03:41:38 +02:00
|
|
|
if (ctx->pos >= ctx->len)
|
2014-07-14 20:32:38 +02:00
|
|
|
return -1;
|
2013-12-10 09:03:45 +01:00
|
|
|
|
2014-06-21 23:55:01 +02:00
|
|
|
wmemmove(&ctx->line[ctx->pos], &ctx->line[ctx->pos + 1], ctx->len - ctx->pos - 1);
|
|
|
|
ctx->line[--ctx->len] = L'\0';
|
2014-07-14 20:32:38 +02:00
|
|
|
|
|
|
|
return 0;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
2014-07-14 20:32:38 +02:00
|
|
|
/* Deletes the line from beginning to pos and puts discarded portion in yank buffer.
|
|
|
|
Return 0 on success, -1 if noting to discard. */
|
|
|
|
int discard_buf(ChatContext *ctx)
|
2013-12-10 09:03:45 +01:00
|
|
|
{
|
2014-06-06 21:27:06 +02:00
|
|
|
if (ctx->pos <= 0)
|
2014-07-14 20:32:38 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
ctx->yank_len = ctx->pos;
|
|
|
|
wmemcpy(ctx->yank, ctx->line, ctx->yank_len);
|
|
|
|
ctx->yank[ctx->yank_len] = L'\0';
|
2013-12-10 09:03:45 +01:00
|
|
|
|
2014-06-21 23:55:01 +02:00
|
|
|
wmemmove(ctx->line, &ctx->line[ctx->pos], ctx->len - ctx->pos);
|
|
|
|
ctx->len -= ctx->pos;
|
2014-06-06 21:27:06 +02:00
|
|
|
ctx->pos = 0;
|
2014-06-21 05:08:13 +02:00
|
|
|
ctx->start = 0;
|
2014-06-21 23:55:01 +02:00
|
|
|
ctx->line[ctx->len] = L'\0';
|
2014-07-14 20:32:38 +02:00
|
|
|
|
|
|
|
return 0;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
2014-07-14 20:32:38 +02:00
|
|
|
/* Deletes the line from pos to len and puts killed portion in yank buffer.
|
|
|
|
Return 0 on success, -1 if nothing to kill. */
|
|
|
|
int kill_buf(ChatContext *ctx)
|
2013-12-10 09:03:45 +01:00
|
|
|
{
|
2014-07-14 20:32:38 +02:00
|
|
|
if (ctx->len <= ctx->pos)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ctx->yank_len = ctx->len - ctx->pos;
|
|
|
|
wmemcpy(ctx->yank, &ctx->line[ctx->pos], ctx->yank_len);
|
|
|
|
ctx->yank[ctx->yank_len] = L'\0';
|
2013-12-10 09:03:45 +01:00
|
|
|
|
2014-06-06 21:27:06 +02:00
|
|
|
ctx->line[ctx->pos] = L'\0';
|
|
|
|
ctx->len = ctx->pos;
|
2014-07-14 20:32:38 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Inserts string in ctx->yank into line at pos.
|
|
|
|
Return 0 on success, -1 if yank buffer is empty or too long */
|
|
|
|
int yank_buf(ChatContext *ctx)
|
|
|
|
{
|
|
|
|
if (!ctx->yank[0])
|
|
|
|
return -1;
|
|
|
|
|
2014-07-27 01:16:07 +02:00
|
|
|
if (ctx->yank_len + ctx->len >= MAX_STR_SIZE)
|
2014-07-14 20:32:38 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
wmemmove(&ctx->line[ctx->pos + ctx->yank_len], &ctx->line[ctx->pos], ctx->len - ctx->pos);
|
|
|
|
wmemcpy(&ctx->line[ctx->pos], ctx->yank, ctx->yank_len);
|
|
|
|
|
|
|
|
ctx->pos += ctx->yank_len;
|
|
|
|
ctx->len += ctx->yank_len;
|
|
|
|
ctx->line[ctx->len] = L'\0';
|
2014-10-06 05:12:58 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-26 03:56:45 +01:00
|
|
|
/* Deletes all characters from line starting at pos and going backwards
|
2014-10-06 05:12:58 +02:00
|
|
|
until we find a space or run out of characters.
|
|
|
|
Return 0 on success, -1 if nothing to delete */
|
|
|
|
int del_word_buf(ChatContext *ctx)
|
|
|
|
{
|
|
|
|
if (ctx->len == 0 || ctx->pos == 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
int i = ctx->pos, count = 0;
|
|
|
|
|
|
|
|
/* traverse past empty space */
|
2016-09-25 03:07:04 +02:00
|
|
|
while (i > 0 && ctx->line[i - 1] == L' ') {
|
2014-10-06 05:12:58 +02:00
|
|
|
++count;
|
|
|
|
--i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* traverse past last entered word */
|
2016-09-25 03:07:04 +02:00
|
|
|
while (i > 0 && ctx->line[i - 1] != L' ') {
|
2014-10-06 05:12:58 +02:00
|
|
|
++count;
|
|
|
|
--i;
|
|
|
|
}
|
|
|
|
|
|
|
|
wmemmove(&ctx->line[i], &ctx->line[ctx->pos], ctx->len - ctx->pos);
|
|
|
|
|
|
|
|
ctx->start = MAX(0, ctx->start - count); /* TODO: take into account widechar */
|
|
|
|
ctx->len -= count;
|
|
|
|
ctx->pos -= count;
|
|
|
|
ctx->line[ctx->len] = L'\0';
|
|
|
|
|
2014-07-14 20:32:38 +02:00
|
|
|
return 0;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
2014-06-21 05:08:13 +02:00
|
|
|
/* nulls line and sets pos, len and start to 0 */
|
2014-06-06 21:27:06 +02:00
|
|
|
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;
|
2014-06-21 05:08:13 +02:00
|
|
|
ctx->start = 0;
|
2013-12-10 09:03:45 +01:00
|
|
|
}
|
|
|
|
|
2015-12-04 20:15:31 +01:00
|
|
|
/* Removes trailing spaces and newlines from line. */
|
2014-06-06 21:27:06 +02:00
|
|
|
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;
|
|
|
|
|
2015-12-04 20:15:31 +01:00
|
|
|
if (ctx->line[ctx->len - 1] != ' ' && ctx->line[ctx->len - 1] != L'¶')
|
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) {
|
2015-12-04 20:15:31 +01:00
|
|
|
if (ctx->line[i] != ' ' && ctx->line[i] != L'¶')
|
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-07-25 23:55:21 +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-06-26 08:33:09 +02:00
|
|
|
if (key_dir == KEY_UP) {
|
2014-06-06 21:27:06 +02:00
|
|
|
if (--ctx->hst_pos < 0) {
|
|
|
|
ctx->hst_pos = 0;
|
2015-03-26 03:56:45 +01:00
|
|
|
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
|
2013-12-11 10:49:21 +01:00
|
|
|
}
|
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
|
|
|
}
|
2015-12-04 20:15:31 +01:00
|
|
|
|
2016-09-25 03:07:04 +02:00
|
|
|
void strsubst(char *str, char old, char new)
|
2015-12-04 20:15:31 +01:00
|
|
|
{
|
|
|
|
int i;
|
2016-09-25 03:07:04 +02:00
|
|
|
|
2015-12-04 20:15:31 +01:00
|
|
|
for (i = 0; str[i] != '\0'; ++i)
|
|
|
|
if (str[i] == old)
|
2016-09-25 03:07:04 +02:00
|
|
|
str[i] = new;
|
2015-12-04 20:15:31 +01:00
|
|
|
}
|
|
|
|
|
2016-09-25 03:07:04 +02:00
|
|
|
void wstrsubst(wchar_t *str, wchar_t old, wchar_t new)
|
2015-12-04 20:15:31 +01:00
|
|
|
{
|
|
|
|
int i;
|
2016-09-25 03:07:04 +02:00
|
|
|
|
2015-12-04 20:15:31 +01:00
|
|
|
for (i = 0; str[i] != L'\0'; ++i)
|
|
|
|
if (str[i] == old)
|
2016-09-25 03:07:04 +02:00
|
|
|
str[i] = new;
|
2015-12-04 20:15:31 +01:00
|
|
|
}
|