static void parse_key(char *p,
		      struct SYMBOL *s)
{
	int sf, empty, instr;
//	int mode;
	char *clef_name, *clef_middle, *clef_stlines, *clef_scale;
	char *p_octave, *p_cue, *p_map;

	// set important default values
//	s->u.key.stafflines = "|||||";
	s->u.key.octave = NO_OCTAVE;

	if (*p == '\0') {
		s->u.key.empty = 1;
		return;
	}
	sf = 0;
//	mode = 0;
	empty = 0;
	instr = 0;
	switch (*p++) {
	case 'F': sf = -1; break;
	case 'B': sf++;
	case 'E': sf++;
	case 'A': sf++;
	case 'D': sf++;
	case 'G': sf++;
	case 'C': break;
	case 'H':
		if (*p == 'P') {
			instr = K_HP;
			p++;
		} else if (*p == 'p') {
			instr = K_Hp;
			sf = 2;
			p++;
		} else {
			syntax("Unknown bagpipe-like key", p);
		}
		break;
	case 'P':
		instr = K_DRUM;
		p++;
		break;
	case 'n':
		if (strncmp(p, "one", 3) == 0) {	// none
			empty = 2;
			p += 3;
			while (isspace((unsigned char) *p))
				p++;
			if (*p == '\0') {
				s->u.key.empty = empty;
				return;
			}
			break;
		}
		// fall thru
	default:
		p--;
		empty = 1;
		break;
	}
	s->u.key.empty = empty;

	if (!empty) {
		if (*p == '#') {
			sf += 7;
			p++;
		} else if (*p == 'b') {
			sf -= 7;
			p++;
		}
		while (isspace((unsigned char) *p))
			p++;
		switch (*p) {
		case 'a':
		case 'A':
			if (strncasecmp(p, "aeo", 3) == 0) {
				sf -= 3;
//				mode = 5;
				break;
			}
			goto unk;
		case 'd':
		case 'D':
			if (strncasecmp(p, "dor", 3) == 0) {
				sf -= 2;
//				mode = 1;
				break;
			}
			goto unk;
		case 'i':
		case 'I':
			if (strncasecmp(p, "ion", 3) == 0) {
//				mode = 0;
				break;
			}
			goto unk;
		case 'l':
		case 'L':
			if (strncasecmp(p, "loc", 3) == 0) {
				sf -= 5;
//				mode = 6;
				break;
			}
			if (strncasecmp(p, "lyd", 3) == 0) {
				sf += 1;
//				mode = 3;
				break;
			}
			goto unk;
		case 'm':
		case 'M':
			if (strncasecmp(p, "maj", 3) == 0)
				break;
			if (strncasecmp(p, "mix", 3) == 0) {
				sf -= 1;
//				mode = 4;
				break;
			}
			if (strncasecmp(p, "min", 3) == 0
			 || !isalpha((unsigned char) p[1])) { /* 'm' alone */
				sf -= 3;
//				mode = 5;
				break;
			}
			goto unk;
		case 'p':
		case 'P':
			if (strncasecmp(p, "phr", 3) == 0) {
				sf -= 4;
//				mode = 2;
				break;
			}
			goto unk;
		default:
unk:
			empty = 1;			// (local value)
			break;
		}
		if (!empty) {
			while (isalpha((unsigned char) *p))
				p++;
			while (isspace((unsigned char) *p))
				p++;
		}

		// [exp] accidentals
		if (strncmp(p, "exp ", 4) == 0) {
			p += 4;
			while (isspace((unsigned char) *p))
				p++;
			if (*p == '\0')
				syntax("no accidental after 'exp'", p);
			s->u.key.exp = 1;
		}
		if (s->u.key.exp && strncmp(p, "none", 4) == 0) {
			sf = 0;
			p += 4;
			while (isspace((unsigned char) *p))
				p++;
		} else switch (*p) {
			case '^':
			case '_':
			case '=':
				p = parse_acc(p, s);		/* accidentals */
				break;
		}
	}

	if (sf > 7 || sf < -7) {
		syntax("Too many sharps/flats", p);
		if (sf > 0)
			sf -= 12;
		else
			sf += 12;
	}

	// extra parameters
	clef_name = clef_middle = clef_stlines = clef_scale = NULL;
	p_octave = p_cue = p_map = NULL;
	parse_extra(p, &clef_name, &clef_middle, &clef_stlines,
			&clef_scale, &p_octave, &p_cue, &p_map);

	s->u.key.sf = sf;
//	s->u.key.mode = mode;
	s->u.key.instr = instr;
	s->u.key.octave = parse_octave(p_octave);
	if (p_cue) {
		if (strncmp(p_cue, "on", 2) == 0)
			s->u.key.cue = 1;
		else
			s->u.key.cue = -1;
	}
	if (clef_stlines)
		s->u.key.stafflines = clef_stlines;
	if (clef_scale) {
		float sc;

		sc = atof(clef_scale);
		if (sc >= 0.5 && sc <= 3)
			s->u.key.staffscale = sc;
		else
			syntax("Bad value of staffscale", clef_scale);
	}
	if (clef_name || clef_middle) {
		s = abc_new(ABC_T_CLEF, NULL);
		parse_clef(s, clef_name, clef_middle);
	}
	if (p_map) {
		strcpy(tex_buf, "%%voicemap ");
		get_str(&tex_buf[11], p_map, TEX_BUF_SZ - 12);
		abc_new(ABC_T_PSCOM, tex_buf);
	}
}
static void parse_key(char *p,
		      struct SYMBOL *s)
{
	int sf, empty, instr;
 
