/* fut_add_chan inserts a new output channel into a fut. * Unlike itbls, otbls, and gtbls, the channel structure is not sharable * and so the caller must not free the chan after this call. (If the * passed channel structure needs to be saved, use fut_copy_chan). * The iomask in this case simply tells which output channel is being * added, and if this channel already exists, an error (0) is returned. * * fut_add_chan is intended to be used in conjunction with fut_new_chan * to construct futs with independent input tables. It does not update * the list of common input tables as does fut_new and fut_defchan and * should not be mixed with calls to fut_defchan. */ KpInt32_t fut_add_chan (fut_p fut, KpInt32_t iomask, fut_chan_p chan) { KpInt32_t ochan; if ( ! IS_FUT(fut) || (chan != FUT_NULL_CHAN && ! IS_CHAN(chan)) ) { return (0); } /* get output channel no. */ ochan = FUT_CHAN ((KpInt32_t)FUT_OMASK(iomask)); /* prohibit redefinition of channel */ if ( ochan >= FUT_NOCHAN || fut->chan[ochan] != NULL) return (0); /* insert channel into fut */ fut->chan[ochan] = chan; fut->chanHandle[ochan] = (IS_CHAN(fut->chan[ochan])) ? fut->chan[ochan]->handle : FUT_NULL_HANDLE; /* update iomasks */ if ( IS_CHAN(chan) ) { fut->iomask.out |= FUT_BIT(ochan); fut->iomask.in |= chan->imask; } return (1); }
/* fut_new allocates and initializes a new fut_t data structure. * iomask specifies which (common) input tables and which output channels * are being defined. Additional channels may be added later using * fut_defchan. * * NOTES: * 1. All the tables must be packed into a single array. * * 2. If a needed input table is not supplied (as determined from the * grid table) or if a supplied input table is NULL, then a ramp * input table will be automatically generated and inserted into * the common itbl list. The grid sizes are inferred from the * supplied grid tables. */ fut_p fut_new ( KpInt32_t iomask, fut_itbl_p FAR* itbls, fut_gtbl_p FAR* gtbls, fut_otbl_p FAR* otbls) { fut_itbl_p itbl[FUT_NICHAN]; fut_otbl_p otbl[FUT_NOCHAN]; fut_gtbl_p gtbl[FUT_NOCHAN]; fut_p fut; KpInt32_t tIndex, imask, omask, i; /* get input and output masks */ imask = (KpInt32_t)FUT_IMASK(iomask); omask = (KpInt32_t)FUT_OMASK(iomask); if ( imask > FUT_ALLIN || omask > FUT_ALLOUT ) { DIAG("fut_new: too many input or output channels.\n", 0); return (NULL); } /* get args specified by iomask */ for ( i=0, tIndex = 0; i<FUT_NICHAN; i++ ) { itbl[i] = (((imask & FUT_BIT(i)) != 0) && (itbls != NULL)) ? itbls[tIndex++] : FUT_NULL_ITBL; } for ( i=0, tIndex = 0; i<FUT_NOCHAN; i++ ) { gtbl[i] = FUT_NULL_GTBL; otbl[i] = FUT_NULL_OTBL; if ((omask & FUT_BIT(i)) != 0) { if (gtbls != NULL) { gtbl[i] = gtbls[tIndex]; } if (otbls != NULL) { otbl[i] = otbls[tIndex]; } tIndex++; } } /* allocate and clear the fut_t structure */ fut = fut_alloc_fut (); if ( fut == NULL ) { return (NULL); } /* set the interpolation order */ fut->iomask.order = (KpInt32_t)FUT_ORDMASK(iomask); /* insert the specified input tables */ for ( i=0; i<FUT_NICHAN; i++ ) { if ( itbl[i] == NULL) continue; if ( ! IS_ITBL (itbl[i]) ) { fut_free (fut); return (NULL); } fut->iomask.in |= FUT_BIT(i); fut->itbl[i] = fut_share_itbl(itbl[i]); fut->itblHandle[i] = fut->itbl[i]->handle; } /* define the specified output channels */ for ( i=0; i<FUT_NOCHAN; i++ ) { if ( gtbl[i] == NULL) continue; if ( ! fut_defchan(fut,FUT_OUT(FUT_BIT(i)),NULL,gtbl[i],otbl[i]) ) { fut_free (fut); return (NULL); } } fut->lutConfig = LUT_TYPE_UNKNOWN; return (fut); }
fut_p fut_comp (fut_p fut1, fut_p fut0, KpInt32_t iomask) { KpInt32_t ok = 1, nGridPoints, omask, evalomask, imask, pmask, order, i, j, nEntries, nOutChans; fut_p fut2 = NULL, evalFut = NULL; fut_itbl_p oitbls[FUT_NICHAN]; mf2_tbldat_p indat[FUT_NICHAN], outdat[FUT_NOCHAN]; fut_gtbl_p fut1_gtbls[FUT_NOCHAN]; if (( ! IS_FUT(fut0)) || ( ! IS_FUT(fut1))) { return (NULL); } /* extract component masks from iomask */ omask = FUT_OMASK(iomask); /* which output chans? */ pmask = FUT_PMASK(iomask); /* which ones allowed to pass through? */ order = FUT_ORDMASK(iomask); /* which interpolation to use? */ if ( order == FUT_DEFAULT ) { order = fut1->iomask.order; } /* adjust masks for iomask_check below */ pmask &= fut0->iomask.out; /* available for "pass through" */ if ( omask == 0 ) { /* required outputs (0 means all) */ omask = fut1->iomask.out; } /* see if fut0 can provide required inputs to fut1 */ imask = fut0->iomask.out; /* available inputs for fut1 */ iomask = FUT_OUT(omask) | FUT_IN(imask) | FUT_PASS(pmask); if ( ! fut_iomask_check (fut1, iomask) ) { return (NULL); } /* make sure the futs are in the reference state */ if ((fut_to_mft (fut0) != 1) || (fut_to_mft (fut1) != 1)) { return (NULL); } /* fut1 will be used to process the grid tables of fut0, placing the * results in the grid tables of fut2. Fut0's grid table data must first * be passed through its output tables before sending it through fut1's * input tables. This is accomplished more efficiently by composing * fut1's input tables with fut0's output tables and using these directly * on fut0 grid data rather than the normal input tables. * * Create the result fut (fut2) which will be the composition of fut1 * and fut0. Fut2 will inherit the input tables of fut0 and the output * tables of fut1. Its grid data will be in the same color coordinates * as fut1's. */ fut2 = fut_new (FUT_IN(FUT_ALLIN), fut0->itbl, NULL, NULL); if ( fut2 == NULL ) { return (NULL); } /* for each desired channel i in fut2, create a new grid table. The * dimensions of each new grid table are derived from fut0 and fut1 * like so: for every input required for channel i of fut1, form the * union of the input sets of all corresponding fut0 outputs. */ /* null all io tables and table pointers */ KpMemSet (oitbls, 0, sizeof(oitbls)); imask = 0; /* will be the input mask for all inputs needed to fut1 */ evalomask = 0; /* omask for evaluation */ for (i = 0; (i < FUT_NOCHAN) && ok; i++) { KpInt32_t size[FUT_NICHAN]; fut_gtbl_p gtbl; KpInt32_t imask1, imask2; fut1_gtbls[i] = NULL; /* assume not needed */ if ((omask & FUT_BIT(i)) == 0) { /* is this output channel needed? */ continue; /* no */ } /* if a specified output is to be passed through from fut0, do that here */ if ( ! IS_CHAN(fut1->chan[i]) && IS_CHAN(fut0->chan[i])) { ok = fut_defchan (fut2, FUT_OUT(FUT_BIT(i)), NULL, fut0->chan[i]->gtbl, fut0->chan[i]->otbl); continue; /* no need to evaluate this ochan */ } if (! IS_CHAN(fut1->chan[i])) { ok = 0; /* something wrong */ goto GetOut; } /* At this point we know that (fut1->chan[i] != 0). We also * have determined (from iomask_check above) that fut0->chan[j] != 0. */ imask2 = 0; /* determine inputs from fut0 needed for this channel */ imask1 = fut1->chan[i]->imask; /* inputs used by this chan */ for (j = 0; (j < FUT_NICHAN) && ok; j++) { if ((imask1 & FUT_BIT(j)) != 0) { /* this input chan is needed */ if ( ! IS_CHAN(fut0->chan[j])) { /* available? */ ok = 0; /* composition fails */ goto GetOut; } if (fut1->itbl[j] != fut1->chan[i]->itbl[j]) { /* shared itbl? */ goto nextOChan; /* nope, ignore this ochan */ } imask2 |= fut0->chan[j]->imask; } } evalomask |= FUT_BIT(i); /* will be evalutating this channel */ imask |= imask1; /* build mask of all needed inputs */ /* determine required dimensions from mask */ for (j = 0; j < FUT_NICHAN; j++) { size[j] = (imask2 & (KpInt32_t)FUT_BIT(j)) ? fut0->itbl[j]->size : 1; } /* create the new grid table * insert it along with fut1's output table into fut2 */ gtbl = fut_new_gtblEx (FUT_IN(FUT_ALLIN), NULL, NULL, size); ok = fut_defchan (fut2, FUT_OUT(FUT_BIT(i)), NULL, gtbl, fut1->chan[i]->otbl); fut_free_gtbl (gtbl); if (!ok) { goto GetOut; } fut1_gtbls[i] = fut1->chan[i]->gtbl; /* collect gtbls for evaluation fut */ /* verify the input data for the evaluation of the output channel in fut1 */ for (j = 0; j < FUT_NICHAN; j++) { if ((imask1 & FUT_BIT(j)) != 0) { /* this channel needed as input */ if ((fut0->chan[j]->imask & (~fut2->chan[i]->imask)) != 0) { /* it's inputs must be used by output */ ok = 0; /* composition fails */ goto GetOut; } } } nextOChan:; } /* collect the gtbls which are the input data for the chan evaluation. * also pre-compose fut0's otbls with fut1's itbls. */ for (i = 0; i < FUT_NICHAN; i++) { oitbls[i] = NULL; if (ok) { fut_chan_p theChan = fut0->chan[i]; if ((imask & FUT_BIT(i)) == 0) { continue; /* this output from fut0 not required */ } indat[i] = theChan->gtbl->refTbl; /* collect gtbls: the input data for the evaluation */ ok = (indat[i] != NULL); /* allocate memory for composed i/o tables * these have the same size as the output tables of the channel supplying the input */ if (ok) { fut_itbl_p theITbl = fut1->itbl[i]; fut_otbl_p theOTbl = theChan->otbl; oitbls[i] = fut_alloc_itbl (); /* get an itbl */ oitbls[i]->size = theITbl->size; oitbls[i]->dataClass = KCP_FIXED_RANGE; nEntries = MAX(theITbl->refTblEntries, theOTbl->refTblEntries); ok = (fut_alloc_imftdat (oitbls[i], nEntries) != NULL); if (ok) { /* make input table for evaluation */ ok = fut_comp_iotblMF (theITbl, theOTbl, oitbls[i]); } } } } /* make an evaluation fut with the composed I/O tables, fut1's gtbls, and no otbls */ evalFut = fut_new (iomask, oitbls, fut1_gtbls, NULL); if (( ! ok) || (evalFut == NULL) || /* if evaluation fut ok */ (fut_to_mft (fut2) != 1)) { /* make sure the futs are in the reference state */ ok = 0; goto GetOut; } else { /* Finally, we are ready to pass fut0's grid tables through fut1 */ for (i = 0, nOutChans = 0; (i < FUT_NOCHAN) && ok; i++) { if ((evalomask & FUT_BIT(i)) != 0) { fut_gtbl_p gtbl; gtbl = fut2->chan[i]->gtbl; nGridPoints = gtbl->tbl_size / sizeof (fut_gtbldat_t); /* grid points for eval */ if (evalFut->iomask.in != evalFut->chan[i]->imask) { /* must evaluate this channel singly */ evalomask &= ~FUT_BIT(i); /* remove channel from multiple eval list */ ok = evaluateFut (evalFut, FUT_BIT(i), KCM_USHORT, nGridPoints, (KpGenericPtr_t FAR*) indat, (KpGenericPtr_t FAR*) &(gtbl->refTbl)); } else { outdat[nOutChans] = gtbl->refTbl; nOutChans++; } } } /* eval result is composed fut's gtbls */ ok = evaluateFut (evalFut, evalomask, KCM_USHORT, nGridPoints, (KpGenericPtr_t FAR*) indat, (KpGenericPtr_t FAR*) outdat); } GetOut: /* must always free up the evaluation fut and io tables, even if an error occurred! */ fut_free (evalFut); fut_free_tbls (FUT_NICHAN, (void *)oitbls); /* check for errors */ if ( !ok ) { fut_free (fut2); fut2 = NULL; } return (fut2); }
fut_p constructfut ( KpInt32_t iomask, KpInt32_p sizeArray, fut_calcData_p fData, fut_ifunc_p ifunArray, fut_gfunc_p gfunArray, fut_ofunc_p ofunArray, PTDataClass_t iClass, PTDataClass_t oClass) { fut_p futp; KpInt32_t i1, imask, omask; fut_itbl_p itbls[FUT_NICHAN] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; fut_gtbl_p gtbls[FUT_NOCHAN] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; fut_otbl_p otbls[FUT_NOCHAN] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; fut_ifunc_t ifun; fut_gfunc_t gfun; fut_ofunc_t ofun; fData_t fDataL; fut_calcData_p fDataP; if (sizeArray == NULL) return NULL; if (fData == NULL) { fDataP = &fDataL.std; } else { fDataP = fData; } imask = FUT_IMASK(iomask); omask = FUT_OMASK(iomask); #if defined KCP_DIAG_LOG {KpChar_t string[256], str2[256]; KpInt32_t i1; sprintf (string, "constructfut\n iomask %x, sizeArray[]", iomask); for (i1 = 0; i1 < FUT_NICHAN; i1++) { if ((FUT_BIT(i1) & imask) != 0) { sprintf (str2, " %d", sizeArray[i1]); strcat (string, str2); } } sprintf (str2, ", fData %x, ifunArray %x, gfunArray %x, ofunArray %x, iClass %d, oClass %d\n", fData, ifunArray, gfunArray, ofunArray, iClass, oClass); strcat (string, str2); kcpDiagLog (string);} #endif /* Compute shared input tables: */ for (i1 = 0; i1 < FUT_NICHAN; i1++) { if ((imask & FUT_BIT(i1)) != 0) { if ((ifunArray == NULL) || (ifunArray[i1] == NULL)) { ifun = fut_irampEx; fDataP = &fDataL.std; if (iClass == KCP_VARIABLE_RANGE) { fDataL.scale = KCP_16_TO_8_ENCODING; } else { fDataL.scale = 1.0; } } else { ifun = ifunArray[i1]; } fDataP->chan = i1; /* define the channel # */ itbls[i1] = fut_new_itblEx (KCP_REF_TABLES, iClass, sizeArray[i1], ifun, fDataP); itbls[i1]->id = fut_unique_id (); itbls[i1]->dataClass = iClass; } } /* Compute grid tables and output tables: */ for (i1 = 0; i1 < FUT_NOCHAN; i1++) { if ((omask & FUT_BIT(i1)) != 0) { if ((gfunArray == NULL) || (gfunArray[i1] == NULL)) { gfun = fut_grampEx; } else { gfun = gfunArray[i1]; } fDataP->chan = i1; /* define the channel # */ gtbls[i1] = fut_new_gtblEx (KCP_REF_TABLES, iomask, gfun, fDataP, sizeArray); gtbls[i1]->id = fut_unique_id(); if ((ofunArray == NULL) || (ofunArray[i1] == NULL)) { ofun = fut_orampEx; fDataP = &fDataL.std; if (oClass == KCP_VARIABLE_RANGE) { fDataL.scale = KCP_8_TO_16_ENCODING; } else { fDataL.scale = 1.0; } } else { ofun = ofunArray[i1]; } otbls[i1] = fut_new_otblEx (KCP_REF_TABLES, oClass, ofun, fDataP); otbls[i1]->id = fut_unique_id(); otbls[i1]->dataClass = oClass; } } /* Assemble FuT: */ futp = fut_new (iomask, itbls, gtbls, otbls); fut_free_tbls (FUT_NICHAN, (KpGenericPtr_t *)itbls); fut_free_tbls (FUT_NOCHAN, (KpGenericPtr_t *)gtbls); fut_free_tbls (FUT_NOCHAN, (KpGenericPtr_t *)otbls); if (fut_to_mft (futp) != 1) { /* convert to reference tables */ fut_free (futp); futp = NULL; } return (futp); }
PTErr_t PTEvaluate ( PTRefNum_t PTRefNum, PTEvalDTPB_p evalDef, PTEvalTypes_t evalID, KpInt32_t devNum, KpInt32_t aSync, opRefNum_p opRefNum, callBack_p callBack) { PTErr_t PTErr; PTEvalDTPB_t lEvalDef; PTCompDef_t thisInput [FUT_NICHAN], thisOutput [FUT_NOCHAN]; PTRefNum_t PTList [MAX_PT_CHAIN_SIZE]; PTTable_p evalList [MAX_PT_CHAIN_SIZE], PTTableP; PTTable_p* listStart; KpInt32_t theSerialCount, i1, i2, i3, i4, nOutputs, nFuts, PTcount; KpUInt32_t tempMemNeeded, oMask, ioMaskList [MAX_PT_CHAIN_SIZE]; PTImgAddr_t addr; #if defined (KCP_ACCEL) PTEvalTypes_t evaluator; KpInt32_t numEvals; #endif if (devNum) {} if (aSync) {} if (opRefNum) {} #if defined (KCP_MACPPC_MP) KCPInitializeMP (); #endif PTErr = getPTStatus (PTRefNum); /* must be an active or serial PT */ if ((PTErr != KCP_PT_ACTIVE) && (PTErr != KCP_SERIAL_PT)) { goto ErrOut0; } #if defined (KCP_ACCEL) PTErr = GetEval (evalID, &evaluator); /* get an evaluator */ if (PTErr != KCP_SUCCESS) { goto ErrOut0; } #endif /* valid PTEvalDTPB_p? */ if (evalDef == NULL) goto ErrOut1; if (evalDef->input == NULL) goto ErrOut1; if (evalDef->output == NULL) goto ErrOut1; if (evalDef->nInputs > FUT_NICHAN) goto ErrOut3; if (evalDef->nOutputs > FUT_NOCHAN) goto ErrOut3; /* set up the local evaluation structures */ /* set input and output to NULL */ /* this preserves the channel position while allowing */ /* the number of channels to indicate the number of valid addresses */ /* this is needed to keep both the CTE and SW evaluations happy */ for (i1 = 0; i1 < FUT_NICHAN; i1++) { thisInput[i1].pelStride = 0; thisInput[i1].lineStride = 0; thisInput[i1].addr = NULL; } lEvalDef.nPels = evalDef->nPels; lEvalDef.nLines = evalDef->nLines; lEvalDef.nInputs = FUT_NICHAN; lEvalDef.dataTypeI = evalDef->dataTypeI; lEvalDef.input = thisInput; for (i1 = 0; i1 < evalDef->nInputs; i1++) { lEvalDef.input[i1].pelStride = evalDef->input[i1].pelStride; lEvalDef.input[i1].lineStride = evalDef->input[i1].lineStride; lEvalDef.input[i1].addr = evalDef->input[i1].addr; } /* output addresses are loaded in the evaluation loop, no need to do anything here */ /* clear the PT and evaluation lists, just for clarity */ for (i1 = 0; i1 < MAX_PT_CHAIN_SIZE; i1++) { PTList[i1] = NULL; evalList[i1] = NULL; } /* get the list of PTs which we must actually evaluate */ PTErr = resolvePTData (PTRefNum, &theSerialCount, PTList); /* set up list of futs through which the image is evaluated */ for (i1 = 0; i1 < theSerialCount; i1++) { PTTableP = lockPTTable (PTList[i1]); /* lock tables while evaluating */ evalList[i1] = PTTableP; } /* initialize the evaluation list */ PTErr = setupEvalList (theSerialCount, evalList, ioMaskList, evalDef, &tempMemNeeded); if (PTErr != KCP_SUCCESS) { goto ErrOut2; } /* if temporary memory is not needed, */ /* then evaluate a full image at a time until */ /* the image has been processed through all futs */ /* if temporary memory is needed, */ /* then this level processes the image just once */ /* and a lower level processes the image through all futs */ if (tempMemNeeded == 0) { PTcount = theSerialCount; } else { PTcount = 1; } initProgressPasses (PTcount, callBack); /* process the image through each fut in the list */ for (i1 = 0; i1 < PTcount; i1++) { /* set up the output data addresses */ /* use io mask to order output channels properly */ if (tempMemNeeded == 1) { nFuts = theSerialCount; /* this many futs to evaluate */ listStart = &evalList[0]; oMask = FUT_OMASK(ioMaskList[nFuts-1]); /* use mask of last fut */ } else { nFuts = 1; /* evaluate one fut */ listStart = &evalList[i1]; oMask = FUT_OMASK(ioMaskList[i1]); /* use mask of this fut */ } /* initialize the output data structures */ lEvalDef.nOutputs = FUT_NOCHAN; lEvalDef.dataTypeO = evalDef->dataTypeO; lEvalDef.output = thisOutput; for (i2 = 0; i2 < FUT_NOCHAN; i2++) { thisOutput[i2].pelStride = 0; thisOutput[i2].lineStride = 0; thisOutput[i2].addr = NULL; } /* set the output channel addresses */ if (i1 == (PTcount -1)) { /* last, just use supplied stuff */ for (i2 = 0, nOutputs = 0; i2 < evalDef->nOutputs; i2++) { lEvalDef.output[i2].pelStride = evalDef->output[i2].pelStride; lEvalDef.output[i2].lineStride = evalDef->output[i2].lineStride; lEvalDef.output[i2].addr = evalDef->output[i2].addr; nOutputs++; /* count actual outputs */ } getDataBytes (evalDef->dataTypeO, &i3); /* get output data size */ if (i3 == 0) { nOutputs = 3; } } else { for (i2 = oMask, i3 = 0, i4 = 0, nOutputs = 0; i2 != 0; i2 >>= 1, i3++) { if ((i2 & 1) == 1) { /* this output channel is needed */ while ((addr = evalDef->output[i4].addr) == NULL) { i4++; /* get next available output channel */ } if (i4 > evalDef->nOutputs) { PTErr = KCP_PTERR_4; /* programming error */ goto ErrOut2; } lEvalDef.output[i3].pelStride = evalDef->output[i4].pelStride; lEvalDef.output[i3].lineStride = evalDef->output[i4].lineStride; lEvalDef.output[i3].addr = addr; i4++; /* next output address */ nOutputs++; /* count actual outputs */ } } } #if defined (KCP_ACCEL) /* if there are less than FASTER_IN_SW evaluations, it's faster to do it in software. */ numEvals = lEvalDef.nPels * lEvalDef.nLines * nOutputs; if ((numEvals < FASTER_IN_SW) || (tempMemNeeded == 1)) { evaluator = KCP_EVAL_SW; } switch (evaluator) { case KCP_EVAL_SW: /* evaluate in software */ software_evaluation: #endif PTErr = PTEvalSeq (nFuts, listStart, ioMaskList, &lEvalDef, callBack); if (PTErr != KCP_SUCCESS) { goto ErrOut2; } #if defined (KCP_ACCEL) break; case KCP_EVAL_CTE: /* evaluate using the NFE */ { PTRefNum_t thePTRefNum; KpHandle_t PTData; thePTRefNum = listStart[0]->refNum; /* get the PT reference number */ PTData = getPTData (thePTRefNum); /* get the transform data */ PTErr = PT_eval_cteDT (PTData, &lEvalDef, 0, 0, callBack); if ((PTErr == KCP_CTE_GRID_TOO_BIG) || (PTErr == KCP_CTE_NOT_ATTEMPTED)) { goto software_evaluation; } break; } default: PTErr = KCP_INVAL_EVAL; break; } #else if (evalID) {} /* unreferenced formal parameter */ #endif /* output for this PT is input for next PT */ lEvalDef.nInputs = lEvalDef.nOutputs; lEvalDef.dataTypeI = lEvalDef.dataTypeO; for (i2 = 0; i2 < lEvalDef.nInputs; i2++) { lEvalDef.input[i2].pelStride = lEvalDef.output[i2].pelStride; lEvalDef.input[i2].lineStride = lEvalDef.output[i2].lineStride; lEvalDef.input[i2].addr = lEvalDef.output[i2].addr; } } ErrOut2: /* unlock the PTs used for evaluation */ for (i1 = 0; i1 < theSerialCount; i1++) { unlockPTTable (PTList[i1]); } ErrOut0: return (PTErr); ErrOut1: PTErr = KCP_BAD_PTR; goto ErrOut0; ErrOut3: PTErr = KCP_INVAL_EVAL; goto ErrOut0; }