GetNext error handling and a few other fixes
diff --git a/inc/qcbor/qcbor_common.h b/inc/qcbor/qcbor_common.h
index 7a7a132..20dff0e 100644
--- a/inc/qcbor/qcbor_common.h
+++ b/inc/qcbor/qcbor_common.h
@@ -34,6 +34,21 @@
 #ifndef qcbor_common_h
 #define qcbor_common_h
 
+
+/**
+ This define indicates a version of QCBOR that supports spiffy decode,
+ the decode functions found in qcbor_spiffy_decode.h.
+
+ Versions of QCBOR that support spiffy decode are backwards compatible
+ with previous versions, but there are a few minor exceptions such as
+ some aspects of tag handling that are different. This define can be
+ used handle these variances.
+*/
+#define QCBOR_SPIFFY_DECODE
+
+
+
+
 /* Standard CBOR Major type for positive integers of various lengths */
 #define CBOR_MAJOR_TYPE_POSITIVE_INT 0
 
@@ -408,6 +423,9 @@
 
 
 /**
+ This is deprecated. See QCBORDecode_GetNthTag() and QCBORDecode_GetNthTagOfLast()
+ for tag handling.
+
  The maximum number of tags that can be in @ref QCBORTagListIn and passed to
  QCBORDecode_SetCallerConfiguredTagList()
  */
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index c440cd2..be6697a 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -829,7 +829,7 @@
  map or array has been encountered. This works the same for both
  definite and indefinite-length arrays.
 
- TODO: revise this documentation
+ TODO: revise this documentation on tags. It is wrong.
  This decoder support CBOR type 6 tagging. The decoding of particular
  given tag value may be supported in one of three different ways.
 
@@ -893,10 +893,26 @@
  - There are a few CBOR constructs that are not handled without some
  extra configuration. These are indefinite length strings and maps
  with labels that are not strings or integers. See QCBORDecode_Init().
+
+ This does not set the internal error code or cease to function when
+ it is set. The error returned must always be checked. See also
+ QCBORDecode_VGetNext().
  */
 QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
 
 
+/**
+ @brief QCBORDecode_GetNext() using internal error state error handling.
+
+ @param[in]  pCtx          The decoder context.
+ @param[out] pDecodedItem  Holds the CBOR item just decoded.
+
+ This is the same as QCBORDecode_GetNext() but uses the error handling
+ method of spiffy decode where an internal error is set instead
+ of returning an error. If the internal error is set, this doesn't
+ do anything.
+*/
+void QCBORDecode_VGetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
 
 
 /**
@@ -1037,16 +1053,24 @@
  @brief Get the decoding error.
 
  @param[in] pCtx    The decoder context.
- @returns The decoding error.
+ @return            The decoding error.
 
- All decoding functions except GetNext() do not return an error.
- Instead they set an internal error state. Once an error has
- occured, no further decoding will be performed even if further
- decoding functions are called.
+ All decoding functions set a saved internal error when they fail.
+ Most decoding functions do not return an error. To know the error,
+ this function must be called.
 
- The error will be returned when QCBORDecode_Finish() finish is
- called. This can make call sequence for decoding a given
- CBOR protocol very clean and simple in many cases.
+ The intended use is that decoding functions can be called one
+ after another with no regard to error until either the whole
+ decode is finished or some data returned from the decode must
+ be referenced. This makes implementations of protocols much
+ cleaner and prettier. For simple protocols the only error check
+ may be the return code from QCBORDecode_Finish().
+
+ Once a decoding error has occured most decode functions will do
+ nothing if called. QCBORDecode_GetNext() is an exception.
+
+ The implementation of this is just an inline accessor function
+ so its use adds very little object code.
 
  Note that no reference to the decoded data should be made until
  after QCBORDecode_Finish() is called as it will not be valid
@@ -1066,6 +1090,7 @@
  */
 static QCBORError QCBORDecode_GetError(QCBORDecodeContext *pCtx);
 
+
 /**
  @brief Get and reset the decoding error.
 
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 6450203..6c66f1e 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -1879,7 +1879,7 @@
       nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
       goto Done;
    }
-   pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel; // TODO: make sure this is right
+   pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
 
 Done:
   return nReturn;
@@ -2087,6 +2087,19 @@
 /*
  Public function, see header qcbor/qcbor_decode.h file
  */
+void QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
+{
+   if(pMe->uLastError != QCBOR_SUCCESS) {
+      return;
+   }
+
+   pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
+}
+
+
+/*
+ Public function, see header qcbor/qcbor_decode.h file
+ */
 QCBORError
 QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
                             QCBORItem *pDecodedItem,
