3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2010 Angel Ortega <angel@triptico.com>
6 mpdm_s.c - String management
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 http://www.triptico.com
36 #ifdef CONFOPT_GETTEXT
49 void *mpdm_poke_o(void *dst
, int *dsize
, int *offset
, const void *org
,
52 if (org
!= NULL
&& osize
) {
54 if (*offset
+ osize
> *dsize
) {
58 dst
= realloc(dst
, *dsize
* esize
);
61 memcpy((char *) dst
+ (*offset
* esize
), org
, osize
* esize
);
69 void *mpdm_poke(void *dst
, int *dsize
, const void *org
, int osize
,
71 /* pokes (adds) org into dst, which is a dynamic string, making it grow */
75 return mpdm_poke_o(dst
, dsize
, &offset
, org
, osize
, esize
);
79 wchar_t *mpdm_pokewsn(wchar_t * dst
, int *dsize
, const wchar_t * str
,
81 /* adds a wide string to dst using mpdm_poke() with size */
84 dst
= mpdm_poke(dst
, dsize
, str
, slen
, sizeof(wchar_t));
90 wchar_t *mpdm_pokews(wchar_t * dst
, int *dsize
, const wchar_t * str
)
91 /* adds a wide string to dst using mpdm_poke() */
94 dst
= mpdm_pokewsn(dst
, dsize
, str
, wcslen(str
));
100 wchar_t *mpdm_pokev(wchar_t * dst
, int *dsize
, const mpdm_t v
)
101 /* adds the string in v to dst using mpdm_poke() */
104 const wchar_t *ptr
= mpdm_string(v
);
107 dst
= mpdm_pokews(dst
, dsize
, ptr
);
115 wchar_t *mpdm_mbstowcs(const char *str
, int *s
, int l
)
116 /* converts an mbs to a wcs, but filling invalid chars
117 with question marks instead of just failing */
120 char tmp
[64]; /* really MB_CUR_MAX + 1 */
125 /* allow NULL values for s */
129 /* if there is a limit, duplicate and break the string */
137 /* try first a direct conversion with mbstowcs */
138 if ((*s
= mbstowcs(NULL
, cstr
, 0)) != -1) {
139 /* direct conversion is possible; do it */
140 if ((ptr
= malloc((*s
+ 1) * sizeof(wchar_t))) != NULL
) {
141 mbstowcs(ptr
, cstr
, *s
);
146 /* zero everything */
150 /* no more characters to process? */
151 if ((c
= cstr
[n
+ i
]) == '\0' && i
== 0)
158 if (mbstowcs(&wc
, tmp
, 1) == (size_t) - 1) {
159 /* can still be an incomplete multibyte char? */
160 if (c
!= '\0' && i
<= (int) MB_CUR_MAX
)
163 /* too many failing bytes; skip 1 byte */
169 /* skip used bytes and back again */
174 if ((ptr
= mpdm_poke(ptr
, s
, &wc
, 1, sizeof(wchar_t))) == NULL
)
178 /* null terminate and count one less */
180 ptr
= mpdm_poke(ptr
, s
, L
"", 1, sizeof(wchar_t));
185 /* free the duplicate */
193 char *mpdm_wcstombs(const wchar_t * str
, int *s
)
194 /* converts a wcs to an mbs, but filling invalid chars
195 with question marks instead of just failing */
198 char tmp
[64]; /* really MB_CUR_MAX + 1 */
201 /* allow NULL values for s */
205 /* try first a direct conversion with wcstombs */
206 if ((*s
= wcstombs(NULL
, str
, 0)) != -1) {
207 /* direct conversion is possible; do it and return */
208 if ((ptr
= malloc(*s
+ 1)) != NULL
) {
209 wcstombs(ptr
, str
, *s
);
216 /* invalid encoding? convert characters one by one */
220 if ((l
= wctomb(tmp
, *str
)) <= 0) {
221 /* if char couldn't be converted,
222 write a question mark instead */
223 l
= wctomb(tmp
, L
'?');
227 if ((ptr
= mpdm_poke(ptr
, s
, tmp
, l
, 1)) == NULL
)
233 /* null terminate and count one less */
235 ptr
= mpdm_poke(ptr
, s
, "", 1, 1);
243 mpdm_t
mpdm_new_wcs(int flags
, const wchar_t * str
, int size
, int cpy
)
244 /* creates a new string value from a wcs */
248 /* a size of -1 means 'calculate it' */
249 if (size
== -1 && str
!= NULL
)
254 /* free() on destruction */
258 if ((ptr
= malloc((size
+ 1) * sizeof(wchar_t))) == NULL
)
261 /* if no source, reset to zeroes; otherwise, copy */
263 memset(ptr
, '\0', size
* sizeof(wchar_t));
265 wcsncpy(ptr
, str
, size
);
270 ptr
= (wchar_t *) str
;
273 flags
|= MPDM_STRING
;
275 return mpdm_new(flags
, ptr
, size
);
279 mpdm_t
mpdm_new_mbstowcs(int flags
, const char *str
, int l
)
280 /* creates a new string value from an mbs */
285 if ((ptr
= mpdm_mbstowcs(str
, &size
, l
)) == NULL
)
289 flags
|= (MPDM_STRING
| MPDM_FREE
);
291 return mpdm_new(flags
, ptr
, size
);
295 mpdm_t
mpdm_new_wcstombs(int flags
, const wchar_t * str
)
296 /* creates a new mbs value from a wbs */
301 ptr
= mpdm_wcstombs(str
, &size
);
305 /* unset the string flag; mbs,s are not 'strings' */
306 flags
&= ~MPDM_STRING
;
308 return mpdm_new(flags
, ptr
, size
);
312 mpdm_t
mpdm_new_i(int ival
)
313 /* creates a new string value from an integer */
317 /* create a string value, but without the 'string' */
318 v
= mpdm_new(MPDM_STRING
| MPDM_FREE
, NULL
, 0);
319 return mpdm_set_ival(v
, ival
);
323 mpdm_t
mpdm_new_r(double rval
)
324 /* creates a new string value from a real number */
328 /* create a string value, but without the 'string' */
329 v
= mpdm_new(MPDM_STRING
| MPDM_FREE
, NULL
, 0);
330 return mpdm_set_rval(v
, rval
);
337 * mpdm_string2 - Returns a printable representation of a value (with buffer).
339 * @wtmp: the external buffer
341 * Returns a printable representation of a value. For strings, it's
342 * the value data itself; for any other type, a conversion to string
343 * is returned instead. If @v is not a string, the @wtmp buffer
344 * can be used as a placeholder for the string representation.
346 * The reference count value in @v is not touched.
349 wchar_t *mpdm_string2(const mpdm_t v
, wchar_t *wtmp
)
354 /* if it's NULL, return a constant */
358 /* if it's a string, return it */
359 if (v
->flags
& MPDM_STRING
) {
361 if (v
->data
== NULL
) {
364 /* string but no data? most probably a 'lazy' number */
365 if (v
->flags
& MPDM_RVAL
) {
366 char *prev_locale
= setlocale(LC_NUMERIC
, "C");
368 /* creates the visual representation */
369 snprintf(tmp
, sizeof(tmp
), "%lf", v
->rval
);
371 setlocale(LC_NUMERIC
, prev_locale
);
373 /* manually strip useless zeroes */
374 if (strchr(tmp
, '.') != NULL
) {
377 for (ptr
= tmp
+ strlen(tmp
) - 1; *ptr
== '0'; ptr
--);
379 /* if it's over the ., strip it also */
387 if (v
->flags
& MPDM_IVAL
) {
388 /* creates the visual representation */
389 snprintf(tmp
, sizeof(tmp
), "%d", v
->ival
);
392 v
->data
= (void *)mpdm_mbstowcs(tmp
, &v
->size
, -1);
395 ret
= (wchar_t *) v
->data
;
398 /* otherwise, return a visual representation */
399 snprintf(tmp
, sizeof(tmp
), "%p", v
);
400 mbstowcs(wtmp
, tmp
, sizeof(tmp
) * sizeof(wchar_t));
410 * mpdm_string - Returns a printable representation of a value.
413 * Returns a printable representation of a value. For strings, it's
414 * the value data itself; for any other type, a conversion to string
415 * is returned instead. This value should be used immediately, as it
416 * can be a pointer to a static buffer.
418 * The reference count value in @v is not touched.
421 wchar_t *mpdm_string(const mpdm_t v
)
423 static wchar_t tmp
[32];
425 return mpdm_string2(v
, tmp
);
430 * mpdm_cmp - Compares two values.
431 * @v1: the first value
432 * @v2: the second value
434 * Compares two values. If both has the MPDM_STRING flag set,
435 * a comparison using wcscoll() is returned; if both are arrays,
436 * the size is compared first and, if they have the same number
437 * elements, each one is compared; otherwise, a simple visual
438 * representation comparison is done.
441 int mpdm_cmp(const mpdm_t v1
, const mpdm_t v2
)
452 /* is any value NULL? */
459 if (MPDM_IS_ARRAY(v1
) && MPDM_IS_ARRAY(v2
)) {
460 /* compare first the sizes */
461 if ((r
= mpdm_size(v1
) - mpdm_size(v2
)) == 0) {
464 /* they have the same size;
465 compare each pair of elements */
466 for (n
= 0; n
< mpdm_size(v1
); n
++) {
467 if ((r
= mpdm_cmp(mpdm_aget(v1
, n
),
468 mpdm_aget(v2
, n
))) != 0)
476 r
= wcscoll(mpdm_string(v1
), mpdm_string2(v2
, tmp
));
487 * mpdm_cmp_s - Compares two values (string version).
488 * @v1: the first value
489 * @v2: the second value
491 * Compares two values. If both has the MPDM_STRING flag set,
492 * a comparison using wcscoll() is returned; if both are arrays,
493 * the size is compared first and, if they have the same number
494 * elements, each one is compared; otherwise, a simple visual
495 * representation comparison is done.
497 int mpdm_cmp_s(const mpdm_t v1
, const wchar_t * v2
)
499 return mpdm_cmp(v1
, MPDM_AS(v2
));
504 * mpdm_splice - Creates a new string value from another.
505 * @v: the original value
506 * @i: the value to be inserted
507 * @offset: offset where the substring is to be inserted
508 * @del: number of characters to delete
510 * Creates a new string value from @v, deleting @del chars at @offset
511 * and substituting them by @i. If @del is 0, no deletion is done.
512 * both @offset and @del can be negative; if this is the case, it's
513 * assumed as counting from the end of @v. If @v is NULL, @i will become
514 * the new string, and both @offset and @del will be ignored. If @v is
515 * not NULL and @i is, no insertion process is done (only deletion, if
518 * Returns a two element array, with the new string in the first
519 * element and the deleted string in the second (with a NULL value
523 mpdm_t
mpdm_splice(const mpdm_t v
, const mpdm_t i
, int offset
, int del
)
538 /* negative offsets start from the end */
540 offset
= os
+ 1 - offset
;
542 /* never add further the end */
546 /* negative del counts as 'characters left' */
548 del
= os
+ 1 - offset
+ del
;
550 /* something to delete? */
552 /* never delete further the end */
553 if (offset
+ del
> os
)
557 d
= MPDM_NS(((wchar_t *) v
->data
) + offset
, del
);
562 /* something to insert? */
565 /* new size and remainder */
569 n
= MPDM_NS(NULL
, ns
);
571 ptr
= (wchar_t *) n
->data
;
573 /* copy the beginning */
575 wcsncpy(ptr
, v
->data
, offset
);
579 /* copy the text to be inserted */
581 wcsncpy(ptr
, i
->data
, ins
);
585 /* copy the remaining */
588 wcsncpy(ptr
, ((wchar_t *) v
->data
) + r
, os
);
598 /* creates the output array */
614 * mpdm_strcat_sn - Concatenates two strings (string with size version).
615 * @s1: the first string
616 * @s2: the second string
617 * @size: the size of the second string
619 * Returns a new string formed by the concatenation of @s1 and @s2.
622 mpdm_t
mpdm_strcat_sn(const mpdm_t s1
, const wchar_t * s2
, int size
)
628 if (s1
== NULL
&& s2
== NULL
)
631 ptr
= mpdm_pokev(ptr
, &s
, s1
);
632 ptr
= mpdm_pokewsn(ptr
, &s
, s2
, size
);
634 ptr
= mpdm_poke(ptr
, &s
, L
"", 1, sizeof(wchar_t));
635 r
= MPDM_ENS(ptr
, s
- 1);
643 * mpdm_strcat_s - Concatenates two strings (string version).
644 * @s1: the first string
645 * @s2: the second string
647 * Returns a new string formed by the concatenation of @s1 and @s2.
650 mpdm_t
mpdm_strcat_s(const mpdm_t s1
, const wchar_t * s2
)
652 return mpdm_strcat_sn(s1
, s2
, s2
? wcslen(s2
) : 0);
657 * mpdm_strcat - Concatenates two strings.
658 * @s1: the first string
659 * @s2: the second string
661 * Returns a new string formed by the concatenation of @s1 and @s2.
664 mpdm_t
mpdm_strcat(const mpdm_t s1
, const mpdm_t s2
)
669 r
= mpdm_strcat_s(s1
, s2
? mpdm_string(s2
) : NULL
);
677 * mpdm_ival - Returns a value's data as an integer.
680 * Returns a value's data as an integer. If the value is a string,
681 * it's converted via sscanf and returned; non-string values have all
682 * an ival of 0. The converted integer is cached, so costly string
683 * conversions are only done once. Values created with the MPDM_IVAL
684 * flag set have its ival cached from the beginning.
688 int mpdm_ival(mpdm_t v
)
695 /* if there is no cached integer, calculate it */
696 if (!(v
->flags
& MPDM_IVAL
)) {
697 /* does it have an rval? */
698 if (v
->flags
& MPDM_RVAL
)
701 /* if it's a string, calculate it; other
702 values will have an ival of 0 */
703 if (v
->flags
& MPDM_STRING
) {
707 wcstombs(tmp
, (wchar_t *) v
->data
, sizeof(tmp
));
708 tmp
[sizeof(tmp
) - 1] = '\0';
710 /* workaround for mingw32: as it doesn't
711 correctly parse octal and hexadecimal
712 numbers, they are tried as special cases */
714 if (tmp
[1] == 'b' || tmp
[1] == 'B') {
719 while (*ptr
== '0' || *ptr
== '1') {
729 if (tmp
[1] == 'x' || tmp
[1] == 'X')
736 sscanf(tmp
, fmt
, &i
);
752 * mpdm_rval - Returns a value's data as a real number (double).
755 * Returns a value's data as a real number (double float). If the value
756 * is a string, it's converted via sscanf and returned; non-string values
757 * have all an rval of 0. The converted double is cached, so costly string
758 * conversions are only done once. Values created with the MPDM_RVAL
759 * flag set have its rval cached from the beginning.
763 double mpdm_rval(mpdm_t v
)
770 /* if there is no cached double, calculate it */
771 if (!(v
->flags
& MPDM_RVAL
)) {
772 /* does it have in ival? */
773 if (v
->flags
& MPDM_IVAL
)
774 r
= (double) v
->ival
;
776 /* if it's a string, calculate it; other
777 values will have an rval of 0.0 */
778 if (v
->flags
& MPDM_STRING
) {
782 wcstombs(tmp
, (wchar_t *) v
->data
, sizeof(tmp
));
783 tmp
[sizeof(tmp
) - 1] = '\0';
785 /* if the number starts with 0, it's
786 an octal or hexadecimal number; just
787 take the integer value and cast it */
788 if (tmp
[0] == '0' && tmp
[1] != '.')
789 r
= (double) mpdm_ival(v
);
791 /* set locale to C for non locale-dependent
792 floating point conversion */
793 prev_locale
= setlocale(LC_NUMERIC
, "C");
796 sscanf(tmp
, "%lf", &r
);
798 /* set previous locale */
799 setlocale(LC_NUMERIC
, prev_locale
);
816 * mpdm_gettext - Translates a string to the current language.
819 * Translates the @str string to the current language.
821 * This function can still be used even if there is no real gettext
822 * support() by manually filling the __I18N__ hash.
824 * If the string is found in the current table, the translation is
825 * returned; otherwise, the same @str value is returned.
829 mpdm_t
mpdm_gettext(const mpdm_t str
)
835 if ((i18n
= mpdm_hget_s(mpdm_root(), L
"__I18N__")) == NULL
)
836 i18n
= mpdm_hset_s(mpdm_root(), L
"__I18N__", MPDM_H(0));
840 /* try first the cache */
841 if ((v
= mpdm_hget(i18n
, str
)) == NULL
) {
842 #ifdef CONFOPT_GETTEXT
847 t
= mpdm_ref(MPDM_2MBS(str
->data
));
849 /* ask gettext for it */
850 s
= gettext((char *) t
->data
);
859 #else /* CONFOPT_GETTEXT */
863 #endif /* CONFOPT_GETTEXT */
865 /* store in the cache */
866 mpdm_hset(i18n
, str
, v
);
876 * mpdm_gettext_domain - Sets domain and data directory for translations.
877 * @dom: the domain (application name)
878 * @data: directory contaning the .mo files
880 * Sets the domain (application name) and translation data for translating
881 * strings that will be returned by mpdm_gettext().@data must point to a
882 * directory containing the .mo (compiled .po) files.
884 * If there is no gettext support, returns 0, or 1 otherwise.
888 int mpdm_gettext_domain(const mpdm_t dom
, const mpdm_t data
)
895 #ifdef CONFOPT_GETTEXT
900 /* convert both to mbs,s */
901 dm
= mpdm_ref(MPDM_2MBS(dom
->data
));
902 dt
= mpdm_ref(MPDM_2MBS(data
->data
));
904 /* bind and set domain */
905 bindtextdomain((char *) dm
->data
, (char *) dt
->data
);
906 textdomain((char *) dm
->data
);
908 mpdm_hset_s(mpdm_root(), L
"__I18N__", MPDM_H(0));
915 #endif /* CONFOPT_GETTEXT */
921 if ((v
= mpdm_hget_s(mpdm_root(), L
"ENV")) != NULL
&&
922 mpdm_hget_s(v
, L
"LANG") == NULL
) {
923 wchar_t *wptr
= L
"en";
925 /* MS Windows crappy language constants... */
927 switch ((GetSystemDefaultLangID() & 0x00ff)) {
933 break; /* bulgarian */
969 break; /* hungarian */
972 break; /* icelandic */
978 break; /* japanese */
987 break; /* norwegian */
993 break; /* portuguese */
996 break; /* romansh (switzerland) */
999 break; /* romanian */
1002 break; /* russian */
1005 break; /* serbian */
1011 break; /* albanian */
1014 break; /* swedish */
1017 mpdm_hset_s(v
, L
"LANG", MPDM_S(wptr
));
1020 #endif /* CONFOPT_WIN32 */
1029 #ifdef CONFOPT_WCWIDTH
1031 int wcwidth(wchar_t);
1033 int mpdm_wcwidth(wchar_t c
)
1038 #else /* CONFOPT_WCWIDTH */
1040 #include "wcwidth.c"
1042 int mpdm_wcwidth(wchar_t c
)
1044 return mk_wcwidth(c
);
1047 #endif /* CONFOPT_WCWIDTH */
1051 * mpdm_sprintf - Formats a sprintf()-like string.
1052 * @fmt: the string format
1053 * @args: an array of values
1055 * Formats a string using the sprintf() format taking the values from @args.
1058 mpdm_t
mpdm_sprintf(const mpdm_t fmt
, const mpdm_t args
)
1060 const wchar_t *i
= fmt
->data
;
1068 /* loop all characters */
1069 while ((c
= *i
++) != L
'\0') {
1071 wchar_t *tptr
= NULL
;
1072 wchar_t *wptr
= NULL
;
1075 /* format directive */
1081 /* transfer the % */
1084 /* transform the format to mbs */
1085 while (*i
!= L
'\0' &&
1086 m
< (int) (sizeof(t_fmt
) - MB_CUR_MAX
- 1) &&
1087 wcschr(L
"-.0123456789", *i
) != NULL
)
1088 m
+= wctomb(&t_fmt
[m
], *i
++);
1090 /* transfer the directive */
1091 m
+= wctomb(&t_fmt
[m
], *i
++);
1095 /* by default, copies the format */
1098 /* pick next value */
1099 v
= mpdm_aget(args
, n
++);
1101 switch (t_fmt
[m
- 1]) {
1110 snprintf(tmp
, sizeof(tmp
) - 1, t_fmt
, mpdm_ival(v
));
1115 /* float (real) value */
1116 snprintf(tmp
, sizeof(tmp
) - 1, t_fmt
, mpdm_rval(v
));
1122 ptr
= mpdm_wcstombs(mpdm_string(v
), NULL
);
1123 snprintf(tmp
, sizeof(tmp
) - 1, t_fmt
, ptr
);
1142 mask
= 1 << ((sizeof(int) * 8) - 1);
1144 if (mask
& (unsigned int) mpdm_ival(v
)) {
1171 wptr
= tptr
= mpdm_mbstowcs(tmp
, &m
, -1);
1180 o
= mpdm_poke(o
, &l
, wptr
, m
, sizeof(wchar_t));
1182 /* free the temporary buffer, if any */
1190 /* null-terminate */
1191 o
= mpdm_poke(o
, &l
, L
"", 1, sizeof(wchar_t));
1196 return MPDM_ENS(o
, l
- 1);
1201 * mpdm_ulc - Converts a string to uppercase or lowecase.
1203 * @u: convert to uppercase (1) or to lowercase (0).
1205 * Converts @s to uppercase (for @u == 1) or to lowercase (@u == 0).
1208 mpdm_t
mpdm_ulc(const mpdm_t s
, int u
)
1218 if ((optr
= malloc((i
+ 1) * sizeof(wchar_t))) != NULL
) {
1219 wchar_t *iptr
= mpdm_string(s
);
1222 for (n
= 0; n
< i
; n
++)
1223 optr
[n
] = u
? towupper(iptr
[n
]) : towlower(iptr
[n
]);
1226 r
= MPDM_ENS(optr
, i
);
1235 /* scanf working buffers */
1236 #define SCANF_BUF_SIZE 1024
1237 static wchar_t scanf_yset
[SCANF_BUF_SIZE
];
1238 static wchar_t scanf_nset
[SCANF_BUF_SIZE
];
1239 static wchar_t scanf_mark
[SCANF_BUF_SIZE
];
1246 { L
's', L
"", L
" \t"},
1247 { L
'u', L
"0123456789", L
""},
1248 { L
'd', L
"-0123456789", L
""},
1249 { L
'i', L
"-0123456789", L
""},
1250 { L
'f', L
"-0123456789.", L
""},
1251 { L
'x', L
"-0123456789xabcdefABCDEF", L
""},
1252 { L
'\0', NULL
, NULL
},
1256 * mpdm_sscanf - Extracts data like sscanf().
1257 * @str: the string to be parsed
1258 * @fmt: the string format
1259 * @offset: the character offset to start scanning
1261 * Extracts data from a string using a special format pattern, very
1262 * much like the scanf() series of functions in the C library. Apart
1263 * from the standard percent-sign-commands (s, u, d, i, f, x,
1264 * n, [, with optional size and * to ignore), it implements S,
1265 * to match a string of characters upto what follows in the format
1266 * string. Also, the [ set of characters can include other % formats.
1268 * Returns an array with the extracted values. If %n is used, the
1269 * position in the scanned string is returned as the value.
1272 mpdm_t
mpdm_sscanf(const mpdm_t str
, const mpdm_t fmt
, int offset
)
1274 wchar_t *i
= (wchar_t *) str
->data
;
1275 wchar_t *f
= (wchar_t *) fmt
->data
;
1287 wchar_t *ptr
= NULL
;
1294 /* empty all buffers */
1295 scanf_yset
[0] = scanf_nset
[0] = scanf_mark
[0] = L
'\0';
1299 /* an asterisk? don't return next value */
1305 /* does it have a size? */
1306 while (wcschr(L
"0123456789", *f
)) {
1312 /* if no size, set it to an arbitrary big limit */
1316 /* now *f should contain a command */
1320 /* is it a verbatim percent sign? */
1324 wcscpy(scanf_yset
, L
"%");
1331 mpdm_push(r
, MPDM_I(i
- (wchar_t *) str
->data
));
1334 /* string upto a mark */
1338 /* fill the mark upto another command */
1343 /* is it an 'n'? ignore and go on */
1350 scanf_mark
[msize
++] = *tmp
;
1355 scanf_mark
[msize
++] = *tmp
;
1360 scanf_mark
[msize
] = L
'\0';
1366 wchar_t *set
= scanf_yset
;
1368 /* is it an inverse set? */
1374 /* first one is a ]? add it */
1380 /* now build the set */
1381 for (; n
< SCANF_BUF_SIZE
- 1 && *f
&& *f
!= L
']'; f
++) {
1382 /* is it a range? */
1386 /* start or end? hyphen itself */
1387 if (n
== 0 || *f
== L
']')
1390 /* pick previous char */
1391 wchar_t c
= set
[n
- 1];
1394 while (n
< SCANF_BUF_SIZE
- 1 && c
< *f
)
1399 /* is it another command? */
1404 for (i
= 0; scanf_sets
[i
].cmd
; i
++) {
1405 if (*f
== scanf_sets
[i
].cmd
) {
1407 wcscat(set
, scanf_sets
[i
].yset
);
1408 n
+= wcslen(scanf_sets
[i
].yset
);
1423 /* a standard set? */
1427 for (n
= 0; scanf_sets
[n
].cmd
!= L
'\0'; n
++) {
1428 if (cmd
== scanf_sets
[n
].cmd
) {
1429 wcscpy(scanf_yset
, scanf_sets
[n
].yset
);
1430 wcscpy(scanf_nset
, scanf_sets
[n
].nset
);
1436 /* now fill the dynamic string */
1438 !wcschr(scanf_nset
, *i
) &&
1439 (scanf_yset
[0] == L
'\0' || wcschr(scanf_yset
, *i
)) &&
1440 (msize
== 0 || wcsncmp(i
, scanf_mark
, msize
) != 0)) {
1442 /* only add if not being ignored */
1444 ptr
= mpdm_poke(ptr
, &size
, i
, 1, sizeof(wchar_t));
1450 if (!ignore
&& size
) {
1451 /* null terminate and push */
1452 ptr
= mpdm_poke(ptr
, &size
, L
"", 1, sizeof(wchar_t));
1453 mpdm_push(r
, MPDM_ENS(ptr
, size
- 1));
1457 if (*f
== L
' ' || *f
== L
'\t') {
1458 /* if it's a blank, sync to next non-blank */
1461 while (*i
== L
' ' || *i
== L
'\t')
1465 /* test for literals in the format string */
1484 * mpdm_tr - Transliterates a string.
1486 * @s1: characters to be changed
1487 * @s2: characters to replace those in s1
1489 * Creates a copy of @str, which will have all characters in @s1
1490 * replaced by those in @s2 matching their position.
1492 mpdm_t
mpdm_tr(mpdm_t str
, mpdm_t s1
, mpdm_t s2
)
1504 /* create a copy of the string */
1505 r
= MPDM_NS((wchar_t *)str
->data
, mpdm_size(str
));
1508 ptr
= (wchar_t *)r
->data
;
1509 cs1
= (wchar_t *)s1
->data
;
1510 cs2
= (wchar_t *)s2
->data
;
1512 while ((c
= *ptr
) != L
'\0') {
1515 for (n
= 0; cs1
[n
] != '\0'; n
++) {