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