Blame src/control/ctlparse.c

Packit Service db8eaa
/**
Packit Service db8eaa
 * \file control/control.c
Packit Service db8eaa
 * \brief CTL interface - parse ASCII identifiers and values
Packit Service db8eaa
 * \author Jaroslav Kysela <perex@perex.cz>
Packit Service db8eaa
 * \date 2010
Packit Service db8eaa
 */
Packit Service db8eaa
/*
Packit Service db8eaa
 *  Control Interface - ASCII parser
Packit Service db8eaa
 *  Copyright (c) 2010 by Jaroslav Kysela <perex@perex.cz>
Packit Service db8eaa
 *
Packit Service db8eaa
 *
Packit Service db8eaa
 *   This library is free software; you can redistribute it and/or modify
Packit Service db8eaa
 *   it under the terms of the GNU Lesser General Public License as
Packit Service db8eaa
 *   published by the Free Software Foundation; either version 2.1 of
Packit Service db8eaa
 *   the License, or (at your option) any later version.
Packit Service db8eaa
 *
Packit Service db8eaa
 *   This program is distributed in the hope that it will be useful,
Packit Service db8eaa
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service db8eaa
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service db8eaa
 *   GNU Lesser General Public License for more details.
Packit Service db8eaa
 *
Packit Service db8eaa
 *   You should have received a copy of the GNU Lesser General Public
Packit Service db8eaa
 *   License along with this library; if not, write to the Free Software
Packit Service db8eaa
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit Service db8eaa
 *
Packit Service db8eaa
 */