	char *clef_name, *clef_middle, *clef_stlines, *clef_scale;
	char *p_octave, *p_cue, *p_map;

	 
 
	s->u.key.octave = NO_OCTAVE;

	if (*p == '\0') {
		s->u.key.empty = 1;
		return;
	}
	sf = 0;
 
	empty = 0;
	instr = 0;
	switch (*p++) {
	case 'F': sf = -1; break;
	case 'B': sf++;
	case 'E': sf++;
	case 'A': sf++;
	case 'D': sf++;
	case 'G': sf++;
	case 'C': break;
	case 'H':
		if (*p == 'P') {
			instr = K_HP;
			p++;
		} else if (*p == 'p') {
			instr = K_Hp;
			sf = 2;
			p++;
		} else {
			syntax("Unknown bagpipe-like key", p);
		}
		break;
	case 'P':
		instr = K_DRUM;
		p++;
		break;
	case 'n':
		if (strncmp(p, "one", 3) == 0) {	 
			empty = 2;
			p += 3;
			while (isspace((unsigned char) *p))
				p++;
			if (*p == '\0') {
				s->u.key.empty = empty;
				return;
			}
			break;
		}
		 
	default:
		p--;
		empty = 1;
		break;
	}
	s->u.key.empty = empty;

	if (!empty) {
		if (*p == '#') {
			sf += 7;
			p++;
		} else if (*p == 'b') {
			sf -= 7;
			p++;
		}
		while (isspace((unsigned char) *p))
			p++;
		switch (*p) {
		case 'a':
		case 'A':
			if (strncasecmp(p, "aeo", 3) == 0) {
				sf -= 3;
 
				break;
			}
			goto unk;
		case 'd':
		case 'D':
			if (strncasecmp(p, "dor", 3) == 0) {
				sf -= 2;
 
				break;
			}
			goto unk;
		case 'i':
		case 'I':
			if (strncasecmp(p, "ion", 3) == 0) {
 
				break;
			}
			goto unk;
		case 'l':
		case 'L':
			if (strncasecmp(p, "loc", 3) == 0) {
				sf -= 5;
 
				break;
			}
			if (strncasecmp(p, "lyd", 3) == 0) {
				sf += 1;
 
				break;
			}
			goto unk;
		case 'm':
		case 'M':
			if (strncasecmp(p, "maj", 3) == 0)
				break;
			if (strncasecmp(p, "mix", 3) == 0) {
				sf -= 1;
 
				break;
			}
			if (strncasecmp(p, "min", 3) == 0
			 || !isalpha((unsigned char) p[1])) {  
				sf -= 3;
 
				break;
			}
			goto unk;
		case 'p':
		case 'P':
			if (strncasecmp(p, "phr", 3) == 0) {
				sf -= 4;
 
				break;
			}
			goto unk;
		default:
unk:
			empty = 1;			 
			break;
		}
		if (!empty) {
			while (isalpha((unsigned char) *p))
				p++;
			while (isspace((unsigned char) *p))
				p++;
		}

		 
		if (strncmp(p, "exp ", 4) == 0) {
			p += 4;
			while (isspace((unsigned char) *p))
				p++;
			if (*p == '\0')
				syntax("no accidental after 'exp'", p);
			s->u.key.exp = 1;
		}
		if (s->u.key.exp && strncmp(p, "none", 4) == 0) {
			sf = 0;
			p += 4;
			while (isspace((unsigned char) *p))
				p++;
		} else switch (*p) {
			case '^':
			case '_':
			case '=':
				p = parse_acc(p, s);		 
				break;
		}
	}

	if (sf > 7 || sf < -7) {
		syntax("Too many sharps/flats", p);
		if (sf > 0)
			sf -= 12;
		else
			sf += 12;
	}

	 
	clef_name = clef_middle = clef_stlines = clef_scale = NULL;
	p_octave = p_cue = p_map = NULL;
	parse_extra(p, &clef_name, &clef_middle, &clef_stlines,
			&clef_scale, &p_octave, &p_cue, &p_map);

	s->u.key.sf = sf;
 
	s->u.key.instr = instr;
	s->u.key.octave = parse_octave(p_octave);
	if (p_cue) {
		if (strncmp(p_cue, "on", 2) == 0)
			s->u.key.cue = 1;
		else
			s->u.key.cue = -1;
	}
	if (clef_stlines)
		s->u.key.stafflines = clef_stlines;
	if (clef_scale) {
		float sc;

		sc = atof(clef_scale);
		if (sc >= 0.5 && sc <= 3)
			s->u.key.staffscale = sc;
		else
			syntax("Bad value of staffscale", clef_scale);
	}
	if (clef_name || clef_middle) {
		s = abc_new(ABC_T_CLEF, NULL);
		parse_clef(s, clef_name, clef_middle);
	}
	if (p_map) {
		strcpy(tex_buf, "%%voicemap ");
		get_str(&tex_buf[11], p_map, TEX_BUF_SZ - 12);
		abc_new(ABC_T_PSCOM, tex_buf);
	}
}