Age Owner Branch data TLA Line data Source code
1 : : /*-----------------------------------------------------------------------
2 : : * ascii.c
3 : : * The PostgreSQL routine for string to ascii conversion.
4 : : *
5 : : * Portions Copyright (c) 1999-2024, PostgreSQL Global Development Group
6 : : *
7 : : * IDENTIFICATION
8 : : * src/backend/utils/adt/ascii.c
9 : : *
10 : : *-----------------------------------------------------------------------
11 : : */
12 : : #include "postgres.h"
13 : :
14 : : #include "mb/pg_wchar.h"
15 : : #include "utils/ascii.h"
16 : : #include "utils/fmgrprotos.h"
17 : : #include "varatt.h"
18 : :
19 : : static void pg_to_ascii(unsigned char *src, unsigned char *src_end,
20 : : unsigned char *dest, int enc);
21 : : static text *encode_to_ascii(text *data, int enc);
22 : :
23 : :
24 : : /* ----------
25 : : * to_ascii
26 : : * ----------
27 : : */
28 : : static void
7580 tgl@sss.pgh.pa.us 29 :UBC 0 : pg_to_ascii(unsigned char *src, unsigned char *src_end, unsigned char *dest, int enc)
30 : : {
31 : : unsigned char *x;
32 : : const unsigned char *ascii;
33 : : int range;
34 : :
35 : : /*
36 : : * relevant start for an encoding
37 : : */
38 : : #define RANGE_128 128
39 : : #define RANGE_160 160
40 : :
8256 ishii@postgresql.org 41 [ # # ]: 0 : if (enc == PG_LATIN1)
42 : : {
43 : : /*
44 : : * ISO-8859-1 <range: 160 -- 255>
45 : : */
6777 tgl@sss.pgh.pa.us 46 : 0 : ascii = (const unsigned char *) " cL Y \"Ca -R 'u ., ?AAAAAAACEEEEIIII NOOOOOxOUUUUYTBaaaaaaaceeeeiiii nooooo/ouuuuyty";
8653 bruce@momjian.us 47 : 0 : range = RANGE_160;
48 : : }
8256 ishii@postgresql.org 49 [ # # ]: 0 : else if (enc == PG_LATIN2)
50 : : {
51 : : /*
52 : : * ISO-8859-2 <range: 160 -- 255>
53 : : */
6777 tgl@sss.pgh.pa.us 54 : 0 : ascii = (const unsigned char *) " A L LS \"SSTZ-ZZ a,l'ls ,sstz\"zzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTBraaaalccceeeeiiddnnoooo/ruuuuyt.";
8653 bruce@momjian.us 55 : 0 : range = RANGE_160;
56 : : }
7055 tgl@sss.pgh.pa.us 57 [ # # ]: 0 : else if (enc == PG_LATIN9)
58 : : {
59 : : /*
60 : : * ISO-8859-15 <range: 160 -- 255>
61 : : */
6777 62 : 0 : ascii = (const unsigned char *) " cL YS sCa -R Zu .z EeY?AAAAAAACEEEEIIII NOOOOOxOUUUUYTBaaaaaaaceeeeiiii nooooo/ouuuuyty";
7055 63 : 0 : range = RANGE_160;
64 : : }
8256 ishii@postgresql.org 65 [ # # ]: 0 : else if (enc == PG_WIN1250)
66 : : {
67 : : /*
68 : : * Window CP1250 <range: 128 -- 255>
69 : : */
6777 tgl@sss.pgh.pa.us 70 : 0 : ascii = (const unsigned char *) " ' \" %S<STZZ `'\"\".-- s>stzz L A \"CS -RZ ,l'u .,as L\"lzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTBraaaalccceeeeiiddnnoooo/ruuuuyt ";
8653 bruce@momjian.us 71 : 0 : range = RANGE_128;
72 : : }
73 : : else
74 : : {
7567 tgl@sss.pgh.pa.us 75 [ # # ]: 0 : ereport(ERROR,
76 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
77 : : errmsg("encoding conversion from %s to ASCII not supported",
78 : : pg_encoding_to_char(enc))));
79 : : return; /* keep compiler quiet */
80 : : }
81 : :
82 : : /*
83 : : * Encode
84 : : */
7683 85 [ # # ]: 0 : for (x = src; x < src_end; x++)
86 : : {
8424 bruce@momjian.us 87 [ # # ]: 0 : if (*x < 128)
7580 tgl@sss.pgh.pa.us 88 : 0 : *dest++ = *x;
8653 bruce@momjian.us 89 [ # # ]: 0 : else if (*x < range)
7580 tgl@sss.pgh.pa.us 90 : 0 : *dest++ = ' '; /* bogus 128 to 'range' */
91 : : else
92 : 0 : *dest++ = ascii[*x - range];
93 : : }
94 : : }
95 : :
96 : : /* ----------
97 : : * encode text
98 : : *
99 : : * The text datum is overwritten in-place, therefore this coding method
100 : : * cannot support conversions that change the string length!
101 : : * ----------
102 : : */
103 : : static text *
8653 bruce@momjian.us 104 : 0 : encode_to_ascii(text *data, int enc)
105 : : {
2489 tgl@sss.pgh.pa.us 106 : 0 : pg_to_ascii((unsigned char *) VARDATA(data), /* src */
107 : 0 : (unsigned char *) (data) + VARSIZE(data), /* src end */
108 : 0 : (unsigned char *) VARDATA(data), /* dest */
109 : : enc); /* encoding */
110 : :
8653 bruce@momjian.us 111 : 0 : return data;
112 : : }
113 : :
114 : : /* ----------
115 : : * convert to ASCII - enc is set as 'name' arg.
116 : : * ----------
117 : : */
118 : : Datum
119 : 0 : to_ascii_encname(PG_FUNCTION_ARGS)
120 : : {
7559 121 : 0 : text *data = PG_GETARG_TEXT_P_COPY(0);
6028 tgl@sss.pgh.pa.us 122 : 0 : char *encname = NameStr(*PG_GETARG_NAME(1));
123 : 0 : int enc = pg_char_to_encoding(encname);
124 : :
125 [ # # ]: 0 : if (enc < 0)
126 [ # # ]: 0 : ereport(ERROR,
127 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
128 : : errmsg("%s is not a valid encoding name", encname)));
129 : :
7580 130 : 0 : PG_RETURN_TEXT_P(encode_to_ascii(data, enc));
131 : : }
132 : :
133 : : /* ----------
134 : : * convert to ASCII - enc is set as int4
135 : : * ----------
136 : : */
137 : : Datum
8653 bruce@momjian.us 138 : 0 : to_ascii_enc(PG_FUNCTION_ARGS)
139 : : {
7559 140 : 0 : text *data = PG_GETARG_TEXT_P_COPY(0);
141 : 0 : int enc = PG_GETARG_INT32(1);
142 : :
6028 tgl@sss.pgh.pa.us 143 [ # # # # ]: 0 : if (!PG_VALID_ENCODING(enc))
144 [ # # ]: 0 : ereport(ERROR,
145 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
146 : : errmsg("%d is not a valid encoding code", enc)));
147 : :
7580 148 : 0 : PG_RETURN_TEXT_P(encode_to_ascii(data, enc));
149 : : }
150 : :
151 : : /* ----------
152 : : * convert to ASCII - current enc is DatabaseEncoding
153 : : * ----------
154 : : */
155 : : Datum
8653 bruce@momjian.us 156 : 0 : to_ascii_default(PG_FUNCTION_ARGS)
157 : : {
7559 158 : 0 : text *data = PG_GETARG_TEXT_P_COPY(0);
159 : 0 : int enc = GetDatabaseEncoding();
160 : :
7580 tgl@sss.pgh.pa.us 161 : 0 : PG_RETURN_TEXT_P(encode_to_ascii(data, enc));
162 : : }
163 : :
164 : : /* ----------
165 : : * Copy a string in an arbitrary backend-safe encoding, converting it to a
166 : : * valid ASCII string by replacing non-ASCII bytes with '?'. Otherwise the
167 : : * behavior is identical to strlcpy(), except that we don't bother with a
168 : : * return value.
169 : : *
170 : : * This must not trigger ereport(ERROR), as it is called in postmaster.
171 : : * ----------
172 : : */
173 : : void
4559 tgl@sss.pgh.pa.us 174 :CBC 7234 : ascii_safe_strlcpy(char *dest, const char *src, size_t destsiz)
175 : : {
176 [ - + ]: 7234 : if (destsiz == 0) /* corner case: no room for trailing nul */
4559 tgl@sss.pgh.pa.us 177 :UBC 0 : return;
178 : :
4559 tgl@sss.pgh.pa.us 179 [ + - ]:CBC 161753 : while (--destsiz > 0)
180 : : {
181 : : /* use unsigned char here to avoid compiler warning */
182 : 161753 : unsigned char ch = *src++;
183 : :
rhaas@postgresql.org 184 [ + + ]: 161753 : if (ch == '\0')
185 : 7234 : break;
186 : : /* Keep printable ASCII characters */
187 [ + - + - ]: 154519 : if (32 <= ch && ch <= 127)
tgl@sss.pgh.pa.us 188 : 154519 : *dest = ch;
189 : : /* White-space is also OK */
4559 rhaas@postgresql.org 190 [ # # # # :UBC 0 : else if (ch == '\n' || ch == '\r' || ch == '\t')
# # ]
tgl@sss.pgh.pa.us 191 : 0 : *dest = ch;
192 : : /* Everything else is replaced with '?' */
193 : : else
194 : 0 : *dest = '?';
4559 tgl@sss.pgh.pa.us 195 :CBC 154519 : dest++;
196 : : }
197 : :
198 : 7234 : *dest = '\0';
199 : : }
|