Packit Service db8eaa
Packit Service db8eaa
#include <unistd.h>
Packit Service db8eaa
#include <string.h>
Packit Service db8eaa
#include <ctype.h>
Packit Service db8eaa
#include <math.h>
Packit Service db8eaa
#include "control_local.h"
Packit Service db8eaa
Packit Service db8eaa
/* Function to convert from percentage to volume. val = percentage */
Packit Service db8eaa
Packit Service db8eaa
static inline long int convert_prange1(long perc, long min, long max)
Packit Service db8eaa
{
Packit Service db8eaa
	long tmp;
Packit Service db8eaa
Packit Service db8eaa
#ifdef HAVE_SOFT_FLOAT
Packit Service db8eaa
	tmp = perc * (max - min);
Packit Service db8eaa
	tmp = tmp / 100 + ((tmp % 100) < 50 ? 0 : 1);
Packit Service db8eaa
#else
Packit Service db8eaa
	tmp = rint((double)perc * (double)(max - min) * 0.01);
Packit Service db8eaa
#endif
Packit Service db8eaa
	if (tmp == 0 && perc > 0)
Packit Service db8eaa
		tmp++;
Packit Service db8eaa
	return tmp + min;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
#define check_range(val, min, max) \
Packit Service db8eaa
	((val < min) ? (min) : ((val > max) ? (max) : (val)))
Packit Service db8eaa
Packit Service db8eaa
static long get_integer(const char **ptr, long min, long max)
Packit Service db8eaa
{
Packit Service db8eaa
	long val = min;
Packit Service db8eaa
	char *p = (char *)*ptr, *s;
Packit Service db8eaa
Packit Service db8eaa
	if (*p == ':')
Packit Service db8eaa
		p++;
Packit Service db8eaa
	if (*p == '\0' || (!isdigit(*p) && *p != '-'))
Packit Service db8eaa
		goto out;
Packit Service db8eaa
Packit Service db8eaa
	s = p;
Packit Service db8eaa
	val = strtol(s, &p, 0);
Packit Service db8eaa
	if (*p == '.') {
Packit Service db8eaa
		p++;
Packit Service db8eaa
		(void)strtol(p, &p, 10);
Packit Service db8eaa
	}
Packit Service db8eaa
	if (*p == '%') {
Packit Service db8eaa
		val = (long)convert_prange1(strtod(s, NULL), min, max);
Packit Service db8eaa
		p++;
Packit Service db8eaa
	}
Packit Service db8eaa
	val = check_range(val, min, max);
Packit Service db8eaa
	if (*p == ',')
Packit Service db8eaa
		p++;
Packit Service db8eaa
 out:
Packit Service db8eaa
	*ptr = p;
Packit Service db8eaa
	return val;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static long long get_integer64(const char **ptr, long long min, long long max)
Packit Service db8eaa
{
Packit Service db8eaa
	long long val = min;
Packit Service db8eaa
	char *p = (char *)*ptr, *s;
Packit Service db8eaa
Packit Service db8eaa
	if (*p == ':')
Packit Service db8eaa
		p++;
Packit Service db8eaa
	if (*p == '\0' || (!isdigit(*p) && *p != '-'))
Packit Service db8eaa
		goto out;
Packit Service db8eaa
Packit Service db8eaa
	s = p;
Packit Service db8eaa
	val = strtol(s, &p, 0);
Packit Service db8eaa
	if (*p == '.') {
Packit Service db8eaa
		p++;
Packit Service db8eaa
		(void)strtol(p, &p, 10);
Packit Service db8eaa
	}
Packit Service db8eaa
	if (*p == '%') {
Packit Service db8eaa
		val = (long long)convert_prange1(strtod(s, NULL), min, max);
Packit Service db8eaa
		p++;
Packit Service db8eaa
	}
Packit Service db8eaa
	val = check_range(val, min, max);
Packit Service db8eaa
	if (*p == ',')
Packit Service db8eaa
		p++;
Packit Service db8eaa
 out:
Packit Service db8eaa
	*ptr = p;
Packit Service db8eaa
	return val;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief return ASCII CTL element identifier name
Packit Service db8eaa
 * \param id CTL identifier
Packit Service db8eaa
 * \return ascii identifier of CTL element
Packit Service db8eaa
 *
Packit Service db8eaa
 * The string is allocated using strdup().
Packit Service db8eaa
 */
Packit Service db8eaa
char *snd_ctl_ascii_elem_id_get(snd_ctl_elem_id_t *id)
Packit Service db8eaa
{
Packit Service db8eaa
	unsigned int index, device, subdevice;
Packit Service db8eaa
	char buf[256], buf1[32];
Packit Service db8eaa
Packit Service db8eaa
	snprintf(buf, sizeof(buf), "numid=%u,iface=%s,name='%s'",
Packit Service db8eaa
				snd_ctl_elem_id_get_numid(id),
Packit Service db8eaa
				snd_ctl_elem_iface_name(
Packit Service db8eaa
					snd_ctl_elem_id_get_interface(id)),
Packit Service db8eaa
				snd_ctl_elem_id_get_name(id));
Packit Service db8eaa
	buf[sizeof(buf)-1] = '\0';
Packit Service db8eaa
	index = snd_ctl_elem_id_get_index(id);
Packit Service db8eaa
	device = snd_ctl_elem_id_get_device(id);
Packit Service db8eaa
	subdevice = snd_ctl_elem_id_get_subdevice(id);
Packit Service db8eaa
	if (index) {
Packit Service db8eaa
		snprintf(buf1, sizeof(buf1), ",index=%u", index);
Packit Service db8eaa
		if (strlen(buf) + strlen(buf1) < sizeof(buf))
Packit Service db8eaa
			strcat(buf, buf1);
Packit Service db8eaa
	}
Packit Service db8eaa
	if (device) {
Packit Service db8eaa
		snprintf(buf1, sizeof(buf1), ",device=%u", device);
Packit Service db8eaa
		if (strlen(buf) + strlen(buf1) < sizeof(buf))
Packit Service db8eaa
			strcat(buf, buf1);
Packit Service db8eaa
	}
Packit Service db8eaa
	if (subdevice) {
Packit Service db8eaa
		snprintf(buf1, sizeof(buf1), ",subdevice=%u", subdevice);
Packit Service db8eaa
		if (strlen(buf) + strlen(buf1) < sizeof(buf))
Packit Service db8eaa
			strcat(buf, buf1);
Packit Service db8eaa
	}
Packit Service db8eaa
	return strdup(buf);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
#ifndef DOC_HIDDEN
Packit Service db8eaa
/* used by UCM parser, too */
Packit Service db8eaa
int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str,
Packit Service db8eaa
				  const char **ret_ptr)
Packit Service db8eaa
{
Packit Service db8eaa
	int c, size, numid;
Packit Service db8eaa
	int err = -EINVAL;
Packit Service db8eaa
	char *ptr;
Packit Service db8eaa
Packit Service db8eaa
	while (isspace(*str))
Packit Service db8eaa
		str++;
Packit Service db8eaa
	if (!(*str))
Packit Service db8eaa
		goto out;
Packit Service db8eaa
	snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER);	/* default */
Packit Service db8eaa
	while (*str) {
Packit Service db8eaa
		if (!strncasecmp(str, "numid=", 6)) {
Packit Service db8eaa
			str += 6;
Packit Service db8eaa
			numid = atoi(str);
Packit Service db8eaa
			if (numid <= 0) {
Packit Service db8eaa
				fprintf(stderr, "amixer: Invalid numid %d\n", numid);
Packit Service db8eaa
				goto out;
Packit Service db8eaa
			}
Packit Service db8eaa
			snd_ctl_elem_id_set_numid(dst, atoi(str));
Packit Service db8eaa
			while (isdigit(*str))
Packit Service db8eaa
				str++;
Packit Service db8eaa
		} else if (!strncasecmp(str, "iface=", 6)) {
Packit Service db8eaa
			str += 6;
Packit Service db8eaa
			if (!strncasecmp(str, "card", 4)) {
Packit Service db8eaa
				snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_CARD);
Packit Service db8eaa
				str += 4;
Packit Service db8eaa
			} else if (!strncasecmp(str, "mixer", 5)) {
Packit Service db8eaa
				snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER);
Packit Service db8eaa
				str += 5;
Packit Service db8eaa
			} else if (!strncasecmp(str, "pcm", 3)) {
Packit Service db8eaa
				snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_PCM);
Packit Service db8eaa
				str += 3;
Packit Service db8eaa
			} else if (!strncasecmp(str, "rawmidi", 7)) {
Packit Service db8eaa
				snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_RAWMIDI);
Packit Service db8eaa
				str += 7;
Packit Service db8eaa
			} else if (!strncasecmp(str, "timer", 5)) {
Packit Service db8eaa
				snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_TIMER);
Packit Service db8eaa
				str += 5;
Packit Service db8eaa
			} else if (!strncasecmp(str, "sequencer", 9)) {
Packit Service db8eaa
				snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_SEQUENCER);