@@ -2814,40 +2827,14 @@
 
 /**
  @param[in] TagSpec  Specification for matching tags.
- @param[in] uDataType  A QCBOR data type
+ @param[in] pItem    The item to check.
 
  @retval QCBOR_SUCCESS   \c uDataType is allowed by @c TagSpec
  @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
 
  The data type must be one of the QCBOR_TYPEs, not the IETF CBOR Registered tag value.
  */
-static QCBORError CheckTagRequirement(const TagSpecification TagSpec, uint8_t uDataType)
-{
-   if((TagSpec.uTagRequirement & (~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) == QCBOR_TAG_REQUIREMENT_TAG) {
-      // Must match the tag and only the tag
-      return CheckTypeList(uDataType, TagSpec.uTaggedTypes);
-   }
-
-   QCBORError uReturn = CheckTypeList(uDataType, TagSpec.uAllowedContentTypes);
-   if(uReturn == QCBOR_SUCCESS) {
-      return QCBOR_SUCCESS;
-   }
-
-   if((TagSpec.uTagRequirement & (~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
-      /* Must match the content type and only the content type.
-       There was no match just above so it is a fail. */
-      return QCBOR_ERR_UNEXPECTED_TYPE;
-   }
-
-   /* If here it can match either the tag or the content
-    and it hasn't matched the content, so the end
-    result is whether it matches the tag. This is
-    also the case that the CBOR standard discourages. */
-
-   return CheckTypeList(uDataType, TagSpec.uTaggedTypes);
-}
-
-static QCBORError CheckTagRequirement2(const TagSpecification TagSpec, const QCBORItem *pItem)
+static QCBORError CheckTagRequirement(const TagSpecification TagSpec, const QCBORItem *pItem)
 {
    if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
       pItem->uTags[0] != CBOR_TAG_INVALID16) {
@@ -2883,136 +2870,7 @@
    return CheckTypeList(nItemType, TagSpec.uTaggedTypes);
 }
 
-#if 0
-/**
- @param[in] TagSpec  Specification for matching tags.
- @param[in] uDataType  A QCBOR data type
 
- @retval QCBOR_SUCCESS   \c uDataType is allowed by @c TagSpec
- @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
-
- The data type must be one of the QCBOR_TYPEs, not the IETF CBOR Registered tag value.
- */
-static QCBORError CheckTagRequirement2(const TagSpecification TagSpec, uint8_t uDataType)
-{
-   const uint16_t *pTags;
-/*
-For all the tag-specific accessor methods supported, GetNext will
- process then automatically when encountered during decoding.
- The will have a QCBOR_TYPE and a representation in QCBORItem.
- There are no expections to this (so far).
-
- That means the tag list in the QCBORItem will never have
- these tags in it. The tags in that list never need to
- be examined here.
-
-
-
-1 Tag list must be empty
-
-2 and 5, first tag must be in expected list
-
-4
-
-3 tag list must be empty or one in the expected list
-
-6, if first tag is expected, consume it, pass the rest on
-
-
- */
-
-   /*
-    First thing to understand is that GetNext will have processed
-    the tags this code knows about. They will not be in the unprocessed
-    tags list and the dataType will be of the processed CBOR.
-    */
-
-   const bool bUnprocessedTagsEmpty = pTags[0] != CBOR_TAG_INVALID16;
-
-   const bool bDataTypeMatchesRequestedTaggedType = !CheckTypeList(uDataType, TagSpec.uTaggedTypes);
-
-   const bool bDataTypeMatchesRequestedContentType = !CheckTypeList(uDataType, TagSpec.uAllowedContentTypes);
-
-
-   if(TagSpec.uTagRequirement == 1) {
-      /* There should be no tags at all, so the unprocessed tag
-       list should be empty.
-
-       The content has to match the expected content. If
-       there was a tag that was interpreted, the content
-       wouldn't match.
-
-       */
-      if(!bUnprocessedTagsEmpty) {
-         return QCBOR_ERR_UNEXPECTED_TYPE;
-      } else {
-         if(!bDataTypeMatchesRequestedContentType) {
-            return QCBOR_ERR_UNEXPECTED_TYPE;
-         } else {
-            return QCBOR_SUCCESS;
-         }
-
-      }
-
-
-
-   } else if(TagSpec.uTagRequirement == 2) {
-      /* The tag was present so GetNext will have interpreted it by now.
-       The data type should be one of the requested types
-       and there should be no other tags. */
-
-      if(!bUnprocessedTagsEmpty) {
-          return QCBOR_ERR_UNEXPECTED_TYPE;
-      } else {
-         if(!bDataTypeMatchesRequestedTaggedType) {
-            return QCBOR_ERR_UNEXPECTED_TYPE;
-         } else {
-            return QCBOR_SUCCESS;
-         }
-      }
-   } else if(TagSpec.uTagRequirement == 3) {
-      if(!bUnprocessedTagsEmpty) {
-         return QCBOR_ERR_UNEXPECTED_TYPE;
-      } else {
-         if(bDataTypeMatchesRequestedTaggedType || bDataTypeMatchesRequestedContentType) {
-            return true;
-         } else {
-            return false;
-         }
-      }
-   } else if(TagSpec.uTagRequirement == 4) {
-
-
-
-
-
-
-
-   if(TagSpec.uTagRequirement == QCBOR_TAG_REQUIREMENT_TAG) {
-      // Must match the tag and only the tag
-      return CheckTypeList(uDataType, TagSpec.uTaggedTypes);
-   }
-
-   QCBORError uReturn = CheckTypeList(uDataType, TagSpec.uAllowedContentTypes);
-   if(uReturn == QCBOR_SUCCESS) {
-      return QCBOR_SUCCESS;
-   }
-
-   if(TagSpec.uTagRequirement == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
-      /* Must match the content type and only the content type.
-       There was no match just above so it is a fail. */
-      return QCBOR_ERR_UNEXPECTED_TYPE;
-   }
-
-   /* If here it can match either the tag or the content
-    and it hasn't matched the content, so the end
-    result is whether it matches the tag. This is
-    also the case that the CBOR standard discourages. */
-
-   return CheckTypeList(uDataType, TagSpec.uTaggedTypes);
-}
-
-#endif
 
 
 // Semi-private
@@ -3027,7 +2885,7 @@
       return;
    }
 
-   pMe->uLastError = (uint8_t)CheckTagRequirement2(TagSpec, pItem);
+   pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem);
 }
 
 // Semi-private
@@ -3041,7 +2899,7 @@
       return;
    }
 
