static char *parse_meter(char *p,
				struct SYMBOL *s)
{
	int m1, m2, d, wmeasure, nm, in_parenth;
	unsigned i;
	char *q;
static char top_err[] = "Cannot identify meter top";

	if (*p == '\0')
		return "Empty meter string";
	nm = 0;
	in_parenth = 0;
	m1 = 0;
	if (strncmp(p, "none", 4) == 0) {
		p += 4;				/* no meter */
		wmeasure = 1;	/* simplify measure numbering and MREST conversion */
	} else {
	    wmeasure = 0;
	    while (*p != '\0') {
		if (*p == '=')
			break;
		if (nm >= MAX_MEASURE)
			return "Too many values in M:";
		switch (*p) {
		case 'C':
			s->u.meter.meter[nm].top[0] = *p++;
			if (*p == '|')
				s->u.meter.meter[nm].top[1] = *p++;
			m1 = 4;
			m2 = 4;
			break;
		case 'c':
		case 'o':
			if (*p == 'c')
				m1 = 4;
			else
				m1 = 3;
			m2 = 4;
			s->u.meter.meter[nm].top[0] = *p++;
			if (*p == '.')
				s->u.meter.meter[nm].top[1] = *p++;
			break;
		case '(':
			if (p[1] == '(') {	/* "M:5/4 ((2+3)/4)" */
				in_parenth = 1;
				s->u.meter.meter[nm++].top[0] = *p++;
			}
			q = p + 1;
			while (*q != '\0') {
				if (*q == ')' || *q == '/')
					break;
				q++;
			}
			if (*q == ')' && q[1] == '/') {	/* "M:5/4 (2+3)/4" */
				p++;		/* remove the parenthesis */
				continue;
			}			/* "M:5 (2+3)" */
			/* fall thru */
		case ')':
			in_parenth = *p == '(';
			s->u.meter.meter[nm++].top[0] = *p++;
			continue;
		default:
			if (sscanf(p, "%d", &m1) != 1
			 || m1 <= 0)
				return top_err;
			i = 0;
			m2 = 2;			/* default when no bottom value */
			for (;;) {
				while (isdigit((unsigned char) *p)
				    && i < sizeof s->u.meter.meter[0].top)
					s->u.meter.meter[nm].top[i++] = *p++;
				if (*p == ')') {
					if (p[1] != '/')
						break;
					p++;
				}
				if (*p == '/') {
					p++;
					if (sscanf(p, "%d", &m2) != 1
					 || m2 <= 0)
						return "Cannot identify meter bottom";
					i = 0;
					while (isdigit((unsigned char) *p)
					    && i < sizeof s->u.meter.meter[0].bot)
						s->u.meter.meter[nm].bot[i++] = *p++;
					break;
				}
				if (*p != ' ' && *p != '+')
					break;
				if (*p == '\0' || p[1] == '(')	/* "M:5 (2/4+3/4)" */
					break;
				if (i < sizeof s->u.meter.meter[0].top)
					s->u.meter.meter[nm].top[i++] = *p++;
				if (sscanf(p, "%d", &d) != 1
				 || d <= 0)
					return top_err;
				if (p[-1] == ' ') {
					if (d > m1)
						m1 = d;
				} else {
					m1 += d;
				}
			}
			break;
		}
		if (!in_parenth)
			wmeasure += m1 * BASE_LEN / m2;
		nm++;
		if (*p == ' ')
			p++;
		else if (*p == '+')
			s->u.meter.meter[nm++].top[0] = *p++;
	    }
	}
	meter = m1;
	if (*p == '=') {
		if (sscanf(++p, "%d/%d", &m1, &m2) != 2
		 || m1 <= 0
		 || m2 <= 0)
			return "Cannot identify meter explicit duration";
		wmeasure = m1 * BASE_LEN / m2;
		s->u.meter.expdur = 1;
	}
	s->u.meter.wmeasure = wmeasure;
	s->u.meter.nmeter = nm;