Packit Service db8eaa
				str += 9;
Packit Service db8eaa
			} else {
Packit Service db8eaa
				goto out;
Packit Service db8eaa
			}
Packit Service db8eaa
		} else if (!strncasecmp(str, "name=", 5)) {
Packit Service db8eaa
			char buf[64];
Packit Service db8eaa
			str += 5;
Packit Service db8eaa
			ptr = buf;
Packit Service db8eaa
			size = 0;
Packit Service db8eaa
			if (*str == '\'' || *str == '\"') {
Packit Service db8eaa
				c = *str++;
Packit Service db8eaa
				while (*str && *str != c) {
Packit Service db8eaa
					if (size < (int)sizeof(buf)) {
Packit Service db8eaa
						*ptr++ = *str;
Packit Service db8eaa
						size++;
Packit Service db8eaa
					}
Packit Service db8eaa
					str++;
Packit Service db8eaa
				}
Packit Service db8eaa
				if (*str == c)
Packit Service db8eaa
					str++;
Packit Service db8eaa
			} else {
Packit Service db8eaa
				while (*str && *str != ',') {
Packit Service db8eaa
					if (size < (int)sizeof(buf)) {
Packit Service db8eaa
						*ptr++ = *str;
Packit Service db8eaa
						size++;
Packit Service db8eaa
					}
Packit Service db8eaa
					str++;
Packit Service db8eaa
				}
Packit Service db8eaa
			}
Packit Service db8eaa
			*ptr = '\0';
Packit Service db8eaa
			snd_ctl_elem_id_set_name(dst, buf);
Packit Service db8eaa
		} else if (!strncasecmp(str, "index=", 6)) {
Packit Service db8eaa
			str += 6;
Packit Service db8eaa
			snd_ctl_elem_id_set_index(dst, atoi(str));
Packit Service db8eaa
			while (isdigit(*str))
Packit Service db8eaa
				str++;
Packit Service db8eaa
		} else if (!strncasecmp(str, "device=", 7)) {
Packit Service db8eaa
			str += 7;
Packit Service db8eaa
			snd_ctl_elem_id_set_device(dst, atoi(str));
Packit Service db8eaa
			while (isdigit(*str))
Packit Service db8eaa
				str++;
Packit Service db8eaa
		} else if (!strncasecmp(str, "subdevice=", 10)) {
Packit Service db8eaa
			str += 10;
Packit Service db8eaa
			snd_ctl_elem_id_set_subdevice(dst, atoi(str));
Packit Service db8eaa
			while (isdigit(*str))
Packit Service db8eaa
				str++;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (*str == ',') {
Packit Service db8eaa
			str++;
Packit Service db8eaa
		} else {
Packit Service db8eaa
			/* when ret_ptr is given, allow to terminate gracefully
Packit Service db8eaa
			 * at the next space letter
Packit Service db8eaa
			 */
Packit Service db8eaa
			if (ret_ptr && isspace(*str))
Packit Service db8eaa
				break;
Packit Service db8eaa
			if (*str)
Packit Service db8eaa
				goto out;
Packit Service db8eaa
		}
Packit Service db8eaa
	}			
