GAWK Shift_JIS用の文字列操作DLL
GAWK4 を使用していて困るのが、全半角混在の文字列の取り扱いです。データベースの固定長フィールドに文字列を流したり、ファイル内の文字列を綺麗に整形したりできないのです。もちろん、GAWK4 をバイトモードで起動させればできなくはありませんが、上記データベースの例では、溢れないように文字列を取り出す際に2バイト文字が分割され「文字化け」の問題が起こります。
そこで 文字列操作関連の DLL(ダイナミックリンクライブラリ) を作成します。
GAWK4 の DLL を使用したことがない方は、 こちらのページ を参照してください。
筆者のPC作業で使用する文字セットは、専ら Shift_JIS ですので、文字列をバイト単位で操作することは比較的容易です。
DLL ダウンロード win_sjis2(zip 10KB)
注:GAWK4.2.0 for win32以降対応
( 4.1.4以前は こちら DLL名 win_sjis )
DLL のテスト#1
lengthb() と swritef() をテストする
1 : # awk_dll_test.awk;
2 : # DLL win_sjis2 lengthb() swritef()の使用例
3 : @load "win_sjis2";
4 : BEGIN {
5 : str1 = "プログラミング言語AWK";
6 :
7 : char = length(str1);
8 : byte = lengthb(str1);
9 : print str1 "\n length():char=" char "\nlengthb():byte=" byte;
10 :
11 : book[1] = str1;
12 : book[2] = "正規表現辞典";
13 : book[3] = "AWKを256倍使うための本";
14 : book[4] = "シェル芸に効く!AWK処方箋";
15 : book[5] = "sed & awkプログラミング";
16 : book[6] = "AWK実践入門";
17 :
18 : print "\n#sprintf()にて右詰め w=30";
19 : for (i in book) print sprintf("%30s", book[i]);
20 : print "\n#swritef()にて右詰め w=30";
21 : for (i in book) print swritef(30, book[i]);
22 : }
実行結果
GAWK4 の組み込み関数 sprintf() は仕事をしない
lengthb()
関数名 lengthb() 文字列のバイト数を返す
式 ret = lengthb(string);
戻り値 ret: 文字列のバイト数 数値
第1引数 string: 全半角混在の文字列 文字列/変数
備考: stringに配列が代入されるとエラーとなり、-1 を返す
極めて高速です。Cソースを確認してください。
swritef()
関数名 swritef() 書式に従い整形された文字列を返す
式 ret = swritef(flgwidths, precision, string);
戻り値 ret: 整形された文字列 文字列
第1引数 flgwidths: 最小幅(バイト) 符号左右詰め 正(右詰め)負(左詰め)数値/変数
第2引数 precision: 最大出力文字数(バイト) 数値/変数 [※省略可]
第3引数 string: 文字列(数値=文字列に変換) 文字列リテラル/数値/変数
備考: 可変引数には対応していない
precision 出力で壊された2バイト文字はスペースに変換される
ページ冒頭のデータベースの例ですが、固定長30バイトのフィールドに文字列を流す例では以下のように書けばよいことになります。
data = swritef(0, 30, string);
30バイト目と31バイト目で一つの文字を形成していた場合でも、文字化けすることはなく、30バイト目はスペースになります。
文字列データの長さをそろえる場合は次のように書きます。
例) 幅30バイトで左詰めに整形
data = swritef(-30, 30, string);
30バイトに満たない文字列には、文字列の右側に足りない分のスペースが補完され、超える部分は切り捨てられます。(文字化けはスペースに変換)
第二引数を省略しますと、超える部分があった場合、問答無用に全文字列を返します。
文字列データを右詰めにしたい場合は第一引数を 30(正の整数) にします。
DLL のテスト#2
substrb() をテストする
1 : # awk_dll_test2.awk;
2 : # DLL win_sjis2 substrb()の使用例
3 : @load "win_sjis2";
4 : BEGIN {
5 : book[1] = "プログラミング言語AWK";
6 : book[2] = "正規表現辞典";
7 : book[3] = "AWKを256倍使うための本";
8 : book[4] = "シェル芸に効く!AWK処方箋";
9 : book[5] = "sed & awkプログラミング";
10 : book[6] = "AWK実践入門";
11 :
12 : print "配列 book の要素 2バイト目から10バイト取り出す\n";
13 : for (i in book) print substrb(book[i], 2, 10);
14 : }
実行結果
substrb()
関数名 substrb() バイト単位で文字列を取り出す
式 ret = substrb(string, start-byte, byte);
戻り値 ret: 取り出した文字列 文字列
第1引数 string: 対象文字列 文字列リテラル/数値/変数
第2引数 start-byte: 取り出し開始位置(バイト) 数値/変数
第3引数 byte: 取り出す量(バイト) 数値/変数 [※省略可]
備考: 第3引数を省略すると開始位置から全文字列を返す
開始位置及び終了位置での壊れた2バイト文字はスペースに変換される
以下 DLL のソース全文です。(バイトモード動作は考慮していませんので悪しからず)
writef() write() trim() はおまけです。
win_sjis2.c (win_sjis2.dll)
1 : /*
2 : * win_sjis2.c - Builtin functions for Windows-Shift_JIS ver.0.4
3 : * GAWK 4.2.1 for win32
4 : * include byte-conscious functions
5 : * for Japanese Zenkaku/Hankaku string on Shift_JIS char set
6 : *
7 : * lengthb(): return length of string as byte
8 : * substrb(): return substring from string byte by byte
9 : * writef(): print format string byte by byte
10 : * swritef(): return format string byte by byte
11 : * write(): print string with LF
12 : * trim(): remove extra whitespace(multibyte) from string
13 : *
14 : * Copyright 2018 Mary'sFactory
15 : */
16 :
17 :
18 : #ifdef HAVE_CONFIG_H
19 : #include <config.h>
20 : #endif
21 : #include <stdio.h>
22 : #include <assert.h>
23 : #include <stdlib.h>
24 : #include <string.h>
25 : #include <unistd.h>
26 : #include <sys/types.h>
27 : #include <sys/stat.h>
28 : #include <locale.h>
29 : #include "gawkapi.h"
30 : #include "gettext.h"
31 : #define _(msgid) gettext(msgid)
32 : #define N_(msgid) msgid
33 : static const gawk_api_t *api; /* for convenience macros to work */
34 : static awk_ext_id_t *ext_id;
35 : static const char *ext_version = "win_sjis2 extension: version 0.2";
36 : static awk_bool_t (*init_func)(void) = NULL;
37 : int plugin_is_GPL_compatible;
38 :
39 : #define M_ERR "Malloc could not allocate memory!"
40 : #define SIZE_AR (2048) /* initial buf-size */
41 :
42 : /*----- c_string_bufs can use common substring function only -----*/
43 : static char csb_arr1[SIZE_AR], csb_arr2[SIZE_AR];
44 : static char *c_string_buf1 = NULL;
45 : static char *c_string_buf2 = NULL;
46 : /*----------------------------------------------------------------*/
47 :
48 :
49 : /* c_substr() -- common substring function
50 : * get substring from string as byte by byte [for Shift_JIS]
51 : * replace broken-2bytes-characters spaces
52 : * do not forget to manage malloc. so use free_c_string_bufs() */
53 : static char *c_substr(const char *src,
54 : unsigned long srclen,
55 : unsigned long arg_stp,
56 : unsigned long *arg_bytes)
57 : {
58 : const char BRK = ' '; /* b2c (broken-2bytes-character) -> space */
59 : char *rst, *p_fwd, *p_sub;
60 : int size = 0;
61 : int flag = 0;
62 : unsigned long stp, bytes, gtr;
63 : stp = (arg_stp) ? arg_stp - 1 : 0; /* as zero-based index */
64 : bytes = (*arg_bytes > srclen - stp) ? srclen - stp : *arg_bytes;
65 : *arg_bytes = bytes; /* correct *arg_bytes */
66 :
67 : if (!bytes || !srclen || srclen < stp + 1){
68 : csb_arr1[0]='\0';
69 : rst = csb_arr1;
70 : *arg_bytes = 0; /* correct *arg_bytes */
71 : goto RETURNPOINT;
72 : }
73 :
74 : /* string buffers */
75 : gtr = (bytes > stp + 1) ? bytes : stp + 1;
76 : if (SIZE_AR > gtr + 1){ /* use array */
77 : p_fwd = csb_arr1;
78 : p_sub = csb_arr2;
79 : }
80 : else{ /* use malloc */
81 : p_fwd = c_string_buf1 = (char *)malloc(stp + 1);
82 : if (!c_string_buf1){ printf(M_ERR); exit(1); }
83 : p_sub = c_string_buf2 = (char *)malloc(bytes + 1);
84 : if (!c_string_buf2){ printf(M_ERR); exit(1); }
85 : }
86 :
87 : /* get substring and check last char whether is b2c */
88 : setlocale(LC_CTYPE, "ja_JP.Shift_JIS"); /* to use mblen() on SJIS */
89 : int i = 0;
90 : if (!stp){ /* get substring from beginning of line */
91 : memcpy(p_sub, src, bytes);
92 : p_sub[bytes] = '\0';
93 : while (p_sub[i] != '\0'){ /* check from beginning to last char */
94 : size = mblen(&p_sub[i], MB_CUR_MAX);
95 : if (size == -1){ p_sub[i] = BRK; size = 1; }
96 : /* if is the last char b2c, then replace it space
97 : * and overwrite size to proceed next '\0' */
98 : i += size; /* next character */
99 : }
100 : }
101 : else{ /* get substring from middle of line */
102 : /* at first check "just before" stp ... Not stp !
103 : * mblen() does not know whether it is b2c
104 : * even if it checks stp. */
105 : memcpy(p_fwd, src, stp);
106 : p_fwd[stp] = '\0';
107 : while (p_fwd[i] != '\0') {
108 : size = mblen(&p_fwd[i], MB_CUR_MAX);
109 : if (size == -1){ flag = 1; size = 1; } /* Not replace here */
110 : i += size;
111 : }
112 : if (flag){ /* stp was b2c. because just before stp was b2c */
113 : p_sub[0] = BRK; /* so beginning is space */
114 : memcpy(p_sub + 1, src + (stp + 1), bytes - 1); /* copy remains */
115 : p_sub[bytes] = '\0';
116 : }
117 : else{ /* stp was wholesome character */
118 : memcpy(p_sub, src + stp, bytes);
119 : p_sub[bytes] = '\0';
120 : }
121 : i = 0;
122 : while (p_sub[i] != '\0') { /* check substring */
123 : size = mblen(&p_sub[i], MB_CUR_MAX);
124 : if (size == -1){ p_sub[i] = BRK; size = 1; }
125 : i += size;
126 : }
127 : }
128 : rst = p_sub;
129 :
130 : RETURNPOINT:
131 : return rst;
132 : }
133 :
134 :
135 : /* free_c_string_bufs() -- common free function
136 : * to free global memory-allocated */
137 : static void free_c_string_bufs(void)
138 : {
139 : free(c_string_buf1);
140 : free(c_string_buf2);
141 : c_string_buf1 = c_string_buf2 = NULL;
142 : }
143 :
144 :
145 : /* do_lengthb -- return length of string as byte.
146 : * usage: ret = lengthb(string); error = -1
147 : * Faster tnan nomal mode length() maybe [for Shift_JIS]
148 : * Cannot use it for array sorry */
149 : static awk_value_t *
150 : do_lengthb(int nargs, awk_value_t *result, struct awk_ext_func *unused)
151 : {
152 : awk_value_t tstr;
153 : double ret = -1;
154 : assert(result != NULL);
155 : if (do_lint && nargs > 1)
156 : lintwarn(ext_id,
157 : _("lengthb: called with too many arguments"));
158 : if (get_argument(0, AWK_STRING, & tstr)) {
159 : /* size of tstr (bytes) */
160 : ret = tstr.str_value.len;
161 : } else if (do_lint) {
162 : if (nargs == 0)
163 : lintwarn(ext_id,
164 : _("lengthb: called with no arguments"));
165 : else
166 : lintwarn(ext_id,
167 : _("lengthb: called with inappropriate argument(s)"));
168 : }
169 : /* Set the return value */
170 : return make_number(ret, result);
171 : }
172 :
173 :
174 : /* do_substrb -- get substring from string as byte by byte.
175 : * ...substr() get with character by character on nomal mode.
176 : * usage: ret = substrb(string, start_bytes, bytes);
177 : * broken-2-byte char is converted to space [for Shift_JIS] */
178 : static awk_value_t *
179 : do_substrb(int nargs, awk_value_t *result, struct awk_ext_func *unused){
180 : awk_value_t srcstr, nstart, nbytes;
181 : char *ret;
182 : double d_st, d_bt;
183 : unsigned long arg_start, arg_bytes, tlen;
184 : assert(result != NULL);
185 : if (do_lint && nargs > 3)
186 : lintwarn(ext_id,
187 : _("substrb: called with too many arguments"));
188 : switch (nargs){
189 : case 2:
190 : if (get_argument(0, AWK_STRING, &srcstr) &&
191 : get_argument(1, AWK_NUMBER, &nstart)){
192 : d_st = nstart.num_value;
193 : arg_start = (d_st > 1) ? d_st : 1; /*double to u_long */
194 : tlen = srcstr.str_value.len;
195 : arg_bytes = (tlen - arg_start + 1 > 0) ?
196 : tlen - arg_start + 1 : 0; /* double to u_long */
197 :
198 : if (!tlen || !arg_bytes){ ret = ""; arg_bytes = 0; }
199 : else ret = c_substr(srcstr.str_value.str,
200 : tlen, arg_start, &arg_bytes);
201 :
202 : make_const_string(ret, arg_bytes, result);
203 : if(c_string_buf1 != NULL) free_c_string_bufs();
204 : return result;
205 : }
206 : break;
207 : case 3:
208 : if (get_argument(0, AWK_STRING, &srcstr) &&
209 : get_argument(1, AWK_NUMBER, &nstart) &&
210 : get_argument(2, AWK_NUMBER, &nbytes)){
211 : d_st = nstart.num_value;
212 : arg_start = (d_st > 1) ? d_st : 1; /* double to u_long */
213 : tlen = srcstr.str_value.len;
214 : d_bt = nbytes.num_value;
215 : arg_bytes = (d_bt >= 1) ? d_bt : 0; /* double to u_long */
216 :
217 : if (!tlen || !arg_bytes){ ret = ""; arg_bytes = 0; }
218 : else ret = c_substr(srcstr.str_value.str,
219 : tlen, arg_start, &arg_bytes);
220 :
221 : make_const_string(ret, arg_bytes, result);
222 : if (c_string_buf1 != NULL) free_c_string_bufs();
223 : return result;
224 : }
225 : break;
226 : default:
227 : if (do_lint) {
228 : if (nargs == 0)
229 : lintwarn(ext_id,
230 : _("substrb: called with no arguments"));
231 : else if (nargs == 1)
232 : lintwarn(ext_id,
233 : _("substrb: called with 1 arguments"));
234 : else
235 : lintwarn(ext_id,
236 : _("substrb: called with inappropriate argument(s)"));
237 : }
238 : break;
239 : }
240 : return make_const_string("", 0, result);
241 : }
242 :
243 :
244 : /* do_writef -- instead of printf("%*.*s",str);
245 : * usage: ret = writef(width, option_maxbyte, string);
246 : * use format string only,others could not.
247 : * format string byte by byte [for Shift_JIS]
248 : * broken-2byte-char is converted space */
249 : static awk_value_t *
250 : do_writef(int nargs, awk_value_t *result, struct awk_ext_func *unused)
251 : {
252 : awk_value_t flgwidths, prec, srcstr;
253 : char *tstr;
254 : double d_wid, d_pre;
255 : long l_wid;
256 : unsigned long tlen, ul_pre;
257 : int ret = -1; /* return value = -1 (argument's error) */
258 : assert(result != NULL);
259 : if (do_lint && nargs >3)
260 : lintwarn(ext_id,
261 : _("writef: called with too many arguments"));
262 :
263 : switch (nargs){
264 : case 1:
265 : if (get_argument(0, AWK_STRING, &srcstr))
266 : ret = printf("%s", srcstr.str_value.str);
267 : break;
268 : case 2:
269 : if (get_argument(0, AWK_NUMBER, &flgwidths) &&
270 : get_argument(1, AWK_STRING, &srcstr)){
271 : d_wid = flgwidths.num_value;
272 : l_wid = d_wid; /* double to long */
273 : ret = printf("%*s", l_wid, srcstr.str_value.str);
274 : }
275 : break;
276 : case 3:
277 : if (get_argument(0, AWK_NUMBER, &flgwidths) &&
278 : get_argument(1, AWK_NUMBER, &prec) &&
279 : get_argument(2, AWK_STRING, &srcstr)){
280 : tlen = srcstr.str_value.len;
281 : d_wid = flgwidths.num_value;
282 : l_wid = d_wid; /* double to long */
283 : d_pre = prec.num_value;
284 : ul_pre = (d_pre < 0) ? -d_pre : d_pre; /* abs double to u_long */
285 : tstr = c_substr(srcstr.str_value.str, tlen, 1, &ul_pre);
286 : ret = printf("%*s",l_wid, tstr);
287 : if (c_string_buf1 != NULL) free_c_string_bufs();
288 : }
289 : break;
290 : default:
291 : if (do_lint) {
292 : if (nargs == 0)
293 : lintwarn(ext_id,
294 : _("writef: called with no arguments"));
295 : else if (nargs == 1)
296 : lintwarn(ext_id,
297 : _("writef: called with 1 arguments"));
298 : else
299 : lintwarn(ext_id,
300 : _("writef: called with inappropriate argument(s)"));
301 : }
302 : break;
303 : }
304 : return make_number(ret, result);
305 : }
306 :
307 :
308 : /* do_swritef -- instead of sprintf("%*.*s",str);
309 : * usage: ret = swritef(width, option_maxbyte, string);
310 : * use format string only,others could not.
311 : * format string byte by byte [for Shift_JIS]
312 : * broken-2byte-char is converted space */
313 : static awk_value_t *
314 : do_swritef(int nargs, awk_value_t *result, struct awk_ext_func *unused)
315 : {
316 : awk_value_t flgwidths, prec, srcstr;
317 : char *tstr, *rst, *p;
318 : char *malp = NULL;
319 : char sfw[SIZE_AR];
320 : double dtmp = 0.0;
321 : long tlen, l_wid;
322 : unsigned long abswid, absmax;
323 :
324 : assert(result != NULL);
325 : if (do_lint && nargs >3)
326 : lintwarn(ext_id,
327 : _("swritef: called with too many arguments"));
328 :
329 : switch (nargs){
330 : /* case 1: do not have to use maybe
331 : /* case 2: no width,no prec should be used "sprintf" */
332 : case 2:
333 : if (get_argument(0, AWK_NUMBER, &flgwidths) &&
334 : get_argument(1, AWK_STRING, &srcstr)){
335 : l_wid = flgwidths.num_value; /* double to long */
336 : abswid = (l_wid < 0) ? -l_wid : l_wid;
337 : tstr = srcstr.str_value.str;
338 : tlen = srcstr.str_value.len;
339 :
340 : if (abswid <= tlen){
341 : rst = tstr; abswid = tlen;
342 : goto CASE2RETURN;
343 : }
344 :
345 : /* string buffer */
346 : if (SIZE_AR > abswid + 1) p = sfw;
347 : else{
348 : p = malp = (char *)malloc(abswid + 1);
349 : if (!malp){ printf(M_ERR); exit(1); }
350 : }
351 :
352 : /* fill spaces to buffer and terminate string */
353 : memset(p, ' ', abswid);
354 : p[abswid] = '\0';
355 :
356 : /* aligne */
357 : if (l_wid < 0) memcpy(p, tstr, tlen);
358 : else if (!tlen); /* return only spaces */
359 : else memcpy(p + (abswid - tlen), tstr, tlen);
360 :
361 : rst = p;
362 :
363 : CASE2RETURN:
364 : make_const_string(rst, abswid, result);
365 : if (malp != NULL) free(malp);
366 : return result;
367 : }
368 : break;
369 : case 3:
370 : if (get_argument(0, AWK_NUMBER, &flgwidths) &&
371 : get_argument(1, AWK_NUMBER, &prec) &&
372 : get_argument(2, AWK_STRING, &srcstr)){
373 : l_wid = flgwidths.num_value; /* double to long */
374 : abswid = (l_wid < 0) ? -l_wid : l_wid;
375 : tstr = srcstr.str_value.str;
376 : tlen = srcstr.str_value.len;
377 : dtmp = prec.num_value;
378 : absmax = (dtmp < 0) ? -dtmp : dtmp;
379 : absmax = (tlen < absmax) ? tlen : absmax;
380 :
381 : if (SIZE_AR > abswid + 1) p = sfw;
382 : else{
383 : p = malp = (char *)malloc(abswid + 1);
384 : if (!malp){ printf(M_ERR); exit(1); }
385 : }
386 :
387 : memset(p, ' ', abswid);
388 : p[abswid] = '\0';
389 :
390 : if (absmax) tstr = c_substr(tstr, tlen, 1, &absmax);
391 : else{ rst = p; goto CASE3RETURN; } /* return only spaces */
392 :
393 : if (abswid <= absmax){
394 : rst = tstr; abswid = absmax;
395 : goto CASE3RETURN;
396 : }
397 :
398 : if (l_wid < 0) memcpy(p, tstr, absmax);
399 : else memcpy(p + (abswid - absmax), tstr, absmax);
400 :
401 : rst = p;
402 :
403 : CASE3RETURN:
404 : make_const_string(rst, abswid, result);
405 : if (malp != NULL) free(malp);
406 : if (c_string_buf1 != NULL) free_c_string_bufs();
407 : return result;
408 : }
409 : break;
410 : default:
411 : if (do_lint) {
412 : if (nargs == 0)
413 : lintwarn(ext_id,
414 : _("swritef: called with no arguments"));
415 : else if (nargs == 1)
416 : lintwarn(ext_id,
417 : _("swritef: called with 1 arguments"));
418 : else
419 : lintwarn(ext_id,
420 : _("swritef: called with inappropriate argument(s)"));
421 : }
422 : break;
423 : }
424 : return make_const_string("", 0, result); /* error of arguments */
425 : }
426 :
427 :
428 : /* do_write -- instead of print(str);
429 : * usage: ret = write(string); */
430 : static awk_value_t *
431 : do_write(int nargs, awk_value_t *result, struct awk_ext_func *unused)
432 : {
433 : awk_value_t srcstr;
434 : long ret = -1; /* error */
435 : assert(result != NULL);
436 : if (do_lint && nargs > 1)
437 : lintwarn(ext_id,
438 : _("write: called with too many arguments"));
439 :
440 : if (get_argument(0, AWK_STRING, &srcstr)) {
441 : ret = printf("%s\n", srcstr.str_value.str); /* add LF */
442 : }
443 : else if (do_lint) {
444 : if (nargs == 0)
445 : lintwarn(ext_id,
446 : _("write: called with no arguments"));
447 : else
448 : lintwarn(ext_id,
449 : _("write: called with inappropriate argument(s)"));
450 : }
451 : return make_number(ret, result);
452 : }
453 :
454 :
455 : /* do_trim -- trim spaces from string (multibyte)
456 : * usage: sz = trim(string); trim left and right
457 : * sz = trim(string, 0); trim left
458 : * sz = trim(string, 1); trim right */
459 : static awk_value_t *
460 : do_trim(int nargs, awk_value_t *result, struct awk_ext_func *unused)
461 : {
462 : int max = 2048;
463 : int f = 0;
464 : awk_value_t srcstr, srcnum;
465 : char *p, scpy[max];
466 : unsigned long tlen, lws;
467 : assert(result != NULL);
468 : if (do_lint && nargs > 2)
469 : lintwarn(ext_id,
470 : _("trim: called with too many arguments"));
471 :
472 : setlocale(LC_CTYPE, "ja_JP.Shift_JIS"); /* to use _mbsspn() on SJIS */
473 :
474 : switch (nargs){
475 : case 1:
476 : if (get_argument(0, AWK_STRING, &srcstr)) {
477 : tlen = srcstr.str_value.len;
478 : if (!tlen) goto NULSTR_RETURN;
479 :
480 : if (max > tlen) p = scpy; /* use array */
481 : else{
482 : p = (char *)malloc(tlen); /* use malloc */
483 : if (!p){ printf(M_ERR); exit(1); }
484 : f = 1;
485 : }
486 : /* do not overwrite srcstr */
487 : memcpy(p, srcstr.str_value.str, tlen); /* there is no '\0' */
488 : /* look for nonspaces char from end (right) */
489 : while (p){
490 : if(isspace(p[tlen - 1])){ /* isspace() <ctype.h> */
491 : --tlen;
492 : /* multibyte spaces(Shift_JIS Zenkaku Space) */
493 : }else if((0xffffff81 == p[tlen - 2])
494 : && (0x40 == p[tlen - 1])){
495 : tlen -= 2;
496 : }else break;
497 : }
498 : if (!tlen) goto NULSTR_RETURN; /* spaces only */
499 :
500 : /* spaces multibyte-span from beginning (left) */
501 : lws = _mbsspn(p, " \n\r\t\v");
502 : memmove(p, p + lws, tlen -= lws);
503 : make_const_string(p, tlen, result);
504 : if (f) free(p);
505 : }
506 : else{
507 : goto NULSTR_RETURN;
508 : }
509 : break;
510 : case 2:
511 : if (get_argument(0, AWK_STRING, &srcstr) &&
512 : get_argument(1, AWK_NUMBER, &srcnum)) {
513 : tlen = srcstr.str_value.len;
514 :
515 : if (!tlen) goto NULSTR_RETURN;
516 :
517 : if (max > tlen) p = scpy; /* use array */
518 : else{
519 : p = (char *)malloc(tlen); /* use malloc */
520 : if (!p){ printf(M_ERR); exit(1); }
521 : f = 1;
522 : }
523 :
524 : memcpy(p, srcstr.str_value.str, tlen); /* there is no '\0' */
525 :
526 : if (srcnum.num_value){
527 : while (p){
528 : if(isspace(p[tlen - 1])){ /* isspace() <ctype.h> */
529 : --tlen;
530 : /* multibyte spaces(Shift_JIS Zenkaku Space) */
531 : }else if((0xffffff81 == p[tlen - 2])
532 : && (0x40 == p[tlen - 1])){
533 : tlen -= 2;
534 : }else break;
535 : }
536 : make_const_string(p, tlen, result);
537 : }
538 : else{
539 : /* spaces multibyte-span from beginning (left) */
540 : lws = _mbsspn(p, " \n\r\t\v");
541 : memmove(p, p + lws, tlen -= lws);
542 : make_const_string(p, tlen, result);
543 : }
544 : if (f) free(p);
545 : }
546 : else{
547 : goto NULSTR_RETURN;
548 : }
549 : break;
550 : default:
551 : if (do_lint) {
552 : if (nargs == 0)
553 : lintwarn(ext_id,
554 : _("trim: called with no arguments"));
555 : else
556 : lintwarn(ext_id,
557 : _("trim: called with inappropriate argument(s)"));
558 : }
559 : NULSTR_RETURN:
560 : make_const_string("", 0, result);
561 : break;
562 : }
563 : return result;
564 : }
565 :
566 :
567 : /* register functions version 2.0 (GAWK4.2.1 for win32) */
568 : static awk_ext_func_t func_table[] = {
569 : /* callname, function, nargs, at-least-nargs,, */
570 : { "lengthb", do_lengthb, 1, 1, awk_false, NULL },
571 : { "substrb", do_substrb, 3, 2, awk_false, NULL },
572 : { "writef", do_writef, 3, 1, awk_false, NULL },
573 : { "swritef", do_swritef, 3, 2, awk_false, NULL },
574 : { "write", do_write, 1, 1, awk_false,NULL },
575 : { "trim", do_trim, 2, 1, awk_false,NULL }
576 : };
577 :
578 :
579 : /* define the dl_load function using the boilerplate macro
580 : * write befor BEGIN section like '@load "win_sjis2";' */
581 : dl_load_func(func_table, win_sjis2, "")