	/* in the tune header, change the unit note length */
	if (parse.abc_state == ABC_S_HEAD && ulen == 0) {
		if (wmeasure >= BASE_LEN * 3 / 4
		 || wmeasure <= 1)
			ulen = BASE_LEN / 8;
		else
			ulen = BASE_LEN / 16;
	}
	return 0;
}
static char *parse_meter(char *p,
				struct SYMBOL *s)
{
	int m1, m2, d, wmeasure, nm, in_parenth;
	unsigned i;
	char *q;
static char top_err[] = "Cannot identify meter top";

	if (*p == '\0')
		return "Empty meter string";
	nm = 0;
	in_parenth = 0;
	m1 = 0;
	if (strncmp(p, "none", 4) == 0) {
		p += 4;				 
		wmeasure = 1;	 
	} else {
	    wmeasure = 0;
	    while (*p != '\0') {
		if (*p == '=')
			break;
		if (nm >= MAX_MEASURE)
			return "Too many values in M:";
		switch (*p) {
		case 'C':
			s->u.meter.meter[nm].top[0] = *p++;
			if (*p == '|')
				s->u.meter.meter[nm].top[1] = *p++;
			m1 = 4;
			m2 = 4;
			break;
		case 'c':
		case 'o':
			if (*p == 'c')
				m1 = 4;
			else
				m1 = 3;
			m2 = 4;
			s->u.meter.meter[nm].top[0] = *p++;
			if (*p == '.')
				s->u.meter.meter[nm].top[1] = *p++;
			break;
		case '(':
			if (p[1] == '(') {	 
				in_parenth = 1;
				s->u.meter.meter[nm++].top[0] = *p++;
			}
			q = p + 1;
			while (*q != '\0') {
				if (*q == ')' || *q == '/')
					break;
				q++;
			}
			if (*q == ')' && q[1] == '/') {	 
				p++;		 
				continue;
			}			 
			 
		case ')':
			in_parenth = *p == '(';
			s->u.meter.meter[nm++].top[0] = *p++;
			continue;
		default:
			if (sscanf(p, "%d", &m1) != 1
			 || m1 <= 0)
				return top_err;
			i = 0;
			m2 = 2;			 
			for (;;) {
				while (isdigit((unsigned char) *p)
				    && i < sizeof s->u.meter.meter[0].top)
					s->u.meter.meter[nm].top[i++] = *p++;
				if (*p == ')') {
					if (p[1] != '/')
						break;
					p++;
				}
				if (*p == '/') {
					p++;
					if (sscanf(p, "%d", &m2) != 1
					 || m2 <= 0)
						return "Cannot identify meter bottom";
					i = 0;
					while (isdigit((unsigned char) *p)
					    && i < sizeof s->u.meter.meter[0].bot)
						s->u.meter.meter[nm].bot[i++] = *p++;
					break;
				}
				if (*p != ' ' && *p != '+')
					break;
				if (*p == '\0' || p[1] == '(')	 
					break;
				if (i < sizeof s->u.meter.meter[0].top)
					s->u.meter.meter[nm].top[i++] = *p++;
				if (sscanf(p, "%d", &d) != 1
				 || d <= 0)
					return top_err;
				if (p[-1] == ' ') {
					if (d > m1)
						m1 = d;
				} else {
					m1 += d;
				}
			}
			break;
		}
		if (!in_parenth)
			wmeasure += m1 * BASE_LEN / m2;
		nm++;
		if (*p == ' ')
			p++;
		else if (*p == '+')
			s->u.meter.meter[nm++].top[0] = *p++;
	    }
	}
	meter = m1;
	if (*p == '=') {
		if (sscanf(++p, "%d/%d", &m1, &m2) != 2
		 || m1 <= 0
		 || m2 <= 0)
			return "Cannot identify meter explicit duration";
		wmeasure = m1 * BASE_LEN / m2;
		s->u.meter.expdur = 1;
	}
	s->u.meter.wmeasure = wmeasure;
	s->u.meter.nmeter = nm;

	 
	if (parse.abc_state == ABC_S_HEAD && ulen == 0) {
		if (wmeasure >= BASE_LEN * 3 / 4
		 || wmeasure <= 1)
			ulen = BASE_LEN / 8;
		else
			ulen = BASE_LEN / 16;
	}
	return 0;
}