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 */ 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 */ 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 */ 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