xref: /netbsd/external/bsd/less/dist/cvt.c (revision 29ea9d98)
1 /*	$NetBSD: cvt.c,v 1.3 2013/09/04 19:44:21 tron Exp $	*/
2 
3 /*
4  * Copyright (C) 1984-2012  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  */
24 	public int
cvt_length(len,ops)25 cvt_length(len, ops)
26 	int len;
27 	int ops;
28 {
29 	if (utf_mode)
30 		/*
31 		 * Just copying a string in UTF-8 mode can cause it to grow
32 		 * in length.
33 		 * Four output bytes for one input byte is the worst case.
34 		 */
35 		len *= 4;
36 	return (len + 1);
37 }
38 
39 /*
40  * Allocate a chpos array for use by cvt_text.
41  */
42 	public int *
cvt_alloc_chpos(len)43 cvt_alloc_chpos(len)
44 	int len;
45 {
46 	int i;
47 	int *chpos = (int *) ecalloc(sizeof(int), len);
48 	/* Initialize all entries to an invalid position. */
49 	for (i = 0;  i < len;  i++)
50 		chpos[i] = -1;
51 	return (chpos);
52 }
53 
54 /*
55  * Convert text.  Perform the transformations specified by ops.
56  * Returns converted text in odst.  The original offset of each
57  * odst character (when it was in osrc) is returned in the chpos array.
58  */
59 	public void
cvt_text(odst,osrc,chpos,lenp,ops)60 cvt_text(odst, osrc, chpos, lenp, ops)
61 	char *odst;
62 	char *osrc;
63 	int *chpos;
64 	int *lenp;
65 	int ops;
66 {
67 	char *dst;
68 	char *edst = odst;
69 	char *src;
70 	register char *src_end;
71 	LWCHAR ch;
72 
73 	if (lenp != NULL)
74 		src_end = osrc + *lenp;
75 	else
76 		src_end = osrc + strlen(osrc);
77 
78 	for (src = osrc, dst = odst;  src < src_end;  )
79 	{
80 		int src_pos = src - osrc;
81 		int dst_pos = dst - odst;
82 		ch = step_char(&src, +1, src_end);
83 		if ((ops & CVT_BS) && ch == '\b' && dst > odst)
84 		{
85 			/* Delete backspace and preceding char. */
86 			do {
87 				dst--;
88 			} while (dst > odst &&
89 				!IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst));
90 		} else if ((ops & CVT_ANSI) && IS_CSI_START(ch))
91 		{
92 			/* Skip to end of ANSI escape sequence. */
93 			src++;  /* skip the CSI start char */
94 			while (src < src_end)
95 				if (!is_ansi_middle(*src++))
96 					break;
97 		} else
98 		{
99 			/* Just copy the char to the destination buffer. */
100 			if ((ops & CVT_TO_LC) && IS_UPPER(ch))
101 				ch = TO_LOWER(ch);
102 			put_wchar(&dst, ch);
103 			/* Record the original position of the char. */
104 			if (chpos != NULL)
105 				chpos[dst_pos] = src_pos;
106 		}
107 		if (dst > edst)
108 			edst = dst;
109 	}
110 	if ((ops & CVT_CRLF) && edst > odst && edst[-1] == '\r')
111 		edst--;
112 	*edst = '\0';
113 	if (lenp != NULL)
114 		*lenp = edst - odst;
115 	/* FIXME: why was this here?  if (chpos != NULL) chpos[dst - odst] = src - osrc; */
116 }
117