bool Allegro_reader::parse_attribute(char *field, Parameter_ptr param) { int i = 1; while (i < (int) strlen(field)) { if (field[i] == ':') { char attr[80]; subseq(attr, field, 1, i); char type_char = field[i - 1]; if (strchr("iarsl", type_char)) { param->set_attr(symbol_table.insert_string(attr)); parse_val(param, field, i + 1); } return !error_flag; } i = i + 1; } return false; }
#include "assert.h" #include "stdlib.h" #include "stdio.h" #include "allegro.h" #include "string.h" #include "ctype.h" //#include "memory.h" #include "trace.h" #include "strparse.h" #ifndef EXPERIMENTAL_NOTE_TRACK #include "allegrord.h" #endif /* EXPERIMENTAL_NOTE_TRACK */ #define streql(s1, s2) (strcmp(s1, s2) == 0) #define field_max 80 //Note that this is an #ifdef, not an #ifndef #ifdef EXPERIMENTAL_NOTE_TRACK class Alg_reader { public: FILE *file; int line_no; String_parse line_parser; bool line_parser_flag; char field[field_max]; bool error_flag; Alg_seq_ptr seq; double tsnum; double tsden; Alg_reader(FILE *a_file, Alg_seq_ptr new_seq); void readline(); Alg_parameters_ptr process_attributes(Alg_parameters_ptr attributes, double time); bool parse(); long parse_chan(char *field); long parse_int(char *field); int find_real_in(char *field, int n); double parse_real(char *field); void parse_error(char *field, long offset, char *message); double parse_dur(char *field, double base); double parse_after_dur(double dur, char *field, int n, double base); double parse_loud(char *field); long parse_key(char *field); double parse_pitch(char *field); long parse_after_key(int key, char *field, int n); long find_int_in(char *field, int n); bool parse_attribute(char *field, Alg_parameter_ptr parm); bool parse_val(Alg_parameter_ptr param, char *s, int i); bool check_type(char type_char, Alg_parameter_ptr param); }; #endif /* EXPERIMENTAL_NOTE_TRACK */ void subseq(char *result, char *source, int from, int to) { memcpy(result, source + from, to - from); result[to - from] = 0; } #ifndef EXPERIMENTAL_NOTE_TRACK double Allegro_reader::parse_pitch(char *field) #else /* EXPERIMENTAL_NOTE_TRACK */ double Alg_reader::parse_pitch(char *field) #endif /* EXPERIMENTAL_NOTE_TRACK */ { if (isdigit(field[1])) { char real_string[80]; int last = find_real_in(field, 1); subseq(real_string, field, 1, last); return atof(real_string); } else { return (double) parse_key(field); } } #ifndef EXPERIMENTAL_NOTE_TRACK Allegro_reader::Allegro_reader(FILE *a_file) { file = a_file; // save the file line_parser_flag = false; line_no = 0; seq = Seq(); tsnum = 4; // default time signature tsden = 4; } #else /* EXPERIMENTAL_NOTE_TRACK */ // it is the responsibility of the caller to delete // the seq Alg_reader::Alg_reader(FILE *a_file, Alg_seq_ptr new_seq) { file = a_file; // save the file line_parser_flag = false; line_no = 0; tsnum = 4; // default time signature tsden = 4; seq = new_seq; } #endif /* EXPERIMENTAL_NOTE_TRACK */ //Note that this is an #ifdef, not an #ifndef #ifdef EXPERIMENTAL_NOTE_TRACK Alg_seq_ptr alg_read(FILE *file, Alg_seq_ptr new_seq) // read a sequence from allegro file { if (!new_seq) new_seq = new Alg_seq(); Alg_reader alg_reader(file, new_seq); alg_reader.parse(); return alg_reader.seq; } #endif /* EXPERIMENTAL_NOTE_TRACK */ #ifndef EXPERIMENTAL_NOTE_TRACK void Allegro_reader::readline() #else /* EXPERIMENTAL_NOTE_TRACK */ void Alg_reader::readline() #endif /* EXPERIMENTAL_NOTE_TRACK */ { char line[256]; char *line_flag = fgets(line, 256, file); line_parser_flag = false; if (line_flag) { line_parser.init(line); line_parser_flag = true; error_flag = false; } } #ifndef EXPERIMENTAL_NOTE_TRACK void Allegro_reader::process_attributes(Parameters_ptr attributes, double time) { // print "process_attributes:", attributes bool ts_flag; if (attributes) { Parameters_ptr a; if (a = Parameters::remove_key(&attributes, "tempor")) { double tempo = a->parm.r; seq.insert_tempo(tempo, seq.map.time_to_beat(time)); } if (a = Parameters::remove_key(&attributes, "beatr")) { double beat = a->parm.r; seq.insert_beat(time, beat); } if (a = Parameters::remove_key(&attributes, "tsnumr")) { tsnum = a->parm.r; ts_flag = true; } if (a = Parameters::remove_key(&attributes, "tsdenr")) { tsden = a->parm.r; ts_flag = true; } if (ts_flag) { seq.set_time_sig(seq.map.time_to_beat(time), tsnum, tsden); } } } #else /* EXPERIMENTAL_NOTE_TRACK */ Alg_parameters_ptr Alg_reader::process_attributes( Alg_parameters_ptr attributes, double time) { // print "process_attributes:", attributes bool ts_flag = false; if (attributes) { Alg_parameters_ptr a; bool in_seconds = seq->get_units_are_seconds(); if (a = Alg_parameters::remove_key(&attributes, "tempor")) { double tempo = a->parm.r; seq->insert_tempo(tempo, seq->get_time_map()->time_to_beat(time)); } if (a = Alg_parameters::remove_key(&attributes, "beatr")) { double beat = a->parm.r; seq->insert_beat(time, beat); } if (a = Alg_parameters::remove_key(&attributes, "timesig_numr")) { tsnum = a->parm.r; ts_flag = true; } if (a = Alg_parameters::remove_key(&attributes, "timesig_denr")) { tsden = a->parm.r; ts_flag = true; } if (ts_flag) { seq->set_time_sig(seq->get_time_map()->time_to_beat(time), tsnum, tsden); } if (in_seconds) seq->convert_to_seconds(); } return attributes; // in case it was modified } #endif /* EXPERIMENTAL_NOTE_TRACK */ #ifndef EXPERIMENTAL_NOTE_TRACK bool Allegro_reader::parse() { int voice = 0; int key = 60; double loud = 100.0; double pitch = 60.0; double dur = 1.0; double time = 0.0; readline(); bool valid = false; // ignore blank lines while (line_parser_flag) { bool time_flag = false; bool next_flag = false; double next; bool voice_flag = false; bool loud_flag = false; bool dur_flag = false; bool new_pitch_flag = false; // "P" syntax double new_pitch = 0.0; bool new_key_flag = false; // "K" syntax int new_key = 0; bool new_note_flag = false; // "A"-"G" syntax int new_note = 0; Parameters_ptr attributes = NULL; line_parser.get_nonspace_quoted(field); char pk = line_parser.peek(); if (pk && !isspace(pk)) { line_parser.get_nonspace_quoted(field + strlen(field)); } while (field[0]) { // print "field", "|";field;"|", "|";line_parser.string;"|", line_parser.pos char first = toupper(field[0]); if (strchr("ABCDEFGKLPUSIQHW-", first)) { valid = true; // it's a note or event } if (first == 'V') { if (voice_flag) { parse_error(field, 0, "Voice specified twice"); } else { voice = parse_int(field); } voice_flag = true; } else if (first == 'T') { if (time_flag) { parse_error(field, 0, "Time specified twice"); } else { time = parse_dur(field, 0.0); } time_flag = true; } else if (first == 'N') { if (next_flag) { parse_error(field, 0, "Next specified twice"); } else { next = parse_dur(field, time); } next_flag = true; } else if (first == 'K') { if (new_key_flag) { parse_error(field, 0, "Key specified twice"); } else { new_key = parse_key(field); new_key_flag = true; } } else if (first == 'L') { if (loud_flag) { parse_error(field, 0, "Loudness specified twice"); } else { loud = parse_loud(field); } loud_flag = true; } else if (first == 'P') { if (new_note_flag || new_pitch_flag) { parse_error(field, 0, "Pitch specified twice"); } else { new_pitch = parse_pitch(field); new_pitch_flag = true; } } else if (first == 'U') { if (dur_flag) { parse_error(field, 0, "Dur specified twice"); } else { dur = parse_dur(field, time); dur_flag = true; } } else if (strchr("SIQHW", first)) { if (dur_flag) { parse_error(field, 0, "Dur specified twice"); } else { // prepend 'U' to field, copy EOS too memmove(field + 1, field, strlen(field) + 1); field[0] = 'U'; dur = parse_dur(field, time); dur_flag = true; } } else if (strchr("ABCDEFG", first)) { if (new_note_flag || new_pitch_flag) { parse_error(field, 0, "Pitch specified twice"); } else { // prepend 'K' to field, copy EOS too memmove(field + 1, field, strlen(field) + 1); field[0] = 'K'; new_note = parse_key(field); new_note_flag = true; } } else if (first == '-') { Parameter parm; if (parse_attribute(field, &parm)) { // enter attribute-value pair attributes = new Parameters(attributes); attributes->parm = parm; parm.s = NULL; // protect string from deletion by destructor } } else { parse_error(field, 0, "Unknown field"); } if (error_flag) { field[0] = 0; // exit the loop } else { line_parser.get_nonspace_quoted(field); pk = line_parser.peek(); if (pk && !isspace(pk)) { line_parser.get_nonspace_quoted(field + strlen(field)); } } } // a case analysis: // Key < 128 counts as both key and pitch // A-G implies pitch AND key unless key given too // K60 P60 -- both are specified, use 'em // K60 P60 C4 -- overconstrained, an error // K60 C4 -- overconstrained // K60 -- OK, pitch is 60 // C4 P60 -- over constrained // P60 -- OK, key is from before, pitch is 60 // C4 -- OK, key is 60, pitch is 60 // <nothing> -- OK, key and pitch from before // K200 with P60 ok, pitch is 60 // K200 with neither P60 nor C4 uses // pitch from before // figure out what the key/instance is: if (new_key_flag) { // it was directly specified key = new_key; if (key < 128 && new_note_flag) { parse_error("", 0, "Pitch specified twice"); } } else if (new_note_flag) { // "A"-"G" used key = new_note; } if (new_pitch_flag) { pitch = new_pitch; } else if (key < 128) { pitch = key; } // now we've acquired new parameters // if (it is a note, then enter the note if (valid) { // change tempo or beat process_attributes(attributes, time); // if there's a duration or pitch, make a note: if (new_pitch_flag || dur_flag || new_note_flag) { new_key_flag = false; new_pitch_flag = false; Allegro_note_ptr note_ptr = new Allegro_note; note_ptr->chan = voice; note_ptr->time = time; note_ptr->dur = dur; note_ptr->key = key; note_ptr->pitch = pitch; note_ptr->loud = loud; note_ptr->parameters = attributes; seq.add_event(note_ptr); // sort later } else { int update_key = -1; // key or pitch must appear explicitly; otherwise // update applies to channel if (new_key_flag || new_pitch_flag) { update_key = key; } if (loud_flag) { Allegro_update_ptr new_upd = new Allegro_update; new_upd->chan = voice; new_upd->time = time; new_upd->key = update_key; new_upd->parameter.set_attr(symbol_table.insert_string("loudr")); new_upd->parameter.r = pitch; seq.add_event(new_upd); } if (attributes) { while (attributes) { Allegro_update_ptr new_upd = new Allegro_update; new_upd->chan = voice; new_upd->time = time; new_upd->key = update_key; new_upd->parameter = attributes->parm; seq.add_event(new_upd); Parameters_ptr p = attributes; attributes = attributes->next; delete p; } } } if (next_flag) { time = time + next; } else if (dur_flag) { time = time + dur; } } readline(); } //print "Finished reading score" if (!error_flag) { seq.convert_to_seconds(); // make sure format is correct // seq.notes.sort('event_greater_than'); } // print "parse returns error_flag", error_flag return error_flag; } #else /* EXPERIMENTAL_NOTE_TRACK */ bool Alg_reader::parse() { int voice = 0; int key = 60; double loud = 100.0; double pitch = 60.0; double dur = 1.0; double time = 0.0; int track_num = 0; seq->convert_to_seconds(); //seq->set_real_dur(0.0); // just in case it's not initialized already readline(); bool valid = false; // ignore blank lines while (line_parser_flag) { bool time_flag = false; bool next_flag = false; double next; bool voice_flag = false; bool loud_flag = false; bool dur_flag = false; bool new_pitch_flag = false; // "P" syntax double new_pitch = 0.0; bool new_key_flag = false; // "K" syntax int new_key = 0; bool new_note_flag = false; // "A"-"G" syntax int new_note = 0; Alg_parameters_ptr attributes = NULL; if (line_parser.peek() == '#') { // look for #track line_parser.get_nonspace_quoted(field); if (streql(field, "#track")) { line_parser.get_nonspace_quoted(field); // number track_num = parse_int(field - 1); seq->add_track(track_num); } // maybe we have a comment } else { // we must have a track to insert into if (seq->tracks() == 0) seq->add_track(0); line_parser.get_nonspace_quoted(field); char pk = line_parser.peek(); // attributes are parsed as two adjacent nonspace_quoted tokens // so we have to conditionally call get_nonspace_quoted() again if (pk && !isspace(pk)) { line_parser.get_nonspace_quoted(field + strlen(field)); } while (field[0]) { char first = toupper(field[0]); if (strchr("ABCDEFGKLPUSIQHW-", first)) { valid = true; // it's a note or event } if (first == 'V') { if (voice_flag) { parse_error(field, 0, "Voice specified twice"); } else { voice = parse_chan(field); } voice_flag = true; } else if (first == 'T') { if (time_flag) { parse_error(field, 0, "Time specified twice"); } else { time = parse_dur(field, 0.0); } time_flag = true; } else if (first == 'N') { if (next_flag) { parse_error(field, 0, "Next specified twice"); } else { next = parse_dur(field, time); } next_flag = true; } else if (first == 'K') { if (new_key_flag) { parse_error(field, 0, "Key specified twice"); } else { new_key = parse_key(field); new_key_flag = true; } } else if (first == 'L') { if (loud_flag) { parse_error(field, 0, "Loudness specified twice"); } else { loud = parse_loud(field); } loud_flag = true; } else if (first == 'P') { if (new_note_flag || new_pitch_flag) { parse_error(field, 0, "Pitch specified twice"); } else { new_pitch = parse_pitch(field); new_pitch_flag = true; } } else if (first == 'U') { if (dur_flag) { parse_error(field, 0, "Dur specified twice"); } else { dur = parse_dur(field, time); dur_flag = true; } } else if (strchr("SIQHW", first)) { if (dur_flag) { parse_error(field, 0, "Dur specified twice"); } else { // prepend 'U' to field, copy EOS too memmove(field + 1, field, strlen(field) + 1); field[0] = 'U'; dur = parse_dur(field, time); dur_flag = true; } } else if (strchr("ABCDEFG", first)) { if (new_note_flag || new_pitch_flag) { parse_error(field, 0, "Pitch specified twice"); } else { // prepend 'K' to field, copy EOS too memmove(field + 1, field, strlen(field) + 1); field[0] = 'K'; new_note = parse_key(field); new_note_flag = true; } } else if (first == '-') { Alg_parameter parm; if (parse_attribute(field, &parm)) { // enter attribute-value pair attributes = new Alg_parameters(attributes); attributes->parm = parm; parm.s = NULL; // protect string from deletion by destructor } } else { parse_error(field, 0, "Unknown field"); } if (error_flag) { field[0] = 0; // exit the loop } else { line_parser.get_nonspace_quoted(field); pk = line_parser.peek(); // attributes are parsed as two adjacent nonspace_quoted // tokens so we have to conditionally call // get_nonspace_quoted() again if (pk && !isspace(pk)) { line_parser.get_nonspace_quoted(field + strlen(field)); } } } // a case analysis: // Key < 128 counts as both key and pitch // A-G implies pitch AND key unless key given too // K60 P60 -- both are specified, use 'em // K60 P60 C4 -- overconstrained, an error // K60 C4 -- overconstrained // K60 -- OK, pitch is 60 // C4 P60 -- over constrained // P60 -- OK, key is from before, pitch is 60 // C4 -- OK, key is 60, pitch is 60 // <nothing> -- OK, key and pitch from before // K200 with P60 ok, pitch is 60 // K200 with neither P60 nor C4 uses // pitch from before // figure out what the key/instance is: if (new_key_flag) { // it was directly specified key = new_key; if (key < 128 && new_note_flag) { parse_error("", 0, "Pitch specified twice"); } } else if (new_note_flag) { // "A"-"G" used key = new_note; } if (new_pitch_flag) { pitch = new_pitch; } else if (key < 128) { pitch = key; } // now we've acquired new parameters // if (it is a note, then enter the note if (valid) { // change tempo or beat attributes = process_attributes(attributes, time); // if there's a duration or pitch, make a note: if (new_pitch_flag || dur_flag || new_note_flag) { new_key_flag = false; new_pitch_flag = false; Alg_note_ptr note_ptr = new Alg_note; note_ptr->chan = voice; note_ptr->time = time; note_ptr->dur = dur; note_ptr->set_identifier(key); note_ptr->pitch = pitch; note_ptr->loud = loud; note_ptr->parameters = attributes; seq->add_event(note_ptr, track_num); // sort later if (seq->get_real_dur() < (time + dur)) seq->set_real_dur(time + dur); } else { int update_key = -1; // key or pitch must appear explicitly; otherwise // update applies to channel if (new_key_flag || new_pitch_flag) { update_key = key; } if (loud_flag) { Alg_update_ptr new_upd = new Alg_update; new_upd->chan = voice; new_upd->time = time; new_upd->set_identifier(update_key); new_upd->parameter.set_attr(symbol_table.insert_string("loudr")); new_upd->parameter.r = pitch; seq->add_event(new_upd, track_num); if (seq->get_real_dur() < time) seq->set_real_dur(time); } if (attributes) { while (attributes) { Alg_update_ptr new_upd = new Alg_update; new_upd->chan = voice; new_upd->time = time; new_upd->set_identifier(update_key); new_upd->parameter = attributes->parm; seq->add_event(new_upd, track_num); Alg_parameters_ptr p = attributes; attributes = attributes->next; p->parm.s = NULL; // so we don't delete the string delete p; } } } if (next_flag) { time = time + next; } else if (dur_flag) { time = time + dur; } } } readline(); } //print "Finished reading score" if (!error_flag) { seq->convert_to_seconds(); // make sure format is correct // seq->notes.sort('event_greater_than'); } // real_dur is valid, translate to beat_dur seq->set_beat_dur((seq->get_time_map())->time_to_beat(seq->get_real_dur())); // print "parse returns error_flag", error_flag return error_flag; } #endif /* EXPERIMENTAL_NOTE_TRACK */ //Note that this is an #ifdef, not an #ifndef #ifdef EXPERIMENTAL_NOTE_TRACK long Alg_reader::parse_chan(char *field) { char *int_string = field + 1; char *msg = "Integer or - expected"; char *p = int_string; char c; // check that all chars in int_string are digits or '-': while (c = *p++) { if (!isdigit(c) && c != '-') { parse_error(field, p - field - 1, msg); return 0; } } p--; // p now points to end-of-string character if (p - int_string == 0) { // bad: string length is zero parse_error(field, 1, msg); return 0; } if (p - int_string == 1 && int_string[0] == '-') { // special case: entire string is "-", interpret as -1 return -1; } return atoi(int_string); } #endif /* EXPERIMENTAL_NOTE_TRACK */ #ifndef EXPERIMENTAL_NOTE_TRACK long Allegro_reader::parse_int(char *field) { char int_string[field_max]; strcpy(int_string, field + 1); char *msg = "Integer expected"; char *p = int_string; char c; while (c = *p++) { if (!isdigit(c)) { parse_error(field, 1, msg); return 0; } } if (strlen(int_string) < 1) { parse_error(field, 1, msg); return 0; } return atoi(int_string); } #else /* EXPERIMENTAL_NOTE_TRACK */ long Alg_reader::parse_int(char *field) { char *int_string = field + 1; char *msg = "Integer expected"; char *p = int_string; char c; // check that all chars in int_string are digits: while (c = *p++) { if (!isdigit(c)) { parse_error(field, p - field - 1, msg); return 0; } } p--; // p now points to end-of-string character if (p - int_string == 0) { // bad: string length is zero parse_error(field, 1, msg); return 0; } return atoi(int_string); } #endif /* EXPERIMENTAL_NOTE_TRACK */ #ifndef EXPERIMENTAL_NOTE_TRACK int Allegro_reader::find_real_in(char *field, int n) #else /* EXPERIMENTAL_NOTE_TRACK */ int Alg_reader::find_real_in(char *field, int n) #endif /* EXPERIMENTAL_NOTE_TRACK */ { // scans from offset n to the end of a real constant bool decimal = false; int len = strlen(field); for (int i = n; i < len; i++) { char c = field[i]; if (!isdigit(c)) { if (c == '.' && !decimal) { decimal = true; } else { return i; } } } return strlen(field); } #ifndef EXPERIMENTAL_NOTE_TRACK double Allegro_reader::parse_real(char *field) #else /* EXPERIMENTAL_NOTE_TRACK */ double Alg_reader::parse_real(char *field) #endif /* EXPERIMENTAL_NOTE_TRACK */ { char real_string[80]; char *msg = "Real expected"; bool decimal = false; int last = find_real_in(field, 1); subseq(real_string, field, 1, last); if (last <= 1 || last < (int) strlen(field)) { parse_error(field, 1, msg); return 0; } return atof(real_string); } #ifndef EXPERIMENTAL_NOTE_TRACK void Allegro_reader::parse_error(char *field, long offset, char *message) #else /* EXPERIMENTAL_NOTE_TRACK */ void Alg_reader::parse_error(char *field, long offset, char *message) #endif /* EXPERIMENTAL_NOTE_TRACK */ { int position = line_parser.pos - strlen(field) + offset; error_flag = true; puts(line_parser.string); for (int i = 0; i < position; i++) { putc(' ', stdout); } putc('^', stdout); printf(" %s\n", message); } double duration_lookup[] = { 0.25, 0.5, 1.0, 2.0, 4.0 }; #ifndef EXPERIMENTAL_NOTE_TRACK double Allegro_reader::parse_dur(char *field, double base) { char *msg = "Duration expected"; char real_string[80]; char *durs = "SIQHW"; char *p; int last; double dur; if (strlen(field) < 2) { // fall through to error message return -1; } else if (isdigit(field[1])) { last = find_real_in(field, 1); subseq(real_string, field, 1, last); dur = atof(real_string); // convert dur from seconds to beats dur = seq.map.time_to_beat(base + dur) - seq.map.time_to_beat(base); } else if (p = strchr(durs, field[1])) { dur = duration_lookup[p - durs]; last = 2; } else { parse_error(field, 1, msg); return 0; } dur = parse_after_dur(dur, field, last, base); dur = seq.map.beat_to_time(seq.map.time_to_beat(base) + dur) - base; return dur; } #else /* EXPERIMENTAL_NOTE_TRACK */ double Alg_reader::parse_dur(char *field, double base) { char *msg = "Duration expected"; char real_string[80]; char *durs = "SIQHW"; char *p; int last; double dur; if (strlen(field) < 2) { // fall through to error message return -1; } else if (isdigit(field[1])) { last = find_real_in(field, 1); subseq(real_string, field, 1, last); dur = atof(real_string); // convert dur from seconds to beats dur = seq->get_time_map()->time_to_beat(base + dur) - seq->get_time_map()->time_to_beat(base); } else if (p = strchr(durs, field[1])) { dur = duration_lookup[p - durs]; last = 2; } else { parse_error(field, 1, msg); return 0; } dur = parse_after_dur(dur, field, last, base); dur = seq->get_time_map()->beat_to_time( seq->get_time_map()->time_to_beat(base) + dur) - base; return dur; } #endif /* EXPERIMENTAL_NOTE_TRACK */ #ifndef EXPERIMENTAL_NOTE_TRACK double Allegro_reader::parse_after_dur(double dur, char *field, int n, double base) { char a_string[80]; if ((int) strlen(field) == n) { return dur; } if (field[n] == 'T') { return parse_after_dur(dur * 2/3, field, n + 1, base); } if (field[n] == '.') { return parse_after_dur(dur * 1.5, field, n + 1, base); } if (isdigit(field[n])) { int last = find_real_in(field, n); subseq(a_string, field, n, last); double f = atof(a_string); return parse_after_dur(dur * f, field, last, base); } if (field[n] == '+') { subseq(a_string, field, n + 1, -1); return dur + parse_dur(a_string, seq.map.beat_to_time( seq.map.time_to_beat(base) + dur)); } parse_error(field, n, "Unexpected character in duration"); return dur; } #else /* EXPERIMENTAL_NOTE_TRACK */ double Alg_reader::parse_after_dur(double dur, char *field, int n, double base) { char a_string[80]; if ((int) strlen(field) == n) { return dur; } if (field[n] == 'T') { return parse_after_dur(dur * 2/3, field, n + 1, base); } if (field[n] == '.') { return parse_after_dur(dur * 1.5, field, n + 1, base); } if (isdigit(field[n])) { int last = find_real_in(field, n); subseq(a_string, field, n, last); double f = atof(a_string); return parse_after_dur(dur * f, field, last, base); } if (field[n] == '+') { subseq(a_string, field, n + 1, -1); return dur + parse_dur( a_string, seq->get_time_map()->beat_to_time( seq->get_time_map()->time_to_beat(base) + dur)); } parse_error(field, n, "Unexpected character in duration"); return dur; } #endif /* EXPERIMENTAL_NOTE_TRACK */ #ifndef EXPERIMENTAL_NOTE_TRACK static struct { #else /* EXPERIMENTAL_NOTE_TRACK */ struct loud_lookup_struct { #endif /* EXPERIMENTAL_NOTE_TRACK */ char *str; int val; } loud_lookup[] = { {"FFF", 127}, {"FF", 120}, {"F", 110}, {"MF", 100}, {"MP", 90}, {"P", 80}, {"PP", 70}, {"PPP", 60}, {NULL, 0} }; #ifndef EXPERIMENTAL_NOTE_TRACK double Allegro_reader::parse_loud(char *field) { char *msg = "Loudness expected"; if (isdigit(field[1])) { return parse_int(field); } else { double loud = 0.0; char dyn[field_max]; strcpy(dyn, field + 1); char *p = dyn; while (*p) { if (isupper(*p)) *p = toupper(*p); } for (int i = 0; loud_lookup[i].str; i++) { if (streql(loud_lookup[i].str, dyn)) { return (double) loud_lookup[i].val; } } } parse_error(field, 1, msg); return 100.0; } #else /* EXPERIMENTAL_NOTE_TRACK */ double Alg_reader::parse_loud(char *field) { char *msg = "Loudness expected"; if (isdigit(field[1])) { return parse_int(field); } else { double loud = 0.0; char dyn[field_max]; strcpy(dyn, field + 1); char *p = dyn; while (*p) { if (islower(*p)) *p = toupper(*p); p++; } for (int i = 0; loud_lookup[i].str; i++) { if (streql(loud_lookup[i].str, dyn)) { return (double) loud_lookup[i].val; } } } parse_error(field, 1, msg); return 100.0; } #endif /* EXPERIMENTAL_NOTE_TRACK */ int key_lookup[] = {21, 23, 12, 14, 16, 17, 19}; #ifndef EXPERIMENTAL_NOTE_TRACK long Allegro_reader::parse_key(char *field) #else /* EXPERIMENTAL_NOTE_TRACK */ long Alg_reader::parse_key(char *field) #endif /* EXPERIMENTAL_NOTE_TRACK */ { char *msg = "Pitch expected"; char *pitches = "ABCDEFG"; char *p; if (isdigit(field[1])) { return parse_int(field); } else if (p = strchr(pitches, field[1])) { long key = key_lookup[p - pitches]; key = parse_after_key(key, field, 2); return key; } parse_error(field, 1, msg); return 0; } #ifndef EXPERIMENTAL_NOTE_TRACK long Allegro_reader::parse_after_key(int key, char *field, int n) #else /* EXPERIMENTAL_NOTE_TRACK */ long Alg_reader::parse_after_key(int key, char *field, int n) #endif /* EXPERIMENTAL_NOTE_TRACK */ { char octave[20]; if ((int) strlen(field) == n) { return key; } char c = toupper(field[n]); if (c == 'S') { return parse_after_key(key + 1, field, n + 1); } if (c == 'F') { return parse_after_key(key - 1, field, n + 1); } if (isdigit(c)) { int last = find_int_in(field, n); subseq(octave, field, n, last); int oct = atoi(octave); return parse_after_key(key + oct * 12, field, last); } parse_error(field, n, "Unexpected character in pitch"); return key; } #ifndef EXPERIMENTAL_NOTE_TRACK long Allegro_reader::find_int_in(char *field, int n) #else /* EXPERIMENTAL_NOTE_TRACK */ long Alg_reader::find_int_in(char *field, int n) #endif /* EXPERIMENTAL_NOTE_TRACK */ { while ((int) strlen(field) > n && isdigit(field[n])) { n = n + 1; } return n; } #ifndef EXPERIMENTAL_NOTE_TRACK bool Allegro_reader::parse_attribute(char *field, Parameter_ptr param) { int i = 1; while (i < (int) strlen(field)) { if (field[i] == ':') { char attr[80]; subseq(attr, field, 1, i); char type_char = field[i - 1]; if (strchr("iarsl", type_char)) { param->set_attr(symbol_table.insert_string(attr)); parse_val(param, field, i + 1); } return !error_flag; } i = i + 1; } return false; } #else /* EXPERIMENTAL_NOTE_TRACK */ bool Alg_reader::parse_attribute(char *field, Alg_parameter_ptr param) { int i = 1; while (i < (int) strlen(field)) { if (field[i] == ':') { char attr[80]; subseq(attr, field, 1, i); char type_char = field[i - 1]; if (strchr("iarsl", type_char)) { param->set_attr(symbol_table.insert_string(attr)); parse_val(param, field, i + 1); } else { parse_error(field, 0, "attribute needs to end with typecode: i,a,r,s, or l"); } return !error_flag; } i = i + 1; } return false; }
int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain, struct m_pedit_sel *sel, struct m_pedit_key *tkey) { __u32 mask[4] = { 0 }; __u32 val[4] = { 0 }; __u32 *m = &mask[0]; __u32 *v = &val[0]; __u32 o = 0xFF; int res = -1; int argc = *argc_p; char **argv = *argv_p; if (argc <= 0) return -1; if (pedit_debug) printf("parse_cmd argc %d %s offset %d length %d\n", argc, *argv, tkey->off, len); if (len == 2) o = 0xFFFF; if (len == 4) o = 0xFFFFFFFF; if (matches(*argv, "invert") == 0) { *v = *m = o; } else if (matches(*argv, "set") == 0 || matches(*argv, "add") == 0) { if (matches(*argv, "add") == 0) tkey->cmd = TCA_PEDIT_KEY_EX_CMD_ADD; if (!sel->extended && tkey->cmd) { fprintf(stderr, "Non extended mode. only 'set' command is supported\n"); return -1; } NEXT_ARG(); if (parse_val(&argc, &argv, val, type)) return -1; } else if (matches(*argv, "preserve") == 0) { retain = 0; } else { if (matches(*argv, "clear") != 0) return -1; } argc--; argv++; if (argc && matches(*argv, "retain") == 0) { NEXT_ARG(); if (parse_val(&argc, &argv, &retain, TU32)) return -1; argc--; argv++; } if (len > 4 && retain != ~0) { fprintf(stderr, "retain is not supported for fields longer the 32 bits\n"); return -1; } if (type == TMAC) { res = pack_mac(sel, tkey, (__u8 *)val); goto done; } if (type == TIPV6) { res = pack_ipv6(sel, tkey, val); goto done; } tkey->val = *v; tkey->mask = *m; if (type == TIPV4) tkey->val = ntohl(tkey->val); if (len == 1) { res = pack_key8(retain, sel, tkey); goto done; } if (len == 2) { res = pack_key16(retain, sel, tkey); goto done; } if (len == 4) { res = pack_key32(retain, sel, tkey); goto done; } return -1; done: if (pedit_debug) printf("parse_cmd done argc %d %s offset %d length %d\n", argc, *argv, tkey->off, len); *argc_p = argc; *argv_p = argv; return res; }
int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) { __u32 mask = 0, val = 0; __u32 o = 0xFF; int res = -1; int argc = *argc_p; char **argv = *argv_p; if (argc <= 0) return -1; if (pedit_debug) printf("parse_cmd argc %d %s offset %d length %d\n",argc,*argv,tkey->off,len); if (len == 2) o = 0xFFFF; if (len == 4) o = 0xFFFFFFFF; if (matches(*argv, "invert") == 0) { retain = val = mask = o; } else if (matches(*argv, "set") == 0) { NEXT_ARG(); if (parse_val(&argc, &argv, &val, type)) return -1; } else if (matches(*argv, "preserve") == 0) { retain = mask = o; } else { if (matches(*argv, "clear") != 0) return -1; } argc--; argv++; if (argc && matches(*argv, "retain") == 0) { NEXT_ARG(); if (parse_val(&argc, &argv, &retain, TU32)) return -1; argc--; argv++; } tkey->val = val; if (len == 1) { tkey->mask = 0xFF; res = pack_key8(retain,sel,tkey); goto done; } if (len == 2) { tkey->mask = mask; res = pack_key16(retain,sel,tkey); goto done; } if (len == 4) { tkey->mask = mask; res = pack_key32(retain,sel,tkey); goto done; } return -1; done: if (pedit_debug) printf("parse_cmd done argc %d %s offset %d length %d\n",argc,*argv,tkey->off,len); *argc_p = argc; *argv_p = argv; return res; }
wstring TokenVar::gettext( data_map &data ) { return parse_val(m_key, data)->getvalue() ; }
void TokenVar::gettext( std::wostream &stream, data_map &data ) { stream << parse_val(m_key, data)->getvalue() ; }
/******************************************************************** * FUNCTION parse_parm * * Parse, and fill one val_value_t struct during * processing of a parmset * * Error messages are printed by this function!! * Do not duplicate error messages upon error return * * * INPUTS: * tkc == token chain * val == container val to fill in * keepvals == TRUE to save existing parms in 'ps', as needed * FALSE to overwrite old parms in 'ps', as needed * * RETURNS: * status of the operation *********************************************************************/ static status_t parse_parm (tk_chain_t *tkc, val_value_t *val, boolean keepvals) { obj_template_t *obj; const xmlChar *modname; val_value_t *curparm, *newparm; status_t res; ncx_iqual_t iqual; boolean match, usewarning, isdefault; /* get the next token, which must be a TSTRING * representing the parameter name */ if (TK_CUR_TYP(tkc) != TK_TT_TSTRING) { res = ERR_NCX_WRONG_TKTYPE; ncx_conf_exp_err(tkc, res, "parameter name"); return res; } curparm = NULL; usewarning = ncx_warning_enabled(ERR_NCX_CONF_PARM_EXISTS); /* check if this TSTRING is a parameter in this parmset * make sure to always check for prefix:identifier * This is automatically processed in tk.c */ if (TK_CUR_MOD(tkc)) { modname = xmlns_get_module (xmlns_find_ns_by_prefix(TK_CUR_MOD(tkc))); if (modname) { curparm = val_find_child(val, modname, TK_CUR_VAL(tkc)); } } else { curparm = val_find_child(val, val_get_mod_name(val), TK_CUR_VAL(tkc)); } if (curparm) { obj = curparm->obj; } else { obj = obj_find_child(val->obj, TK_CUR_MOD(tkc), TK_CUR_VAL(tkc)); } if (!obj) { res = ERR_NCX_UNKNOWN_PARM; if (TK_CUR_MOD(tkc)) { log_error("\nError: parameter '%s:%s' not found", TK_CUR_MOD(tkc), TK_CUR_VAL(tkc)); } else { log_error("\nError: parameter '%s' not found", TK_CUR_VAL(tkc)); } ncx_conf_exp_err(tkc, res, "parameter name"); return res; } /* got a valid parameter name, now create a new parm * even if it may not be kept. There are corner-cases * that require the new value be parsed before knowing * if a parm value is a duplicate or not */ newparm = val_new_value(); if (!newparm) { res = ERR_INTERNAL_MEM; ncx_print_errormsg(tkc, NULL, res); return res; } val_init_from_template(newparm, obj); /* parse the parameter value */ res = parse_val(tkc, obj, newparm); if (res != NO_ERR) { val_free_value(newparm); return res; } /* check if a potential current value exists, or just * add the newparm to the parmset */ if (curparm) { isdefault = val_set_by_default(curparm); iqual = obj_get_iqualval(obj); if (iqual == NCX_IQUAL_ONE || iqual == NCX_IQUAL_OPT) { /* only one allowed, check really a match */ match = TRUE; if (val_has_index(curparm) && !val_index_match(newparm, curparm)) { match = FALSE; } if (!match) { val_add_child(newparm, val); } else if (isdefault) { dlq_remove(curparm); val_free_value(curparm); val_add_child(newparm, val); } else if (keepvals) { if (usewarning) { /* keep current value and toss new value */ log_warn("\nWarning: Parameter '%s' already exists. " "Not using new value\n", curparm->name); if (LOGDEBUG2) { val_dump_value(newparm, NCX_DEF_INDENT); log_debug2("\n"); } } val_free_value(newparm); } else { if (usewarning) { /* replace current value and warn old value tossed */ log_warn("\nconf: Parameter '%s' already exists. " "Overwriting with new value\n", curparm->name); if (LOGDEBUG2) { val_dump_value(newparm, NCX_DEF_INDENT); log_debug2("\n"); } } dlq_remove(curparm); val_free_value(curparm); val_add_child(newparm, val); } } else { /* mutliple instances allowed */ val_add_child(newparm, val); } } else { val_add_child(newparm, val); } return NO_ERR; } /* parse_parm */
/******************************************************************** * FUNCTION parse_val * * Parse, and fill one val_value_t struct during * processing of a text config file * * Error messages are printed by this function!! * Do not duplicate error messages upon error return * * The value name is the current token. * Based on the value typdef, the res of the tokens * comprising the value statement will be processed * * INPUTS: * tkc == token chain * obj == the object template struct to use for filling in 'val' * val == initialized value struct, without any value, * which will be filled in by this function * nsid == namespace ID to use for this value * valname == name of the value struct * * RETURNS: * status of the operation *********************************************************************/ static status_t parse_val (tk_chain_t *tkc, obj_template_t *obj, val_value_t *val) { obj_template_t *chobj; val_value_t *chval; const xmlChar *valname, *useval; typ_def_t *typdef; status_t res; ncx_btype_t btyp; boolean done; xmlns_id_t nsid; btyp = obj_get_basetype(obj); nsid = obj_get_nsid(obj); valname = obj_get_name(obj); typdef = obj_get_typdef(obj); /* check if there is an index clause expected */ if (typ_has_index(btyp)) { res = parse_index(tkc, obj, val, nsid); if (res != NO_ERR) { return res; } } /* get next token, NEWLINE is significant at this point */ res = adv_tk(tkc); if (res != NO_ERR) { return res; } /* the current token should be the value for a leaf * or a left brace for the start of a complex type * A NEWLINE is treated as if the user entered a * zero-length string for the value. (Unless the * base type is NCX_BT_EMPTY, in which case the NEWLINE * is the expected token */ if (typ_is_simple(btyp)) { /* form for a leaf is: foo [value] NEWLINE */ if (TK_CUR_TYP(tkc)==TK_TT_NEWLINE) { useval = NULL; } else { useval = TK_CUR_VAL(tkc); } res = val_set_simval(val, typdef, nsid, valname, useval); if (res != NO_ERR) { log_error("\nError: '%s' cannot be set to '%s'", valname, (TK_CUR_VAL(tkc)) ? TK_CUR_VAL(tkc) : EMPTY_STRING); if (btyp == NCX_BT_EMPTY) { ncx_conf_exp_err(tkc, res, "empty"); } else { ncx_conf_exp_err(tkc, res, "simple value string"); } return res; } /* get a NEWLINE unless current token is already a NEWLINE */ if (TK_CUR_TYP(tkc) != TK_TT_NEWLINE) { res = adv_tk(tkc); if (res != NO_ERR) { return res; } if (TK_CUR_TYP(tkc) != TK_TT_NEWLINE) { res = ERR_NCX_WRONG_TKTYPE; ncx_conf_exp_err(tkc, res, "\\n"); } } } else { /* complex type is foo { ... } or * foo index1 index2 { ... } * If there is an index, it was already parsed */ res = consume_tk(tkc, TK_TT_LBRACE); if (res != NO_ERR) { ncx_conf_exp_err(tkc, res, "left brace"); return res; } /* get all the child nodes specified for this complex type */ res = NO_ERR; done = FALSE; while (!done && res==NO_ERR) { /* start out looking for a child node name or a * right brace to end the sub-section */ if (tk_next_typ(tkc)==TK_TT_NEWLINE) { /* skip the NEWLINE token */ (void)adv_tk(tkc); } else if (tk_next_typ(tkc)==TK_TT_RBRACE) { /* found end of sub-section */ done = TRUE; } else { /* get the next token */ res = adv_tk(tkc); if (res != NO_ERR) { continue; } /* make sure cur token is an identifier string * if so, find the child node and call this function * recursively to fill it in and add it to * the parent 'val' */ if (TK_CUR_ID(tkc)) { /* parent 'typdef' must have a child with a name * that matches the current token vale */ chobj = obj_find_child(obj, TK_CUR_MOD(tkc), TK_CUR_VAL(tkc)); if (chobj) { chval = val_new_value(); if (!chval) { res = ERR_INTERNAL_MEM; ncx_print_errormsg(tkc, NULL, res); } else { val_init_from_template(chval, chobj); res = parse_val(tkc, chobj, chval); if (res == NO_ERR) { val_add_child(chval, val); } else { val_free_value(chval); } } } else { /* string is not a child name in this typdef */ res = ERR_NCX_DEF_NOT_FOUND; ncx_conf_exp_err(tkc, res, "identifier string"); } } else { /* token is not an identifier string */ res = ERR_NCX_WRONG_TKTYPE; ncx_conf_exp_err(tkc, res, "identifier string"); } } } /* end loop through all the child nodes */ /* expecting a right brace to finish the complex value */ if (res == NO_ERR) { res = consume_tk(tkc, TK_TT_RBRACE); if (res != NO_ERR) { ncx_conf_exp_err(tkc, res, "right brace"); return res; } } } return res; } /* parse_val */
int let_variable(const char *cmd) { char name[VAR_NAME_MAX + 1]; char *p; const char *cp; int append = 0; assert(initialized); /* currently we support only environment variables */ if(*cmd != '$') { print_msg(1, "", "Incorrect variable type"); return -1; } cmd++; /* copy variable name */ p = name; while(*cmd != '\0' && !isspace(*cmd) && *cmd != '.' && *cmd != '=' && p - name < sizeof(name) - 1) { if(*cmd != '_' && !isalnum(*cmd)) { print_msg(1, "", "Incorrect variable name"); return -1; } *p++ = *cmd++; } /* test for empty variable name */ if(p == name) { print_msg(1, "Unsupported variable name", "empty name"); return -1; } *p = '\0'; /* skip spaces */ while(isspace(*cmd)) cmd++; /* check for dot and skip it */ if(*cmd == '.') { append = 1; cmd++; } /* check for equal sign and skip it and all whitespace */ if(*cmd != '=') { print_msg(1, "Incorrect :let statement", "'=' expected"); return -1; } cmd++; while(isspace(*cmd)) cmd++; /* ensure value starts with quotes */ if(*cmd != '\'' && *cmd != '"') { print_msg(1, "Incorrect :let statement", "expected single or double quote"); return -1; } /* parse value */ cp = parse_val(cmd); if(cp == NULL) return -1; /* update environment variable */ if(append) append_envvar(name, cp); else set_envvar(name, cp); return 0; }