Packit Service db8eaa
	err = 0;
Packit Service db8eaa
Packit Service db8eaa
 out:
Packit Service db8eaa
	if (ret_ptr)
Packit Service db8eaa
		*ret_ptr = str;
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
#endif
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief parse ASCII string as CTL element identifier
Packit Service db8eaa
 * \param dst destination CTL identifier
Packit Service db8eaa
 * \param str source ASCII string
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str)
Packit Service db8eaa
{
Packit Service db8eaa
	return __snd_ctl_ascii_elem_id_parse(dst, str, NULL);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int get_ctl_enum_item_index(snd_ctl_t *handle,
Packit Service db8eaa
				   snd_ctl_elem_info_t *info,
Packit Service db8eaa
				   const char **ptrp)
Packit Service db8eaa
{ 
Packit Service db8eaa
	char *ptr = (char *)*ptrp;
Packit Service db8eaa
	int items, i, len;
Packit Service db8eaa
	const char *name;
Packit Service db8eaa
	char end;
Packit Service db8eaa
  
Packit Service db8eaa
	items = snd_ctl_elem_info_get_items(info);
Packit Service db8eaa
	if (items <= 0)
Packit Service db8eaa
		return -1;
Packit Service db8eaa
Packit Service db8eaa
	end = *ptr;
Packit Service db8eaa
	if (end == '\'' || end == '"')
Packit Service db8eaa
		ptr++;
Packit Service db8eaa
	else
Packit Service db8eaa
		end = '\0';
Packit Service db8eaa
Packit Service db8eaa
	for (i = 0; i < items; i++) {
Packit Service db8eaa
		snd_ctl_elem_info_set_item(info, i);
Packit Service db8eaa
		if (snd_ctl_elem_info(handle, info) < 0)
Packit Service db8eaa
			return -1;
Packit Service db8eaa
		name = snd_ctl_elem_info_get_item_name(info);
Packit Service db8eaa
		len = strlen(name);
Packit Service db8eaa
		if (strncmp(name, ptr, len))
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if (end == '\0' && (ptr[len] == '\0' || ptr[len] == ',' || ptr[len] == '\n')) {
Packit Service db8eaa
			*ptrp = ptr + len;
Packit Service db8eaa
			return i;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (end != '\0' && ptr[len] == end) {
Packit Service db8eaa
			*ptrp = ptr + len + 1;
Packit Service db8eaa
			return i;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	return -1;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static unsigned int get_ctl_type_max_elements(snd_ctl_elem_type_t type)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_ctl_elem_value value;
Packit Service db8eaa
Packit Service db8eaa
	switch (type) {
Packit Service db8eaa
	case SND_CTL_ELEM_TYPE_BOOLEAN:
Packit Service db8eaa
	case SND_CTL_ELEM_TYPE_INTEGER:
Packit Service db8eaa
		return ARRAY_SIZE(value.value.integer.value);
Packit Service db8eaa
	case SND_CTL_ELEM_TYPE_INTEGER64:
Packit Service db8eaa
		return ARRAY_SIZE(value.value.integer64.value);
Packit Service db8eaa
	case SND_CTL_ELEM_TYPE_ENUMERATED:
Packit Service db8eaa
		return ARRAY_SIZE(value.value.enumerated.item);
Packit Service db8eaa
	case SND_CTL_ELEM_TYPE_BYTES:
Packit Service db8eaa
		return ARRAY_SIZE(value.value.bytes.data);
Packit Service db8eaa
	default:
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief parse ASCII string as CTL element value
Packit Service db8eaa
 * \param handle CTL handle
Packit Service db8eaa
 * \param dst destination CTL element value
Packit Service db8eaa
 * \param info CTL element info structure
Packit Service db8eaa
 * \param value source ASCII string
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 *
Packit Service db8eaa
 * Note: For toggle command, the dst must contain previous (current)
Packit Service db8eaa
 * state (do the #snd_ctl_elem_read call to obtain it).
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_ctl_ascii_value_parse(snd_ctl_t *handle,
Packit Service db8eaa
			      snd_ctl_elem_value_t *dst,
Packit Service db8eaa
			      snd_ctl_elem_info_t *info,
Packit Service db8eaa
			      const char *value)
Packit Service db8eaa
{
Packit Service db8eaa
	const char *ptr = value;
Packit Service db8eaa
	snd_ctl_elem_id_t myid = {0};
Packit Service db8eaa
	snd_ctl_elem_type_t type;
Packit Service db8eaa
	unsigned int idx, count;
Packit Service db8eaa
	long tmp;
Packit Service db8eaa
	long long tmp64;
Packit Service db8eaa
Packit Service db8eaa
	snd_ctl_elem_info_get_id(info, &myid);
Packit Service db8eaa
	type = snd_ctl_elem_info_get_type(info);
Packit Service db8eaa
	count = snd_ctl_elem_info_get_count(info);
Packit Service db8eaa
	snd_ctl_elem_value_set_id(dst, &myid);
Packit Service db8eaa
Packit Service db8eaa
	if (count > get_ctl_type_max_elements(type))
Packit Service db8eaa
		count = get_ctl_type_max_elements(type);
Packit Service db8eaa
	
Packit Service db8eaa
	for (idx = 0; idx < count && ptr && *ptr; idx++) {
Packit Service db8eaa
		if (*ptr == ',')
Packit Service db8eaa
			goto skip;
Packit Service db8eaa
		switch (type) {
Packit Service db8eaa
		case SND_CTL_ELEM_TYPE_BOOLEAN:
Packit Service db8eaa
			tmp = 0;
Packit Service db8eaa
			if (!strncasecmp(ptr, "on", 2) ||
Packit Service db8eaa
			    !strncasecmp(ptr, "up", 2)) {
Packit Service db8eaa
				tmp = 1;
Packit Service db8eaa
				ptr += 2;
Packit Service db8eaa
			} else if (!strncasecmp(ptr, "yes", 3)) {
Packit Service db8eaa
				tmp = 1;
Packit Service db8eaa
				ptr += 3;
Packit Service db8eaa
			} else if (!strncasecmp(ptr, "toggle", 6)) {
Packit Service db8eaa
				tmp = snd_ctl_elem_value_get_boolean(dst, idx);
Packit Service db8eaa
				tmp = tmp > 0 ? 0 : 1;
Packit Service db8eaa
				ptr += 6;
Packit Service db8eaa
			} else if (isdigit(*ptr)) {
Packit Service db8eaa
				tmp = atoi(ptr) > 0 ? 1 : 0;
Packit Service db8eaa
				while (isdigit(*ptr))
Packit Service db8eaa
					ptr++;
Packit Service db8eaa
			} else {
Packit Service db8eaa
				while (*ptr && *ptr != ',')
Packit Service db8eaa
					ptr++;
Packit Service db8eaa
			}
Packit Service db8eaa
			snd_ctl_elem_value_set_boolean(dst, idx, tmp);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SND_CTL_ELEM_TYPE_INTEGER:
Packit Service db8eaa
			tmp = get_integer(&ptr,
Packit Service db8eaa
					  snd_ctl_elem_info_get_min(info),
Packit Service db8eaa
					  snd_ctl_elem_info_get_max(info));
Packit Service db8eaa
			snd_ctl_elem_value_set_integer(dst, idx, tmp);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SND_CTL_ELEM_TYPE_INTEGER64:
Packit Service db8eaa
			tmp64 = get_integer64(&ptr,
Packit Service db8eaa
					  snd_ctl_elem_info_get_min64(info),
Packit Service db8eaa
					  snd_ctl_elem_info_get_max64(info));
Packit Service db8eaa
			snd_ctl_elem_value_set_integer64(dst, idx, tmp64);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SND_CTL_ELEM_TYPE_ENUMERATED:
Packit Service db8eaa
			tmp = get_ctl_enum_item_index(handle, info, &ptr);
Packit Service db8eaa
			if (tmp < 0)
Packit Service db8eaa
				tmp = get_integer(&ptr, 0,
Packit Service db8eaa
					snd_ctl_elem_info_get_items(info) - 1);
Packit Service db8eaa
			snd_ctl_elem_value_set_enumerated(dst, idx, tmp);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SND_CTL_ELEM_TYPE_BYTES:
Packit Service db8eaa
			tmp = get_integer(&ptr, 0, 255);
Packit Service db8eaa
			snd_ctl_elem_value_set_byte(dst, idx, tmp);
Packit Service db8eaa
			break;
Packit Service db8eaa
		default:
Packit Service db8eaa
			break;
Packit Service db8eaa
		}
Packit Service db8eaa
	skip:
Packit Service db8eaa
		if (!strchr(value, ','))
Packit Service db8eaa
			ptr = value;
Packit Service db8eaa
		else if (*ptr == ',')
Packit Service db8eaa
			ptr++;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}