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