//***************************************************************************
// MML commands handled by this file: [ ] L
//***************************************************************************
#include <stdio.h>
#include "main.h"
#include "mml_parse.h"
#include "mml_parse_loop.h"
#include "stream.h"
#include "text.h"
//***************************************************************************
// parse_repeat [internal]
// Parses repeat loops ([ ... ] command).
//---------------------------------------------------------------------------
// param mml_state: pointer to MML track's state
//---------------------------------------------------------------------------
// return: 0 on success, -1 on syntax error
//***************************************************************************
int parse_repeat(MmlState *mml_state)
{
// Find the end of the loop
const char *begin = mml_state->ptr;
const char *end = begin;
unsigned depth = 1;
for (;;) {
char ch = *end++;
// Nested repeat?
if (ch == '[') {
depth++;
continue;
}
// End of repeat loop?
if (ch == ']') {
depth--;
if (depth == 0) break;
continue;
}
// End of track data? (unclosed loop)
if (end == mml_state->endptr) {
fprintf(stderr, ERRORMSG_NOREPEATEND,
mml_state->filename,
mml_state->line_num,
mml_state->col_num);
return -1;
}
}
// Update MML state's pointer, and adjust the end of loop pointer to
// exclude the ] at the end (since we want to measure only the data
// inside the loop proper)
mml_state->ptr = end;
end--;
// Also adjust the column number for the error messages below
// This points to the ] for consistency with how the other commands
// are handled (since we pretend that ] is its own command)
mml_state->col_num += end - begin;
// How many times to repeat the loop?
int count;
if (get_number(&mml_state->ptr, &count)) {
fprintf(stderr, ERRORMSG_NOREPEATCOUNT,
mml_state->filename,
mml_state->line_num,
mml_state->col_num);
return -1;
}
if (count < 0) {
fprintf(stderr, ERRORMSG_BADREPEATCOUNT,
mml_state->filename,
mml_state->line_num,
mml_state->col_num,
count);
return -1;
}
// Now execute all the commands within the repeat loop
const char *backup_ptr = mml_state->ptr;
const char *backup_endptr = mml_state->endptr;
int errored = 0;
while (count > 0) {
count--;
mml_state->ptr = begin;
mml_state->endptr = end;
errored |= parse_mml_subloop(mml_state);
}
mml_state->ptr = backup_ptr;
mml_state->endptr = backup_endptr;
// Done
return errored;
}
//***************************************************************************
// parse_loop_point [internal]
// Parses the loop point for the entire stream (L command).
//---------------------------------------------------------------------------
// param mml_state: pointer to MML track's state
//---------------------------------------------------------------------------
// return: 0 on success, -1 on syntax error
//***************************************************************************
int parse_loop_point(MmlState *mml_state)
{
// Add set loop event
Stream *stream = mml_state->stream;
Event *event = create_event(stream);
event->type = EVENT_LOOP;
// Mark stream as looping
stream->looped = 1;
// Always succeed for now
return 0;
}