1195902Sdelphij/*
2240121Sdelphij * Copyright (C) 1984-2012  Mark Nudelman
3195902Sdelphij *
4195902Sdelphij * You may distribute under the terms of either the GNU General Public
5195902Sdelphij * License or the Less License, as specified in the README file.
6195902Sdelphij *
7240121Sdelphij * For more information, see the README file.
8195902Sdelphij */
9195902Sdelphij
10195902Sdelphij/*
11195902Sdelphij * Routines to convert text in various ways.  Used by search.
12195902Sdelphij */
13195902Sdelphij
14195902Sdelphij#include "less.h"
15195902Sdelphij#include "charset.h"
16195902Sdelphij
17195902Sdelphijextern int utf_mode;
18195902Sdelphij
19195902Sdelphij/*
20195902Sdelphij * Get the length of a buffer needed to convert a string.
21195902Sdelphij */
22195902Sdelphij	public int
23195902Sdelphijcvt_length(len, ops)
24195902Sdelphij	int len;
25195902Sdelphij	int ops;
26195902Sdelphij{
27195902Sdelphij	if (utf_mode)
28195902Sdelphij		/*
29195902Sdelphij		 * Just copying a string in UTF-8 mode can cause it to grow
30195902Sdelphij		 * in length.
31195902Sdelphij		 * Four output bytes for one input byte is the worst case.
32195902Sdelphij		 */
33195902Sdelphij		len *= 4;
34195902Sdelphij	return (len + 1);
35195902Sdelphij}
36195902Sdelphij
37195902Sdelphij/*
38195902Sdelphij * Allocate a chpos array for use by cvt_text.
39195902Sdelphij */
40195902Sdelphij	public int *
41195902Sdelphijcvt_alloc_chpos(len)
42195902Sdelphij	int len;
43195902Sdelphij{
44195902Sdelphij	int i;
45195902Sdelphij	int *chpos = (int *) ecalloc(sizeof(int), len);
46195902Sdelphij	/* Initialize all entries to an invalid position. */
47195902Sdelphij	for (i = 0;  i < len;  i++)
48195902Sdelphij		chpos[i] = -1;
49195902Sdelphij	return (chpos);
50195902Sdelphij}
51195902Sdelphij
52195902Sdelphij/*
53195902Sdelphij * Convert text.  Perform the transformations specified by ops.
54195902Sdelphij * Returns converted text in odst.  The original offset of each
55195902Sdelphij * odst character (when it was in osrc) is returned in the chpos array.
56195902Sdelphij */
57195902Sdelphij	public void
58195902Sdelphijcvt_text(odst, osrc, chpos, lenp, ops)
59195902Sdelphij	char *odst;
60195902Sdelphij	char *osrc;
61195902Sdelphij	int *chpos;
62195902Sdelphij	int *lenp;
63195902Sdelphij	int ops;
64195902Sdelphij{
65195902Sdelphij	char *dst;
66240121Sdelphij	char *edst = odst;
67195902Sdelphij	char *src;
68195902Sdelphij	register char *src_end;
69195902Sdelphij	LWCHAR ch;
70195902Sdelphij
71195902Sdelphij	if (lenp != NULL)
72195902Sdelphij		src_end = osrc + *lenp;
73195902Sdelphij	else
74195902Sdelphij		src_end = osrc + strlen(osrc);
75195902Sdelphij
76195902Sdelphij	for (src = osrc, dst = odst;  src < src_end;  )
77195902Sdelphij	{
78195902Sdelphij		int src_pos = src - osrc;
79195902Sdelphij		int dst_pos = dst - odst;
80195902Sdelphij		ch = step_char(&src, +1, src_end);
81195902Sdelphij		if ((ops & CVT_BS) && ch == '\b' && dst > odst)
82195902Sdelphij		{
83195902Sdelphij			/* Delete backspace and preceding char. */
84195902Sdelphij			do {
85195902Sdelphij				dst--;
86195902Sdelphij			} while (dst > odst &&
87195902Sdelphij				!IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst));
88195902Sdelphij		} else if ((ops & CVT_ANSI) && IS_CSI_START(ch))
89195902Sdelphij		{
90195902Sdelphij			/* Skip to end of ANSI escape sequence. */
91195902Sdelphij			src++;  /* skip the CSI start char */
92195902Sdelphij			while (src < src_end)
93195902Sdelphij				if (!is_ansi_middle(*src++))
94195902Sdelphij					break;
95195902Sdelphij		} else
96195902Sdelphij		{
97195902Sdelphij			/* Just copy the char to the destination buffer. */
98195902Sdelphij			if ((ops & CVT_TO_LC) && IS_UPPER(ch))
99195902Sdelphij				ch = TO_LOWER(ch);
100195902Sdelphij			put_wchar(&dst, ch);
101240121Sdelphij			/* Record the original position of the char. */
102240121Sdelphij			if (chpos != NULL)
103195902Sdelphij				chpos[dst_pos] = src_pos;
104195902Sdelphij		}
105240121Sdelphij		if (dst > edst)
106240121Sdelphij			edst = dst;
107195902Sdelphij	}
108240121Sdelphij	if ((ops & CVT_CRLF) && edst > odst && edst[-1] == '\r')
109240121Sdelphij		edst--;
110240121Sdelphij	*edst = '\0';
111195902Sdelphij	if (lenp != NULL)
112240121Sdelphij		*lenp = edst - odst;
113240121Sdelphij	/* FIXME: why was this here?  if (chpos != NULL) chpos[dst - odst] = src - osrc; */
114195902Sdelphij}
115