// here for <!ATTLIST blah> void CMUSHclientDoc::MXP_Attlist (CString strName, CString strTag) { // append attributes strTag to element strName CElement * pElement; strName.MakeLower (); // case-insensitive? // check element already defined if (!m_CustomElementMap.Lookup (strName, pElement)) { MXP_error (DBG_ERROR, errMXP_UnknownElementInAttlist, TFormat ("Cannot add attributes to undefined MXP element: <%s>", (LPCTSTR) strName)); return; } // end of no element matching CArgumentList ArgumentList; // build into an argument list if (BuildArgumentList (ArgumentList, strTag)) { DELETE_LIST (ArgumentList); return; } // add to any existing arguments - is this wise? :) pElement->AttributeList.AddTail (&ArgumentList); // nb - arguments get moved to argument list - no need to delete them } // end of CMUSHclientDoc::MXP_Attlist
TurboParserInterface::TurboParserInterface() { argc_ = 0; argv_ = NULL; BuildArgumentList(); // Initialize Google's logging library. google::InitGoogleLogging(argv_[0]); // Parse command line flags. google::ParseCommandLineFlags(&argc_, &argv_, false); #ifdef _WIN32 google::LogToStderr(); #endif }
int main(int argc, char **argv) { TextStartup(); ShowTitle(); // skip program name itself argv++, argc--; if (argc <= 0) { ShowInfo(); TextShutdown(); exit(1); } if (strcmp(argv[0], "/?") == 0 || strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "-help") == 0 || strcmp(argv[0], "--help") == 0 || strcmp(argv[0], "-HELP") == 0 || strcmp(argv[0], "--HELP") == 0) { ShowOptions(); TextShutdown(); exit(1); } BuildArgumentList(argc, argv); info = default_buildinfo; comms = default_buildcomms; if (GLBSP_E_OK != GlbspParseArgs(&info, &comms, resp_argv, resp_argc)) { TextFatalError("Error: %s\n", comms.message ? comms.message : "(Unknown error when parsing args)"); } #if 0 if (! FileExists(info.filename)) TextFatalError("Error: Cannot find WAD file: %s\n", info.filename); #endif /* process file */ if (GLBSP_E_OK != GlbspCheckInfo(&info, &comms)) { TextFatalError("Error: %s\n", comms.message ? comms.message : "(Unknown error when checking args)"); } if (info.no_progress) TextDisableProgress(); if (GLBSP_E_OK != GlbspBuildNodes(&info, &cmdline_funcs, &comms)) { TextFatalError("Error: %s\n", comms.message ? comms.message : "(Unknown error during build)"); } TextShutdown(); FreeArgumentList(); return 0; }
// here for start tag, eg. <bold> <underline> <usertag> void CMUSHclientDoc::MXP_StartTag (CString strTag) { // are we in secure mode right now? bool bSecure = MXP_Secure (); bool bNoReset = false; MXP_Restore_Mode (); // cancel secure-once mode static CArgumentList ArgumentList; CString strName; GetWord (strName, strTag); // count them m_iMXPtags++; if (!IsValidName (strName)) { MXP_error (DBG_ERROR, errMXP_InvalidElementName, TFormat ("Invalid MXP element name \"%s\" supplied.", strName)); return; } // case insensitive? strName.MakeLower (); // see if we know of this element CAtomicElement * pAtomicElement = NULL; CElement * pElement = NULL; bool bOpen; bool bCommand; POSITION atompos; // find existing styles CStyle * pStyle = m_pCurrentLine->styleList.GetTail (); unsigned short iFlags = pStyle->iFlags; COLORREF iForeColour = pStyle->iForeColour; COLORREF iBackColour = pStyle->iBackColour; CAction * pAction = pStyle->pAction; CString strAction; CString strHint; CString strVariable; // get old action, hint etc. so that something like: // <send href="nick"> <b> blah </b> </send> will work // in this case we want the href (action) to persist through the <b> if (pAction) { strAction = pAction->m_strAction; strHint = pAction->m_strHint; strVariable = pAction->m_strVariable; } // end of having an action etc. if (App.m_ElementMap.Lookup (strName, pAtomicElement)) { bOpen = (pAtomicElement->iFlags & TAG_OPEN) != 0; bCommand = (pAtomicElement->iFlags & TAG_COMMAND) != 0; bNoReset = (pAtomicElement->iFlags & TAG_NO_RESET) != 0; // check for mixing Pueblo and MXP tags /* // ALLOW BOTH for now if ((pAtomicElement->iFlags & TAG_PUEBLO) && !m_bPuebloActive) { MXP_error (DBG_ERROR, errMXP_PuebloOnly, TFormat ("Using Pueblo-only element in MXP mode: <%s>" , (LPCTSTR) strName)); return; } if ((pAtomicElement->iFlags & TAG_MXP) && m_bPuebloActive) { MXP_error (DBG_ERROR, errMXP_MXPOnly, TFormat ("Using MXP-only element in Pueblo mode: <%s>" , (LPCTSTR) strName)); return; } */ } // end of atomic element found else { if (!m_CustomElementMap.Lookup (strName, pElement)) { MXP_error (DBG_ERROR, errMXP_UnknownElement, TFormat ("Unknown MXP element: <%s>" , (LPCTSTR) strName)); return; } pAtomicElement = NULL; bOpen = pElement->bOpen; bCommand = pElement->bCommand; if (!pElement->strFlag.IsEmpty ()) strVariable = pElement->strFlag; // might have a variable to set } // end of not atomic // check for secure tags if (!bOpen && !bSecure && SECURE_ELEMENT_CHECK) { MXP_error (DBG_ERROR, errMXP_ElementWhenNotSecure, TFormat ("Secure MXP tag ignored when not in secure mode: <%s>" , (LPCTSTR) strName)); return; } if (BuildArgumentList (ArgumentList, strTag)) { DELETE_LIST (ArgumentList); return; } // call script if required for user-defined elements // atomic elements have their script called in MXP_OpenAtomicTag if ((m_dispidOnMXP_OpenTag != DISPID_UNKNOWN || m_bPluginProcessesOpenTag) && pAtomicElement == NULL) { bool bNotWanted = MXP_StartTagScript (strName, strTag, ArgumentList); // re-get current style in case the script did a world.note pStyle = m_pCurrentLine->styleList.GetTail (); // put things backt to how they were pStyle->iFlags = iFlags; pStyle->iForeColour = iForeColour; pStyle->iBackColour = iBackColour; if (bNotWanted) return; // they didn't want to go ahead with this tag } // If existing run is zero length, get rid of it, unless it // is a tag marker if (pStyle->iLength == 0 && (pStyle->iFlags & START_TAG) == 0) { DELETESTYLE (pStyle); m_pCurrentLine->styleList.RemoveTail (); } // command tags are not popped from the stack, and thus don't need a record if (!bCommand) { // add a marker to the current line for the tag itself // this is a record of what the text style was at this point AddStyle (iFlags | START_TAG, iForeColour, iBackColour, 0, strName, "", strVariable); // remember what is outstanding CActiveTag * pTag = new CActiveTag; pTag->strName = strName; pTag->bSecure = bSecure; pTag->bNoReset = bNoReset; m_ActiveTagList.AddTail (pTag); // add to outstanding tag list // warn if they are overdoing the outstanding tags if (m_ActiveTagList.GetCount () % OUTSTANDING_TAG_WARNING == 0 && m_ActiveTagList.GetCount () != m_iLastOutstandingTagCount) { MXP_error (DBG_WARNING, wrnMXP_ManyOutstandingTags, TFormat ( "Now have %i outstanding MXP tags" , m_ActiveTagList.GetCount ())); m_iLastOutstandingTagCount = m_ActiveTagList.GetCount (); } } // end of not command tag //if (strName == "ex") /* { iFlags &= ~COLOURTYPE; // clear bits, eg. custom iFlags |= COLOUR_RGB; iForeColour = 255; iBackColour = 255 * 256; } */ // now add another style entry to the line - this will have the // style adjusted for the new attributes (eg. bold) CStyle * pNewStyle = AddStyle (iFlags & STYLE_BITS, iForeColour, iBackColour, 0, NULL); // we will add the action later // atomic element? (looked-up earlier) if (pAtomicElement) { CArgument * pArgument; for (atompos = ArgumentList.GetHeadPosition (); atompos; ) { pArgument = ArgumentList.GetNext (atompos); // Walk the value for &xxx; entries if (pArgument->strValue.Find ('&') != -1) { const char * p = pArgument->strValue; const char * pStart = pArgument->strValue; CString strEntity; CString strFixedValue; strFixedValue.Empty (); long length; for ( ; *p; p++) { if (*p == '&') { // copy up to ampersand length = p - pStart; if (length > 0) strFixedValue += CString (pStart, length); p++; // skip ampersand pStart = p; // where entity starts for ( ; *p && *p != ';'; p++) // look for closing semicolon ; // just keep looking if (*p != ';') { MXP_error (DBG_ERROR, errMXP_NoClosingSemicolonInArgument, TFormat ("No closing \";\" in MXP element argument \"%s\"", (LPCTSTR) pArgument->strValue)); return; } strEntity = CString (pStart, p - pStart); // build entity, excluding & and ; // b. i. Look up entity in attribute list by name (eg. "col") CString strReplacement = "&text;"; if (strEntity != "text") strReplacement = MXP_GetEntity (strEntity); strFixedValue += strReplacement; // add to list pStart = p + 1; // move on past the entity } // end of having an ampersand } // end of processing the value strFixedValue += pStart; pArgument->strValue = strFixedValue; } // end of subsitution needed } // end of processing each argument in the atomic list MXP_OpenAtomicTag (strName, pAtomicElement->iAction, pNewStyle, strAction, strHint, strVariable, ArgumentList); // new style might have changed if they started a new line // (eg. BR) if (!m_pCurrentLine->styleList.IsEmpty ()) { pNewStyle = m_pCurrentLine->styleList.GetTail (); RememberStyle (pNewStyle); if (pNewStyle->pAction) { strAction = pNewStyle->pAction->m_strAction; strHint = pNewStyle->pAction->m_strHint; strVariable = pNewStyle->pAction->m_strVariable; } } pNewStyle->pAction = GetAction (strAction, strHint, strVariable); DELETE_LIST (ArgumentList); // clean up memory return; } // --------- end of processing for ATOMIC element ------------ // must be a user-defined element CElementItem * pElementItem; for (POSITION pos = pElement->ElementItemList.GetHeadPosition (); pos; ) { pElementItem = pElement->ElementItemList.GetNext (pos); CArgumentList BuiltArgumentList; BuiltArgumentList.RemoveAll (); /* we need to build up the arguments to the atomic element from 3 places: 1. The atom itself needs an argument list (eg. <COLOR &col;> ) 2. The user-defined element has an attribute list that lists possible arguments possibly with defaults, eg. col=red 3. The tag itself may supply values, eg. col=blue These are: 1. pElementItem->ArgumentList - what the atomic element wants 2. pElement->AttributeList - what it can get, including defaults 3. ArgumentList - what is specified on *this* tag So, I think we need to: a. Walk the atomic item's argument list b. For any entries in the form &xxx; ... 0. The special case &text; is left alone (for processing later) i. Look up the entity in the attribute list (2) above. ii. If found, go to (c). iii. Look up entity in entities map (could be < for instance) iv. If found, just replace it and continue v. If not found still, error c. If entity is found in attribute list (2) above, then: d. Look up value in supplied arguments (3) by name and position. e. If found, take supplied value. f. If not found, take default from (2) including <nothing> if applicable. Each entry gets built into BuiltArgumentList and passed down to the atomic element processing routine. */ // a. Walk the atom's list CArgument * pArgument; int iArgumentNumber = 0; for (atompos = pElementItem->ArgumentList.GetHeadPosition (); atompos; ) { pArgument = pElementItem->ArgumentList.GetNext (atompos); // b. Walk the value for &xxx; entries const char * p = pArgument->strValue; const char * pStart = pArgument->strValue; CString strEntity; CString strFixedValue; long length; strFixedValue.Empty (); for ( ; *p; p++) { if (*p == '&') { // copy up to ampersand length = p - pStart; if (length > 0) strFixedValue += CString (pStart, length); p++; // skip ampersand pStart = p; // where entity starts for ( ; *p && *p != ';'; p++) // look for closing semicolon ; // just keep looking if (*p != ';') { MXP_error (DBG_ERROR, errMXP_NoClosingSemicolonInArgument, TFormat ("No closing \";\" in MXP element argument \"%s\"", (LPCTSTR) pArgument->strValue)); return; } strEntity = CString (pStart, p - pStart); // build entity, excluding & and ; // b. i. Look up entity in attribute list by name (eg. "col") CString strReplacement = "&text;"; if (strEntity != "text") { CString strDefault; CArgument * pAttribute = NULL; int iSequence = 1; for (POSITION attpos = pElement->AttributeList.GetHeadPosition (); attpos; iSequence++) { pAttribute = pElement->AttributeList.GetNext (attpos); if (pAttribute->strName.IsEmpty ()) // no name, value is name (ie. no default) { if (pAttribute->strValue.CompareNoCase (strEntity) == 0) break; } else if (pAttribute->strName.CompareNoCase (strEntity) == 0) { strDefault = pAttribute->strValue; break; } pAttribute = NULL; // indicates it wasn't found } // end of looking for the attribute if (pAttribute) { // we now have a default and a position - look it up in the supplied arguments strReplacement = GetArgument (ArgumentList, strEntity, iSequence, false); if (strReplacement.IsEmpty ()) // empty? take default { strReplacement = strDefault; // stil empty? Warn them. if (strReplacement.IsEmpty ()) MXP_error (DBG_WARNING, wrnMXP_ArgumentNotSupplied, TFormat ("Non-default argument \"%s\" not supplied to <%s>", (LPCTSTR) strEntity, (LPCTSTR) strName )); } } // end of attribute found else strReplacement = MXP_GetEntity (strEntity); } // end of not being the entity &text; strFixedValue += strReplacement; // add to list pStart = p + 1; // move on past the entity } // end of having an ampersand } // end of processing the value strFixedValue += pStart; // add fixed argument to the built argument list CArgument * pNewArgument; if (pArgument->strName.IsEmpty ()) // just a positional argument { pNewArgument = new CArgument ("", strFixedValue, ++iArgumentNumber); BuiltArgumentList.AddTail (pNewArgument); } else { pNewArgument = new CArgument (pArgument->strName, strFixedValue, 0); BuiltArgumentList.AddTail (pNewArgument); } } // end of processing each argument in the atomic list MXP_OpenAtomicTag (pElementItem->pAtomicElement->strName, pElementItem->pAtomicElement->iAction, pNewStyle, strAction, strHint, strVariable, BuiltArgumentList); DELETE_LIST (BuiltArgumentList); // just a temporary list } // end of doing each atomic element // new style might have changed if they started a new line // (eg. BR) if (!m_pCurrentLine->styleList.IsEmpty ()) { pNewStyle = m_pCurrentLine->styleList.GetTail (); RememberStyle (pNewStyle); } // make an action for the built-up action/hint/variable pNewStyle->pAction = GetAction (strAction, strHint, strVariable); // check all arguments used CheckArgumentsUsed (strName, ArgumentList); DELETE_LIST (ArgumentList); // clean up memory } // end of CMUSHclientDoc::MXP_StartTag
int main(int argc, char **argv) { int extra_idx = 0; TextStartup(); ShowTitle(); // skip program name itself argv++, argc--; if (argc <= 0) { ShowInfo(); TextShutdown(); exit(1); } if (strcmp(argv[0], "/?") == 0 || strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "-help") == 0 || strcmp(argv[0], "--help") == 0 || strcmp(argv[0], "-HELP") == 0 || strcmp(argv[0], "--HELP") == 0) { ShowOptions(); TextShutdown(); exit(1); } BuildArgumentList(argc, argv); info = default_buildinfo; comms = default_buildcomms; if (GLBSP_E_OK != GlbspParseArgs(&info, &comms, resp_argv, resp_argc)) { TextFatalError("Error: %s\n", comms.message ? comms.message : "(Unknown error when parsing args)"); } if (info.extra_files) { int ext_j; /* catch this mistake: glbsp in.wad out.wad (forget the -o) */ if (info.input_file && info.extra_files[0] && ! info.extra_files[1] && FileExists(info.input_file) && ! FileExists(info.extra_files[0])) { TextFatalError("Error: Cannot find WAD file: %s (" "Maybe you forgot -o)\n", info.extra_files[0]); } /* balk NOW if any of the input files doesn't exist */ if (! FileExists(info.input_file)) TextFatalError("Error: Cannot find WAD file: %s\n", info.input_file); for (ext_j = 0; info.extra_files[ext_j]; ext_j++) { if (FileExists(info.extra_files[ext_j])) continue; TextFatalError("Error: Cannot find WAD file: %s\n", info.extra_files[ext_j]); } } /* process each input file */ for (;;) { if (GLBSP_E_OK != GlbspCheckInfo(&info, &comms)) { TextFatalError("Error: %s\n", comms.message ? comms.message : "(Unknown error when checking args)"); } if (info.no_progress) TextDisableProgress(); if (GLBSP_E_OK != GlbspBuildNodes(&info, &cmdline_funcs, &comms)) { TextFatalError("Error: %s\n", comms.message ? comms.message : "(Unknown error during build)"); } /* when there are extra input files, process them too */ if (! info.extra_files || ! info.extra_files[extra_idx]) break; ShowDivider(); GlbspFree(info.input_file); GlbspFree(info.output_file); info.input_file = GlbspStrDup(info.extra_files[extra_idx]); info.output_file = NULL; extra_idx++; } TextShutdown(); FreeArgumentList(); return 0; }
// here for <!ELEMENT blah> void CMUSHclientDoc::MXP_Element (CString strName, CString strTag) { static CArgumentList ArgumentList; // get arguments to !ELEMENT definition if (BuildArgumentList (ArgumentList, strTag)) { DELETE_LIST (ArgumentList); return; } CElement * pElement; bool bDelete = GetKeyword (ArgumentList, "delete"); strName.MakeLower (); // case-insensitive? // see if we know of this atom CAtomicElement * element_item; if (App.m_ElementMap.Lookup (strName, element_item)) { MXP_error (DBG_ERROR, errMXP_CannotRedefineElement, TFormat ("Cannot redefine built-in MXP element: <%s>" , (LPCTSTR) strName)); return; } // if element already defined, delete old one if (m_CustomElementMap.Lookup (strName, pElement)) { if (!bDelete) MXP_error (DBG_WARNING, wrnMXP_ReplacingElement, TFormat ("Replacing previously-defined MXP element: <%s>", (LPCTSTR) strName)); DELETE_LIST (pElement->ElementItemList); DELETE_LIST (pElement->AttributeList); delete pElement; } // end of existing element if (bDelete) return; // all done! // add new element to map m_CustomElementMap.SetAt (strName, pElement = new CElement); pElement->strName = strName; // get keywords first, so we won't mistake them for arguments // (eg. so OPEN doesn't become an argument) // look for keyword OPEN pElement->bOpen = GetKeyword (ArgumentList, "open"); // look for keyword EMPTY pElement->bCommand = GetKeyword (ArgumentList, "empty"); CString strArgument; // get definition ( <COLOR &col;> ) strArgument = GetArgument (ArgumentList, "", 1, false); // get definition // add atomic items here -------------------------- CString strAtom; const char * p = strArgument; const char * pStart; while (*p) { // check opening < if (*p != '<') { MXP_error (DBG_ERROR, errMXP_NoTagInDefinition, TFormat ("No opening \"<\" in MXP element definition \"%s\"", (LPCTSTR) strArgument)); return; } p++; // skip < pStart = p; // remember start of tag // skip <, look for > for (; *p && *p != '>'; p++) // look for closing tag { if (*p == '<') { MXP_error (DBG_ERROR, errMXP_UnexpectedDefinitionSymbol, TFormat ("Unexpected \"<\" in MXP element definition \"%s\"", (LPCTSTR) strArgument)); return; } if (*p == '\'' || *p == '\"') // quoted string? { char c = *p; // remember opening quote for (p++; *p && *p != c; p++) // look for closing quote ; // just keep looking if (*p != c) { MXP_error (DBG_ERROR, errMXP_NoClosingDefinitionQuote, TFormat ("No closing quote in MXP element definition \"%s\"", (LPCTSTR) strArgument)); return; } } // end of quoted string } // end of search for closing tag // check closing > if (*p != '>') { MXP_error (DBG_ERROR, errMXP_NoClosingDefinitionTag, TFormat ("No closing \">\" in MXP element definition \"%s\"", (LPCTSTR) strArgument)); return; } strAtom = CString (pStart, p - pStart); // build tag, excluding < and > CString strAtomName; if (GetWord (strAtomName, strAtom)) { MXP_error (DBG_ERROR, errMXP_NoDefinitionTag, TFormat ("No element name in MXP element definition \"<%s>\"", (LPCTSTR) CString (pStart, p - pStart))); return; } if (strAtomName == "/") { GetWord (strAtomName, strAtom); // try to get next word strAtomName.MakeLower (); // case insensitive? MXP_error (DBG_ERROR, errMXP_DefinitionCannotCloseElement, TFormat ("Element definitions cannot close other elements: </%s>" , (LPCTSTR) strAtomName)); return; } if (strAtomName == "!") { GetWord (strAtomName, strAtom); // try to get next word strAtomName.MakeLower (); // case insensitive? MXP_error (DBG_ERROR, errMXP_DefinitionCannotDefineElement, TFormat ("Element definitions cannot define other elements: <!%s>" , (LPCTSTR) strAtomName)); return; } strAtomName.MakeLower (); // case insensitive? // see if we know of this atom CAtomicElement * element_item; if (!App.m_ElementMap.Lookup (strAtomName, element_item)) { MXP_error (DBG_ERROR, errMXP_NoInbuiltDefinitionTag, TFormat ("Unknown MXP element: <%s>" , (LPCTSTR) strAtomName)); return; } // yes? add to list CElementItem * pElementItem = new CElementItem; if (BuildArgumentList (pElementItem->ArgumentList, strAtom)) // add arguments { // bad arguments DELETE_LIST (pElementItem->ArgumentList); delete pElementItem; return; } pElement->ElementItemList.AddTail (pElementItem ); pElementItem->pAtomicElement = element_item; // which atomic element p++; // skip > } // end of processing each atomic item // end of add atomic items -------------------------- // get attributes (COLOR=RED NAME=FRED) if (BuildArgumentList (pElement->AttributeList, GetArgument (ArgumentList, "att", 2, false))) { // bad arguments DELETE_LIST (pElement->AttributeList); return; } // get tag (TAG=22) strArgument = GetArgument (ArgumentList, "tag", 3, true); // get tag number if (IsNumeric (strArgument)) { int i = atoi (strArgument); if (i >= 20 && i <= 99) pElement->iTag = i; } // get tag (FLAG=roomname) strArgument = GetArgument (ArgumentList, "flag", 4, true); // get flag name if (!strArgument.IsEmpty ()) { /* // I won't check names right now ... if (strArgument == "roomname" || strArgument == "roomdesc" || strArgument == "roomexit" || strArgument == "roomnum" || strArgument == "prompt") pElement->strFlag = strArgument; else */ if (strArgument.Left (4) == "set ") pElement->strFlag = strArgument.Mid (4); // what variable to set else pElement->strFlag = strArgument; pElement->strFlag.TrimLeft (); pElement->strFlag.TrimRight (); // make things a bit easier - let spaces through but change to underscores pElement->strFlag.Replace (" ", "_"); // check variable name is OK if (CheckObjectName (pElement->strFlag) != eOK) { MXP_error (DBG_ERROR, errMXP_BadVariableName, TFormat ("Bad variable name \"%s\" - for MXP FLAG definition", (LPCTSTR) pElement->strFlag)); pElement->strFlag.Empty (); } } // end of having a flag DELETE_LIST (ArgumentList); } // end of CMUSHclientDoc::MXP_Element