/* -*- c++ -*- FILE: MacroManager.cpp RCS REVISION: $Revision: 1.13 $ COPYRIGHT: (c) 1999 -- 2003 Melinda Green, Don Hatch, and Jay Berkenbilt - Superliminal Software LICENSE: Free to use and modify for non-commercial purposes as long as the following conditions are adhered to: 1) Obvious credit for the source of this code and the designs it embodies are clearly made, and 2) Ports and derived versions of 4D Magic Cube programs are not distributed without the express written permission of the authors. DESCRIPTION: Implementation of the MacroManager class */ #include "MacroManager.h" #include "History.h" #include "Math4d.h" #include "Polymgr.h" #include "Preferences.h" #include /* for isspace */ MacroManager::MacroManager(Preferences& prefs, PolygonManager4D* polymgr) : prefs(prefs), polymgr(polymgr), nmacros(0), nmacros_allocated(0), the_macros(0), the_writing_macro(0), the_reading_macro(0) { // nothing needed } MacroManager::~MacroManager() { int j; if (the_macros) { for (j = 0; j < nmacros_allocated; ++j) { delete the_macros[j]; } delete [] the_macros; } } void* MacroManager::destroy(int i) { if (!INRANGE(0 <=, i, getUIData(); delete the_macros[i]; int j; for (j = i + 1; j < nmacros; ++j) the_macros[j - 1] = the_macros[j]; --nmacros; return ui_data; } void MacroManager::create(char *name, int nrefs, int refs[MAXREFS][4]) { int j; if (!nmacros_allocated) { nmacros_allocated = 1; the_macros = new Macro*[nmacros_allocated]; for (j = 0; j < nmacros_allocated; ++j) { the_macros[j] = 0; } } if (nmacros == nmacros_allocated) { // This is less efficient than using realloc(), but it is more // C++-like, guarantees proper initialization of the new // pointers, and makes cleanup easier. Besides, we're only // copying pointers. int new_allocated = nmacros_allocated * 3 / 2 + 1; Macro** new_macros = new Macro*[new_allocated]; for (j = 0; j < nmacros_allocated; ++j) { new_macros[j] = the_macros[j]; } for (j = nmacros_allocated + 1; j < new_allocated; ++j) { new_macros[j] = 0; } nmacros_allocated = new_allocated; delete [] the_macros; the_macros = new_macros; } the_macros[nmacros] = new Macro(name, nrefs, refs, this->prefs, this->polymgr); ++nmacros; } void MacroManager::setUIData(int which, void* ui_data) { the_macros[which]->setUIData(ui_data); } void* MacroManager::getUIData(int which) { return the_macros[which]->getUIData(); } int MacroManager::findWithUIData(void* ui_data) { int result = -1; for (int i = 0; i < this->nmacros; ++i) { if (this->the_macros[i]->getUIData() == ui_data) { result = i; break; } } assert(result >= 0); return result; } void MacroManager::setMacroName(int i, char *name) { the_macros[i]->setName(name); } void MacroManager::setMacroRefs(int i, int nrefs, int refs[MAXREFS][4]) { the_macros[i]->setRefs(nrefs, refs); } // Returns true on success, false if reading and it doesn't exist or // the reference stickers don't match the macro. bool MacroManager::open(int i, int nrefs, int refs[MAXREFS][4], mode_e mode, int direction) { bool result = false; Macro* mac = the_macros[i]; if (mode == m_writing) { // direction is always forward when writing the_writing_macro = mac; result = true; } else { assert(nrefs == 3); /* BLEAH! */ if (mac->get4dMatThatRotatesThese3ToMy3( refs[0], refs[1], refs[2], the_reading_mat)) { the_reading_mat_det = DET4(the_reading_mat); /* MWAHAHAHA! */ the_reading_macro = mac; the_reading_macro_direction = direction; if (direction < 0) mac->goToEnd(); else mac->goToBeginning(); result = true; } } return result; } void MacroManager::close() { // Sometimes it happens that the user will invoke a macro // in the process of defining a new macro. Therefore // if two macros are opened, the one that should be closed first // is the one for reading. if (the_reading_macro) the_reading_macro = NULL; else the_writing_macro = NULL; } void MacroManager::setRefs(int i, int nrefs, int refs[MAXREFS][4]) { the_macros[i]->setRefs(nrefs, refs); } // Return true on success, false if not opened properly bool MacroManager::addMove(struct stickerspec *sticker, int dir, int slicesmask) { if (!the_writing_macro) return false; the_writing_macro->addMove(sticker, dir, slicesmask); return true; } // Return true on success, false if at end of the macro bool MacroManager::getMove(struct stickerspec *grip, int *direction, int *slicesmask) { bool status = false; if (the_reading_macro) { status = the_reading_macro->getMove(the_reading_macro_direction, the_reading_mat_det, the_reading_mat, grip, direction, slicesmask); } return status; } void MacroManager::dump(FILE *fp) { int i; for (i = 0; i < nmacros; ++i) { the_macros[i]->dump(fp); } } // Returns true on success bool MacroManager::read(FILE *fp) { int c; Macro* mac; int nrefs, refs[MAXREFS][4]; int face, stickerwithinface; struct stickerspec sticker; char name[1234]; char format[10]; sprintf(format, " @%%%d[^@]@(", (int)sizeof(name) - 1); sprintf(format, " @%%[^@]@("); /* ARGH! FIX THIS-- maybe the other way worked after all, check it out */ /* FIX THIS! overflow is quite likely if the final delimiter is missing in the file */ while (1) { while ((c = getc(fp)) && isspace(c)) { // nothing } if (c != '@') { ungetc(c, fp); break; } /* * scanf fails if the string is 0-length, so we need to check * for this explicitly... */ if (ungetc(getc(fp), fp) == '@') { name[0] = 0; (void)getc(fp); /* assume it's a '@' */ (void)getc(fp); /* assume it's a '(' */ } else { if (fscanf(fp, "%[^@]@(", name) != 1) break; } nrefs = 0; while (fscanf(fp, "%1d%d ", &face, &stickerwithinface) == 2) { if (nrefs >= MAXREFS) { fprintf(stderr, "Error: Too many refs for macro \"%s\"!\n", name); goto abort; } sticker.face = face; sticker.id_within_face = stickerwithinface; polymgr->fillStickerspecFromFaceAndId(&sticker); SET4(refs[nrefs], sticker.coords); nrefs++; } fscanf(fp, ")"); create(name, nrefs, refs); mac = the_macros[nmacros - 1]; assert((strcmp(mac->getName(), name) == 0)); if (!mac->readHistory(fp)) { fprintf(stderr, " (macro reading aborted.)\n"); (void)destroy(nmacros - 1); goto abort; } } return true; abort: return false; } int MacroManager::getNMacros() { return nmacros; } char * MacroManager::getMacroName(int i) { return the_macros[i]->getName(); } // Local Variables: // c-basic-offset: 4 // c-comment-only-line-offset: 0 // c-file-offsets: ((defun-block-intro . +) (block-open . 0) (substatement-open . 0) (statement-cont . +) (statement-case-open . +4) (arglist-intro . +) (arglist-close . +) (inline-open . 0)) // indent-tabs-mode: nil // End: