Tizen 2.1 base
[external/alsa-utils.git] / alsamixer / utils.c
1 /*
2  * utils.c - multibyte-string helpers
3  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #define _XOPEN_SOURCE
20 #include "aconfig.h"
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <wchar.h>
25 #include "utils.h"
26
27 /*
28  * mbs_at_width - compute screen position in a string
29  *
30  * For displaying strings on the screen, we have to know how many character
31  * cells are occupied.  This function calculates the position in a multibyte
32  * string that is at a desired position.
33  *
34  * Parameters:
35  * s:     the string
36  * width: on input, the desired number of character cells; on output, the actual
37  *        position, in character cells, of the return value
38  * dir:   -1 or 1; in which direction to round if a multi-column character goes
39  *        over the desired width
40  *
41  * Return value:
42  * Pointer to the place in the string that is as near the desired width as
43  * possible.  If the string is too short, the return value points to the
44  * terminating zero.  If the last character is a multi-column character that
45  * goes over the desired width, the return value may be one character cell
46  * earlier or later than desired, depending on the dir parameter.
47  * In any case, the return value points after any zero-width characters that
48  * follow the last character.
49  */
50 const char *mbs_at_width(const char *s, int *width, int dir)
51 {
52         size_t len;
53         wchar_t wc;
54         int bytes;
55         int width_so_far, w;
56
57         if (*width <= 0)
58                 return s;
59         mbtowc(NULL, NULL, 0); /* reset shift state */
60         len = strlen(s);
61         width_so_far = 0;
62         while (len && (bytes = mbtowc(&wc, s, len)) > 0) {
63                 w = wcwidth(wc);
64                 if (width_so_far + w > *width && dir < 0)
65                         break;
66                 if (w >= 0)
67                         width_so_far += w;
68                 s += bytes;
69                 len -= bytes;
70                 if (width_so_far >= *width) {
71                         while (len && (bytes = mbtowc(&wc, s, len)) > 0) {
72                                 w = wcwidth(wc);
73                                 if (w != 0)
74                                         break;
75                                 s += bytes;
76                                 len -= bytes;
77                         }
78                         break;
79                 }
80         }
81         *width = width_so_far;
82         return s;
83 }
84
85 /*
86  * get_mbs_width - compute screen width of a string
87  */
88 unsigned int get_mbs_width(const char *s)
89 {
90         int width;
91
92         width = INT_MAX;
93         mbs_at_width(s, &width, 1);
94         return width;
95 }
96
97 /*
98  * get_max_mbs_width - get width of longest string in an array
99  */
100 unsigned int get_max_mbs_width(const char *const *s, unsigned int count)
101 {
102         unsigned int max_width, i, len;
103
104         max_width = 0;
105         for (i = 0; i < count; ++i) {
106                 len = get_mbs_width(s[i]);
107                 if (len > max_width)
108                         max_width = len;
109         }
110         return max_width;
111 }