Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ippResponseParser.cpp

Go to the documentation of this file.
00001 // 
00002 // DISCLAIMER: 
00003 //  This software was produced by the National Institute of Standards 
00004 //  and Technology (NIST), an agency of the U.S. government, and by statute is 
00005 //  not subject to copyright in the United States.  Recipients of this 
00006 //  software assume all responsibility associated with its operation,
00007 //  modification,maintenance, and subsequent redistribution. 
00008 //
00009 //  See NIST Administration Manual 4.09.07 b and Appendix I. 
00010 //
00011 #include "stdafx.h"
00012 
00013 
00014 /* ippResponseParser.cc
00015 
00016 This is a response parser for version 1.40 of the I++ DME Spec.
00017 
00018 This defines functions in the ippResponseParser class and defines a main function
00019 outside the ippResponseParser class.
00020 
00021 Functions named makeXXX (where XXX is a response name) are used to
00022 check the components of each type of response and to return an instance
00023 of the response.
00024 
00025 References to the responses are given here. The reference pages
00026 reference both text and examples. Text references are given in
00027 parentheses. Example references are given in brackets.  Other
00028 references are not enclosed.
00029 
00030 Example: Reference pages: 23 26 (39) [40] 85
00031 This means there is relevantippPtMeasOrGetResponse text on page 39 and an example on page 40.
00032 
00033 */
00034 
00035 #include "ippdme/ippChangeToolActionType.h"
00036 #include "ippdme/Property/ippOnePropertyNumber.h"
00037 #include "ippdme/Property/ippOnePropertyAlignment.h"
00038 #include "ippdme/Property/ippOnePropertyName.h"
00039 #include "ippdme/Property/ippOnePropertyId.h"
00040 #include "ippdme/Property/ippOnePropertyCollisionVolume.h"
00041 
00042 #include "ippdme/Response/ippResponse.h"
00043 #include "ippdme/Response/ippAlignResponse.h"
00044 #include "ippdme/Response/ippCenterPartResponse.h"
00045 #include "ippdme/Response/ippChangeToolEResponse.h"
00046 #include "ippdme/Response/ippEnumPropResponse.h"
00047 #include "ippdme/Response/ippErrorResponse.h"
00048 #include "ippdme/Response/ippGetChangeToolActionResponse.h"
00049 #include "ippdme/Response/ippGetCoordSystemResponse.h"
00050 #include "ippdme/Response/ippGetCsyTransformationResponse.h"
00051 #include "ippdme/Response/ippGetDMEVersionResponse.h"
00052 #include "ippdme/Response/ippGetErrStatusEResponse.h"
00053 #include "ippdme/Response/ippGetMachineClassResponse.h"
00054 #include "ippdme/Response/ippGetPropResponse.h"
00055 #include "ippdme/Response/ippGoToEResponse.h"
00056 #include "ippdme/Response/ippIsHomedResponse.h"
00057 #include "ippdme/Response/ippIsUserEnabledResponse.h"
00058 #include "ippdme/Response/ippKeyPressEResponse.h"
00059 #include "ippdme/Response/ippPtMeasEResponse.h"
00060 #include "ippdme/Response/ippPtMeasOrGetResponse.h"
00061 #include "ippdme/Response/ippScanResponse.h"
00062 #include "ippdme/Response/ippSetPropEResponse.h"
00063 #include "ippdme/Response/ippOnMoveReportEResponse.h"
00064 #include "ippdme/Response/ippStringResponse.h"
00065 #include "ippdme/Response/ippTiltCenterPartResponse.h"
00066 #include "ippdme/Response/ippTiltPartResponse.h"
00067 #include "ippdme/Response/ippAckResponse.h"
00068 #include "ippdme/Response/ippCompleteResponse.h"
00069 
00070 
00071 #include "ippdme/Parser/ippResponseParser.h"
00072 #include "ippdme/ippResponseNameStrings.h"
00073 
00074 #include "ippPatternChecker.h"
00075 #include "ippdme/misc/ippPropDefinition.h"
00076 #include "ippdme/assert.h"
00077 
00078 #include <memory>
00079 #include <iostream>
00080 #include <iomanip>
00081 using namespace ipp;
00082 
00083 
00084 #define INITSIZE 10
00085 
00086 #ifdef _DEBUG
00087 #define new DEBUG_NEW
00088 #undef THIS_FILE
00089 static char THIS_FILE[] = __FILE__;
00090 #endif
00091 
00092 
00093 
00094 //=============================================================================
00095 ippResponseParser::ippResponseParser()
00096 // ----------------------------------------------------------------------------
00097 {
00098   _itemCount = 0;
00099   _resSize = INITSIZE;
00100   _resTypes.resize(_resSize);
00101   _resKeywords.resize(_resSize);
00102   _resDoubles.resize(_resSize);
00103   _arrayIndex = 0;
00104 }
00105 
00106 //=============================================================================
00107 ippResponseParser::~ippResponseParser()
00108 // ----------------------------------------------------------------------------
00109 {
00110  
00111 }
00112 
00113 /*******************************************************************/
00114 
00115 /* ippResponseParser::getErrorMessage
00116 
00117 Returned Value : const char *
00118   If there is a problem with providing a string, this returns NULL.
00119   Otherwise, it returns the buffer argument.
00120 
00121 Called By:
00122   external functions
00123   main (in stand-alone response parser)
00124 
00125 Errors: None.
00126 
00127 This copies an error message into the buffer.
00128 
00129 The symbol for each error code is the same as the text of the error
00130 message, except that the symbol has underscores. The symbol serves as
00131 an index into the array of strings defined here. The symbols are
00132 defined in ippResponseParser.h.
00133 
00134 */
00135 
00136 std::string ippResponseParser::getErrorMessageString() const
00137 {
00138   static const char * const errorStrings[] = {
00139     "OK",
00140     "BAD CHARACTER AFTER KEYWORD",
00141     "BAD CHARACTER AFTER RESPONSE END",
00142     "BAD COORDINATE SYSTEM",
00143     "BAD E NUMBER EXPONENT MUST HAVE ONE TWO OR THREE DIGITS",
00144     "BAD ERROR CODE",
00145     "BAD GOTOPAR PROPERTY",
00146     "BAD KEYWORD",
00147     "BAD MACHINE CLASS",
00148     "BAD NUMBER MORE THAN 16 DIGITS",
00149     "BAD NUMBER NO DIGITS",
00150     "BAD NUMBER TWO DECIMAL POINTS",
00151     "BAD PTMEASPAR PROPERTY",
00152     "BAD RESPONSE ITEMS",
00153     "BAD SECOND KEYWORD",
00154     "BAD SEVENTH CHARACTER IN RESPONSE",
00155     "BAD SEVERITY",
00156     "BAD STRING",
00157     "BAD _tag CHARACTER",
00158     "BAD TEXT",
00159     "BAD THIRD KEYWORD",
00160     "BUG",
00161     "ER USED TWICE",
00162     "ERROR CODE MUST HAVE FOUR DIGITS",
00163     "FIRST ARGUMENT MUST BE SWITCH ROTATE MOVEAUTO OR MOVEMAN",
00164     "IJK USED TWICE",
00165     "IJKAct USED TWICE",
00166     "Q USED TWICE",
00167     "IJK VALUES MUST BE ZERO",
00168     "ILLEGAL SPACE",
00169     "R USED TWICE",
00170     "RESPONSE NAME MUST BE ERROR",
00171     "SEVERITY MUST HAVE ONE DIGIT",
00172     "SPACE MISSING AFTER _tag",
00173     "SPACE MISSING AT EIGHTH CHARACTER OF RESPONSE",
00174     "_tag NUMBER OUT OF RANGE FOR COMMAND _tag",
00175     "TOOL A USED TWICE",
00176     "TOOL B USED TWICE",
00177     "TOOL C USED TWICE",
00178     "VALUE MUST BE 0 OR 1",
00179     "X USED TWICE",
00180     "Y USED TWICE",
00181     "Z USED TWICE",
00182     "ZERO _tag MUST BE SERVER INITIATED RESPONSE",
00183     "Bad Property"
00184   };
00185   static char buffer[1000];
00186   if ((_responseName > -1) && (_responseName < ippResponseNameType_MAXVALUE))
00187     sprintf(buffer, "%s: %s",
00188             ippResponseNameStrings[_responseName], errorStrings[_errorCode]);
00189   else
00190     sprintf(buffer, "%s",errorStrings[_errorCode]);
00191   return buffer;
00192 }
00193 
00194 /*******************************************************************/
00195 
00196 /* parserCmd::makeArraysBigger
00197 
00198 Returned Value: None.
00199 
00200 Called By: ippResponseParser::parseArguments
00201 
00202 Rules: None.
00203 
00204 This doubles the sizes of the four arrays in which response items are stored.
00205 It also doubles resSize.
00206 
00207 This makes new arrays twice the size of the old arrays and copies the
00208 contents of the old arrays into the first half of the new arrays.
00209 The old arrays are deleted.
00210 
00211 */
00212 
00213 void ippResponseParser::makeArraysBigger()
00214 {
00215   _resSize = (2 * _resSize);
00216   _resKeywords.resize(_resSize);
00217   _resDoubles.resize(_resSize);
00218   _resTypes.resize(_resSize);
00219 }
00220 
00221 /*******************************************************************/
00222 
00223 /* ippResponseParser::makeAlignResponse
00224 
00225 Returned Value: An AlignResponse as described by the response text,
00226    or NULL if the response text is bad.
00227 
00228 Called By:  ippResponseParser::makeDataResponse
00229 
00230 Errors:
00231 1. If the response does not match either of the patterns
00232    (double, double, double)
00233    (double, double, double, double, double, double)   :
00234    BAD_RESPONSE_ITEMS.
00235 
00236 This is called when the first data character of a data response is
00237 a left parenthesis, because the only valid response which has a left
00238 parenthesis in that position is an AlignResponse.
00239 
00240 An AlignResponse responds to either an AlignTool command or an AlignPart
00241 command.
00242 
00243 Example 1. 00010 # (0.6, 0.0, 0.8)
00244 Example 2. 00010 # (1, 0, 0, 0, 0, 1)
00245 
00246 AlignPart Reference pages: 24 28 63 (95) 105
00247 AlignTool Reference pages: 24 27 29 (55) 66 70 102 107
00248 
00249 */
00250 
00251 
00252 
00253 ippResponsePtr ippResponseParser::makeAlignResponse()
00254 {
00255   _responseName = DataAlign;
00256 
00257   if (match(_resTypes,"(#,#,#)")) { 
00258     return new ippAlignResponse(_tag,
00259                   _resDoubles[1], _resDoubles[3],_resDoubles[5]);
00260 
00261   } else if (match(_resTypes,"(#,#,#,#,#,#)")) {
00262       return new ippAlignResponse(_tag,
00263                   _resDoubles[1], _resDoubles[3],_resDoubles[5],
00264                   _resDoubles[7], _resDoubles[9], _resDoubles[11] );
00265  } else {
00266     _errorCode = BAD_RESPONSE_ITEMS;
00267  }
00268   return 0;
00269 }
00270 
00271 /*******************************************************************/
00272 
00273 /* ippResponseParser::makeCenterPartResponse
00274 
00275 Returned Value: A CenterPartResponse as described by the response text,
00276    or NULL if the response text is bad.
00277 
00278 Called By: ippResponseParser::makeDataResponse
00279 
00280 Errors:
00281 1. If the response items do not match the pattern
00282    CenterPart(double)
00283    or the double is not a single character: BAD_RESPONSE_ITEMS.
00284 2. If the double is not 0 or 1: VALUE_MUST_BE_0_OR_1;
00285 
00286 This function is called when (_resTypes[0] == RESKEYWORD) and
00287 (_resKeywords[0] == CenterPart), so those conditions are not checked here.
00288 
00289 The check on _inputArray[20] ensures there is only one character between
00290 parentheses.
00291 
00292 A CenterPartResponse responds to a CenterPart command.
00293 
00294 Example 1. 00010 # CenterPart(1)
00295 
00296 Reference pages: 24 27 (96) 102
00297 
00298 */
00299 
00300 ippResponsePtr ippResponseParser::makeCenterPartResponse()
00301 {
00302   _responseName = DataCenterPart;
00303 
00304   // check the syntax
00305   if (!match(_resTypes,"k(#)")) {
00306     _errorCode = BAD_RESPONSE_ITEMS;
00307     return 0;
00308   }
00309   // check the arguments
00310   if ((_resDoubles[2] != 0) && (_resDoubles[2] != 1)) {
00311     _errorCode = VALUE_MUST_BE_0_OR_1;
00312     return 0;
00313   }
00314   bool value = ((_resDoubles[2] == 1) ? true : false);
00315 
00316   return  new ippCenterPartResponse(_tag, value);
00317 }
00318 
00319 /*******************************************************************/
00320 
00321 /* ippResponseParser::makeChangeToolEResponse
00322 
00323 Returned Value: A ChangeToolEResponse as described by the response text,
00324    or NULL if the response text is bad.
00325 
00326 Called By:  ippResponseParser::makeServerInitiatedResponse
00327 
00328 Errors:
00329   1. If the response does not have the pattern
00330      ChangeTool(string)
00331      BAD_RESPONSE_ITEMS
00332 
00333 This is called when (_resTypes[0] == RESKEYWORD) and
00334 (_resKeywords[0] == ChangeToolKey), so those conditions are not checked here.
00335 
00336 A ChangeToolE response is server-initiated and is not a response to a command.
00337 
00338 Example 1. E0000 # ChangeTool("Probe1")
00339 
00340 Reference pages: (78)
00341 
00342 */
00343 
00344 ippResponsePtr ippResponseParser::makeChangeToolEResponse()
00345 {
00346   _responseName = DataChangeToolE;
00347   // check the syntax
00348   if (!match(_resTypes,"k(s)")) {
00349     _errorCode = BAD_RESPONSE_ITEMS;
00350     return 0;
00351   }
00352         return  new ippChangeToolEResponse(_resStrings[2].c_str());
00353 }
00354 
00355 /*******************************************************************/
00356 
00357 /* ippResponseParser::makeDataResponse
00358 
00359 Returned Value: A data ippResponse of the appropriate type as described
00360    by the response text, or NULL if the response text is bad.
00361 
00362 Called By:  ippResponseParser::parseResponse
00363 
00364 Errors:
00365 1. The response items do not conform to any defined pattern of response
00366    items: BAD_RESPONSE_ITEMS.
00367 
00368 This examines the type of the first response item (and possibly other
00369 information about response items), decides what type of response it must
00370 be, and calls a subordinate function to make a response of that type.
00371 
00372 This is called if the seventh character of the response is # and the
00373 _tag is OK but is not E0000.
00374 
00375 */
00376 
00377 ippResponsePtr ippResponseParser::makeDataResponse()
00378 {
00379   ippResponsePtr aResponse;
00380 
00381   if (_resTypes[0] == RESPARENLEFT)
00382     aResponse = makeAlignResponse();
00383   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == CenterPartKey))
00384     aResponse = makeCenterPartResponse();
00385   else if ((_resTypes[0] == RESSTRING) && (_itemCount == 3))
00386     aResponse = makeEnumPropResponse();
00387   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == ChangeToolAction))
00388     aResponse = makeGetChangeToolActionResponse();
00389   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == CoordSystem))
00390     aResponse = makeGetCoordSystemResponse();
00391   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == GetCsyTr))
00392     aResponse = makeGetCsyTransformationResponse();
00393   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == DMEVersion))
00394     aResponse = makeGetDMEVersionResponse();
00395   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == ErrStatus))
00396     aResponse = makeGetErrStatusEResponse();
00397   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == GetMachineKey))
00398     aResponse = makeGetMachineClassResponse();
00399   else if (  match(_resTypes,"k.k")  && IsMainObject(_resKeywords[0],_resKeywords[2])) 
00400     aResponse = makeGetPropResponse();
00401   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == IsHomedKey))
00402     aResponse = makeIsHomedResponse();
00403   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == IsUserEnabledKey))
00404     aResponse = makeIsUserEnabledResponse();
00405   else if ((_resTypes[0] == RESKEYWORD) &&
00406            ((_resKeywords[0] == ER)  ||
00407             (_resKeywords[0] == IJK) ||
00408             (_resKeywords[0] == R)   ||
00409             (_resKeywords[0] == X)   ||
00410             (_resKeywords[0] == Y)   ||
00411             (_resKeywords[0] == Z)   ||
00412             (_resKeywords[0] == Tool)))
00413     aResponse = makePtMeasOrGetResponse();
00414   else if (_resTypes[0] == RESDOUBLE)
00415     aResponse = makeScanResponse();
00416   else if ((_resTypes[0] == RESSTRING) && (_itemCount == 1))
00417     aResponse = makeStringResponse();
00418   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == TiltCenterPartKey))
00419     aResponse = makeTiltCenterPartResponse();
00420   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == TiltPartKey))
00421     aResponse = makeTiltPartResponse();
00422   else
00423     {
00424       aResponse = NULL;
00425       _errorCode = BAD_RESPONSE_ITEMS;
00426     }
00427   return aResponse;
00428 }
00429 
00430 /*******************************************************************/
00431 
00432 /* ippResponseParser::makeEnumPropResponse
00433 
00434 Returned Value: An EnumPropResponse as described by the response text,
00435    or NULL if the response text is bad.
00436 
00437 Called By:  ippResponseParser::makeDataResponse
00438 
00439 Errors:
00440 1. If the response items do not match the pattern
00441    string, string
00442    BAD_RESPONSE_ITEMS
00443 
00444 This is called when (_itemCount == 3) and (_resTypes[0] == RESSTRING),
00445 so those conditions are not checked here.
00446 
00447 An EnumPropResponse responds to an EnumProp command or an EnumAllProp command.
00448 
00449 Example 1. 00020 # "GoToPar", "Property"
00450 
00451 EnumAllProp Reference pages: 24 26 45 (46) [74] 99
00452 EnumProp Reference pages: 24 26 29 (45) [73] 99 108 109 110 111
00453 
00454 */
00455 
00456 ippResponsePtr ippResponseParser::makeEnumPropResponse()
00457 {
00458   _responseName = DataEnumProp;
00459 
00460   if (!match(_resTypes,"s,s")) {
00461     _errorCode = BAD_RESPONSE_ITEMS;
00462     return 0;
00463   }
00464   return new ippEnumPropResponse(_tag, 
00465     _resStrings[0].c_str(), _resStrings[2].c_str());
00466 }
00467 
00468 /*******************************************************************/
00469 
00470 /* ippResponseParser::makeErrorResponse
00471 
00472 Returned Value: An ErrorResponse as described by the response text,
00473    or NULL if the response text is bad.
00474 
00475 Called By:  ippResponseParser::parseResponse
00476 
00477 Errors:
00478 1. If the response does not match the pattern
00479    keyword(double, double, string, string):
00480    BAD_RESPONSE_ITEMS.
00481 2. If the keyword is not Error: RESPONSE_NAME_MUST_BE_ERROR.
00482 3. If the first double (the severity) has more than one digit:
00483    SEVERITY_MUST_HAVE_ONE_DIGIT.
00484 4. If the second double (the error code) does not consist of four digits:
00485    ERROR_CODE_IS_MUST_HAVE_FOUR_DIGITS.
00486 5. If the severity is 4 (which happens only if the error code is not a
00487    defined error code): BAD_ERROR_CODE.
00488 6. If the error text is not the correct error text for the given error
00489    code: BAD_TEXT.
00490 7. If the severity is not the correct severity for the given error code:
00491    BAD_SEVERITY.
00492 
00493 This is called when an exclamation point follows the _tag.
00494 
00495 An ErrorResponse responds to any command whose execution causes an error.
00496 An ErrorResponse may also be server-initiated.
00497 
00498 Example 1. 00010 ! Error(3,1008, "Do", "Target position out of machine volume")
00499 Example 2. E0000 ! Error(3, 1009, "pressureCheck", "Air pressure out of range")
00500 
00501 Reference pages: 20 26 30 31 33-35 [36] 37 38 [38] 39 [39]
00502                  40 43 [43] [44] (75-76) 100 101 113
00503 These reference pages cover only the format and use of error messages.
00504 They do not cover the specific errors that can occur for each command.
00505 They do not cover ClearAllErrors, GetErrStatusE, or GetXtdErrStatus.
00506 
00507 */
00508 
00509 ippResponsePtr ippResponseParser::makeErrorResponse()
00510 {
00511   char severity;
00512   ipp::parserResErrorId  code = OK;
00513   ippErrorResponsePtr aResponse;
00514 
00515   // check the syntax
00516   if (!match(_resTypes,"k(#,#,s,s)")) {
00517     _errorCode = BAD_RESPONSE_ITEMS;
00518     return 0;
00519   }
00520   _responseName = ErrorError;
00521 
00522   if (_resKeywords[0] != ErrorKey) {
00523     _errorCode = RESPONSE_NAME_MUST_BE_ERROR;
00524 
00525   } else if (_inputArray[15] != ','){
00526     _errorCode = SEVERITY_MUST_HAVE_ONE_DIGIT;
00527 
00528   } else if (
00529      !isdigit(_inputArray[16]) ||
00530            !isdigit(_inputArray[17]) ||
00531            !isdigit(_inputArray[18]) ||
00532            !isdigit(_inputArray[19]) ||
00533      (_inputArray[20] != ',')) {
00534         _errorCode = ERROR_CODE_MUST_HAVE_FOUR_DIGITS;
00535   } else {
00536     severity = ((_resDoubles[2] == 0) ? '0' :
00537                 (_resDoubles[2] == 1) ? '1' :
00538                 (_resDoubles[2] == 2) ? '2' :
00539                 (_resDoubles[2] == 3) ? '3' :
00540                 (_resDoubles[2] == 9) ? '9' : '4');
00541     
00542    ippErrorNameType errCode = Convert2ippErrorNameType(_resDoubles[4]);
00543    
00544    aResponse = new ippErrorResponse(_tag, _tagType, errCode, _resStrings[6].c_str());
00545  
00546    std::string errTxt = aResponse->getTheError()->getText();
00547    if (aResponse->getTheError()->getSeverity() == '4') {
00548       _errorCode = BAD_ERROR_CODE;
00549 
00550     } else if ( aResponse->getTheError()->getText()!= _resStrings[8] ){
00551       _errorCode = BAD_TEXT;
00552     } else if (severity != aResponse->getTheError()->getSeverity()){
00553       _errorCode = BAD_SEVERITY;
00554     }
00555   }
00556   return ((_errorCode != OK) ? NULL : aResponse);
00557 }
00558 
00559 /*******************************************************************/
00560 
00561 /* ippResponseParser::makeGetChangeToolActionResponse
00562 
00563 Returned Value: A GetChangeToolActionResponse as described by the response
00564    text, or NULL if the response text is bad.
00565 
00566 Called By:  ippResponseParser::makeDataResponse
00567 
00568 Errors:
00569   1. The response does not have the pattern
00570      ChangeToolAction(Arg, X(<number>), Y(<number>), Z(<number>))
00571      BAD_RESPONSE_ITEMS
00572   2. The arg is not SWITCH, ROTATE, MOVEAUTO, MOVEMAN
00573      FIRST_ARGUMENT_MUST_BE_SWITCH_ROTATE_MOVEAUTO_OR_MOVEMAN
00574   
00575 This is called when (_resTypes[0] == RESKEYWORD) and
00576 (_resKeywords[0] == ChangeToolAction), so those conditions are not checked here.
00577 
00578 A ChangeToolActionResponse responds to a GetChangeToolAction command.
00579 
00580 Example 1. 00010 # ChangeToolAction(Switch, X(1), Y(2), Z(3))
00581 
00582 Reference pages: 24 27 29 (57-58) 102 106
00583 
00584 */
00585 
00586 
00587 ippResponsePtr ippResponseParser::makeGetChangeToolActionResponse()
00588 {
00589   _responseName = DataGetChangeToolAction;
00590 
00591   if (!match(_resTypes,"k(k,k(#),k(#),k(#))")) {
00592      _errorCode = BAD_RESPONSE_ITEMS;
00593      return 0;
00594   }
00595   if (_resKeywords[4] != X) {
00596     _errorCode = BAD_RESPONSE_ITEMS;
00597     return 0;
00598   }
00599   if (_resKeywords[9] != Y) {
00600     _errorCode = BAD_RESPONSE_ITEMS;
00601     return 0;
00602   }
00603   if (_resKeywords[14]!= Z) {
00604     _errorCode = BAD_RESPONSE_ITEMS;
00605     return 0;
00606   }
00607 
00608   ippChangeToolActionType action = ChangeToolActionFromKeyWord(_resKeywords[2]);
00609 
00610   if (ippChangeToolActionType_INVALID == action) {
00611     _errorCode = FIRST_ARGUMENT_MUST_BE_SWITCH_ROTATE_MOVEAUTO_OR_MOVEMAN;
00612     return 0;
00613  }
00614  return new ippGetChangeToolActionResponse(_tag,action,
00615                                           _resDoubles[6],
00616                                           _resDoubles[11],
00617                                           _resDoubles[16]);
00618 }
00619 
00620 /*******************************************************************/
00621 
00622 /* ippResponseParser::makeGetCoordSystemResponse
00623 
00624 Returned Value: A GetCoordSystemResponse as described by the response
00625    text, or NULL if the response text is bad.
00626 
00627 Called By:  ippResponseParser::makeDataResponse
00628 
00629 Errors:
00630 1. If the response items do not match the pattern
00631    CoordSystem(keyword)
00632    BAD_RESPONSE_ITEMS.
00633 2. If the keyword is not MachineCsy, MoveableMachineCsy, MultipleArmCsy
00634    or PartCsy:
00635    BAD_COORDINATE_SYSTEM.
00636 
00637 This function is called when (_resTypes[0] == RESKEYWORD) and
00638 (_resKeywords[0] == CoordSystem), so those conditions are not checked here.
00639 
00640 A GetCoordSystemResponse responds to a GetCoordSystem command.
00641 
00642 Example 1. 00010 # CoordSystem(PartCsy)
00643 
00644 Reference pages: 24 28 (59) 103
00645 
00646 */
00647 
00648 ippResponsePtr ippResponseParser::makeGetCoordSystemResponse()
00649 {
00650   _responseName = DataGetCoordSystem;
00651   if (!match(_resTypes,"k(k)")) {
00652     _errorCode = BAD_RESPONSE_ITEMS;
00653     return 0;
00654   }
00655 
00656   if ( (_resKeywords[2] < MachineCsy) ||  (_resKeywords[2] > PartCsy)) {
00657     _errorCode = BAD_COORDINATE_SYSTEM;
00658     return 0;
00659   }
00660   return ((_errorCode != OK) ? NULL :
00661           new ippGetCoordSystemResponse(_tag, (ippCoordSysType)_resKeywords[2]));
00662 }
00663 
00664 /*******************************************************************/
00665 
00666 /* ippResponseParser::makeGetCsyTransformationResponse
00667 
00668 Returned Value: A GetCsyTransformationResponse as described by the
00669    response text, or NULL if the response text is bad.
00670 
00671 Called By:  ippResponseParser::makeDataResponse
00672 
00673 Errors:
00674 1. If the response items do not match the pattern:
00675    GetCsyTransformation(double, double, double, double, double, double)
00676    BAD_RESPONSE_ITEMS.
00677 
00678 This function is called when (_resTypes[0] == RESKEYWORD) and
00679 (_resKeywords[0] == GetCsyTr), so those conditions are not checked here.
00680 
00681 A GetCsyTransformationResponse responds to a GetCsyTransformation command.
00682 
00683 Example 1. 00040 # GetCsyTransformation(1,2,3,4,5,6)
00684 
00685 Reference pages: 24 28 (60) (80) 103
00686 
00687 Note: The response does not identify the coordinate system. Release 2.1
00688 mistakenly included that.
00689 
00690 */
00691 
00692 ippResponsePtr ippResponseParser::makeGetCsyTransformationResponse()
00693 {
00694   _responseName = DataGetCsyTransformation;
00695 
00696   if (!match(_resTypes,"k(#,#,#,#,#,#)")) {
00697     _errorCode = BAD_RESPONSE_ITEMS;
00698     return 0;
00699   }
00700 
00701         return new ippGetCsyTransformationResponse(_tag,
00702                 _resDoubles[2], _resDoubles[4], _resDoubles[6],
00703                 _resDoubles[8], _resDoubles[10], _resDoubles[12]);
00704 }
00705 
00706 /*******************************************************************/
00707 
00708 /* ippResponseParser::makeGetDMEVersionResponse
00709 
00710 Returned Value: A GetDMEVersionResponse as described by the response
00711    text, or NULL if the response text is bad.
00712 
00713 Called By:  ippResponseParser::makeDataResponse
00714 
00715 Errors:
00716 1. If the response items do not match the pattern
00717    DMEVersion(string)
00718    BAD_RESPONSE_ITEMS.
00719 
00720 This is called when (_resTypes[0] == RESKEYWORD) and
00721 (_resKeywords[0] == DMEVersion), so those conditions are not checked here.
00722 
00723 A GetDMEVersionResponse responds to a GetDMEVersion command.
00724 
00725 Example 1. 00010 # DMEVersion("1.3.9")
00726 
00727 Reference pages: 24 26 (46) [47] 99
00728 
00729 */
00730 
00731 ippResponsePtr ippResponseParser::makeGetDMEVersionResponse()
00732 {
00733   _responseName = DataGetDMEVersion;
00734   if (!match(_resTypes,"k(s)")) {
00735     _errorCode = BAD_RESPONSE_ITEMS;
00736     return 0;
00737   }
00738   return ((_errorCode != OK) ? NULL :
00739           new ippGetDMEVersionResponse(_tag, _resStrings[2].c_str()));
00740 }
00741 
00742 /*******************************************************************/
00743 
00744 /* ippResponseParser::makeGetErrStatusEResponse
00745 
00746 Returned Value: A GetErrStatusResponse as described by the response
00747    text, or NULL if the response text is bad.
00748 
00749 Called By:  ippResponseParser::makeDataResponse
00750 
00751 Errors:
00752 1. If the response items do not match the pattern
00753    ErrStatus(double)
00754    or the double does not consist of a single character:
00755    BAD_RESPONSE_ITEMS.
00756 2. If the double is not 0 or 1: VALUE_MUST_BE_0_OR_1.
00757 
00758 This is called when (_resTypes[0] == RESKEYWORD) and
00759 (_resKeywords[0] == ErrStatus), so those conditions are not checked here.
00760 
00761 The check on _inputArray[19] ensures there is only one character between
00762 parentheses.
00763 
00764 A GetErrStatusEResponse responds to a GetErrStatusE command.
00765 
00766 Example 1. E0010 # ErrStatus(1)
00767 
00768 Reference pages: 24 27 (50) 102
00769 
00770 */
00771 
00772 ippResponsePtr ippResponseParser::makeGetErrStatusEResponse()
00773 {
00774   _responseName = DataGetErrStatusE;
00775   
00776   if (!match(_resTypes,"k(#)")) {
00777     _errorCode = BAD_RESPONSE_ITEMS;
00778     return 0;
00779   }
00780 
00781   if ((_resDoubles[2] != 0) && (_resDoubles[2] != 1)) {
00782     _errorCode = VALUE_MUST_BE_0_OR_1;
00783   }
00784   
00785   bool value = (_resDoubles[2]==1) ? true : false;
00786 
00787   return  new ippGetErrStatusEResponse(_tag, value);
00788 }
00789 
00790 /*******************************************************************/
00791 
00792 /* ippResponseParser::makeGetMachineClassResponse
00793 
00794 Returned Value: A GetMachineClassResponse as described by the response
00795    text, or NULL if the response text is bad.
00796 
00797 Called By:  ippResponseParser::makeDataResponse
00798 
00799 Errors:
00800 1. If the response items do not match the pattern
00801    MachineClass(value)
00802    BAD_RESPONSE_ITEMS.
00803 2. If the value is not CartCMM or CartCMMWithRotaryTable
00804    BAD_MACHINE_CLASS.
00805 
00806 This is called when (_resTypes[0] == RESKEYWORD) and
00807 (_resKeywords[0] == GetMachineKey), so those conditions are not checked here.
00808 
00809 A GetMachineClassResponse responds to a GetMachineClass command.
00810 
00811 Example 1. 00010 # GetMachineClass(CartCMM)
00812 
00813 Reference pages: 18 24 27 (50) 102
00814 
00815 */
00816 
00817 ippResponsePtr ippResponseParser::makeGetMachineClassResponse()
00818 {
00819   _responseName = DataGetMachineClass;
00820 
00821   if (!match(_resTypes,"k(k)")) {
00822     _errorCode = BAD_RESPONSE_ITEMS;
00823     return 0;
00824   }
00825 
00826   ippMachineClassType machineType = MachineClassTypeFromKeyWord(_resKeywords[2]);
00827   if (machineType ==ippMachineClassType_INVALID) { 
00828     _errorCode = BAD_MACHINE_CLASS;
00829     return 0;
00830 
00831   }
00832   return new ippGetMachineClassResponse(_tag,machineType);
00833 }
00834 
00835 /*******************************************************************/
00836 
00837 /* ippResponseParser::makeGetPropResponse
00838 
00839 Returned Value: A GetPropResponse as described by the response text,
00840    or NULL if the response text is bad.
00841 
00842 Called By:  ippResponseParser::makeDataResponse
00843 
00844 Errors:
00845 1. There must be at least one argument, and each argument must have at
00846    least six components and begin with the pattern:
00847    key1.key2 ...
00848    in which key1 is Tool or FoundTool.
00849    BAD_RESPONSE_ITEMS
00850 2. If key1 is Tool, key2 must be Alignment, CollisionVolume, Name,
00851    Id, GoToPar, or PtMeasPar.
00852    If key1 is FoundTool, key2 must be Name, Id, GoToPar, or PtMeasPar.
00853    BAD_SECOND_KEYWORD
00854 
00855 This is called when (_resTypes[0] == RESKEYWORD) and
00856 ((_resKeywords[0] == Tool) or (_resKeywords[0] == FoundTool))
00857 [except when _resKeywords[2] is A, B, or C].
00858 
00859 A GetPropResponse responds to a GetProp or GetPropE command.
00860 
00861 Example 1. 00010 # Tool.GoToPar.Speed(30), Tool.GoToPar.Speed.Act(30)
00862 
00863 Reference pages: 24 26 29 (45) 66 67 [68] [69] 70 [73] [74] 77 79 99 108
00864 
00865 Notes:
00866 
00867 oneProps1 may be larger than necessary, so it is copied to
00868 oneProps2 for making the GetPropResponse.
00869 
00870 Each of the makeOnePropertyXXX functions resets n to be the index of
00871 the next item to be parsed. If there is no next item, the "for" loop
00872 terminates. 
00873 
00874 */
00875 
00876 ippResponsePtr ippResponseParser::makeGetPropResponse()
00877 {
00878 
00879   _responseName = DataGetProp;
00880 
00881   ippGetPropResponsePtr response = new ippGetPropResponse(_tag, _tagType);
00882   
00883 
00884   for (int n = 0; ((n < _itemCount) && (_errorCode == OK)); ) {
00885 
00886     ippOtherKeyType key1 = EmptyKey; 
00887     ippOtherKeyType key2 = EmptyKey; 
00888     ippOtherKeyType key3 = EmptyKey; 
00889     ippOtherKeyType key4 = EmptyKey;
00890     double value = 0;
00891     
00892     int m=n;
00893     bool foundPropertyNumber = false;
00894 /*    if(match(_resTypes,"k(#)",m)) { 
00895       key1 =  _resKeywords[m];
00896       value = _resDoubles[m+2];
00897       foundPropertyNumber = true;
00898       n = (m + 5);
00899     } else
00900     */
00901     if(match(_resTypes,"k.k(#)",m)) { 
00902       key1 =  _resKeywords[m];
00903       key2 =  _resKeywords[m+2];
00904       value = _resDoubles[m+4];
00905       foundPropertyNumber = true;
00906       n = (m + 7);
00907     } else if(match(_resTypes,"k.k.k(#)",m)) { 
00908       key1 =  _resKeywords[m];
00909       key2 =  _resKeywords[m+2];
00910       key3 =  _resKeywords[m+4];
00911       value = _resDoubles[m+6];
00912       foundPropertyNumber = true;
00913       n = (m + 9);
00914     } else if(match(_resTypes,"k.k.k.k(#)",m)) { 
00915       key1 =  _resKeywords[m];
00916       key2 =  _resKeywords[m+2];
00917       key3 =  _resKeywords[m+4];
00918       key4 =  _resKeywords[m+6];
00919       value = _resDoubles[m+8];
00920       foundPropertyNumber = true;
00921       n = (m + 11);
00922     }  
00923     if (foundPropertyNumber) {
00924       ippProp prop(key1,key2,key3,key4);
00925       if (!PropertyIsDouble(prop)) {
00926         _errorCode = BAD_PROPERTY;
00927       }
00928       ippOnePropertyPtr r = new ippOnePropertyNumber(prop,value);
00929       response->append(r);
00930       
00931     } else if (_resKeywords[n + 2] == Alignment){      
00932       response->append(makeOnePropertyAlignment(&n));
00933     } else if (_resKeywords[n+2 ] == AlignmentVolume ) { 
00934       response->append(makeOnePropertyAlignmentVolume(&n));
00935     } else if (_resKeywords[n + 2] == CollisionVolume){
00936       response->append(makeOnePropertyCollisionVolume(&n));
00937     } else if (_resKeywords[n + 2] == Name) {
00938             response->append(makeOnePropertyName(&n));
00939     } else if (_resKeywords[n + 2] == Id){
00940             response->append(makeOnePropertyId(&n));
00941     } else { 
00942             _errorCode = BAD_SECOND_KEYWORD;
00943     }
00944   }
00945   if (_errorCode != OK) {
00946     response =0;
00947   }
00948   return response;
00949 }
00950 
00951 /*******************************************************************/
00952 
00953 /* ippResponseParser::makeGoToEResponse
00954 
00955 Returned Value: A GoToEResponse as described by the response text,
00956    or NULL if the response text is bad.
00957 
00958 Called By:  ippResponseParser::makeServerInitiatedResponse
00959 
00960 Errors:
00961 1. The response does not have the pattern
00962    GoTo(<data items>)
00963    BAD_RESPONSE_ITEMS
00964 2. There are not one to nine data items.
00965    BAD_RESPONSE_ITEMS
00966 3. A data item is not one of: ER(double), IJK(double, double, double),
00967    R(double), X(double), Y(double), Z(double), Tool.A(double),
00968    Tool.B(double), or Tool.C(double).
00969    BAD_RESPONSE_ITEMS
00970 4. An allowed data item appears more than once.
00971    ER_ARGUMENT_USED_TWICE
00972    IJK_ARGUMENT_USED_TWICE
00973    R_ARGUMENT_USED_TWICE
00974    X_ARGUMENT_USED_TWICE
00975    Y_ARGUMENT_USED_TWICE
00976    Z_ARGUMENT_USED_TWICE
00977    TOOL_A_ARGUMENT_USED_TWICE
00978    TOOL_B_ARGUMENT_USED_TWICE
00979    TOOL_C_ARGUMENT_USED_TWICE
00980 5. IJK is used but the not all three doubles are zero.
00981    IJK_VALUES_MUST_BE_ZERO
00982 6. Commas do not separate the response items if there are two or more.
00983    BAD_RESPONSE_ITEMS
00984 
00985 This is called when (_resTypes[0] == RESKEYWORD) and
00986 (_resKeywords[0] == GoToKey), so those conditions are not checked here.
00987 
00988 A GoToE response is server-initiated and is not a response to a command.
00989 
00990 Example 1. E0000 # GoTo(X(15), Z(-0.09))
00991 
00992 server-initiated GoTo Reference pages: (78)
00993 other GoTo Ref. pages : 24 27 [38] [43] (51 - 53) (58) (62) [71] [72] (98) 102
00994 OnPtMeas Report Ref. pages: 24 27 (41) (49) (52) (53) 61 [71] [72] (78) 102
00995 
00996 Notes:
00997 
00998 The spec provides that a server-initiated GoTo response should use the
00999 same format inside the GoTo(..) as a response to an OnPtMeasReport command,
01000 so that is done here. The body of this function is very similar to the body
01001 of makePtMeasOrGetResponse.
01002 
01003 */
01004 
01005 ippResponsePtr ippResponseParser::makeGoToEResponse()
01006 {
01007   int n; // index for components of response items
01008   bool hasER = false;
01009   bool hasIJK = false;
01010   bool hasR = false;
01011   bool hasToolA = false;
01012   bool hasToolB = false;
01013   bool hasToolC = false;
01014   bool hasX = false;
01015   bool hasY = false;
01016   bool hasZ = false;
01017   double ERvalue = 0;
01018   double Rvalue = 0;
01019   double toolAvalue = 0;
01020   double toolBvalue = 0;
01021   double toolCvalue = 0;
01022   double Xvalue = 0;
01023   double Yvalue = 0;
01024   double Zvalue = 0;
01025   double Ivalue = 0;
01026   double Jvalue = 0;
01027   double Kvalue = 0;
01028   _responseName = DataGoToE;
01029 
01030 
01031 
01032   if (_resTypes[1] != RESPARENLEFT) {
01033     _errorCode = BAD_RESPONSE_ITEMS;
01034   }
01035   if (_resTypes[_itemCount-1] != RESPARENRIGHT) {
01036     _errorCode = BAD_RESPONSE_ITEMS;
01037   }
01038 
01039   for (n = 2; ((n < _itemCount) && (_errorCode == OK)); ) {
01040    
01041     int old_n=n;
01042    CheckOptionalArgument(n,hasER,ER,ERvalue,ER_USED_TWICE);
01043    CheckOptionalArgument(n,hasX, _X,Xvalue ,X_USED_TWICE);
01044    CheckOptionalArgument(n,hasY, _Y,Yvalue ,Y_USED_TWICE);
01045    CheckOptionalArgument(n,hasZ, _Z,Zvalue ,Z_USED_TWICE);
01046    CheckOptionalArgument(n,hasR, _R,Rvalue ,R_USED_TWICE);
01047    CheckOptionalArgument(n,hasToolA,Tool,_A,toolAvalue ,TOOL_A_USED_TWICE);
01048    CheckOptionalArgument(n,hasToolB,Tool,_B,toolBvalue ,TOOL_B_USED_TWICE);
01049    CheckOptionalArgument(n,hasToolC,Tool,_C,toolCvalue ,TOOL_C_USED_TWICE);
01050    CheckOptionalArgument(n,hasIJK  ,_IJK, Ivalue,Jvalue,Kvalue,IJK_USED_TWICE);
01051   //xx CheckOptionalArgument(n,hasIJKAct,_IJKAct, IJKActvalue,IJK_USED_TWICE);
01052      if (old_n == n && _errorCode == OK) { 
01053       // the argument has not been recognized:
01054       _errorCode = BAD_RESPONSE_ITEMS;
01055    }
01056  }
01057 
01058  if (hasIJK) { 
01059    if (Ivalue!=0 || Jvalue !=0 || Kvalue!=0 ){
01060      _errorCode = IJK_VALUES_MUST_BE_ZERO;
01061    }
01062  }
01063   return ((_errorCode != OK) ? NULL:
01064           new ippGoToEResponse(hasER, hasIJK, hasR, hasToolA, hasToolB, hasToolC,
01065                             hasX, hasY, hasZ, ERvalue, Rvalue, toolAvalue,
01066                             toolBvalue, toolCvalue, Xvalue, Yvalue, Zvalue));
01067 }
01068 
01069 /*******************************************************************/
01070 
01071 /* ippResponseParser::makeIsHomedResponse
01072 
01073 Returned Value: An IsHomedResponse as described by the response
01074    text, or NULL if the response text is bad.
01075 
01076 Called By:  ippResponseParser::makeDataResponse
01077 
01078 Errors:
01079 1. If the response items do not match the pattern
01080    IsHomed(double)
01081    or the double is not a single character: BAD_RESPONSE_ITEMS.
01082 2. If the double is not 0 or 1: VALUE_MUST_BE_0_OR_1.
01083 
01084 This is called when (_resTypes[0] == RESKEYWORD) and
01085 (_resKeywords[0] == IsHomedKey), so those conditions are not checked here.
01086 
01087 An IsHomedResponse responds to an IsHomed command.
01088 
01089 Example 1. 00010 # IsHomed(1)
01090 
01091 Reference pages: 24 27 (48) 102 111
01092 
01093 Notes:
01094 
01095 The check on _inputArray[17] ensures there is only one character between
01096 parentheses.
01097 
01098 */
01099 
01100 ippResponsePtr ippResponseParser::makeIsHomedResponse()
01101 {
01102   _responseName = DataIsHomed;
01103 
01104    // check the syntax
01105   if (!match(_resTypes,"k(#)")) {
01106     _errorCode = BAD_RESPONSE_ITEMS;
01107     return 0;
01108   }
01109   // check the arguments
01110   if ((_resDoubles[2] != 0) && (_resDoubles[2] != 1)) {
01111     _errorCode = VALUE_MUST_BE_0_OR_1;
01112     return 0;
01113   }
01114   bool value = ((_resDoubles[2] == 1) ? true : false);
01115   return ((_errorCode != OK) ? NULL :
01116           new ippIsHomedResponse(_tag, value));
01117 }
01118 
01119 /*******************************************************************/
01120 
01121 /* ippResponseParser::makeIsUserEnabledResponse
01122 
01123 Returned Value: An IsUserEnabledResponse as described by the response
01124    text, or NULL if the response text is bad.
01125 
01126 Called By:  ippResponseParser::makeDataResponse
01127 
01128 Errors:
01129 1. If the response items do not match the pattern
01130    IsUserEnabled(double)
01131    or the double is not a single character: BAD_RESPONSE_ITEMS.
01132 2. If the double is not 0 or 1: VALUE_MUST_BE_0_OR_1.
01133 
01134 This is called when (_resTypes[0] == RESKEYWORD) and
01135 (_resKeywords[0] == IsUserEnabledKey), so those conditions are not checked
01136 here.
01137 
01138 Example 1. 00010 # IsUserEnabled(1)
01139 
01140 Reference pages: 24 27 (49) 102
01141 
01142 Notes:
01143 
01144 The check on _inputArray[23] ensures there is only one character between
01145 parentheses.
01146 
01147 */
01148 
01149 ippResponsePtr ippResponseParser::makeIsUserEnabledResponse()
01150 {
01151   _responseName = DataIsUserEnabled;
01152 
01153   // check the syntax
01154   if (!match(_resTypes,"k(#)")) {
01155   _errorCode = BAD_RESPONSE_ITEMS;
01156   return 0;
01157   }
01158   // check the arguments
01159   if ((_resDoubles[2] != 0) && (_resDoubles[2] != 1)) {
01160     _errorCode = VALUE_MUST_BE_0_OR_1;
01161     return 0;
01162   }
01163 
01164   bool value = ((_resDoubles[2] == 1) ? true : false);
01165 
01166   return ((_errorCode != OK) ? NULL :
01167           new ippIsUserEnabledResponse(_tag, value));
01168 }
01169 
01170 /*******************************************************************/
01171 
01172 /* ippResponseParser::makeKeyPressEResponse
01173 
01174 Returned Value: A KeyPressEResponse as described by the response text,
01175    or NULL if the response text is bad.
01176 
01177 Called By:  ippResponseParser::makeServerInitiatedResponse
01178 
01179 Errors:
01180 1. The response does not have the pattern
01181    KeyPress(string)
01182    BAD_RESPONSE_ITEMS
01183 
01184 This is called when (_resTypes[0] == RESKEYWORD) and
01185 (_resKeywords[0] == KeyPress), so those conditions are not checked here.
01186 
01187 A KeyPressEResponse is server-initiated and is not a response to a command.
01188 
01189 Example 1. E0000 # KeyPress("F1")
01190 
01191 Reference pages: (78-79)
01192 
01193 */
01194 
01195 ippResponsePtr ippResponseParser::makeKeyPressEResponse()
01196 {
01197   _responseName = DataKeyPressE;
01198 
01199   if (!match(_resTypes,"k(s)")) {
01200     _errorCode = BAD_RESPONSE_ITEMS;
01201     return 0;
01202   }
01203 
01204   return ((_errorCode != OK) ? NULL :
01205           new ippKeyPressEResponse(_resStrings[2].c_str()));
01206 }
01207 
01208 /*******************************************************************/
01209 
01210 /* ippResponseParser::makeOnePropertyAlignment
01211 
01212 Returned Value: A OnePropertyAlignment as described by the response
01213   items, or NULL if the response items are bad.
01214 
01215 Called By:  ippResponseParser::makeGetPropResponse
01216 
01217 Errors:
01218   1. The argument does not have one of the two patterns
01219      Tool.Alignment(double, double, double)
01220      Tool.Alignment(double, double, double, double, double, double)
01221      BAD_RESPONSE_ITEMS
01222   2. There are more response items after this argument, but the next
01223      response item is not a comma.
01224      BAD_RESPONSE_ITEMS
01225 
01226 This is called by makeGetPropResponse when an argument starts with
01227 Tool.Alignment, so the first three response items are not checked here.
01228 
01229 Example 1. Tool.Alignment(0.0, 0.6, 0.8)
01230 
01231 Reference pages: 24 29 (70) 107
01232 
01233 Notes:
01234 
01235 This resets *n to (*n + 11) or (*n + 17), since, including a comma,
01236 this function handles 11 or 17 response items. These settings are OK
01237 when the end of the response items has been reached and there is no
01238 comma, since the loop in makeGetPropResponse will stop in that case.
01239 
01240 It is known that there are at least five more response items to be parsed
01241 when this is called, the first of which (Tool or FoundTool) has index *n.
01242 
01243 */
01244 
01245 ippOnePropertyAlignmentPtr ippResponseParser::makeOnePropertyAlignment(
01246   int* n
01247 )
01248 {
01249 
01250   int m = *n;
01251   if ( _resKeywords[m]!=ipp::Tool  && _resKeywords[m]!=ipp::FoundTool ) { 
01252     _errorCode = BAD_SECOND_KEYWORD;
01253     return 0;
01254   }
01255 
01256   if (match(_resTypes,"k.k(#,#,#)",m)) {
01257     *n = (m + 11);
01258           return new ippOnePropertyAlignment(
01259                     _resKeywords[m],
01260                     _resDoubles[m + 4], _resDoubles[m + 6],_resDoubles[m + 8]);
01261 
01262   } else if (match(_resTypes,"k.k(#,#,#,#,#,#)",m)) {
01263 
01264     *n = (m + 17);
01265           return new ippOnePropertyAlignment(
01266                     _resKeywords[m],
01267                     _resDoubles[m + 4], _resDoubles[m + 6], _resDoubles[m + 8], 
01268                     _resDoubles[m + 10],_resDoubles[m + 12], _resDoubles[m + 14]);
01269   } 
01270 
01271         _errorCode = BAD_RESPONSE_ITEMS;
01272   
01273   return 0;
01274 }
01275 ippOnePropertyAlignmentVolumePtr ippResponseParser::makeOnePropertyAlignmentVolume(
01276   int* n
01277 )
01278 {
01279 
01280   int m = *n;
01281 
01282   if (match(_resTypes,"k.k(k,#,#,#,#)",m)) {
01283     *n = (m + 15);
01284     if ( _resKeywords[m]!=ipp::Tool  && _resKeywords[m]!=ipp::FoundTool ) { 
01285       _errorCode = BAD_SECOND_KEYWORD;
01286       return 0;
01287     }
01288           return new ippOnePropertyAlignmentVolume(
01289             _resKeywords[m],
01290             _resDoubles[m + 6], _resDoubles[m + 8],
01291             _resDoubles[m + 10],_resDoubles[m + 12]);
01292 
01293   } 
01294 
01295         _errorCode = BAD_RESPONSE_ITEMS;
01296   
01297   return 0;
01298 }
01299 /*******************************************************************/
01300 
01301 /* ippResponseParser::makeOnePropertyCollisionVolume
01302 
01303 Returned Value: A OnePropertyCollisionVolume as described by the response
01304   items, or NULL if the response items are bad.
01305 
01306 Called By:  ippResponseParser::makeGetPropResponse
01307 
01308 Errors:
01309   1. The argument being parsed does not have the pattern
01310      Tool.CollisionVolume(OBB,double<15 times>, ... OBB,double<15 times>)
01311      or the pattern Tool.CollisionVolume(), indicating no boxes
01312      BAD_RESPONSE_ITEMS
01313   2. There are more response items after this argument, but the next
01314      response item is not a comma.
01315      BAD_RESPONSE_ITEMS
01316 
01317 This is called by makeGetPropResponse when an argument starts with
01318 Tool.CollisionVolume, so the first three response items are not checked here.
01319 
01320 Example 1. Tool.CollisionVolume(OBB,150,10,530,50,50,50,1,0,0,0,1,0,0,0,1),
01321 
01322 Example 2. Tool.CollisionVolume(),
01323 
01324 Reference pages: 24 29 (67-70) [68] [69] 107
01325 
01326 Notes:
01327 
01328 This resets *n to (*n + 6) if there are no boxes and to (*n + 5 + (m *
01329 32)) where m > 0 is the number of boxes in the CollisionVolume, since,
01330 including a comma at the end, this function handles 6 or (5 + (m * 32)
01331 response items. This setting is OK when the end of the response items
01332 has been reached and there is no comma, since the loop in
01333 makeGetPropResponse will stop in that case.
01334 
01335 It is known that there are at least five more response items to be
01336 parsed when this is called, the first of which (Tool) has index *n.
01337 
01338 */
01339 // ER note : for some reason the compiler of VC6 doesn't optimise this function
01340 //           very well and cause this code to misinterpret the 
01341 //           _resTypes[k + 1] != RESKEYWORD)
01342 #if _MSC_VER <= 1200
01343 #ifndef _DEBUG
01344 #pragma message("Turning  compiler optimisation off to make makeOnePropertyCollisionVolume work ")
01345 #pragma optimize("",off)
01346 #endif
01347 
01348 #endif
01349 
01350 ippOnePropertyCollisionVolumePtr 
01351 ippResponseParser::makeOnePropertyCollisionVolume(int * n)
01352 {
01353   
01354   ippOtherKeyType _keyword = _resKeywords[*n];
01355   if ( _keyword!=ipp::Tool  && _keyword!=ipp::FoundTool ) { 
01356     _errorCode = BAD_SECOND_KEYWORD;
01357     return 0;
01358   }
01359   int m =0;       // number of boxes
01360 
01361 
01362   int j = 0;       // utility counter
01363   
01364   std::vector<ippBox> boxes; // array of boxes
01365   
01366   int k = (*n + 3);// index for response items
01367   if (_resTypes[k] != RESPARENLEFT) {
01368     _errorCode = BAD_RESPONSE_ITEMS;
01369 
01370   } else if (_resTypes[k + 1] == RESPARENRIGHT) {
01371 
01372     *n = (*n + 6);
01373     m = 0;
01374     if ((_itemCount != (k + 2)) && (_resTypes[k + 2] != RESCOMMA)){
01375             _errorCode = BAD_RESPONSE_ITEMS;  
01376     }
01377 
01378   } else {
01379   
01380     while(_errorCode == OK) {
01381      
01382       m++;
01383       
01384       //xx dump_token(k+1);
01385 
01386             if (_resTypes[k + 1] != RESKEYWORD)  {
01387          // the next element must be  a KEYWORD
01388                _errorCode = BAD_RESPONSE_ITEMS;
01389       } else if (_resKeywords[k + 1] != OBB) {
01390         // .. and should be a OBB keyword 
01391               _errorCode = BAD_RESPONSE_ITEMS;
01392       } else if (_itemCount < (k + 32) ) {
01393         // let check if there is enough parameters to form a valid OBB block
01394               _errorCode = BAD_RESPONSE_ITEMS;
01395       }
01396 
01397             if (_errorCode == OK) {
01398         // verify that we have a suite of 15 time [ comma double 
01399               k +=  2;
01400 
01401               for (j = 0; j < 30; j = (j + 2)) {
01402                       if ((_resTypes[k + j] != RESCOMMA) ||
01403             (_resTypes[k + j + 1] != RESDOUBLE)) {
01404                           _errorCode = BAD_RESPONSE_ITEMS;
01405           }
01406                     }
01407             }
01408 
01409             if (_errorCode == OK) { 
01410 
01411         if (_resTypes[k + 30] == RESPARENRIGHT) {
01412            // this was the last OBB block in the string
01413                  break;
01414         } else if (_resTypes[k + 30] != RESCOMMA) {
01415            // if not last we expect a comma again
01416                 _errorCode = BAD_RESPONSE_ITEMS;
01417         } else {
01418           // everything is fine, lets seek for the next OBB sequence
01419                 k += 30;
01420         }
01421             }
01422           }
01423     if (_errorCode == OK) {
01424       if ((_itemCount != (k + 31)) && (_resTypes[k + 31] != RESCOMMA)){
01425               _errorCode = BAD_RESPONSE_ITEMS;
01426       }
01427           }
01428     if (_errorCode == OK) {
01429            
01430       k = (*n + 6);
01431            
01432             for (j = 0; j < m; j++) {
01433         ippBox box;
01434               box.Cx = _resDoubles[k + 0];
01435               box.Cy = _resDoubles[k + 2];
01436               box.Cz = _resDoubles[k + 4];
01437               box.Ex = _resDoubles[k + 6];
01438               box.Ey = _resDoubles[k + 8];
01439               box.Ez = _resDoubles[k + 10];
01440               box.Ix = _resDoubles[k + 12];
01441               box.Iy = _resDoubles[k + 14];
01442               box.Iz = _resDoubles[k + 16];
01443               box.Jx = _resDoubles[k + 18];
01444               box.Jy = _resDoubles[k + 20];
01445               box.Jz = _resDoubles[k + 22];
01446               box.Kx = _resDoubles[k + 24];
01447               box.Ky = _resDoubles[k + 26];
01448               box.Kz = _resDoubles[k + 28];
01449         boxes.push_back(box);
01450 
01451               k = (k + 32);
01452             }
01453           } 
01454     *n = (*n + 5 + (m * 32));
01455   }
01456   return ((_errorCode != OK) ? NULL :
01457           new ippOnePropertyCollisionVolume(_keyword, boxes));
01458 }
01459 
01460 /*******************************************************************/
01461 
01462 /* ippResponseParser::makeOnePropertyId
01463 
01464 Returned Value: A OnePropertyId as described by the response
01465   items, or NULL if the response items are bad.
01466 
01467 Called By:  ippResponseParser::makeGetPropResponse
01468 
01469 Errors:
01470   1. The argument being parsed does not have either pattern
01471      Tool.Id(string) or FoundTool.Id(string)
01472      BAD_RESPONSE_ITEMS
01473   2. There are more response items after this argument, but the next
01474      response item is not a comma.
01475      BAD_RESPONSE_ITEMS
01476 
01477 
01478 This is called by makeGetPropResponse when an argument starts with Tool.Id
01479 or FoundTool.Id, so the first three response items are not checked here.
01480 
01481 Example 1. Tool.Id("123")
01482 
01483 Reference pages: 24 29 (66) 107
01484 
01485 Notes:
01486 
01487 This resets *n to (*n + 7), since, including a comma, this function
01488 handles seven response items. This setting is OK when the end of the
01489 response items has been reached and there is no comma, since the loop
01490 in makeGetPropResponse will stop in that case.
01491 
01492 It is known that there are at least five more response items to be
01493 parsed when this is called, the first of which (Tool or FoundTool)
01494 has index *n.
01495 
01496 */
01497 
01498 ippOnePropertyIdPtr ippResponseParser::makeOnePropertyId(int * n)
01499 {
01500   int m;
01501   m = *n;
01502   if ((_itemCount < (m + 6))              ||
01503       (_resTypes[m + 3] != RESPARENLEFT)  ||
01504       (_resTypes[m + 4] != RESSTRING)     ||
01505       (_resTypes[m + 5] != RESPARENRIGHT) ||
01506       ((_itemCount != (m + 6)) && (_resTypes[m + 6] != RESCOMMA)))
01507     _errorCode = BAD_RESPONSE_ITEMS;
01508   *n = (m + 7);
01509   return ((_errorCode != OK) ? NULL :
01510           new ippOnePropertyId(_resKeywords[m], _resStrings[m + 4].c_str()));
01511 }
01512 
01513 /*******************************************************************/
01514 
01515 /* ippResponseParser::makeOnePropertyName
01516 
01517 Returned Value: A OnePropertyName as described by the response
01518   items, or NULL if the response items are bad.
01519 
01520 Called By:  ippResponseParser::makeGetPropResponse
01521 
01522 Errors:
01523   1. The argument being parsed does not have either pattern
01524      Tool.Name(string) or FoundTool.Name(string)
01525      BAD_RESPONSE_ITEMS
01526   2. There are more response items after this argument, but the next
01527      response item is not a comma.
01528      BAD_RESPONSE_ITEMS
01529 
01530 This is called by makeGetPropResponse when an argument starts with Tool.Name
01531 or FoundTool.Name, so the first three response items are not checked here.
01532 
01533 Example 1. Tool.Name("probe1")
01534 
01535 Reference pages: 24 29 (66) 107
01536 
01537 Notes:
01538 
01539 This resets *n to (*n + 7), since, including a comma, this function
01540 handles seven response items. This setting is OK when the end of the
01541 response items has been reached and there is no comma, since the loop
01542 in makeGetPropResponse will stop in that case.
01543 
01544 It is known that there are at least six more response items to be
01545 parsed when this is called, the first of which (Tool or FoundTool)
01546 has index *n.
01547 
01548 */
01549 
01550 ippOnePropertyNamePtr ippResponseParser::makeOnePropertyName(int * n)
01551 {
01552   int m;
01553   m = *n;
01554   if ((_itemCount < (m + 6))              ||
01555       (_resTypes[m + 3] != RESPARENLEFT)  ||
01556       (_resTypes[m + 4] != RESSTRING)     ||
01557       (_resTypes[m + 5] != RESPARENRIGHT) ||
01558       ((_itemCount != (m + 6)) && (_resTypes[m + 6] != RESCOMMA)))
01559     _errorCode = BAD_RESPONSE_ITEMS;
01560   *n = (m + 7);
01561   return ((_errorCode != OK) ? NULL :
01562           new ippOnePropertyName(_resKeywords[m], _resStrings[m+4].c_str()));
01563 }
01564 
01565 
01566 /*******************************************************************/
01567 
01568 /* ippResponseParser::makePtMeasEResponse
01569 
01570 Returned Value: A PtMeasOrGetResponse as described by the response text,
01571    or NULL if the response text is bad.
01572 
01573 Called By:  ippResponseParser::makeDataResponse
01574 
01575 Errors:
01576 1. The response items do not have the pattern
01577    PtMeas(<data items>)
01578    BAD_RESPONSE_ITEMS
01579 2. There are not one to nine data items.
01580    BAD_RESPONSE_ITEMS
01581 3. A data item is not one of: ER(double), IJK(double, double, double),
01582    R(double), X(double), Y(double), Z(double), Tool.A(double),
01583    Tool.B(double), or Tool.C(double).
01584    BAD_RESPONSE_ITEMS
01585 4. An allowed data item appears more than once.
01586    ER_USED_TWICE
01587    IJK_USED_TWICE
01588    R_USED_TWICE
01589    X_USED_TWICE
01590    Y_USED_TWICE
01591    Z_USED_TWICE
01592    TOOL_A_USED_TWICE
01593    TOOL_B_USED_TWICE
01594    TOOL_C_USED_TWICE
01595 5. Commas do not separate the response items if there are two or more.
01596    BAD_RESPONSE_ITEM
01597 
01598 This is called when (_resTypes[0] == RESKEYWORD) and
01599 (_resKeywords[0] == PtMeasKey), so those conditions are not checked here.
01600 
01601 A PtMeasEResponse is server-initiated and is not a response to a command.
01602 
01603 Example 1. E0000 # PtMeas(X(15), Z(-0.09))
01604 
01605 server-initiated PtMeas Reference pages: (78)
01606 other PtMeas Reference pages: 9 24 27 (41) (49) (52 - 53) (62) [71] [72]
01607                               83 84 86 87 89 90 91 102
01608 
01609 */
01610 bool ippResponseParser::CheckOptionalArgument(
01611   int& n,
01612   bool& hasArgument,
01613   ippOtherKeyType type,
01614   double& value,
01615   parserResErrorId errorIfDuplicated
01616 )
01617 {
01618   // keyword ( # )
01619   if (_errorCode != OK)  { return false; }
01620   if (_itemCount < n+3)  { return false; }
01621   if (!match(_resTypes,"k(#)",n)) {
01622     return true;// ignore ,not for us
01623   }
01624   if (_resKeywords[n] != type ){ 
01625     return true;// ignore ,not for us
01626   }
01627   if (hasArgument ) { 
01628     _errorCode = errorIfDuplicated;      
01629   } else {
01630     hasArgument = true;
01631     value = _resDoubles[ n + 2];
01632     n += 5;
01633   }
01634 //  if (n <=_resTypes.size()) {
01635 //    // next must be a ) or a ,
01636 //    if (_resTypes[n-1]!=RESPARENRIGHT &&_resTypes[n-1]!=RESCOMMA) {
01637 //      _errorCode = BAD_RESPONSE_ITEMS;
01638 //    }
01639 //  }
01640   return true;
01641 }
01642 bool ippResponseParser::CheckOptionalArgument(
01643   int& n,
01644   bool& hasArgument,
01645   ippOtherKeyType type1,
01646   ippOtherKeyType type2,
01647   double& value,
01648   parserResErrorId errorIfDuplicated
01649 )
01650 {
01651   // keyword ( # )
01652   if (_errorCode != OK)  { return false; }
01653   if (_itemCount < n+3)  { return false; }
01654   if (!match(_resTypes,"k.k(#)",n)) {
01655     return true;// ignore ,not for us
01656   }
01657   if (_resKeywords[n] != type1  || _resKeywords[n+2] != type2){ 
01658     return true;// ignore ,not for us
01659   }
01660   if (hasArgument ) { 
01661     _errorCode = errorIfDuplicated;      
01662   } else {
01663     hasArgument = true;
01664     value = _resDoubles[ n + 4];
01665     n += 7;
01666   }
01667   return true;
01668 }
01669 
01670 bool ippResponseParser::CheckOptionalArgument(
01671   int& n,
01672   bool& hasArgument,
01673   ippOtherKeyType type,
01674   double& value1,
01675   double& value2,
01676   double& value3,
01677   parserResErrorId errorIfDuplicated
01678 )
01679 {
01680   // keyword ( # )
01681   if (_errorCode != OK)  { return false; }
01682   if (_itemCount < n+3)  { return false; }
01683   if (!match(_resTypes,"k(#,#,#)",n)) {
01684     return true;// ignore ,not for us
01685   }
01686   if (_resKeywords[n] != type  ){ 
01687     return true;// ignore ,not for us
01688   }
01689   if (hasArgument ) { 
01690     _errorCode = errorIfDuplicated;      
01691   } else {
01692     hasArgument = true;
01693     value1 = _resDoubles[ n + 2];
01694     value2 = _resDoubles[ n + 4];
01695     value3 = _resDoubles[ n + 6];
01696     n += 9;
01697   }
01698 //  if (n <_resTypes.size()) {
01699 //    // next must be a ) or a ,
01700 //    if (_resTypes[n-1]!=RESPARENRIGHT &&_resTypes[n-1]!=RESCOMMA) {
01701 //      _errorCode = BAD_RESPONSE_ITEMS;
01702 //    }
01703 //  }
01704   return true;
01705 }
01706 
01707 ippResponsePtr ippResponseParser::makePtMeasEResponse()
01708 {
01709   int n; // index for components of response items
01710   bool hasER = false;
01711   bool hasIJK = false;
01712   bool hasIJKAct = false;
01713   bool hasQ  = false;
01714   bool hasR = false;
01715   bool hasToolA = false;
01716   bool hasToolB = false;
01717   bool hasToolC = false;
01718   bool hasX = false;
01719   bool hasY = false;
01720   bool hasZ = false;
01721   double ERvalue = 0;
01722   double Ivalue = 0;
01723   double Jvalue = 0;
01724   double Kvalue = 0;
01725   double Rvalue = 0;
01726   double IJKActvalue = 0;
01727   double QValue = 0;
01728   double toolAvalue = 0;
01729   double toolBvalue = 0;
01730   double toolCvalue = 0;
01731   double Xvalue = 0;
01732   double Yvalue = 0;
01733   double Zvalue = 0;
01734 
01735   _responseName = DataPtMeasE;
01736 
01737   if (_resTypes[1] != RESPARENLEFT) {
01738     _errorCode = BAD_RESPONSE_ITEMS;
01739   }
01740 
01741   for (n = 2; ((n < _itemCount) && (_errorCode == OK)); ) {
01742    
01743    int old_n=n;
01744    CheckOptionalArgument(n,hasER,ER,ERvalue,ER_USED_TWICE);
01745    CheckOptionalArgument(n,hasX, _X,Xvalue ,X_USED_TWICE);
01746    CheckOptionalArgument(n,hasY, _Y,Yvalue ,Y_USED_TWICE);
01747    CheckOptionalArgument(n,hasZ, _Z,Zvalue ,Z_USED_TWICE);
01748    CheckOptionalArgument(n,hasR, _R,Rvalue ,R_USED_TWICE);
01749    CheckOptionalArgument(n,hasToolA,Tool,_A,toolAvalue ,TOOL_A_USED_TWICE);
01750    CheckOptionalArgument(n,hasToolB,Tool,_B,toolBvalue ,TOOL_B_USED_TWICE);
01751    CheckOptionalArgument(n,hasToolC,Tool,_C,toolCvalue ,TOOL_C_USED_TWICE);
01752    CheckOptionalArgument(n,hasIJK  ,_IJK, Ivalue,Jvalue,Kvalue,IJK_USED_TWICE);
01753    CheckOptionalArgument(n,hasIJKAct,_IJKAct, IJKActvalue,IJK_USED_TWICE);
01754    if (old_n == n && _errorCode == OK) { 
01755       // the argument has not been recognized:
01756       _errorCode = BAD_RESPONSE_ITEMS;
01757    }
01758  }
01759  return ((_errorCode != OK) ? NULL :
01760           new ippPtMeasEResponse(hasER, hasIJK,hasIJKAct, hasR, hasToolA, hasToolB,
01761                               hasToolC, hasX, hasY, hasZ, ERvalue, Ivalue,
01762                               Jvalue, Kvalue, IJKActvalue,Rvalue, toolAvalue, toolBvalue,
01763                               toolCvalue, Xvalue, Yvalue, Zvalue));
01764 }
01765 
01766 /*******************************************************************/
01767 
01768 /* ippResponseParser::makePtMeasOrGetResponse
01769 
01770 Returned Value: A PtMeasOrGetResponse as described by the response text,
01771    or NULL if the response text is bad.
01772 
01773 Called By:  ippResponseParser::makeDataResponse
01774 
01775 Errors:
01776 1. There must be one to nine data items.
01777    BAD_RESPONSE_ITEMS
01778 2. A data item is not one of: ER(double), IJK(double, double, double),
01779    R(double), X(double), Y(double), Z(double), Tool.A(double),
01780    Tool.B(double), or Tool.C(double).
01781    BAD_RESPONSE_ITEMS
01782 3. An allowed data item appears more than once.
01783    ER_USED_TWICE
01784    IJK_USED_TWICE
01785    R_USED_TWICE
01786    X_USED_TWICE
01787    Y_USED_TWICE
01788    Z_USED_TWICE
01789    TOOL_A_USED_TWICE
01790    TOOL_B_USED_TWICE
01791    TOOL_C_USED_TWICE
01792 4. Commas do not separate the response items if there are two or more.
01793    BAD_RESPONSE_ITEMS
01794 
01795 This is called when (_resTypes[0] == RESKEYWORD) and the keyword is ER, IJK, R,
01796 X, Y, Z, or [the keyword is Tool and the keyword after that is A, B, or C].
01797 Other responses where (_resTypes[0] == RESKEYWORD) and the keyword is Tool
01798 are handled by makeGetPropResponse.
01799 
01800 A PtMeasOrGetResponse responds to a PtMeas command or a Get command.
01801 
01802 Example 1. X(3), Y(4)
01803 
01804 PtMeas Reference pages: 9 24 27 (41) (49) (52 - 53) (62) [71] [72] (78)
01805                         83 84 86 87 89 90 91 102
01806 Get Reference pages: 24 27 [38] [44] (49) (51) 57 (61) (63) (66) (81) 102
01807 
01808 Note: A PtMeasOrGetResponse responding to a Get command should never
01809 have ER or IJK. When the response does not have ER or IJK, it is not
01810 possible to tell solely by examining the response whether the command
01811 was a PtMeas or a Get. The caller must keep a record of commands and
01812 check the _tag to determine what the command was.
01813 
01814 Which items should be included in a PtMeasOrGetResponse made in
01815 response to a PtMeas command is determined by the most recent
01816 OnPtMeasReport command. This function does not try to determine if
01817 the appropriate items have been reported.
01818 
01819 */
01820 
01821 ippResponsePtr ippResponseParser::makePtMeasOrGetResponse()
01822 {
01823   int n; // index for components of response items
01824   bool hasER = false;
01825   bool hasIJK = false;
01826   bool hasIJKAct = false;
01827   bool hasQ  = false;
01828 
01829   bool hasR = false;
01830   bool hasToolA = false;
01831   bool hasToolB = false;
01832   bool hasToolC = false;
01833   bool hasX = false;
01834   bool hasY = false;
01835   bool hasZ = false;
01836   double ERvalue = 0;
01837   double Ivalue = 0;
01838   double Jvalue = 0;
01839   double Kvalue = 0;
01840   double IJKActvalue = 0;
01841   double Qvalue =0;
01842   double Rvalue = 0;
01843   double toolAvalue = 0;
01844   double toolBvalue = 0;
01845   double toolCvalue = 0;
01846   double Xvalue = 0;
01847   double Yvalue = 0;
01848   double Zvalue = 0;
01849 
01850   _responseName = DataPtMeasOrGet;
01851 
01852   for (n = 0; ((n <=_itemCount) && (_errorCode == OK)); ) {
01853 
01854      int old_n=n;
01855      CheckOptionalArgument(n,hasER,ER,ERvalue,ER_USED_TWICE);
01856      CheckOptionalArgument(n,hasX, _X,Xvalue ,X_USED_TWICE);
01857      CheckOptionalArgument(n,hasY, _Y,Yvalue ,Y_USED_TWICE);
01858      CheckOptionalArgument(n,hasZ, _Z,Zvalue ,Z_USED_TWICE);
01859      CheckOptionalArgument(n,hasR, _R,Rvalue ,R_USED_TWICE);
01860      CheckOptionalArgument(n,hasToolA,Tool,_A,toolAvalue ,TOOL_A_USED_TWICE);
01861      CheckOptionalArgument(n,hasToolB,Tool,_B,toolBvalue ,TOOL_B_USED_TWICE);
01862      CheckOptionalArgument(n,hasToolC,Tool,_C,toolCvalue ,TOOL_C_USED_TWICE);
01863      CheckOptionalArgument(n,hasIJK  ,_IJK, Ivalue,Jvalue,Kvalue,IJK_USED_TWICE);
01864      CheckOptionalArgument(n,hasIJKAct,_IJKAct, IJKActvalue,IJKACT_USED_TWICE);
01865      CheckOptionalArgument(n,hasQ  ,Q, Qvalue,Q_USED_TWICE);
01866      if (old_n == n && _errorCode == OK) { 
01867         // the argument has not been recognized:
01868         _errorCode = BAD_RESPONSE_ITEMS;
01869      } 
01870   }
01871   if(_errorCode != OK) {
01872     return 0;
01873   }
01874   if (_tagType == EventTag) {
01875     
01876     if (hasER || hasIJK) { 
01877           _errorCode = BAD_RESPONSE_ITEMS;
01878       return 0;
01879     }
01880           return  new  ippOnMoveReportEResponse(_tag, hasR, hasToolA,
01881                                    hasToolB, hasToolC, hasX, hasY, hasZ,
01882                                      Rvalue,
01883                                      toolAvalue, toolBvalue, toolCvalue,
01884                             Xvalue, Yvalue, Zvalue);
01885 
01886   } else {
01887           return  new  ippPtMeasOrGetResponse(
01888              _tag, hasER, hasIJK,hasIJKAct,hasQ, hasR,
01889              hasToolA,hasToolB, hasToolC, 
01890              hasX, hasY, hasZ,
01891                                      ERvalue, Ivalue, Jvalue, Kvalue, int(IJKActvalue),Qvalue,Rvalue,
01892                                      toolAvalue, toolBvalue, toolCvalue,
01893                                     Xvalue, Yvalue, Zvalue);
01894   }
01895 }
01896 
01897 /*******************************************************************/
01898 
01899 /* ippResponseParser::makeScanResponse
01900 
01901 Returned Value: A ScanResponse as described by the response text,
01902    or NULL if the response text is bad.
01903 
01904 Called By:  ippResponseParser::makeDataResponse
01905 
01906 Errors:
01907 1. If the number of response items is not odd:
01908    BAD_RESPONSE_ITEMS.
01909 2. If the first of a pair of response items is not a double:
01910    BAD_RESPONSE_ITEMS
01911 3. If the second of a pair of response items (followed by more response
01912    items) is not a comma: BAD_RESPONSE_ITEMS.
01913 
01914 This is called when (_resTypes[0] == RESDOUBLE). Scan data is just
01915 doubles separated by commas.
01916 
01917 Example 1. 00010 # 1, 2, 3, 4, 5, 6
01918 
01919 Reference pages: 24 27 (41) (81) 82 83 84 86 87 88 90 91 [93] 103
01920 
01921 */
01922 
01923 ippResponsePtr ippResponseParser::makeScanResponse()
01924 {
01925   int n;
01926   
01927   
01928   _responseName = DataScan;
01929   
01930   if ((_itemCount % 2) != 1) {
01931     _errorCode = BAD_RESPONSE_ITEMS;
01932   }
01933 
01934   std::auto_ptr<double> scanData(new double[(_itemCount + 1) / 2]);
01935   
01936   for (n = 0; (_errorCode == OK); n++) {    
01937     if (_resTypes[n] == RESDOUBLE) {
01938         scanData.get()[n / 2] = _resDoubles[n];
01939     } else {      
01940             _errorCode = BAD_RESPONSE_ITEMS;
01941     }
01942     n++;
01943     if (n >= _itemCount) {
01944             break;
01945     }
01946     if (_resTypes[n] != RESCOMMA) {
01947              _errorCode = BAD_RESPONSE_ITEMS;
01948     }
01949   }
01950   return ((_errorCode != OK) ? NULL :
01951           new ippScanResponse(_tag, ((_itemCount + 1) / 2), scanData.get()));
01952 }
01953 
01954 /*******************************************************************/
01955 
01956 /* ippResponseParser::makeServerInitiatedResponse
01957 
01958 Returned Value: A data ippResponse of the appropriate type as described
01959    by the response text, or NULL if the response text is bad.
01960 
01961 Called By:  ippResponseParser::parseResponse
01962 
01963 Errors:
01964 1. The response items do not conform to any defined pattern of response
01965    items: BAD_RESPONSE_ITEMS.
01966 
01967 This examines the type of the first response item (and possibly other
01968 information about response items), decides what type of response it must
01969 be, and calls a subordinate function to make a response of that type.
01970 
01971 This is called only if the _tag is known to be E0000.
01972 
01973 */
01974 
01975 ippResponsePtr ippResponseParser::makeServerInitiatedResponse()
01976 {
01977   ippResponsePtr aResponse;
01978 
01979   if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == ChangeToolKey))
01980     aResponse = makeChangeToolEResponse();
01981   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == GoToKey))
01982     aResponse = makeGoToEResponse();
01983   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == KeyPress))
01984     aResponse = makeKeyPressEResponse();
01985   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == PtMeasKey))
01986     aResponse = makePtMeasEResponse();
01987   else if ((_resTypes[0] == RESKEYWORD) && (_resKeywords[0] == SetPropKey))
01988     aResponse = makeSetPropEResponse();
01989   else
01990     {
01991       aResponse = NULL;
01992       _errorCode = BAD_RESPONSE_ITEMS;
01993     }
01994   return aResponse;
01995 }
01996 
01997 /*******************************************************************/
01998 
01999 /* ippResponseParser::makeSetPropEResponse
02000 
02001 Returned Value: A SetPropEResponse as described by the response text,
02002    or NULL if the response text is bad.
02003 
02004 Called By:  makeServerInitiatedResponse
02005 
02006 Errors:
02007 1. If the response items do not match one of the three patterns:
02008    SetProp(key1.key2(val))           --  9 components in _itemCount
02009    SetProp(key1.key2.key3(val))      -- 11 components in _itemCount
02010    SetProp(key1.key2.key3.key4(val)) -- 13 components in _itemCount
02011    BAD_RESPONSE_ITEMS
02012 2. key1 must be FoundTool or Tool.
02013    BAD_KEYWORD
02014 3. key2 must be GoToPar or PtMeasPar.
02015    BAD_KEYWORD
02016 4. If key2 is GoToPar, key3 must be either Speed or Accel. If key2 is
02017    PtMeasPar, key3 must be one of Speed, Accel, Approach, Retract, or Search.
02018    BAD_KEYWORD
02019 5. If there is a key4, it must be Actual.
02020    BAD_KEYWORD
02021 
02022 This is called when (_resTypes[0] == RESKEYWORD) and
02023 (_resKeywords[0] == SetPropKey), so those conditions are not checked here.
02024 
02025 A SetPropE response is server-initiated and is not a response to a command.
02026 
02027 Example 1. E0000 # SetProp(Tool.GoToPar.Speed(55))
02028 
02029 server-initiated SetProp Reference pages: (78)
02030 other SetProp Reference pages: 24 26 29 (45) 65 [73] 77 99 108
02031 Also see the reference pages for GetProp, since several of those imply
02032 that certain properties cannot be set directly.
02033 
02034 */
02035 
02036 ippResponsePtr ippResponseParser::makeSetPropEResponse()
02037 {
02038   _responseName = DataSetPropE;
02039 
02040   ippSetPropEResponsePtr response = new ippSetPropEResponse();
02041   
02042   IPP_ASSERT(_resTypes[0] == RESKEYWORD || _resKeywords[0] == SetPropKey);
02043   if (_resTypes[1] != RESPARENLEFT) { 
02044     _errorCode = BAD_CHARACTER_AFTER_KEYWORD;
02045     return 0;
02046   }
02047   if (_resTypes[_itemCount-1] != RESPARENRIGHT) { 
02048     _errorCode = BAD_CHARACTER_AFTER_KEYWORD;
02049     return 0;
02050   }
02051 
02052   int n =2;
02053   for ( n = 2; ((n < _itemCount-1) && (_errorCode == OK)); ) {
02054 
02055     ippOtherKeyType key1 = EmptyKey; 
02056     ippOtherKeyType key2 = EmptyKey; 
02057     ippOtherKeyType key3 = EmptyKey; 
02058     ippOtherKeyType key4 = EmptyKey;
02059     double value = 0;
02060     
02061     int m=n;
02062     bool foundPropertyNumber = false;
02063 
02064     if(match(_resTypes,"k.k(#)",m)) { 
02065       key1 =  _resKeywords[m];
02066       key2 =  _resKeywords[m+2];
02067       value = _resDoubles[m+4];
02068       foundPropertyNumber = true;
02069       n = (m + 7);
02070     } else if(match(_resTypes,"k.k.k(#)",m)) { 
02071       key1 =  _resKeywords[m];
02072       key2 =  _resKeywords[m+2];
02073       key3 =  _resKeywords[m+4];
02074       value = _resDoubles[m+6];
02075       foundPropertyNumber = true;
02076       n = (m + 9);
02077     } else if(match(_resTypes,"k.k.k.k(#)",m)) { 
02078       key1 =  _resKeywords[m];
02079       key2 =  _resKeywords[m+2];
02080       key3 =  _resKeywords[m+4];
02081       key4 =  _resKeywords[m+6];
02082       value = _resDoubles[m+8];
02083       foundPropertyNumber = true;
02084       n = (m + 11);
02085     }  
02086     if (foundPropertyNumber) {
02087       ippProp prop(key1,key2,key3,key4);
02088       if (!PropertyIsAllowedAndWritable(prop)) {
02089         _errorCode = BAD_PROPERTY;
02090       }
02091       //xx ippOnePropertyPtr r = new ippOnePropertyNumber(prop,value);
02092       response->addPropValue(prop,value);
02093       
02094     /*} else if (_resKeywords[n + 2] == Alignment){      
02095       response->append(makeOnePropertyAlignment(&n));
02096     } else if (_resKeywords[n+2 ] == AlignmentVolume ) { 
02097       response->append(makeOnePropertyAlignmentVolume(&n));
02098     } else if (_resKeywords[n + 2] == CollisionVolume){
02099       response->append(makeOnePropertyCollisionVolume(&n));
02100     } else if (_resKeywords[n + 2] == Name) {
02101             response->append(makeOnePropertyName(&n));
02102     } else if (_resKeywords[n + 2] == Id){
02103             response->append(makeOnePropertyId(&n));
02104     */
02105     } else { 
02106             _errorCode = BAD_SECOND_KEYWORD;
02107     }
02108   }
02109   if (n -1 >= _resTypes.size() || _resTypes[n-1] != RESPARENRIGHT) { 
02110     _errorCode = BAD_CHARACTER_AFTER_KEYWORD;
02111     return 0;
02112   }
02113   if (_errorCode != OK) {
02114     response =0;
02115   }
02116   return response;
02117 
02118 }
02119 
02120 /*******************************************************************/
02121 
02122 /* ippResponseParser::makeStringResponse
02123 
02124 Returned Value: A StringResponse as described by the response text,
02125    or NULL if the response text is bad.
02126 
02127 Called By:  ippResponseParser::makeDataResponse
02128 
02129 Errors: None.
02130 
02131 This is called when (_itemCount == 1) and (_resTypes[0] == RESSTRING),
02132 so those conditions are not checked here.
02133 
02134 StringResponse responds to a GetErrorInfo command or an EnumTools command.
02135 
02136 Example 1. "No clue"
02137 Example 2. "Probe6"
02138 
02139 GetErrorInfo Reference pages: 19 24 26 (43) 76 99
02140 Page 76 does not mention the command but gives allowable error numbers.
02141 EnumTools Reference pages: 24 29 (53) (54) (56) 106
02142 
02143 */
02144 
02145 ippResponsePtr ippResponseParser::makeStringResponse()
02146 {
02147   _responseName = DataString;
02148   return new ippStringResponse(_tag, _resStrings[0].c_str());
02149 }
02150 
02151 /*******************************************************************/
02152 
02153 /* ippResponseParser::makeTiltCenterPartResponse
02154 
02155 Called By:  ippResponseParser::makeDataResponse
02156 
02157 Errors: 
02158 1. If the response items do not match the pattern
02159    TiltCenterPart(double)
02160    or the double is not a single character: BAD_RESPONSE_ITEMS.
02161 2. If the double is not 0 or 1: VALUE_MUST_BE_0_OR_1.
02162 
02163 
02164 This is called when (_resTypes[0] == RESKEYWORD) and
02165 (_resKeywords[0] = TiltCenterPartKey), so those conditions are not checked here.
02166 
02167 A TiltCenterPartResponse responds to a TiltCenterPart command.
02168 
02169 Example 1. 00010 # TiltCenterPart(1)
02170 
02171 Reference pages: 24 27 (97) 102
02172 
02173 */
02174 
02175 ippResponsePtr ippResponseParser::makeTiltCenterPartResponse()
02176 {
02177   _responseName = DataTiltCenterPart;
02178   if ((_itemCount != 4) || !match(_resTypes,"k(#)")) {
02179     _errorCode = BAD_RESPONSE_ITEMS;
02180   } else if ((_resDoubles[2] != 0) && (_resDoubles[2] != 1)) {
02181     _errorCode = VALUE_MUST_BE_0_OR_1;
02182   }
02183   return ((_errorCode != OK) ? NULL :
02184           new ippTiltCenterPartResponse(_tag,((_resDoubles[2] == 1) ? true :false)));
02185 }
02186 
02187 /*******************************************************************/
02188 
02189 /* ippResponseParser::makeTiltPartResponse
02190 
02191 Called By:  ippResponseParser::makeDataResponse
02192 
02193 Errors: 
02194 1. If the response items do not match the pattern
02195    TiltPart(double)
02196    or the double is not a single character: BAD_RESPONSE_ITEMS.
02197 2. If the double is not 0 or 1: VALUE_MUST_BE_0_OR_1.
02198 
02199 
02200 This is called when (_resTypes[0] == RESKEYWORD) and
02201 (_resKeywords[0] = TiltPartKey), so those conditions are not checked here.
02202 
02203 A TiltPartResponse responds to a TiltPart command.
02204 
02205 Example 1. 00010 # TiltPart(1)
02206 
02207 Reference pages: 24 27 (97) 102
02208 
02209 */
02210 
02211 ippResponsePtr ippResponseParser::makeTiltPartResponse()
02212 {
02213   _responseName = DataTiltPart;
02214   if ((_itemCount != 4) || !match(_resTypes,"k(#)")) {
02215     _errorCode = BAD_RESPONSE_ITEMS;
02216   } else if ((_resDoubles[2] != 0) && (_resDoubles[2] != 1)) {
02217     _errorCode = VALUE_MUST_BE_0_OR_1;
02218   }
02219   return ((_errorCode != OK) ? NULL :
02220           new ippTiltPartResponse(_tag, ((_resDoubles[2] == 1) ? true : false)));
02221 }
02222 
02223 /*******************************************************************/
02224 
02225 /* ippResponseParser::parseKeyword
02226 
02227 Returned Value: None.
02228 
02229 Called By: ippResponseParser::parseResItems
02230 
02231 Errors:
02232 1. If the letters starting with _inputArray[arrayIndex] do not make
02233    any defined keyword: BAD_KEYWORD.
02234 2. If the keyword is not followed by a dot, comma, left parenthesis,
02235    or right parenthesis: BAD_CHARACTER_AFTER_KEYWORD.
02236 
02237 This is called only if the character at _inputArray[arrayIndex] is an
02238 upper case letter.
02239 
02240 If there are extra letters after a valid keyword, that is detected.
02241 
02242 If one keyword is the same as the beginning of another keyword, a check
02243 for the longer keyword must be made first. There are several cases of that.
02244 
02245 When the keyword is a single letter, it is not necessary to use a
02246 check like [if (strncmp(keyword, "A", 1) == 0)] since that is already
02247 known from the case statement to be true, but those checks are
02248 included just to keep the code looking consistent.
02249 
02250 If the keyword is OK, it is stored in the parser's _resKeywords[_itemCount].
02251 
02252 */
02253 
02254 
02255 
02256 ippOtherKeyType getFromString(const std::string& );
02257 
02258 void ippResponseParser::parseKeyword()
02259 {
02260   int length =0;
02261 
02262   _resKeywords[_itemCount] = ippOtherKeyType_INVALID;
02263   _errorCode = BAD_KEYWORD;
02264   const char* keyword = (_inputArray + _arrayIndex);
02265   const char* endkeyword = keyword;
02266   while(isalpha(*endkeyword++));
02267   
02268   int keywordLength = (endkeyword-keyword)-1;
02269  
02270   _resKeywords[_itemCount] =   getFromString(std::string(keyword,keywordLength));
02271   if (ippOtherKeyType_INVALID== _resKeywords[_itemCount]) {
02272     _errorCode = BAD_KEYWORD;
02273     return;
02274   }
02275 
02276   if (_resKeywords[_itemCount] != -1) {
02277       _arrayIndex = (_arrayIndex + keywordLength)-1;
02278       if ((_inputArray[_arrayIndex + 1] == '.') ||
02279                 (_inputArray[_arrayIndex + 1] == ',') ||
02280                 (_inputArray[_arrayIndex + 1] == '(') ||
02281           (_inputArray[_arrayIndex + 1] == ')')) {
02282         _errorCode = OK;
02283       }   else {
02284         _errorCode = BAD_CHARACTER_AFTER_KEYWORD;
02285       }
02286     }
02287 }
02288 
02289 /*******************************************************************/
02290 
02291 /* ippResponseParser::parseNumber
02292 
02293 Returned Value: None.
02294 
02295 Called By: ippResponseParser::parseResItems
02296 
02297 Errors:
02298 1. If the characters that might form a number include two dots:
02299    BAD_NUMBER_TWO_DECIMAL_POINTS.
02300 2. If the characters that might form a number include no digits:
02301    BAD_NUMBER_NO_DIGITS.
02302 3. If the characters that might form a number include more than
02303    sixteen digits: BAD_NUMBER_MORE_THAN_16_DIGITS.
02304 4. If the number has an exponent and the exponent does not have
02305    one, two, or three digits:
02306    BAD_E_NUMBER_EXPONENT_MUST_HAVE_ONE_TWO_OR_THREE_DIGITS.
02307 
02308 This is called only if the response item being parsed starts with a
02309 plus sign, minus sign, digit, or [decimal point not followed by an
02310 upper case letter].
02311 
02312 If the number is OK, it is stored in the parser's _resDoubles[_itemCount].
02313 
02314 Reference pages: (33 - 34)
02315 
02316 */
02317 
02318 void ippResponseParser::parseNumber()
02319 {
02320   int sign = 0; // set to 1 if first character is '+' or '-'
02321   int dot = 0;  // set to 1 if a decimal point is found
02322   int k;        // index for _inputArray
02323   int j;        // counts digits of exponent
02324   char save;
02325 
02326   if ((_inputArray[_arrayIndex] == '-') || (_inputArray[_arrayIndex] == '+')) {
02327     sign = 1;
02328   }
02329   for (k = (_arrayIndex + sign); ((_errorCode == OK) && ((_inputArray[k] == '.') || ((_inputArray[k] > 47) && (_inputArray[k] < 58)))); k++) {
02330     if (_inputArray[k] == '.') {
02331       if (dot == 0) {
02332               dot = 1;
02333       } else {
02334               _errorCode = BAD_NUMBER_TWO_DECIMAL_POINTS;
02335       }
02336           }   
02337   }
02338   if ((_errorCode == OK) && ((_arrayIndex + sign + dot) == k)) {
02339     _errorCode = BAD_NUMBER_NO_DIGITS;
02340   }
02341   if ((_errorCode == OK) && ((k - (_arrayIndex + sign + dot)) > 16)) {
02342     _errorCode = BAD_NUMBER_MORE_THAN_16_DIGITS;
02343   }
02344   if ((_errorCode == OK) && ((_inputArray[k] == 'E') || (_inputArray[k] == 'e'))) {
02345     k++;
02346     if ((_inputArray[k] == '+') || (_inputArray[k] == '-')) {
02347             k++;
02348     }
02349     for (j = 0; ((_inputArray[k] > 47) && (_inputArray[k] < 58)); j++) {
02350       k++;
02351     }
02352     if ((j < 1) || (j > 3)) {
02353             _errorCode = BAD_E_NUMBER_EXPONENT_MUST_HAVE_ONE_TWO_OR_THREE_DIGITS;
02354     }
02355   }
02356   if (_errorCode == OK) {
02357     save = _inputArray[k];
02358     _inputArray[k] = 0; //put in temporary null terminator
02359     sscanf((_inputArray +_arrayIndex), "%lf", &(_resDoubles[_itemCount]));
02360     _inputArray[k] = save; // put char back
02361     _arrayIndex = (k - 1); // set arrayIndex to end of number
02362   }
02363 }
02364 
02365 /*******************************************************************/
02366 
02367 /* ippResponseParser::parseResItems
02368 
02369 Returned Value: None.
02370 
02371 Called By: ippResponseParser::parseResponse
02372 
02373 Errors:
02374 1. If the beginning of the response items does not match any allowed
02375    pattern: BAD_RESPONSE_ITEMS.
02376 
02377 A dot may appear either before a capital letter (as in Tool.PtMeasPar)
02378 or at the beginning of a number (as in .123). In the first case it is
02379 a response item. In the second case it is part of the number.
02380 
02381 */
02382 
02383 void ippResponseParser::parseResItems()
02384 {
02385   char c;
02386   char d;
02387 
02388   _arrayIndex = 8;
02389 
02390   for(_itemCount = 0; ((c = _inputArray[_arrayIndex]) != 13); _itemCount++) {
02391     
02392     if (_itemCount == _resSize) {
02393       makeArraysBigger();
02394     }
02395     
02396     d = _inputArray[_arrayIndex + 1];
02397 
02398     if (c == '(') {
02399         _resTypes[_itemCount] = RESPARENLEFT;
02400 
02401     } else if (c == ')') {
02402       _resTypes[_itemCount] = RESPARENRIGHT;
02403 
02404     } else if (c == '"') {
02405       /* open quote */ 
02406             parseString();
02407             _resTypes[_itemCount] = RESSTRING;
02408 
02409     } else if (c == ',') {
02410       _resTypes[_itemCount] = RESCOMMA;
02411 
02412     } else if ((c == '.') && isupper(d) /*(d >= 'A') && (d <= 'Z')*/)  { // dot before upper letter 
02413              _resTypes[_itemCount] = RESDOT;
02414 
02415     } else if ((c == '-') ||(c == '+') ||(c == '.') || isdigit(c)) {
02416              parseNumber();
02417              _resTypes[_itemCount] = RESDOUBLE;
02418 
02419     }  else if (isupper(c)/*(c >= 'A') && (c <= 'Z') */)        { // an upper-case letter
02420             parseKeyword();
02421             _resTypes[_itemCount] = RESKEYWORD;
02422 
02423     } else {
02424         _errorCode = BAD_RESPONSE_ITEMS;
02425     }
02426 
02427     if (_errorCode != OK) {
02428       break;
02429     }
02430     _arrayIndex++; /* move to character after end of item just parsed */
02431   }
02432 }
02433 
02434 /*******************************************************************/
02435 
02436 /* ippResponseParser::parseResponse
02437 
02438 Returned Value: A ippResponse (if the _inputArray holds a valid response)
02439   of NULL (if not).
02440 
02441 Called By:
02442   external functions
02443   main (in stand-alone response parser)
02444 
02445 Errors:
02446 1. If the response items form an allowed response but are not followed
02447    in the _inputArray by  ASCII 13   ASCII 10  ASCII 0  :
02448    BAD_CHARACTER_AFTER_RESPONSE_END.
02449 2. If the seventh character of the response is not one of  & % ! #  :
02450    BAD_SEVENTH_CHARACTER_IN_RESPONSE.
02451 3. if the response is an error response or a data response, and the eighth
02452    character of the response is not a space:
02453    SPACE_MISSING_AT_EIGHTH_CHARACTER_OF_RESPONSE.
02454 
02455 The setInput function copies a response string into the parser's
02456 _inputArray, stopping at the first ASCII 0, so the check for ASCII 0 is
02457 reasonable.
02458 
02459 parseTag sets the _errorCode to OK if the _tag is OK syntactically.
02460 
02461 */
02462 
02463 ippResponsePtr ippResponseParser::parseResponse()
02464 {
02465   ippResponsePtr aResponse;
02466 
02467   _responseName = ippResponseNameType_ERROR;
02468 
02469   parseTag();
02470 
02471   if (_errorCode == OK) {
02472     if (_inputArray[6] == '&'){
02473             if ((_inputArray[7] != 13) ||
02474                 (_inputArray[8] != 10) ||
02475                 (_inputArray[9] != 0)) {
02476                     _errorCode = BAD_CHARACTER_AFTER_RESPONSE_END;
02477             } else {
02478               aResponse = new ippAckResponse(_tag, _tagType);
02479       }
02480           } else if (_inputArray[6] == '%') {
02481             if ((_inputArray[7] != 13) ||
02482                 (_inputArray[8] != 10) ||
02483                 (_inputArray[9] != 0))
02484                   _errorCode = BAD_CHARACTER_AFTER_RESPONSE_END;
02485       else {
02486               aResponse = new ippCompleteResponse(_tag, _tagType);
02487       }
02488 
02489     } else if ((_inputArray[6] != '!') &&(_inputArray[6] != '#')) {
02490              _errorCode = BAD_SEVENTH_CHARACTER_IN_RESPONSE;
02491 
02492     } else if (_inputArray[7] != ' ') {
02493             _errorCode = SPACE_MISSING_AT_EIGHTH_CHARACTER_OF_RESPONSE;
02494 
02495     } else      {
02496             unSpaceInputArray();
02497       
02498       if (_errorCode == OK){
02499               parseResItems();
02500       }
02501             if ((_errorCode == OK) &&
02502               ((_inputArray[_arrayIndex] != 13) ||
02503                (_inputArray[_arrayIndex + 1] != 10) ||
02504          (_inputArray[_arrayIndex + 2] != 0))) {
02505                 _errorCode = BAD_CHARACTER_AFTER_RESPONSE_END;
02506       }
02507             if (_errorCode == OK)  {
02508         if (_inputArray[6] == '!') {
02509           aResponse = makeErrorResponse();
02510         } else if (_tag == 0) { // _tag is E0000 and (_inputArray[6] == '#')
02511                       aResponse = makeServerInitiatedResponse();
02512         } else  { // (_inputArray[6] == '#')
02513                       aResponse = makeDataResponse();
02514         }
02515             }
02516           }
02517   }
02518 
02519   return ((_errorCode == OK) ? aResponse : NULL);
02520 }
02521 
02522 /*******************************************************************/
02523 
02524 /* ippResponseParser::parseString
02525 
02526 Returned Value: None.
02527 
02528 Called By: ippResponseParser::parseResItems
02529 
02530 Errors:
02531 1. The string being read has an illegal character:
02532    BAD_STRING.
02533 
02534 This is called whenever the first character of a response item is a
02535 double-quote (ASCII 34). Reading the string stops at the second
02536 double-quote.
02537 
02538 If the string is OK it is stored in the parser's _resStrings[_itemCount].
02539 
02540 Reference pages: 10 (33) 34 35 43 46 66 73 99 102 106 107 108 109
02541 These references are only those where string is the data type of a
02542 component of a command or a response. The word string is used in other
02543 places to refer to an entire command or response.
02544 
02545 A String starts with a double quote (ASCII 34) and ends at the
02546 next double quote. A double quote cannot be inside a string.
02547 When this function starts, arrayIndex is indicating the opening
02548 double quote.
02549 
02550 */
02551 
02552 
02553 void ippResponseParser::parseString()
02554 {
02555 
02556   _arrayIndex++; // skip starting quote
02557   int start = _arrayIndex;
02558   for (; (_inputArray[_arrayIndex] != '"'); _arrayIndex++) {
02559 
02560     if ((_inputArray[_arrayIndex] < 32) || (_inputArray[_arrayIndex] > 126)) {
02561             _errorCode = BAD_STRING;
02562             return;
02563     }
02564   }
02565   _inputArray[_arrayIndex] = 0; // set temporary null terminator
02566   _resStrings.resize(_itemCount+1,"");
02567   _resStrings[_itemCount]  = _inputArray + start; // hook copy in
02568   _inputArray[_arrayIndex] = '"'; // restore quote at end
02569 }
02570 
02571 /*******************************************************************/
02572 
02573 /* ippResponseParser::parseTag
02574 
02575 Returned Value: None.
02576 
02577 Called By: ippResponseParser::parseResponse
02578 
02579 Errors:
02580 1. If the first character of the response is not E or a digit, or any
02581    of the next four characters is not a digit: BAD_TAG_CHARACTER.
02582 2. If the sixth character of the response is not a space:
02583    SPACE_MISSING_AFTER_TAG.
02584 2. If the first character is a digit and the _tag number is zero:
02585    TAG_NUMBER_OUT_OF_RANGE_FOR_COMMAND_TAG.
02586 4. If the _tag is E0000 and the seventh character is not ! or #
02587    ZERO_TAG_MUST_BE_SERVER_INITIATED_RESPONSE.
02588 
02589 If the _tag is OK, its type (as indicated by the first character) is
02590 stored in the "_tagType" data member of the parser, and the value of
02591 the _tag is stored in the "_tag" data member.
02592 
02593 Reference pages: (21) (22) 26-30 (34-42) (47) (49) (50) (75) (77) 99-113
02594 
02595 There should be a _tag at the beginning of the _inputArray. This function
02596 reads that _tag.
02597 
02598 */
02599 
02600 void ippResponseParser::parseTag()
02601 {
02602   if (!isdigit(_inputArray[1]) ||
02603       !isdigit(_inputArray[2]) ||
02604       !isdigit(_inputArray[3]) ||
02605       !isdigit(_inputArray[4])) {
02606     _errorCode = BAD_TAG_CHARACTER;
02607 
02608   } else if (_inputArray[5] != 32) {
02609     _errorCode = SPACE_MISSING_AFTER_TAG;
02610 
02611   } else if (_inputArray[0] == 'E')  {
02612 
02613       sscanf((_inputArray + 1), "%d", &_tag);
02614 
02615       if ((_tag == 0) && (_inputArray[6] != '!') && (_inputArray[6] != '#')) {
02616         _errorCode = ZERO_TAG_MUST_BE_SERVER_INITIATED_RESPONSE;
02617       } else {
02618               _tagType = EventTag;
02619               _errorCode = OK;
02620             }
02621 
02622   } else if (isdigit(_inputArray[0])) {
02623       
02624     sscanf(_inputArray, "%d", &_tag);
02625     if (_tag == 0) {
02626         _errorCode = TAG_NUMBER_OUT_OF_RANGE_FOR_COMMAND_TAG;
02627     } else {
02628             _tagType = CommandTag;
02629     }
02630           _errorCode = OK;
02631   } else {
02632     _errorCode = BAD_TAG_CHARACTER;
02633   }
02634 }
02635 
02636 /*******************************************************************/
02637 
02638 /* ippResponseParser::setInput
02639 
02640 Returned Value: None.
02641 
02642 Called By:
02643   external functions
02644   main (in stand-alone response parser)
02645 
02646 Errors: None.
02647 
02648 This copies the input string into the parser's _inputArray. If the input
02649 string is too long, it is truncated.
02650 
02651 */
02652 
02653 void ippResponseParser::setInput(
02654   const char * input
02655 )
02656 {
02657   strncpy(_inputArray, input, (IPPSIZE - 1));
02658 }
02659 
02660 
02661 /*******************************************************************/
02662 
02663 /* ippResponseParser::unSpaceInputArray
02664 
02665 Returned Value: None.
02666 
02667 Called By: ippResponseParser::parseResponse
02668 
02669 Errors:
02670 1. Starting with the ninth position of a response string, if a space is
02671    found that is not before or after a comma, before or after a left or
02672    right parenthesis, or in a string:
02673    ILLEGAL_SPACE.
02674 
02675 Reference pages: (33 - 34)
02676 
02677 Notes:
02678 
02679 Starting at the ninth position (index 8), this removes from the
02680 _inputArray all spaces outside of strings. It does this by moving
02681 characters from right to left as necessary to fill in any spaces.
02682 
02683 The n-1 in the termination condition of the "for" loop allows the NULL
02684 to be copied also.
02685 
02686 */
02687 
02688 bool UnSpaceInputArray(char* _inputArray,int start);
02689 
02690 void ippResponseParser::unSpaceInputArray()
02691 {
02692    if (!::UnSpaceInputArray(_inputArray,8)) {
02693       _errorCode  = ILLEGAL_SPACE;
02694    }
02695 }
02696 
02697 
02698 void ippResponseParser::dump_token(int k)
02699 {
02700   std::cout << "item " << std::setw(3) << k << " ";
02701   switch(_resTypes[k])
02702   {
02703     case RESCOMMA: std::cout << "," ;break;
02704     case RESDOT: std::cout << "." ;break;
02705     case RESDOUBLE: std::cout << "#" ;break;
02706       std::cout <<"( value " << _resDoubles[k]  << ")";
02707     case RESKEYWORD: 
02708       std::cout << "K" ;
02709       std::cout <<" ( keywork " << getKeyString(_resKeywords[k]) << ")";
02710       break;
02711     case RESPARENLEFT: std::cout << "(" ;break;
02712     case RESPARENRIGHT: std::cout << ")" ;break;
02713     case RESSTRING: std::cout << "s" ;break;
02714   }
02715   std::cout << std::endl;
02716 }
02717 /*******************************************************************/
02718 
02719 

Generated on Wed Nov 8 00:20:05 2006 for IPPDME by  doxygen 1.4.1