-   pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
+   pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem);
 }
 
 // Semi-private
@@ -3359,7 +3217,7 @@
          {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
       };
 
-   uError = CheckTagRequirement(TagSpec, pItem->uDataType);
+   uError = CheckTagRequirement(TagSpec, pItem);
    if(uError != QCBOR_SUCCESS) {
       goto Done;
    }
@@ -3652,7 +3510,7 @@
    // TODO: this will give an unexpected type error instead of
    // overflow error for QCBOR_TYPE_UINT64 because TagSpec
    // only has three target types.
-   uErr = CheckTagRequirement2(TagSpec, pItem);
+   uErr = CheckTagRequirement(TagSpec, pItem);
    if(uErr != QCBOR_SUCCESS) {
       goto Done;
    }
@@ -3735,7 +3593,7 @@
       return;
    }
 
-   pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, Item.uDataType);
+   pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, &Item);
 
    if(pMe->uLastError == QCBOR_SUCCESS) {
       *pBstr = Item.val.string;
@@ -3759,7 +3617,7 @@
       {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
    };
 
-   QCBORError uErr = CheckTagRequirement(TagSpec, pItem->uDataType);
+   QCBORError uErr = CheckTagRequirement(TagSpec, pItem);
    if(uErr != QCBOR_SUCCESS) {
       return uErr;
    }
@@ -3861,13 +3719,13 @@
 
    QCBORError uReturn;
 
-   if(CheckTagRequirement(TagSpecText, pItem->uDataType) == QCBOR_SUCCESS) {
+   if(CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
       *pMessage = pItem->val.string;
       if(pbIsNot7Bit != NULL) {
          *pbIsNot7Bit = false;
       }
       uReturn = QCBOR_SUCCESS;
-   } else if(CheckTagRequirement(TagSpecBinary, pItem->uDataType) == QCBOR_SUCCESS) {
+   } else if(CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
       *pMessage = pItem->val.string;
       if(pbIsNot7Bit != NULL) {
          *pbIsNot7Bit = true;
@@ -5076,7 +4934,7 @@
    QCBORError uErr;
    // Loops runs at most 1.5 times. Making it a loop saves object code.
    while(1) {
-      uErr = CheckTagRequirement(TagSpec, pItem->uDataType);
+      uErr = CheckTagRequirement(TagSpec, pItem);
       if(uErr != QCBOR_SUCCESS) {
          goto Done;
       }
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index bd10acc..a3798fe 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -4864,8 +4864,8 @@
 
 
    QCBORDecode_Init(&DCtx, ValidEncodedMap, 0);
-   QCBORDecode_GetNext(&DCtx, &Item1);
-   QCBORDecode_GetNext(&DCtx, &Item1);
+   QCBORDecode_VGetNext(&DCtx, &Item1);
+   QCBORDecode_VGetNext(&DCtx, &Item1);
    QCBORDecode_EnterArray(&DCtx);
    QCBORDecode_GetNext(&DCtx, &Item1);
    if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING) {