cvt.c revision 330571
1/*
2 * Copyright (C) 1984-2017  Mark Nudelman
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
6 *
7 * For more information, see the README file.
8 */
9
10/*
11 * Routines to convert text in various ways.  Used by search.
12 */
13
14#include "less.h"
15#include "charset.h"
16
17extern int utf_mode;
18
19/*
20 * Get the length of a buffer needed to convert a string.
21 */
22	public int
23cvt_length(len, ops)
24	int len;
25	int ops;
26{
27	if (utf_mode)
28		/*
29		 * Just copying a string in UTF-8 mode can cause it to grow
30		 * in length.
31		 * Four output bytes for one input byte is the worst case.
32		 */
33		len *= 4;
34	return (len + 1);
35}
36
37/*
38 * Allocate a chpos array for use by cvt_text.
39 */
40	public int *
41cvt_alloc_chpos(len)
42	int len;
43{
44	int i;
45	int *chpos = (int *) ecalloc(sizeof(int), len);
46	/* Initialize all entries to an invalid position. */
47	for (i = 0;  i < len;  i++)
48		chpos[i] = -1;
49	return (chpos);
50}
51
52/*
53 * Convert text.  Perform the transformations specified by ops.
54 * Returns converted text in odst.  The original offset of each
55 * odst character (when it was in osrc) is returned in the chpos array.
56 */
57	public void
58cvt_text(odst, osrc, chpos, lenp, ops)
59	char *odst;
60	char *osrc;
61	int *chpos;
62	int *lenp;
63	int ops;
64{
65	char *dst;
66	char *edst = odst;
67	char *src;
68	char *src_end;
69	LWCHAR ch;
70
71	if (lenp != NULL)
72		src_end = osrc + *lenp;
73	else
74		src_end = osrc + strlen(osrc);
75
76	for (src = osrc, dst = odst;  src < src_end;  )
77	{
78		int src_pos = (int) (src - osrc);
79		int dst_pos = (int) (dst - odst);
80		ch = step_char(&src, +1, src_end);
81		if ((ops & CVT_BS) && ch == '\b' && dst > odst)
82		{
83			/* Delete backspace and preceding char. */
84			do {
85				dst--;
86			} while (dst > odst && utf_mode &&
87				!IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst));
88		} else if ((ops & CVT_ANSI) && IS_CSI_START(ch))
89		{
90			/* Skip to end of ANSI escape sequence. */
91			src++;  /* skip the CSI start char */
92			while (src < src_end)
93				if (!is_ansi_middle(*src++))
94					break;
95		} else
96		{
97			/* Just copy the char to the destination buffer. */
98			if ((ops & CVT_TO_LC) && IS_UPPER(ch))
99				ch = TO_LOWER(ch);
100			put_wchar(&dst, ch);
101			/* Record the original position of the char. */
102			if (chpos != NULL)
103				chpos[dst_pos] = src_pos;
104		}
105		if (dst > edst)
106			edst = dst;
107	}
108	if ((ops & CVT_CRLF) && edst > odst && edst[-1] == '\r')
109		edst--;
110	*edst = '\0';
111	if (lenp != NULL)
112		*lenp = (int) (edst - odst);
113	/* FIXME: why was this here?  if (chpos != NULL) chpos[dst - odst] = src - osrc; */
114}
115