Blame alsamixer/utils.c

Packit Service a9274b
/*
Packit Service a9274b
 * utils.c - multibyte-string helpers
Packit Service a9274b
 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
Packit Service a9274b
 *
Packit Service a9274b
 * This program is free software: you can redistribute it and/or modify
Packit Service a9274b
 * it under the terms of the GNU General Public License as published by
Packit Service a9274b
 * the Free Software Foundation, either version 2 of the License, or
Packit Service a9274b
 * (at your option) any later version.
Packit Service a9274b
 *
Packit Service a9274b
 * This program is distributed in the hope that it will be useful,
Packit Service a9274b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a9274b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a9274b
 * GNU General Public License for more details.
Packit Service a9274b
 *
Packit Service a9274b
 * You should have received a copy of the GNU General Public License
Packit Service a9274b
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service a9274b
 */
Packit Service a9274b
Packit Service a9274b
#ifndef _XOPEN_SOURCE
Packit Service a9274b
#define _XOPEN_SOURCE
Packit Service a9274b
#endif
Packit Service a9274b
#include "aconfig.h"
Packit Service a9274b
#include <limits.h>
Packit Service a9274b
#include <stdlib.h>
Packit Service a9274b
#include <string.h>
Packit Service a9274b
#include <wchar.h>
Packit Service a9274b
#include <errno.h>
Packit Service a9274b
#include <stdio.h>
Packit Service a9274b
#include "utils.h"
Packit Service a9274b
#include "mem.h"
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * mbs_at_width - compute screen position in a string
Packit Service a9274b
 *
Packit Service a9274b
 * For displaying strings on the screen, we have to know how many character
Packit Service a9274b
 * cells are occupied.  This function calculates the position in a multibyte
Packit Service a9274b
 * string that is at a desired position.
Packit Service a9274b
 *
Packit Service a9274b
 * Parameters:
Packit Service a9274b
 * s:     the string
Packit Service a9274b
 * width: on input, the desired number of character cells; on output, the actual
Packit Service a9274b
 *        position, in character cells, of the return value
Packit Service a9274b
 * dir:   -1 or 1; in which direction to round if a multi-column character goes
Packit Service a9274b
 *        over the desired width
Packit Service a9274b
 *
Packit Service a9274b
 * Return value:
Packit Service a9274b
 * Pointer to the place in the string that is as near the desired width as
Packit Service a9274b
 * possible.  If the string is too short, the return value points to the
Packit Service a9274b
 * terminating zero.  If the last character is a multi-column character that
Packit Service a9274b
 * goes over the desired width, the return value may be one character cell
Packit Service a9274b
 * earlier or later than desired, depending on the dir parameter.
Packit Service a9274b
 * In any case, the return value points after any zero-width characters that
Packit Service a9274b
 * follow the last character.
Packit Service a9274b
 */
Packit Service a9274b
const char *mbs_at_width(const char *s, int *width, int dir)
Packit Service a9274b
{
Packit Service a9274b
	size_t len;
Packit Service a9274b
	wchar_t wc;
Packit Service a9274b
	int bytes;
Packit Service a9274b
	int width_so_far, w;
Packit Service a9274b
Packit Service a9274b
	if (*width <= 0)
Packit Service a9274b
		return s;
Packit Service a9274b
	mbtowc(NULL, NULL, 0); /* reset shift state */
Packit Service a9274b
	len = strlen(s);
Packit Service a9274b
	width_so_far = 0;
Packit Service a9274b
	while (len && (bytes = mbtowc(&wc, s, len)) > 0) {
Packit Service a9274b
		w = wcwidth(wc);
Packit Service a9274b
		if (width_so_far + w > *width && dir < 0)
Packit Service a9274b
			break;
Packit Service a9274b
		if (w >= 0)
Packit Service a9274b
			width_so_far += w;
Packit Service a9274b
		s += bytes;
Packit Service a9274b
		len -= bytes;
Packit Service a9274b
		if (width_so_far >= *width) {
Packit Service a9274b
			while (len && (bytes = mbtowc(&wc, s, len)) > 0) {
Packit Service a9274b
				w = wcwidth(wc);
Packit Service a9274b
				if (w != 0)
Packit Service a9274b
					break;
Packit Service a9274b
				s += bytes;
Packit Service a9274b
				len -= bytes;
Packit Service a9274b
			}
Packit Service a9274b
			break;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	*width = width_so_far;
Packit Service a9274b
	return s;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * get_mbs_width - compute screen width of a string
Packit Service a9274b
 */
Packit Service a9274b
unsigned int get_mbs_width(const char *s)
Packit Service a9274b
{
Packit Service a9274b
	int width;
Packit Service a9274b
Packit Service a9274b
	width = INT_MAX;
Packit Service a9274b
	mbs_at_width(s, &width, 1);
Packit Service a9274b
	return width;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * get_max_mbs_width - get width of longest string in an array
Packit Service a9274b
 */
Packit Service a9274b
unsigned int get_max_mbs_width(const char *const *s, unsigned int count)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int max_width, i, len;
Packit Service a9274b
Packit Service a9274b
	max_width = 0;
Packit Service a9274b
	for (i = 0; i < count; ++i) {
Packit Service a9274b
		len = get_mbs_width(s[i]);
Packit Service a9274b
		if (len > max_width)
Packit Service a9274b
			max_width = len;
Packit Service a9274b
	}
Packit Service a9274b
	return max_width;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
#define MAX_FILE_SIZE 1048576
Packit Service a9274b
char *read_file(const char *file_name, unsigned int *file_size)
Packit Service a9274b
{
Packit Service a9274b
	FILE *f;
Packit Service a9274b
	int err;
Packit Service a9274b
	char *buf;
Packit Service a9274b
	unsigned int allocated = 2048;
Packit Service a9274b
	unsigned int bytes_read;
Packit Service a9274b
Packit Service a9274b
	f = fopen(file_name, "r");
Packit Service a9274b
	if (!f) {
Packit Service a9274b
		err = errno;
Packit Service a9274b
		errno = err;
Packit Service a9274b
		return NULL;
Packit Service a9274b
	}
Packit Service a9274b
	*file_size = 0;
Packit Service a9274b
	buf = NULL;
Packit Service a9274b
	do {
Packit Service a9274b
		allocated *= 2;
Packit Service a9274b
		buf = crealloc(buf, allocated);
Packit Service a9274b
		bytes_read = fread(buf + *file_size, 1, allocated - *file_size, f);
Packit Service a9274b
		*file_size += bytes_read;
Packit Service a9274b
	} while (*file_size == allocated && allocated < MAX_FILE_SIZE);
Packit Service a9274b
	fclose(f);
Packit Service a9274b
	if (*file_size > 0 && buf[*file_size - 1] != '\n' && *file_size < allocated) {
Packit Service a9274b
		buf[*file_size] = '\n';
Packit Service a9274b
		++*file_size;
Packit Service a9274b
	}
Packit Service a9274b
	return buf;
Packit Service a9274b
}
Packit Service a9274b