/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ //Designed specifically for pulling out command line arugments //used in the command line startup routine. This class knows //about two kinds of delimeters, spaces and quotes. Quotes //when placed in front and in back of characters delimit spaces and //any combination of any other characters. Spaces delimit quoted //strings and other non quoted strings. Error checking is flaged //on quoted string groups and non quoted string which are //not separated by a space. There is no failure continue mode. //When an error is flaged, the routine exits and signals false. //Command line parsing implementation file. #include "stdafx.h" #include "cmdparse.h" #include /************************************************************************/ //Purpose: Contructor takes two arguments to initialize the class. //Args: pszStringToParse: a pointer to the command line to parse // lStringList: A reference to the list to hold the arguments /************************************************************************/ CCmdParse::CCmdParse(char *pszStringToParse,CStringList &lStringList) { strcpy(m_szParseString,pszStringToParse); m_pStringList = &lStringList; m_nIndex = 0; } CCmdParse::CCmdParse() { m_pStringList = NULL; m_nIndex = 0; } /************************************************************************/ //Purpose: Destructor removes any objects still on the list /************************************************************************/ CCmdParse::~CCmdParse() { if(m_pStringList) { POSITION pos1,pos2; char *pTemp = NULL; if (m_pStringList->GetCount() > 0) { for( pos1 = m_pStringList->GetHeadPosition(); ( pos2 = pos1 ) != NULL; ) { m_pStringList->GetNext( pos1 ); // Save the old pointer for //deletion. m_pStringList->RemoveAt( pos2 ); } } } } /************************************************************************/ //Purpose: Initialize class members and construction has taken place /************************************************************************/ void CCmdParse::Init(char *pszStringToParse,CStringList &lStringList) { strcpy(m_szParseString,pszStringToParse); m_pStringList = &lStringList; m_nIndex = 0; } /************************************************************************/ //Purpose: Places the accumulated character in m_Token on the list in // the order they were seen, and resets m_Token. /************************************************************************/ void CCmdParse::AddNewToken() { CString strNew = m_Token; m_pStringList->AddTail(strNew); memset(m_Token,'\0',sizeof(m_Token)); m_nIndex = 0; } /************************************************************************/ //Purpose: State machine and token builder. This optionally could have // been broken down into separate modules for each state; however // due to the limited number of states and delimeters it seemed // resonable to bundle it in this function. Additional // functionality would require breaking this up into constituent // subroutines. //Called by: ProcessCmdLine(); /************************************************************************/ void CCmdParse::AddChar() { if (*m_pCurrent == '\0') { //check to see if we were in the middle of building something, //otherwise quit. if (strlen(m_Token) > 0) AddNewToken(); State = e_end; return; } if (State == e_start && (*m_pCurrent == '"')) { //we are handling a quoted string State = e_quote; Previous = e_start; ++m_pCurrent; return; } if (State == e_start && ((*m_pCurrent != '"') && (!isspace(*m_pCurrent))) ) { //we are handling a non quoted string State = e_other; Previous = e_start; return; } if (State == e_start && (isspace(*m_pCurrent))) { State = e_space; Previous = e_start; return; } if (State == e_quote && (*m_pCurrent != '"')) { //add it to the token builder m_Token[m_nIndex++] = *m_pCurrent++; return; } if (State == e_quote && (*m_pCurrent == '"')) { //we found another quote. if (*(m_pCurrent -1) == '"') { //look back and see if quotes are wrong //path names must be separated by quotes!!!! State = e_error; return; } if( !isspace(*(m_pCurrent +1)) && (*(m_pCurrent +1) != '\0') ) { //look ahead and make sure they delimeted the quoted argument State = e_error; return; } Previous = State;//not used //set the state so we know what we last saw and can expect State = e_end_quote; //add the quoted string minus the quotes AddNewToken(); return; } if (State == e_end_quote && (*m_pCurrent != '"')) { //we are expecting a space or a non quote if(isspace(*m_pCurrent)) { ++m_pCurrent; State = e_space; Previous = e_end_quote; } else { State = e_other; Previous = e_end_quote; } return; } if (State == e_end_quote && (*m_pCurrent == '"')) { //suscpicious ++m_pCurrent; return; } if (State == e_other && ((!isspace(*m_pCurrent)) && (*m_pCurrent != '"')) ) { //add it to the token builder m_Token[m_nIndex++] = *m_pCurrent++; return; } else if(State == e_other && (isspace(*m_pCurrent)) ) { //add the non quoted token AddNewToken(); Previous = e_other; if ( isspace(*m_pCurrent) ) State = e_space; else State = e_start; return; } else if(State == e_other && (*m_pCurrent == '"')) { State = e_error; return; } if (State == e_space && (!isspace(*m_pCurrent) ) ) { State = e_start; Previous = e_space; return; } if (State == e_space && (isspace(*m_pCurrent)) ) { //eat up spaces. while (isspace(*m_pCurrent)) ++m_pCurrent; return; } } /*************************************************************************/ //Purpose: Called to start command line processing. // This function is used in a very minimal sense. However, it // is prepared to grow such that more detailed errors and // potentially more states may be added to compensate for // additional delimiters. Currently it simply calls AddChar() // and waits for an error or state end. //RETURNS: True on success and False on failure. /*************************************************************************/ BOOL CCmdParse::ProcessCmdLine() { State = e_start; Previous = State; //may be used in the future m_pCurrent = &m_szParseString[0]; memset(m_Token,'\0',512); while(State != e_end) { switch(State) { // case e_error: return FALSE; default: AddChar(); } } return TRUE; }