/* BEGIN_ICS_COPYRIGHT7 ****************************************

Copyright (c) 2015-2020, Intel Corporation

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Intel Corporation nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

** END_ICS_COPYRIGHT7   ****************************************/

/* [ICS VERSION STRING: unknown] */

#include "topology.h"
#include "topology_internal.h"

#ifndef __VXWORKS__
#include <strings.h>
#include <fnmatch.h>
#else
#include "icsBspUtil.h"
#endif

#define FILENAME				256 //Length of file name
#define MIN_LIST_ITEMS				100 // minimum items for ListInit to allocate for
#define NODE_PAIR_DELIMITER_SIZE		1 //Length of delimiter while parsing for node pairs



// Functions to Parse Focus arguments and build POINTs for matches
typedef boolean (PointPortElinkCompareCallback_t)(ExpectedLink *elinkp, void *nodecmp, uint8 portnum);
static FSTATUS ParsePointPort(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, PointPortElinkCompareCallback_t *callback, void *nodecmp, char **pp);

/* check arg to see if 1st characters match prefix, if so return pointer
 * into arg just after prefix, otherwise return NULL
 */
char* ComparePrefix(char *arg, const char *prefix)
{
	int len = strlen(prefix);
	if (strncmp(arg, prefix, len) == 0)
		return arg+len;
	else
		return NULL;
}

static FSTATUS ParseGidPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	IB_GID gid;
	
	ASSERT(! PointValid(pPoint));
	if (FSUCCESS != StringToGid(&gid.AsReg64s.H, &gid.AsReg64s.L, arg, pp, TRUE)) {
		fprintf(stderr, "%s: Invalid GID format: '%s'\n", g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}
	if (! gid.AsReg64s.H || ! gid.AsReg64s.L) {
		fprintf(stderr, "%s: Invalid GID: 0x%016"PRIx64":0x%016"PRIx64"\n",
					g_Top_cmdname, gid.AsReg64s.H, gid.AsReg64s.L);
		return FINVALID_PARAMETER;
	}
#if 0
	/* This could be an optimization of the error case, testing SubnetPrefix
	 * below should be sufficient until we encounter IB routers
	 */
	/* TBD - if we allow for MC GIDs, this test is inappropriate */
	/* TBD - cleanup use of g_portAttrib global */
	if (g_portAttrib
		&& gid.Type.Global.SubnetPrefix != g_portAttrib->GIDTable[0].Type.Global.SubnetPrefix) {
		fprintf(stderr, "%s: Invalid GID: 0x%016"PRIx64":0x%016"PRIx64"\n",
					g_Top_cmdname, 
					gid.Type.Global.SubnetPrefix, gid.Type.Global.InterfaceID);
		fprintf(stderr, "%s: Subnet Prefix: 0x%016"PRIx64" does not match local port: 0x%016"PRIx64"\n",
					g_Top_cmdname, gid.Type.Global.SubnetPrefix, 
					g_portAttrib->GIDTable[0].Type.Global.SubnetPrefix);
		return FNOT_FOUND;
	}
#endif
	return FindGidPoint(fabricp, gid, pPoint, find_flag, 0);
}

static FSTATUS ParseLidPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	STL_LID lid;
	PortData *portp = NULL;
	char *param;
	
	ASSERT(! PointValid(pPoint));
	if (FSUCCESS != StringToUint32(&lid, arg, pp, 0, TRUE))  {
		fprintf(stderr, "%s: Invalid LID format: '%s'\n", g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}
	if (! lid) {
		fprintf(stderr, "%s: Invalid LID: 0x%x\n", g_Top_cmdname, lid);
		return FINVALID_PARAMETER;
	}

	if (0 == (find_flag & FIND_FLAG_FABRIC))
		return FINVALID_OPERATION;
	if (find_flag & FIND_FLAG_FABRIC) {
		portp = FindLid(fabricp, lid);
		if (portp) {
			pPoint->u.portp = portp;
			pPoint->Type = POINT_TYPE_PORT;
		}
	}
	// N/A for FIND_FLAG_ENODE, FIND_FLAG_ESM and FIND_FLAG_ELINK
	if (PointValid(pPoint)) {
		ASSERT(portp);	// since we only handle FIND_FLAG_FABRIC
		if (NULL != (param = ComparePrefix(*pp, ":node"))) {
			*pp = param;
			pPoint->u.nodep = portp->nodep;
			pPoint->Type = POINT_TYPE_NODE;
		} else if (NULL != (param = ComparePrefix(*pp, ":port:"))) {
			pPoint->u.nodep = portp->nodep;
			pPoint->Type = POINT_TYPE_NODE;
			return ParsePointPort(fabricp, param, pPoint, find_flag, NULL, NULL, pp);
		}
		return FSUCCESS;
	} else {
		fprintf(stderr, "%s: LID Not Found: 0x%x\n", g_Top_cmdname, lid);
		return FNOT_FOUND;
	}
}

static FSTATUS ParsePortGuidPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	EUI64 guid;
	
	ASSERT(! PointValid(pPoint));
	if (FSUCCESS != StringToUint64(&guid, arg, pp, 0, TRUE))  {
		fprintf(stderr, "%s: Invalid Port GUID format: '%s'\n",
						g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}
	if (! guid) {
		fprintf(stderr, "%s: Invalid Port GUID: 0x%016"PRIx64"\n",
						g_Top_cmdname, guid);
		return FINVALID_PARAMETER;
	}
	return FindPortGuidPoint(fabricp, guid, pPoint, find_flag, 0);
}

/* Parse a :port:# suffix, this will limit the Point to the list of ports
 * with the given number
 */
static FSTATUS ParsePointPort(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, PointPortElinkCompareCallback_t *callback, void *nodecmp, char **pp)
{
	uint8 portnum;
	FSTATUS status;
	Point newPoint;
	boolean fabric_fail = FALSE;

	ASSERT(PointValid(pPoint));
	PointInit(&newPoint);
	if (FSUCCESS != StringToUint8(&portnum, arg, pp, 0, TRUE))  {
		fprintf(stderr, "%s: Invalid Port Number format: '%s'\n",
						g_Top_cmdname, arg);
		status = FINVALID_PARAMETER;
		goto fail;
	}
	// for fabric we try to provide a more detailed message using the
	// fabric_fail flag and leaving some of the information in the pPoint
	if (find_flag & FIND_FLAG_FABRIC) {
		switch (pPoint->Type) {
		case POINT_TYPE_NONE:
			break;
		case POINT_TYPE_PORT:
			ASSERT(0);	// should not be called for this type of point
			status = FINVALID_PARAMETER;
			goto fail;
		case POINT_TYPE_PORT_LIST:
			ASSERT(0);	// should not be called for this type of point
			status = FINVALID_PARAMETER;
			goto fail;
		case POINT_TYPE_NODE_PAIR_LIST:
			ASSERT(0);	// should not be called for this type of point
			status = FINVALID_PARAMETER;
			goto fail;
		case POINT_TYPE_NODE:
			{
			PortData *portp = FindNodePort(pPoint->u.nodep, portnum);
			if (! portp) {
				fabric_fail = TRUE;
			} else {
				pPoint->Type = POINT_TYPE_PORT;
				pPoint->u.portp = portp;
			}
			}
			break;
		case POINT_TYPE_NODE_LIST:
			{
			LIST_ITERATOR i;
			DLIST *pNodeList = &pPoint->u.nodeList;

			for (i=ListHead(pNodeList); i != NULL; i = ListNext(pNodeList, i)) {
				NodeData *nodep = (NodeData*)ListObj(i);
				PortData *portp = FindNodePort(nodep, portnum);
				if (portp) {
					status = PointListAppend(&newPoint, POINT_TYPE_PORT_LIST, portp);
					if (FSUCCESS != status)
						goto fail;
				}
			}
			if (! PointValid(&newPoint)) {
				fabric_fail = TRUE;
			} else {
				PointFabricCompress(&newPoint);
				status = PointFabricCopy(pPoint, &newPoint);
				PointDestroy(&newPoint);
				if (FSUCCESS != status)
					goto fail;
			}
			}
			break;
#if !defined(VXWORKS) || defined(BUILD_DMC)
		case POINT_TYPE_IOC:
			{
			PortData *portp = FindNodePort(pPoint->u.iocp->ioup->nodep, portnum);
			if (! portp) {
				fabric_fail = TRUE;
			} else {
				pPoint->Type = POINT_TYPE_PORT;
				pPoint->u.portp = portp;
			}
			}
			break;
		case POINT_TYPE_IOC_LIST:
			{
			LIST_ITERATOR i;
			DLIST *pIocList = &pPoint->u.iocList;

			for (i=ListHead(pIocList); i != NULL; i = ListNext(pIocList, i)) {
				IocData *iocp = (IocData*)ListObj(i);
				PortData *portp = FindNodePort(iocp->ioup->nodep, portnum);
				if (portp) {
					status = PointListAppend(&newPoint, POINT_TYPE_PORT_LIST, portp);
					if (FSUCCESS != status)
						goto fail;
				}
			}
			if (! PointValid(&newPoint)) {
				fabric_fail = TRUE;
			} else {
				PointFabricCompress(&newPoint);
				status = PointFabricCopy(pPoint, &newPoint);
				PointDestroy(&newPoint);
				if (FSUCCESS != status)
					goto fail;
			}
			}
			break;
#endif
		case POINT_TYPE_SYSTEM:
			{
			cl_map_item_t *p;
			SystemData *systemp = pPoint->u.systemp;

			for (p=cl_qmap_head(&systemp->Nodes); p != cl_qmap_end(&systemp->Nodes); p = cl_qmap_next(p)) {
				NodeData *nodep = PARENT_STRUCT(p, NodeData, SystemNodesEntry);
				PortData *portp = FindNodePort(nodep, portnum);
				if (portp) {
					status = PointListAppend(&newPoint, POINT_TYPE_PORT_LIST, portp);
					if (FSUCCESS != status)
						goto fail;
				}
			}
			if (! PointValid(&newPoint)) {
				fabric_fail = TRUE;
			} else {
				PointFabricCompress(&newPoint);
				status = PointFabricCopy(pPoint, &newPoint);
				PointDestroy(&newPoint);
				if (FSUCCESS != status)
					goto fail;
			}
			}
			break;
		}
	}

	// for FIND_FLAG_ENODE leave any selected ExpectedNodes as is
	
	if (find_flag & FIND_FLAG_ESM) {
		switch (pPoint->EsmType) {
		case POINT_ESM_TYPE_NONE:
			break;
		case POINT_ESM_TYPE_SM:
			if (! (pPoint->u3.esmp->gotPortNum
					 && pPoint->u3.esmp->PortNum == portnum)) {
				PointEsmDestroy(pPoint);
			}
			break;
		case POINT_ESM_TYPE_SM_LIST:
			{
			LIST_ITERATOR i;
			DLIST *pEsmList = &pPoint->u3.esmList;

			for (i=ListHead(pEsmList); i != NULL; i = ListNext(pEsmList, i)) {
				ExpectedSM *esmp = (ExpectedSM*)ListObj(i);
				if (esmp->gotPortNum && esmp->PortNum == portnum) {
					status = PointEsmListAppend(&newPoint, POINT_ESM_TYPE_SM_LIST, esmp);
					if (FSUCCESS != status)
						goto fail;
				}
			}
			if (! PointValid(&newPoint)) {
				PointEsmDestroy(pPoint);
			} else {
				PointEsmCompress(&newPoint);
				status = PointEsmCopy(pPoint, &newPoint);
				PointDestroy(&newPoint);
				if (FSUCCESS != status)
					goto fail;
			}
			}
			break;
		}
	}

	if ((find_flag & FIND_FLAG_ELINK) && callback) {
		// rather than retain extra information to indicate which side of
		// the ELINK matched the original search criteria (nodeguid, nodedesc,
		// nodedescpat, nodetype) we use a callback to
		// recompare with the original criteria and also check against portnum
		// N/A search critieria: nodedetpat, iocname, ioctype, iocnamepat
		switch (pPoint->ElinkType) {
		case POINT_ELINK_TYPE_NONE:
			break;
		case POINT_ELINK_TYPE_LINK:
			if (! (*callback)(pPoint->u4.elinkp, nodecmp, portnum)){
				PointElinkDestroy(pPoint);
			}
			break;
		case POINT_ELINK_TYPE_LINK_LIST:
			{
			LIST_ITERATOR i;
			DLIST *pElinkList = &pPoint->u4.elinkList;

			for (i=ListHead(pElinkList); i != NULL; i = ListNext(pElinkList, i)) {
				ExpectedLink *elinkp = (ExpectedLink*)ListObj(i);
				if ((*callback)(elinkp, nodecmp, portnum)){
					status = PointElinkListAppend(&newPoint, POINT_ELINK_TYPE_LINK_LIST, elinkp);
					if (FSUCCESS != status)
						goto fail;
				}
			}
			if (! PointValid(&newPoint)) {
				PointElinkDestroy(pPoint);
			} else {
				PointElinkCompress(&newPoint);
				status = PointElinkCopy(pPoint, &newPoint);
				PointDestroy(&newPoint);
				if (FSUCCESS != status)
					goto fail;
			}
			}
			break;
		}
	} else {
		DEBUG_ASSERT(pPoint->ElinkType == POINT_ELINK_TYPE_NONE);
	}

	if (fabric_fail && pPoint->EnodeType == POINT_ENODE_TYPE_NONE
			&& pPoint->EsmType == POINT_ESM_TYPE_NONE
			&& pPoint->ElinkType == POINT_ELINK_TYPE_NONE) {
		// we failed fabric and had no enode, esm, nor elink, so output a good
		// message specific to the fabric point we must have started with
		switch (pPoint->Type) {
		case POINT_TYPE_NONE:
		case POINT_TYPE_PORT:
		case POINT_TYPE_PORT_LIST:
		case POINT_TYPE_NODE_PAIR_LIST:
			ASSERT(0);	// should not get here
			break;
		case POINT_TYPE_NODE:
			fprintf(stderr, "%s: Node %.*s GUID 0x%016"PRIx64" Port %u Not Found\n",
				g_Top_cmdname, STL_NODE_DESCRIPTION_ARRAY_SIZE,
				(char*)pPoint->u.nodep->NodeDesc.NodeString,
				pPoint->u.nodep->NodeInfo.NodeGUID, portnum);
			break;
		case POINT_TYPE_NODE_LIST:
#if !defined(VXWORKS) || defined(BUILD_DMC)
		case POINT_TYPE_IOC_LIST:
#endif
		case POINT_TYPE_SYSTEM:
			fprintf(stderr, "%s: Port %u Not Found\n", g_Top_cmdname, portnum);
			break;
#if !defined(VXWORKS) || defined(BUILD_DMC)
		case POINT_TYPE_IOC:
			fprintf(stderr, "%s: IOC %.*s GUID 0x%016"PRIx64" Port %u Not Found\n",
					g_Top_cmdname, IOC_IDSTRING_SIZE,
					(char*)pPoint->u.iocp->IocProfile.IDString,
					pPoint->u.iocp->IocProfile.IocGUID, portnum);
			break;
#endif
		}
		status = FNOT_FOUND;
	} else if (! PointValid(pPoint)) {
		fprintf(stderr, "%s: Port %u Not Found\n", g_Top_cmdname, portnum);
		status = FNOT_FOUND;
	} else {
		return FSUCCESS;
	}

fail:
	PointDestroy(&newPoint);
	PointDestroy(pPoint);
	return status;
}

static boolean PointPortElinkCompareNodeGuid(ExpectedLink *elinkp, void *nodecmp, uint8 portnum)
{
	EUI64 guid = *(EUI64*)nodecmp;

	return ((elinkp->portselp1 && elinkp->portselp1->NodeGUID == guid
				 && elinkp->portselp1->gotPortNum
				 && elinkp->portselp1->PortNum == portnum)
			|| (elinkp->portselp2 && elinkp->portselp2->NodeGUID == guid
				 && elinkp->portselp2->gotPortNum
				 && elinkp->portselp2->PortNum == portnum));
}

static FSTATUS ParseNodeGuidPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *param;
	EUI64 guid;
	FSTATUS status;
	
	ASSERT(! PointValid(pPoint));
	if (FSUCCESS != StringToUint64(&guid, arg, pp, 0, TRUE))  {
		fprintf(stderr, "%s: Invalid Node GUID format: '%s'\n",
						g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}
	if (! guid) {
		fprintf(stderr, "%s: Invalid Node GUID: 0x%016"PRIx64"\n",
						g_Top_cmdname, guid);
		return FINVALID_PARAMETER;
	}
	status = FindNodeGuidPoint(fabricp, guid, pPoint, find_flag, 0);
	if (FSUCCESS != status)
		return status;

	if (NULL != (param = ComparePrefix(*pp, ":port:"))) {
		return ParsePointPort(fabricp, param, pPoint, find_flag, 
								PointPortElinkCompareNodeGuid, &guid, pp);
	} else {
		return FSUCCESS;
	}
}

#if !defined(VXWORKS) || defined(BUILD_DMC)
static FSTATUS ParseIocGuidPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *param;
	EUI64 guid;
	FSTATUS status;
	
	ASSERT(! PointValid(pPoint));
	if (FSUCCESS != StringToUint64(&guid, arg, pp, 0, TRUE))  {
		fprintf(stderr, "%s: Invalid IOC GUID format: '%s'\n",
						g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}
	if (! guid) {
		fprintf(stderr, "%s: Invalid IOC GUID: 0x%016"PRIx64"\n",
						g_Top_cmdname, guid);
		return FINVALID_PARAMETER;
	}
	if (0 == (find_flag & FIND_FLAG_FABRIC))
		return FINVALID_OPERATION;
	if (find_flag & FIND_FLAG_FABRIC) {
		status = FindIocGuid(fabricp, guid, pPoint);
	}
	// N/A for FIND_FLAG_ENODE, FIND_FLAG_ESM and FIND_FLAG_ELINK
	if (status == FSUCCESS) {
		if (NULL != (param = ComparePrefix(*pp, ":port:"))) {
			return ParsePointPort(fabricp, param, pPoint, find_flag, NULL, NULL, pp);
		}
		return FSUCCESS;
	} else {
		fprintf(stderr, "%s: IOC GUID Not Found: 0x%016"PRIx64"\n",
						g_Top_cmdname, guid);
		return status;
	}
}
#endif

static FSTATUS ParseSystemGuidPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	EUI64 guid;
	char *param;

	ASSERT(! PointValid(pPoint));
	if (FSUCCESS != StringToUint64(&guid, arg, pp, 0, TRUE))  {
		fprintf(stderr, "%s: Invalid System Image GUID format: '%s'\n",
						g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}
	if (! guid) {
		fprintf(stderr, "%s: Invalid System Image GUID: 0x%016"PRIx64"\n",
						g_Top_cmdname, guid);
		return FINVALID_PARAMETER;
	}
	if (0 == (find_flag & FIND_FLAG_FABRIC))
		return FINVALID_OPERATION;
	if (find_flag & FIND_FLAG_FABRIC) {
		pPoint->u.systemp = FindSystemGuid(fabricp, guid);
		if (pPoint->u.systemp)
			pPoint->Type = POINT_TYPE_SYSTEM;
	}
	// N/A for FIND_FLAG_ENODE, FIND_FLAG_ESM and FIND_FLAG_ELINK
	if (PointValid(pPoint)) {
		if (NULL != (param = ComparePrefix(*pp, ":port:"))) {
			return ParsePointPort(fabricp, param, pPoint, find_flag, NULL, NULL, pp);
		}
		return FSUCCESS;
	} else {
		fprintf(stderr, "%s: System Image GUID Not Found: 0x%016"PRIx64"\n",
						g_Top_cmdname, guid);
		return FNOT_FOUND;
	}
}

static boolean PointPortElinkCompareNodeName(ExpectedLink *elinkp, void *nodecmp, uint8 portnum)
{
	char *name = (char*)nodecmp;

	return ((elinkp->portselp1 && elinkp->portselp1->NodeDesc
				&& elinkp->portselp1->gotPortNum
				&& elinkp->portselp1->PortNum == portnum
				&& 0 == strncmp(elinkp->portselp1->NodeDesc,
								name, STL_NODE_DESCRIPTION_ARRAY_SIZE))
			|| (elinkp->portselp2 && elinkp->portselp2->NodeDesc
				&& elinkp->portselp2->gotPortNum
				&& elinkp->portselp2->PortNum == portnum
				&& 0 == strncmp(elinkp->portselp2->NodeDesc,
								name, STL_NODE_DESCRIPTION_ARRAY_SIZE)));
}

static FSTATUS ParseNodeNamePoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Name[STL_NODE_DESCRIPTION_ARRAY_SIZE+1];
	char *param;
	FSTATUS status;

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Node name format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > STL_NODE_DESCRIPTION_ARRAY_SIZE) {
			fprintf(stderr, "%s: Node name Not Found (too long): %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Name, arg, sizeof(Name));
		Name[p-arg] = '\0';
		*pp = p;
		arg = Name;
	} else {
		*pp = arg + strlen(arg);
	}

	status = FindNodeNamePoint(fabricp, arg, pPoint, find_flag, 0);
	if (FSUCCESS != status)
		return status;

	if (NULL != (param = ComparePrefix(*pp, ":port:"))) {
		return ParsePointPort(fabricp, param, pPoint, find_flag,
								PointPortElinkCompareNodeName, arg, pp);
	} else {
		return FSUCCESS;
	}
}

#ifndef __VXWORKS__
static boolean PointPortElinkCompareNodeNamePat(ExpectedLink *elinkp, void *nodecmp, uint8 portnum)
{
	char *pattern = (char*)nodecmp;

	return ( (elinkp->portselp1 && elinkp->portselp1->NodeDesc
				&& elinkp->portselp1->gotPortNum
				&& elinkp->portselp1->PortNum == portnum
				&& 0 == fnmatch(pattern, elinkp->portselp1->NodeDesc, 0))
			|| (elinkp->portselp2 && elinkp->portselp2->NodeDesc
				&& elinkp->portselp2->gotPortNum
				&& elinkp->portselp2->PortNum == portnum
				&& 0 == fnmatch(pattern, elinkp->portselp2->NodeDesc, 0)));
}

/* Initialize the nodepatPairs list*/
static FSTATUS InitNodePatPairs(NodePairList_t *nodePatPairs)
{
	//Initialize the left side of the list here.
	ListInitState(&nodePatPairs->nodePairList1);
	if (! ListInit(&nodePatPairs->nodePairList1, MIN_LIST_ITEMS)) {
		fprintf(stderr, "%s: unable to allocate memory\n", g_Top_cmdname);
		return FINSUFFICIENT_MEMORY;
	}

	//Initialize the right side of the list here.
	ListInitState(&nodePatPairs->nodePairList2);
	if (! ListInit(&nodePatPairs->nodePairList2, MIN_LIST_ITEMS)) {
		fprintf(stderr, "%s: unable to allocate memory\n", g_Top_cmdname);
		if(&nodePatPairs->nodePairList1)
			ListDestroy(&nodePatPairs->nodePairList1);
		return FINSUFFICIENT_MEMORY;
	}
	return FSUCCESS;
}

/* Delete the nodepatpairs list*/
FSTATUS DeleteNodePatPairs(NodePairList_t *nodePatPairs)
{
	if(nodePatPairs) {
		//delete the left side of the list.
		ListDestroy(&nodePatPairs->nodePairList1);
		//delete the right side of the list.
		ListDestroy(&nodePatPairs->nodePairList2);
	}
	return FSUCCESS;
}

/* Parse the node pairs/nodes file */
static FSTATUS ParseNodePairPatFilePoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, uint8 pair_flag, char **pp)
{
	char *p, *pEol;
	char patternLine[STL_NODE_DESCRIPTION_ARRAY_SIZE*2+NODE_PAIR_DELIMITER_SIZE+1];
	char pattern[STL_NODE_DESCRIPTION_ARRAY_SIZE+1];
	FSTATUS status;
	char nodePatFileName[FILENAME] = {0};
	struct stat fileStat;
	FILE *fp;
	NodePairList_t nodePatPairs;

	ASSERT(PointIsInInit(pPoint));

	if (0 == pair_flag)
		return FINVALID_OPERATION;

	if (NULL == arg) {
		fprintf(stderr, "%s: Node pattern Filename missing\n", g_Top_cmdname);
		return FINVALID_PARAMETER;
	}

	if (strlen(arg) > FILENAME - 1) {
		fprintf(stderr, "%s: Node pattern Filename too long: %.*s\n",
						g_Top_cmdname, (int)strlen(arg), arg);
		return FINVALID_PARAMETER;
	}

	if ((PAIR_FLAG_NODE != pair_flag) && (PAIR_FLAG_NONE != pair_flag) ) {
		fprintf(stderr, "%s: Pair flag argument is invalid: %d\n",
						g_Top_cmdname, pair_flag);
		return FINVALID_PARAMETER;
	}
	//Get file name
	StringCopy(nodePatFileName, arg, (int)sizeof(nodePatFileName));
	nodePatFileName[strlen(arg)] = '\0';

	//There are no further focus to evaluate for node pair list
	*pp = arg + strlen(arg);

	// Check if file is present
	if (stat(nodePatFileName, &fileStat) < 0) {
		fprintf(stderr, "Error taking stat of file {%s}: %s\n",
			nodePatFileName, strerror(errno));
			return FINVALID_PARAMETER;
	}

	//Open file
	if ((fp = fopen(nodePatFileName, "r")) == NULL) {
		fprintf(stderr, "Error opening file %s for input: %s\n", nodePatFileName, strerror(errno));
		return FINVALID_PARAMETER;
	}

	memset(patternLine, 0, sizeof(patternLine));

	//Get one line at a time
	while(fgets(patternLine, sizeof(patternLine), fp) != NULL){
		//remove newline
		if ((pEol = strrchr(patternLine, '\n')) != NULL) {
			*pEol= '\0';
		}
		//When node pairs are given
		if (PAIR_FLAG_NODE == pair_flag ) {
			p = strchr(patternLine, ':');
			if (p) {
				memset(pattern, 0, sizeof(pattern));
				//just log the error meesage
				if (p - patternLine > STL_NODE_DESCRIPTION_ARRAY_SIZE) {
					fprintf(stderr, "%s: Left side node name Not Found (too long): %.*s\n",
						g_Top_cmdname, (int)(p - patternLine), patternLine);
				}
				// copy the Left side of node pair. +1 for '\0'
				StringCopy(pattern, patternLine, (p - patternLine + 1));
				pattern[(p - patternLine) + 1] = '\0';
				status = InitNodePatPairs(&nodePatPairs);
				if(FSUCCESS != status){
					fprintf(stderr, "%s: Insufficient Memory\n",g_Top_cmdname );
					goto fail;
				}
				// Find all the nodes that match the pattern for the left side
				status = FindNodePatPairs(fabricp, pattern, &nodePatPairs, find_flag, LSIDE_PAIR);
				// When there is invalid entry in the Left side of each line, the entire line is skipped
				if ((FSUCCESS != status)){
					DeleteNodePatPairs(&nodePatPairs);
					continue;
				}
				memset(pattern, 0, sizeof(pattern));
				//When there is invalid entry in the right side don't mark error as corresponding left side entry could be a Switch
				if (pEol - p <= STL_NODE_DESCRIPTION_ARRAY_SIZE) {
					// copy the Right side of node pair. +1 is for ':'
					StringCopy(pattern, patternLine + (p - patternLine + 1), (pEol - p + 1));
					// Find all the nodes that match the pattern for the right side
					status = FindNodePatPairs(fabricp, pattern, &nodePatPairs, find_flag, RSIDE_PAIR);
					// Only when there is insufficient memory error mark as error and return
					if ((FSUCCESS != status) && (FINVALID_OPERATION != status) &&
						(FNOT_FOUND != status)){
						DeleteNodePatPairs(&nodePatPairs);
						goto fail;
					}
				} else {
					//just log the error meesage
					fprintf(stderr, "%s: Right side node name (too long): %.*s\n",
						g_Top_cmdname, (int)(pEol - p), p);
				}
			}else {
				//just log error message
				fprintf(stderr, "%s: Node pair is missing: %.*s\n",
					g_Top_cmdname, (int)sizeof(patternLine), patternLine);
			}
			// The complete node pair List N*M  is populated for a single line in file
			status = PointPopulateNodePairList(pPoint, &nodePatPairs);
			if (FSUCCESS != status) {
				//Log error and return if it fails to fom N*M list
				fprintf(stderr, "%s: Error creating node pairs\n", g_Top_cmdname);
				DeleteNodePatPairs(&nodePatPairs);
				goto fail;
			}
			// Now the line is parsed and nadepat pairs are created, so free nodePatPairs
			DeleteNodePatPairs(&nodePatPairs);
		//When only one node is given
		} else {
			if (strlen(patternLine) <= STL_NODE_DESCRIPTION_ARRAY_SIZE) {
				// Only when there is insufficient memory error or invalid operation error mark as error and return
				// else proceed with next node in list
				status = FindNodeNamePatPointUncompress(fabricp, patternLine, pPoint, find_flag);
				if ((FSUCCESS != status) && (FNOT_FOUND != status))
					goto fail;
			} else {
				//just log the error message and parse next line
				fprintf(stderr, "%s: Node name (too long): %.*s\n",
					g_Top_cmdname, (int)sizeof(patternLine), patternLine);
			}
		}
		memset(patternLine, 0, sizeof(patternLine));
	}
	PointCompress(pPoint);
	fclose(fp);
	return FSUCCESS;

fail:
	fclose(fp);
	return status;
}

static FSTATUS ParseNodeNamePatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[STL_NODE_DESCRIPTION_ARRAY_SIZE*5+1];
	char *param;
	FSTATUS status;

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Node name pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: Node name pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	status = FindNodeNamePatPoint(fabricp, arg, pPoint, find_flag);
	if (FSUCCESS != status)
		return status;

	if (NULL != (param = ComparePrefix(*pp, ":port:"))) {
		return ParsePointPort(fabricp, param, pPoint, find_flag,
								PointPortElinkCompareNodeNamePat, arg, pp);
	} else {
		return FSUCCESS;
	}
}

static FSTATUS ParseNodeDetPatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[NODE_DETAILS_STRLEN*5+1];
	char *param;
	FSTATUS status;

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Node Details pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: Node Details pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	if (0 == (find_flag & (FIND_FLAG_FABRIC|FIND_FLAG_ENODE))
		&& ! QListCount(&fabricp->ExpectedFIs)
		&& ! QListCount(&fabricp->ExpectedSWs))
		fprintf(stderr, "%s: Warning: No Node Details supplied via topology_input\n", g_Top_cmdname);
	status = FindNodeDetailsPatPoint(fabricp, arg, pPoint, find_flag);
	if (FSUCCESS != status)
		return status;

	if (NULL != (param = ComparePrefix(*pp, ":port:"))) {
		return ParsePointPort(fabricp, param, pPoint, find_flag, NULL, NULL, pp);
	} else {
		return FSUCCESS;
	}
}
#endif /* __VXWORKS__ */

static boolean PointPortElinkCompareNodeType(ExpectedLink *elinkp, void *nodecmp, uint8 portnum)
{
	NODE_TYPE type = *(NODE_TYPE*)nodecmp;

	return ((elinkp->portselp1 && elinkp->portselp1->NodeType == type
				 && elinkp->portselp1->gotPortNum
				 && elinkp->portselp1->PortNum == portnum)
			|| (elinkp->portselp2 && elinkp->portselp2->NodeType == type
				 && elinkp->portselp2->gotPortNum
				 && elinkp->portselp2->PortNum == portnum));
}

static FSTATUS ParseNodeTypePoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char *param;
	FSTATUS status;
	NODE_TYPE type;

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Node type format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg != 2) {
			fprintf(stderr, "%s: Invalid Node type: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		*pp = p;
	} else {
		if (strlen(arg) != 2) {
			fprintf(stderr, "%s: Invalid Node type: %s\n", g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		*pp = arg + strlen(arg);
	}
	if (strncasecmp(arg, "FI", 2) == 0)
		type = STL_NODE_FI;
	else if (strncasecmp(arg, "SW", 2) == 0)
		type = STL_NODE_SW;
	else {
		fprintf(stderr, "%s: Invalid Node type: %.*s\n", g_Top_cmdname, 2, arg);
		*pp = arg; /* back up to start of type for syntax error */
		return FINVALID_PARAMETER;
	}

	status = FindNodeTypePoint(fabricp, type, pPoint, find_flag);
	if (FSUCCESS != status)
		return status;

	if (NULL != (param = ComparePrefix(*pp, ":port:"))) {
		return ParsePointPort(fabricp, param, pPoint, find_flag,
								PointPortElinkCompareNodeType, &type, pp);
	} else {
		return FSUCCESS;
	}
}

#if !defined(VXWORKS) || defined(BUILD_DMC)
static FSTATUS ParseIocNamePoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Name[IOC_IDSTRING_SIZE+1];
	char *param;
	FSTATUS status;

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid IOC name format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > IOC_IDSTRING_SIZE) {
			fprintf(stderr, "%s: IOC name Not Found (too long): %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Name, arg, sizeof(Name));
		Name[p-arg] = '\0';
		*pp = p;
		arg = Name;
	} else {
		*pp = arg + strlen(arg);
	}

	status = FindIocNamePoint(fabricp, arg, pPoint, find_flag);
	if (FSUCCESS != status)
		return status;

	if (NULL != (param = ComparePrefix(*pp, ":port:"))) {
		return ParsePointPort(fabricp, param, pPoint, find_flag, NULL, NULL, pp);
	} else {
		return FSUCCESS;
	}
}

static FSTATUS ParseIocNamePatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[IOC_IDSTRING_SIZE*5+1];
	char *param;
	FSTATUS status;

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid IOC name pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: IOC name pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	status = FindIocNamePatPoint(fabricp, arg, pPoint, find_flag);
	if (FSUCCESS != status)
		return status;

	if (NULL != (param = ComparePrefix(*pp, ":port:"))) {
		return ParsePointPort(fabricp, param, pPoint, find_flag, NULL, NULL, pp);
	} else {
		return FSUCCESS;
	}
}

static FSTATUS ParseIocTypePoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Type[5+1]; //"OTHER" is longest valid type name  
	char *param;
	FSTATUS status;
	int len;
	IocType type;

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid IOC type format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Type)-1) {
			fprintf(stderr, "%s: Invalid IOC type: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		len = (int)(p-arg);
		StringCopy(Type, arg, sizeof(Type));
		Type[len] = '\0';
		*pp = p;
		arg = Type;
	} else {
		len = strlen(arg);
		*pp = arg + len;
	}
	if (strncasecmp(arg, "SRP", len) == 0) 
		type = IOC_TYPE_SRP;
	else if (strncasecmp(arg, "OTHER", len) == 0){
		type = IOC_TYPE_OTHER;
	}
	else {
		fprintf(stderr, "%s: Invalid IOC type: %.*s\n", g_Top_cmdname, len, arg);
		*pp -= len;	/* back up for syntax error report */
		return FINVALID_PARAMETER;
	}

	status = FindIocTypePoint(fabricp, type, pPoint, find_flag);
	if (FSUCCESS != status)
		return status;

	if (NULL != (param = ComparePrefix(*pp, ":port:"))) {
		return ParsePointPort(fabricp, param, pPoint, find_flag, NULL, NULL, pp);
	} else {
		return FSUCCESS;
	}
}
#endif

static FSTATUS ParseRatePoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Rate[8];	// 37_5g is largest valid rate name, but lets use a couple more chars for future expansion
	FSTATUS status;
	int len;
	uint32 rate;
	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Rate format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Rate)-1) {
			fprintf(stderr, "%s: Invalid Rate: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		len = (int)(p-arg);
		StringCopy(Rate, arg, sizeof(Rate));
		Rate[len] = '\0';
		*pp = p;
		arg = Rate;
	} else {
		len = strlen(arg);
		*pp = arg + len;
	}
	if (strncmp(arg, "12.5g", len) == 0)
		rate = IB_STATIC_RATE_14G;
	else if (strncmp(arg, "25g", len) == 0)
		rate = IB_STATIC_RATE_25G;
	else if (strncmp(arg, "37.5", len) == 0)
		rate = IB_STATIC_RATE_40G;
	else if (strncmp(arg, "50g", len) == 0)
		rate = IB_STATIC_RATE_56G;
	else if (strncmp(arg, "75g", len) == 0)
		rate = IB_STATIC_RATE_80G;
	else if (strncmp(arg, "100g", len) == 0)
		rate = IB_STATIC_RATE_100G;
	else if (strncmp(arg, "150g", len) == 0)
		rate = IB_STATIC_RATE_168G;
	else if (strncmp(arg, "200g", len) == 0)
		rate = IB_STATIC_RATE_200G;
	else {
		fprintf(stderr, "%s: Invalid Rate: %.*s\n", g_Top_cmdname, len, arg);
		*pp -= len;	/* back up for syntax error report */
		return FINVALID_PARAMETER;
	}

	status = FindRatePoint(fabricp, rate, pPoint, find_flag);
	return status;
}

static FSTATUS ParseLedPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	FSTATUS status;
	char *p;
	char LedState[3+1];	// "off" is largest valid state name
	int len;
	boolean ledon;

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Led State format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(LedState)-1) {
			fprintf(stderr, "%s: Invalid Led State: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		len = (int)(p-arg);
		StringCopy(LedState, arg, sizeof(LedState));
		LedState[len] = '\0';
		*pp = p;
		arg = LedState;
	} else {
		len = strlen(arg);
		*pp = arg + len;
	}

	if (strncasecmp(arg, "off", len) == 0)
		ledon = FALSE;
	else if (strncasecmp(arg, "on", len) == 0)
		ledon = TRUE;
	else {
		fprintf(stderr, "%s: Invalid Led State: %.*s\n", g_Top_cmdname, len, arg);
		*pp -= len;	/* back up for syntax error report */
		return FINVALID_PARAMETER;
	}

	status = FindLedStatePoint(fabricp, ledon, pPoint, find_flag);
	return status;
}


static FSTATUS ParsePortStatePoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char State[6+1];	// active is largest valid state name
	FSTATUS status;
	int len;
	IB_PORT_STATE state;

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Port State format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(State)-1) {
			fprintf(stderr, "%s: Invalid Port State: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		len = (int)(p-arg);
		StringCopy(State, arg, sizeof(State));
		State[len] = '\0';
		*pp = p;
		arg = State;
	} else {
		len = strlen(arg);
		*pp = arg + len;
	}
	if (strncasecmp(arg, "down", len) == 0)
		state = IB_PORT_DOWN;
	else if (strncasecmp(arg, "init", len) == 0)
		state = IB_PORT_INIT;
	else if (strncasecmp(arg, "armed", len) == 0)
		state = IB_PORT_ARMED;
	else if (strncasecmp(arg, "active", len) == 0)
		state = IB_PORT_ACTIVE;
	else if (strncasecmp(arg, "notactive", len) == 0)
		state = PORT_STATE_SEARCH_NOTACTIVE;
	else if (strncasecmp(arg, "initarmed", len) == 0)
		state = PORT_STATE_SEARCH_INITARMED;
	else {
		fprintf(stderr, "%s: Invalid Port State: %.*s\n", g_Top_cmdname, len, arg);
		*pp -= len;	/* back up for syntax error report */
		return FINVALID_PARAMETER;
	}

	status = FindPortStatePoint(fabricp, state, pPoint, find_flag);
	return status;
}

static FSTATUS ParsePortPhysStatePoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char PhysState[8+1];	// recovery is largest valid state name
	FSTATUS status;
	int len;
	IB_PORT_PHYS_STATE physstate;

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Port Phys State format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(PhysState)-1) {
			fprintf(stderr, "%s: Invalid Port Phys State: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		len = (int)(p-arg);
		StringCopy(PhysState, arg, sizeof(PhysState));
		PhysState[len] = '\0';
		*pp = p;
		arg = PhysState;
	} else {
		len = strlen(arg);
		*pp = arg + len;
	}
	// SLEEP is N/A to OPA
	if (strncasecmp(arg, "polling", len) == 0)
		physstate = IB_PORT_PHYS_POLLING;
	else if (strncasecmp(arg, "disabled", len) == 0)
		physstate = IB_PORT_PHYS_DISABLED;
	else if (strncasecmp(arg, "training", len) == 0)
		physstate = IB_PORT_PHYS_TRAINING;
	else if (strncasecmp(arg, "linkup", len) == 0)
		physstate = IB_PORT_PHYS_LINKUP;
	else if (strncasecmp(arg, "recovery", len) == 0)
		physstate = IB_PORT_PHYS_LINK_ERROR_RECOVERY;
	else if (strncasecmp(arg, "offline", len) == 0)
		physstate = STL_PORT_PHYS_OFFLINE;
	else if (strncasecmp(arg, "test", len) == 0)
		physstate = STL_PORT_PHYS_TEST;
	else {
		fprintf(stderr, "%s: Invalid Port Phys State: %.*s\n", g_Top_cmdname, len, arg);
		*pp -= len;	/* back up for syntax error report */
		return FINVALID_PARAMETER;
	}

	status = FindPortPhysStatePoint(fabricp, physstate, pPoint, find_flag);
	return status;
}

static FSTATUS ParseMtuPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	uint16 mtu_int;
	IB_MTU mtu;

	ASSERT(! PointValid(pPoint));
	if (FSUCCESS != StringToUint16(&mtu_int, arg, pp, 0, TRUE))  {
		fprintf(stderr, "%s: Invalid MTU format: '%s'\n", g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}
	if (! mtu_int) {
		fprintf(stderr, "%s: Invalid MTU: %u\n",
						g_Top_cmdname, (unsigned)mtu_int);
		return FINVALID_PARAMETER;
	}
	mtu = GetMtuFromBytes(mtu_int);

	return FindMtuPoint(fabricp, mtu, pPoint, find_flag);
}

static FSTATUS ParseCableLabelPatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[CABLE_LABEL_STRLEN*5+1];

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Cable Label pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: Cable Label pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	if (0 == (find_flag & (FIND_FLAG_FABRIC|FIND_FLAG_ELINK))
		&& ! (fabricp->flags & FF_CABLEDATA))
		fprintf(stderr, "%s: Warning: No Cable Data supplied via topology_input\n", g_Top_cmdname);
	return FindCableLabelPatPoint(fabricp, arg, pPoint, find_flag);
}

static FSTATUS ParseCableLenPatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[CABLE_LENGTH_STRLEN*5+1];

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Cable Length pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: Cable Length pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	if (0 == (find_flag & (FIND_FLAG_FABRIC|FIND_FLAG_ELINK))
		&& ! (fabricp->flags & FF_CABLEDATA))
		fprintf(stderr, "%s: Warning: No Cable Data supplied via topology_input\n", g_Top_cmdname);
	return FindCableLenPatPoint(fabricp, arg, pPoint, find_flag);
}

static FSTATUS ParseCableDetailsPatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[CABLE_DETAILS_STRLEN*5+1];

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Cable Details pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: Cable Details pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	if (0 == (find_flag & (FIND_FLAG_FABRIC|FIND_FLAG_ELINK))
		&& ! (fabricp->flags & FF_CABLEDATA))
		fprintf(stderr, "%s: Warning: No Cable Data supplied via topology_input\n", g_Top_cmdname);
	return FindCableDetailsPatPoint(fabricp, arg, pPoint, find_flag);
}

static FSTATUS ParseCabinfLenPatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[STL_CIB_STD_MAX_STRING + 1];

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid CableInfo Cable Length pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: CableInfo Cable Length pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	return FindCabinfLenPatPoint(fabricp, arg, pPoint, find_flag);

}	// End of ParseCabinfLenPatPoint()

static FSTATUS ParseCabinfVendNamePatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[STL_CIB_STD_MAX_STRING + 1];

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Vendor Name pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: Vendor Name pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	return FindCabinfVendNamePatPoint(fabricp, arg, pPoint, find_flag);

}	// End of ParseCabinfVendNamePatPoint()

static FSTATUS ParseCabinfVendPNPatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[STL_CIB_STD_MAX_STRING + 1];

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Vendor PN pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: Vendor PN pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	return FindCabinfVendPNPatPoint(fabricp, arg, pPoint, find_flag);

}	// End of ParseCabinfVendPNPatPoint()

static FSTATUS ParseCabinfVendRevPatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[STL_CIB_STD_MAX_STRING + 1];

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Vendor Rev pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: Vendor Rev pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	return FindCabinfVendRevPatPoint(fabricp, arg, pPoint, find_flag);

}	// End of ParseCabinfVendRevPatPoint()

static FSTATUS ParseCabinfVendSNPatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[STL_CIB_STD_MAX_STRING + 1];

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Vendor SN pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: Vendor SN pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	return FindCabinfVendSNPatPoint(fabricp, arg, pPoint, find_flag);

}	// End of ParseCabinfVendSNPatPoint()


static FSTATUS ParseCabinfCableTypePoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char cabletype[STL_CIB_STD_MAX_STRING + 1];	// 'optical' is largest valid cable type name, but we use some more chars for future expansion
	int len;
	FSTATUS status;


	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Cable Type format: '%s'\n", g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(cabletype)-1) {
			fprintf(stderr, "%s: Invalid Cable Type: %.*s\n", g_Top_cmdname, (int)(p-arg), arg);
			fprintf(stderr, "%s: Available Cable Types are: optical, passive_copper, active_copper and unknown.\n",g_Top_cmdname);
			return FINVALID_PARAMETER;
		}
		StringCopy(cabletype, arg, sizeof(cabletype));
		cabletype[p-arg] = '\0';
		*pp = p;
		arg = cabletype;
	} else {
		*pp = arg +  strlen(arg);
	}

	len = strlen(arg);

	if (!((strncmp(arg, "unknown", len) == 0) || (strncmp(arg, "optical", len) == 0)
			|| (strncmp(arg, "active_copper", len) == 0) || (strncmp(arg, "passive_copper", len) == 0)))
		 {
		fprintf(stderr, "%s: Invalid Cable Type: %.*s\n", g_Top_cmdname, len, arg);
		fprintf(stderr, "%s: Available Cable Types are: optical, passive_copper, active_copper and unknown.\n",g_Top_cmdname);
		*pp -= len;	/* back up for syntax error report */
		return FINVALID_PARAMETER;
	}

	status = FindCabinfCableTypePoint(fabricp, arg, pPoint, find_flag);
	return status;

} // End of ParseCabinCableTypePoint()

static FSTATUS ParseLinkDetailsPatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[LINK_DETAILS_STRLEN*5+1];

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Link Details pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: Link Details pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	if (0 == (find_flag & (FIND_FLAG_FABRIC|FIND_FLAG_ELINK))
		&& ! QListCount(&fabricp->ExpectedLinks))
		fprintf(stderr, "%s: Warning: No Link Details supplied via topology_input\n", g_Top_cmdname);
	return FindLinkDetailsPatPoint(fabricp, arg, pPoint, find_flag);
}

static FSTATUS ParsePortDetailsPatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[PORT_DETAILS_STRLEN*5+1];

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid Port Details pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: Port Details pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	if (0 == (find_flag & (FIND_FLAG_FABRIC|FIND_FLAG_ELINK))
		&& ! QListCount(&fabricp->ExpectedLinks))
		fprintf(stderr, "%s: Warning: No Port Details supplied via topology_input\n", g_Top_cmdname);
	return FindPortDetailsPatPoint(fabricp, arg, pPoint, find_flag);
}

static FSTATUS ParseSmPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{

	*pp = arg;
	ASSERT(! PointValid(pPoint));
	if (0 == (find_flag & FIND_FLAG_FABRIC))
		return FINVALID_OPERATION;
	if (find_flag & FIND_FLAG_FABRIC) {
		pPoint->u.portp = FindMasterSm(fabricp);
		if (pPoint->u.portp) {
			pPoint->Type = POINT_TYPE_PORT;
		}
	}
	// N/A for FIND_FLAG_ENODE, FIND_FLAG_ESM and FIND_FLAG_ELINK
	// while FIND_FLAG_ESM may seem applicable, we can't identify a master SM
	// from what is in topology.xml
	if (! PointValid(pPoint)) {
		fprintf(stderr, "%s: Master SM Not Found\n", g_Top_cmdname);
		return FNOT_FOUND;
	}
	return FSUCCESS;
}

static FSTATUS ParseSmDetailsPatPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	char *p;
	char Pattern[SM_DETAILS_STRLEN*5+1];

	ASSERT(! PointValid(pPoint));
	p = strchr(arg, ':');
	if (p) {
		if (p == arg) {
			fprintf(stderr, "%s: Invalid SM Details pattern format: '%s'\n",
							g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
		if (p - arg > sizeof(Pattern)-1) {
			fprintf(stderr, "%s: SM Details pattern too long: %.*s\n",
							g_Top_cmdname, (int)(p-arg), arg);
			return FINVALID_PARAMETER;
		}
		StringCopy(Pattern, arg, sizeof(Pattern));
		Pattern[p-arg] = '\0';
		*pp = p;
		arg = Pattern;
	} else {
		*pp = arg + strlen(arg);
	}

	if (0 == (find_flag & (FIND_FLAG_FABRIC|FIND_FLAG_ESM))
		&& ! QListCount(&fabricp->ExpectedSMs))
		fprintf(stderr, "%s: Warning: No SM Details supplied via topology_input\n", g_Top_cmdname);
	return FindSmDetailsPatPoint(fabricp, arg, pPoint, find_flag);
}

static FSTATUS ParseLinkCRCPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	LinkCRCCompare comp = CRC_EQ;
	uint16 crc;
	char *next;

	ASSERT(! PointValid(pPoint));
	*pp = arg;
	if (NULL != (next = ComparePrefix(arg, "NE:"))) {
		comp = CRC_NE; // not equal
	} else if (NULL != (next = ComparePrefix(arg, ":"))) {
		comp = CRC_EQ; // equal
	} else {
		fprintf(stderr, "%s: Invalid Link CRC format: '%s'\n",
				g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}

	*pp = next;
	if (NULL != (next = ComparePrefix(*pp, "14b"))) {
		*pp = next;
		crc = STL_PORT_LTP_CRC_MODE_14;
	} else if (NULL != (next = ComparePrefix(*pp, "14-bit"))) {
		*pp = next;
		crc = STL_PORT_LTP_CRC_MODE_14;
	} else if (NULL != (next = ComparePrefix(*pp, "16b"))) {
		*pp = next;
		crc = STL_PORT_LTP_CRC_MODE_16;
	} else if (NULL != (next = ComparePrefix(*pp, "16-bit"))) {
		*pp = next;
		crc = STL_PORT_LTP_CRC_MODE_16;
	} else if (NULL != (next = ComparePrefix(*pp, "48b"))) {
		*pp = next;
		crc = STL_PORT_LTP_CRC_MODE_48;
	} else if (NULL != (next = ComparePrefix(*pp, "48-bit"))) {
		*pp = next;
		crc = STL_PORT_LTP_CRC_MODE_48;
	} else if (NULL != (next = ComparePrefix(*pp, "per_lane"))) {
		*pp = next;
		crc = STL_PORT_LTP_CRC_MODE_12_16_PER_LANE;
	} else if (NULL != (next = ComparePrefix(*pp, "12-16/lane"))) {
		*pp = next;
		crc = STL_PORT_LTP_CRC_MODE_12_16_PER_LANE;
	} else {
		fprintf(stderr, "%s: Invalid Link CRC format: '%s'\n", g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}

	return FindLinkCRCPoint(fabricp, crc, comp, pPoint, find_flag);
}

static FSTATUS ParseLinkQualityPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	LinkQualityCompare comp = QUAL_EQ;
	uint16 quality;
	char *Quality;
	
	ASSERT(! PointValid(pPoint));
	*pp = arg;
	if (NULL != (Quality = ComparePrefix(arg, "LE:"))) {
		comp = QUAL_LE; // below means get all qualities less than given quality
	} else if (NULL != (Quality = ComparePrefix(arg, "GE:"))) {
		comp = QUAL_GE; // above means get all qualities greater than the given quality
	} else if (NULL != (Quality = ComparePrefix(arg, ":"))) {
		comp = QUAL_EQ; // get exact quality
	} else {
		fprintf(stderr, "%s: Invalid Link Quality format: '%s'\n",
				g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}

	*pp = Quality;
	if (FSUCCESS != StringToUint16(&quality, Quality, pp, 0, TRUE)) {
		fprintf(stderr, "%s: Invalid Link Quality format: '%s'\n", g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}
	
	if (quality > STL_LINKQUALITY_EXCELLENT) { // 5 (excellent) is the max value for link quality, anything greater is invalid
		fprintf(stderr, "%s: Link Quality Too Large: %d\n", g_Top_cmdname, quality);
		return FINVALID_PARAMETER;
	}

	return FindLinkQualityPoint(fabricp, quality, comp, pPoint, find_flag);
}

static FSTATUS ParseLinkDownReasonPoint(FabricData_t *fabricp, char *arg, Point *pPoint, uint8 find_flag, char **pp)
{
	uint8 ldr = IB_UINT8_MAX;
	char *ldrp;
	
	ASSERT(! PointValid(pPoint));
	*pp = arg;
	if (NULL != (ldrp = ComparePrefix(arg, ":"))) {
		*pp = ldrp;
		if (FSUCCESS != StringToUint8(&ldr, ldrp, pp, 0, TRUE)) {
			fprintf(stderr, "%s: Invalid Link Down Reason format: '%s'\n", g_Top_cmdname, arg);
			return FINVALID_PARAMETER;
		}
	}

	return FindLinkDownReasonPoint(fabricp, ldr, pPoint, find_flag);
}
/* parse the arg string and find the mentioned Point
 * arg string formats:
 * 	gid:subnet:guid
 *	lid:lid
 *	lid:lid:node
 *	lid:lid:port:#
 *	lid:lid:veswport:#
 *	portguid:guid
 *	nodeguid:guid
 *	nodeguid:guid:port:#
 *	iocguid:guid
 *	iocguid:guid:port:#
 *	systemguid:guid
 *	systemguid:guid:port:#
 *	node:node name
 *	node:node name:port:#
 *	nodepat:node name pattern
 *	nodepat:node name pattern:port:#
 *	nodedetpat:node details pattern
 *	nodedetpat:node details pattern:port:#
 *	nodetype:node type
 *	nodetype:node type:port:#
 *	ioc:ioc name
 *	ioc:ioc name:port:#
 *	iocpat:ioc name pattern
 *	iocpat:ioc name pattern:port:#
 *	ioctype:ioc type
 *	ioctype:ioc type:port:#
 *	rate:rate string
 *	portstate:state string
 *	portphysstate:phys state string
 *	mtu:#
 *	cableinftype:cable type
 *	labelpat:cable label pattern
 *	led:on/off
 *	lengthpat:cable length pattern
 *	cabledetpat:cable details pattern
 *	cabinflenpat:cable info cable length pattern
 *	cabinfvendnamepat:cable info vendor name pattern
 *	cabinfvendpnpat:cable info vendor part number pattern
 *	cabinfvendrevpat:cable info vendor rev pattern
 *	cabinfvendsnpat:cable info vendor serial number pattern
 *	linkdetpat:cable details pattern
 *	portdetpat:port details pattern
 *	sm
 *  smdetpat:sm details pattern
 *  linkqual:link quality level
 *  linkqualLE:link quality level
 *  linkqualGE:link quality level
 */
FSTATUS ParsePoint(FabricData_t *fabricp, char* arg, Point* pPoint, uint8 find_flag, char **pp)
{
	char* param;
	FSTATUS status;

	*pp = arg;
	PointInit(pPoint);
	if (NULL != (param = ComparePrefix(arg, "gid:"))) {
		status = ParseGidPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "lid:"))) {
		status = ParseLidPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "portguid:"))) {
		status = ParsePortGuidPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "nodeguid:"))) {
		status = ParseNodeGuidPoint(fabricp, param, pPoint, find_flag, pp);
#if !defined(VXWORKS) || defined(BUILD_DMC)
	} else if (NULL != (param = ComparePrefix(arg, "iocguid:"))) {
		status = ParseIocGuidPoint(fabricp, param, pPoint, find_flag, pp);
#endif
	} else if (NULL != (param = ComparePrefix(arg, "systemguid:"))) {
		status = ParseSystemGuidPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "node:"))) {
		status = ParseNodeNamePoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "led:"))) {
		status = ParseLedPoint(fabricp, param, pPoint, find_flag, pp);
#ifndef __VXWORKS__
	} else if (NULL != (param = ComparePrefix(arg, "nodepat:"))) {
		status = ParseNodeNamePatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "nodedetpat:"))) {
		status = ParseNodeDetPatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "nodepatfile:"))) {
		status = ParseNodePairPatFilePoint(fabricp, param, pPoint, find_flag, PAIR_FLAG_NONE, pp);
	} else if (NULL != (param = ComparePrefix(arg, "nodepairpatfile:"))) {
		status = ParseNodePairPatFilePoint(fabricp, param, pPoint, find_flag, PAIR_FLAG_NODE, pp);
#endif
	} else if (NULL != (param = ComparePrefix(arg, "nodetype:"))) {
		status = ParseNodeTypePoint(fabricp, param, pPoint, find_flag, pp);
#if !defined(VXWORKS) || defined(BUILD_DMC)
	} else if (NULL != (param = ComparePrefix(arg, "ioc:"))) {
		status = ParseIocNamePoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "iocpat:"))) {
		status = ParseIocNamePatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "ioctype:"))) {
		status = ParseIocTypePoint(fabricp, param, pPoint, find_flag, pp);
#endif
	} else if (NULL != (param = ComparePrefix(arg, "rate:"))) {
		status = ParseRatePoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "portstate:"))) {
		status = ParsePortStatePoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "portphysstate:"))) {
		status = ParsePortPhysStatePoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "mtucap:"))) {
		status = ParseMtuPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "labelpat:"))) {
		status = ParseCableLabelPatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "lengthpat:"))) {
		status = ParseCableLenPatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "cabledetpat:"))) {
		status = ParseCableDetailsPatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "cabinflenpat:"))) {
		status = ParseCabinfLenPatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "cabinfvendnamepat:"))) {
		status = ParseCabinfVendNamePatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "cabinfvendpnpat:"))) {
		status = ParseCabinfVendPNPatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "cabinfvendrevpat:"))) {
		status = ParseCabinfVendRevPatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "cabinfvendsnpat:"))) {
		status = ParseCabinfVendSNPatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "cabinftype:"))) {
		status = ParseCabinfCableTypePoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "linkdetpat:"))) {
		status = ParseLinkDetailsPatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "portdetpat:"))) {
		status = ParsePortDetailsPatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "smdetpat:"))) {
		status = ParseSmDetailsPatPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "sm"))) {
		status = ParseSmPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "linkcrc"))) {
		status = ParseLinkCRCPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "linkqual"))) {
		status = ParseLinkQualityPoint(fabricp, param, pPoint, find_flag, pp);
	} else if (NULL != (param = ComparePrefix(arg, "ldr"))) {
		status = ParseLinkDownReasonPoint(fabricp, param, pPoint, find_flag, pp);
	} else {
		fprintf(stderr, "%s: Invalid format: '%s'\n", g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}
	if (status == FINVALID_OPERATION) {
		fprintf(stderr, "%s: Format Not Allowed: '%s'\n", g_Top_cmdname, arg);
		return FINVALID_PARAMETER;
	}
	return status;
}

///////////////////////////////////////////////////////////////////////////////
// FIPortIteratorHead
//
// Description:
//	Finds the first non-SW port for each type in the point.
//
// Inputs:
//	pFIPortIterator	- Pointer to FIPortIterator object
//	pFocus	- Pointer to user's compare function
//
// Outputs:
//	None
//
// Returns:
//	Pointer to port data.
//
///////////////////////////////////////////////////////////////////////////////
PortData *FIPortIteratorHead(FIPortIterator *pFIPortIterator, Point *pFocus)
{
	pFIPortIterator->pPoint = pFocus;

	switch(pFocus->Type)
	{
		case POINT_TYPE_PORT:
		{
			//return NULL if port belongs to a switch else return the port
			if( STL_NODE_SW !=  pFocus->u.portp->nodep->NodeInfo.NodeType) {
				//Flag to indicate the port is the only port and it is already returned
				pFIPortIterator->u.PortIter.lastPortFlag = TRUE;
				return pFocus->u.portp;
			}
			return NULL;
		}
		break;
		case POINT_TYPE_PORT_LIST:
		{
			LIST_ITERATOR i;
			//Go through the port list to find the first FI port. Skip all SW ports
			for (i = ListHead(&pFocus->u.portList);
				i != NULL; i = ListNext(&pFocus->u.portList, i)) {
				PortData *portp = (PortData *)ListObj(i);
				if(STL_NODE_SW == portp->nodep->NodeInfo.NodeType)
					continue;
				else {
					//Store where in the point the current iterator is.
					pFIPortIterator->u.PortListIter.currentPort = i;
					return portp;
				}
			}
			return NULL;
		}
		break;
		case POINT_TYPE_NODE:
		{
			NodeData *nodep = pFocus->u.nodep;
			// Get the first port only if it is a FI node. Return NULL for switch nodes.
			if(STL_NODE_SW != nodep->NodeInfo.NodeType) {
				cl_map_item_t * p = cl_qmap_head(&nodep->Ports);
				if(p != cl_qmap_end(&nodep->Ports)) {
					PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
					//Store where in the point the current iterator is.
					pFIPortIterator->u.NodeIter.pCurrentPort = p;
					pFIPortIterator->u.NodeIter.lastNodeFlag = TRUE;
					return portp;
				}
			}
			return NULL;
		}
		break;
		case POINT_TYPE_NODE_LIST:
		{
			LIST_ITERATOR i;
			//Iterate over the node list to get the first FI node.
			for (i = ListHead(&pFocus->u.nodeList);
				i != NULL; i = ListNext(&pFocus->u.nodeList, i)) {
				NodeData *nodep = (NodeData*)ListObj(i);

				//skip switches
				if(nodep->NodeInfo.NodeType == STL_NODE_SW)
					continue;
				else {
					cl_map_item_t *p = cl_qmap_head(&nodep->Ports);
					if(p != cl_qmap_end(&nodep->Ports)){
						PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
						//Store where in the point the current iterator is.
						pFIPortIterator->u.NodeListIter.currentNode = i;
						pFIPortIterator->u.NodeListIter.pCurrentPort = p;
						return portp;
					}
				}
			}
			return NULL;
		}
		break;
#if !defined(VXWORKS) || defined(BUILD_DMC)
		case POINT_TYPE_IOC:
		{
			NodeData *nodep = pFocus->u.iocp->ioup->nodep;
			//Get the first port for a FI node.
			if(STL_NODE_SW != nodep->NodeInfo.NodeType) {
				cl_map_item_t *p = cl_qmap_head(&nodep->Ports);
				if(p != cl_qmap_end(&nodep->Ports))
				{
					PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
					//Store where in the point the current iterator is.
					pFIPortIterator->u.IocIter.pCurrentPort = p;
					pFIPortIterator->u.IocIter.lastIocFlag = TRUE;
					return portp;
				}
			}
			return NULL;
		}
		break;
		case POINT_TYPE_IOC_LIST:
		{
			LIST_ITERATOR i;
			//Iterate over the Ioc list to get the first FI node.
			for (i = ListHead(&pFocus->u.iocList);
				i != NULL; i = ListNext(&pFocus->u.iocList, i)) {
				IocData *iocp = (IocData*)ListObj(i);
				NodeData *nodep = iocp->ioup->nodep;
				//skip switches
				if(nodep->NodeInfo.NodeType == STL_NODE_SW)
					continue;
				else {
					cl_map_item_t *p = cl_qmap_head(&nodep->Ports);
					if (p != cl_qmap_end(&nodep->Ports))
					{
						PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
						//Store where in the point the current iterator is.
						pFIPortIterator->u.IocListIter.currentNode = i;
						pFIPortIterator->u.IocListIter.pCurrentPort = p;
						return portp;
					}
				}
			}
			return NULL;
		}
		break;
#endif
		case POINT_TYPE_SYSTEM:
		{
			cl_map_item_t *s;
			//Iterate over the nodes in the system to get the first FI node.
			for (s = cl_qmap_head(&pFocus->u.systemp->Nodes);
				s != cl_qmap_end(&pFocus->u.systemp->Nodes); s = cl_qmap_next(s)){
				NodeData *nodep = PARENT_STRUCT(s, NodeData, SystemNodesEntry);
				if(nodep->NodeInfo.NodeType == STL_NODE_SW)
					continue;
				else {
					cl_map_item_t *p = cl_qmap_head(&nodep->Ports);
					if (p != cl_qmap_end(&nodep->Ports))
					{
						PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
						//Store where in the point the current iterator is.
						pFIPortIterator->u.SystemIter.pCurrentNode = s;
						pFIPortIterator->u.SystemIter.pCurrentPort = p;
						pFIPortIterator->u.SystemIter.lastSystemFlag = TRUE;
						return portp;
					}
				}
			}
			return NULL;
		}
		break;
		case POINT_TYPE_NONE:
		case POINT_TYPE_NODE_PAIR_LIST:
		default:
			return NULL;
		break;
	}
	return NULL;
}

///////////////////////////////////////////////////////////////////////////////
// FIPortIteratorNext
//
// Description:
//	Finds the next non-SW port for each type in the point
//
// Inputs:
//	pFIPortIterator	- Pointer to FIPortIterator object
//
// Outputs:
//	None
//
// Returns:
//	Pointer to port data.
//
///////////////////////////////////////////////////////////////////////////////
PortData *FIPortIteratorNext(FIPortIterator *pFIPortIterator)
{
	Point *pFocus = pFIPortIterator->pPoint;

	switch(pFocus->Type)
	{
		case POINT_TYPE_PORT:
		{
			//Check if port is iterated over
			if(pFIPortIterator->u.PortIter.lastPortFlag)
				pFIPortIterator->u.PortIter.lastPortFlag = FALSE;
			return NULL;
		}
		break;
		case POINT_TYPE_PORT_LIST:
		{
			LIST_ITERATOR i;
			//Get the next FI port using the stored position of the iterator in the point
			for (i = ListNext(&pFocus->u.portList, pFIPortIterator->u.PortListIter.currentPort);
				i != NULL; i = ListNext(&pFocus->u.portList,i)) {
				PortData *portp = (PortData *)ListObj(i);
				if(STL_NODE_SW == portp->nodep->NodeInfo.NodeType)
					continue;
				else {
					//Store where in the point the current iterator is.
					pFIPortIterator->u.PortListIter.currentPort = i;
					return portp;
				}
			}
			return NULL;
		}
		break;
		case POINT_TYPE_NODE:
		{
			if (pFIPortIterator->u.NodeIter.lastNodeFlag){
				//Get the next port using the stored position of the iterator in the point. It is an FI port.
				cl_map_item_t *p = cl_qmap_next(pFIPortIterator->u.NodeIter.pCurrentPort);
				if(p != cl_qmap_end(&pFocus->u.nodep->Ports)){
					PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
					//Store where in the point the current iterator is.
					pFIPortIterator->u.NodeIter.pCurrentPort = p;
					return portp;
				} else
					pFIPortIterator->u.NodeIter.lastNodeFlag = FALSE;
			}
			return NULL;
		}
		break;
		case POINT_TYPE_NODE_LIST:
		{
			LIST_ITERATOR i;
			//Get the next port of the node using the stored position of the iterator in the point. It is an FI port.
			NodeData *nodep = (NodeData*)ListObj(pFIPortIterator->u.NodeListIter.currentNode);
			cl_map_item_t *p = cl_qmap_next(pFIPortIterator->u.NodeListIter.pCurrentPort);
			if(p != cl_qmap_end(&nodep->Ports)){
				PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
				//Store where in the point the current iterator is.
				pFIPortIterator->u.NodeIter.pCurrentPort = p;
				return portp;
			} else {
				//Iterate over the next node of the list
				for (i = ListNext(&pFocus->u.nodeList, pFIPortIterator->u.NodeListIter.currentNode);
					i != NULL; i = ListNext(&pFocus->u.nodeList, i)) {
					nodep = (NodeData*)ListObj(i);
					//skip switches
					if(nodep->NodeInfo.NodeType == STL_NODE_SW)
						continue;
					else {
						p = cl_qmap_head(&nodep->Ports);
						if(p != cl_qmap_end(&nodep->Ports)){
							PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
							//Store where in the point the current iterator is.
							pFIPortIterator->u.NodeListIter.currentNode = i;
							pFIPortIterator->u.NodeListIter.pCurrentPort = p;
							return portp;
						}
					}
				}
			}
			return NULL;
		}
		break;
#if !defined(VXWORKS) || defined(BUILD_DMC)
		case POINT_TYPE_IOC:
		{
			if (pFIPortIterator->u.IocIter.lastIocFlag){
				//Get the next port using the stored position of the iterator in the point. It is an FI port.
				cl_map_item_t *p = cl_qmap_next(pFIPortIterator->u.IocIter.pCurrentPort);
				NodeData *nodep = pFocus->u.iocp->ioup->nodep;
				if(p != cl_qmap_end(&nodep->Ports)){
					PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
					//Store where in the point the current iterator is.
					pFIPortIterator->u.IocIter.pCurrentPort = p;
					return portp;
				} else
					pFIPortIterator->u.IocIter.lastIocFlag = FALSE;
			}
			return NULL;
		}
		break;
		case POINT_TYPE_IOC_LIST:
		{
			LIST_ITERATOR i;
			//Get the next port of the node using the stored position of the iterator in the point. It is an FI port.
			IocData *iocp = (IocData*)ListObj(pFIPortIterator->u.IocListIter.currentNode);
			NodeData *nodep = iocp->ioup->nodep;
			cl_map_item_t *p = cl_qmap_next(pFIPortIterator->u.IocListIter.pCurrentPort);
			if(p != cl_qmap_end(&nodep->Ports)){
				PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
				//Store where in the point the current iterator is.
				pFIPortIterator->u.IocListIter.pCurrentPort = p;
				return portp;
			} else {
				//Iterate over the next Ioc of the list
				for (i = ListNext(&pFocus->u.iocList, pFIPortIterator->u.IocListIter.currentNode);
					i != NULL; i = ListNext(&pFocus->u.iocList, i)) {
					iocp = (IocData*)ListObj(i);
					nodep = iocp->ioup->nodep;
					//skip switches
					if(nodep->NodeInfo.NodeType == STL_NODE_SW)
						continue;
					else {
						p = cl_qmap_head(&nodep->Ports);
						if(p != cl_qmap_end(&nodep->Ports)){
							PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
							//Store where in the point the current iterator is.
							pFIPortIterator->u.IocListIter.currentNode = i;
							pFIPortIterator->u.IocListIter.pCurrentPort = p;
							return portp;
						}
					}
				}
			}
			return NULL;
		}
		break;
#endif
		case POINT_TYPE_SYSTEM:
		{
			cl_map_item_t *s;
			if (pFIPortIterator->u.SystemIter.lastSystemFlag){
				//Get the next port using the stored position of the iterator in the point. It is an FI port.
				NodeData *nodep = PARENT_STRUCT(pFIPortIterator->u.SystemIter.pCurrentNode, NodeData, SystemNodesEntry);
				cl_map_item_t *p = cl_qmap_next(pFIPortIterator->u.SystemIter.pCurrentPort);
				if(p != cl_qmap_end(&nodep->Ports)){
					PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
					//Store where in the point the current iterator is.
					pFIPortIterator->u.SystemIter.pCurrentPort = p;
					return portp;
				} else {
					//Iterate over the next node of the list
					for (s = cl_qmap_next(pFIPortIterator->u.SystemIter.pCurrentNode);
						s != cl_qmap_end(&pFocus->u.systemp->Nodes); s = cl_qmap_next(s)) {
						nodep = PARENT_STRUCT(s, NodeData, SystemNodesEntry);
						//skip switches
						if(nodep->NodeInfo.NodeType == STL_NODE_SW)
							continue;
						else {
							p = cl_qmap_head(&nodep->Ports);
							if(p != cl_qmap_end(&nodep->Ports)){
								PortData *portp = PARENT_STRUCT(p, PortData, NodePortsEntry);
								//Store where in the point the current iterator is.
								pFIPortIterator->u.SystemIter.pCurrentNode = s;
								pFIPortIterator->u.SystemIter.pCurrentPort = p;
								return portp;
							}
						}
					}
					pFIPortIterator->u.SystemIter.lastSystemFlag = FALSE;
				}
			}
			return NULL;
		}
		break;
		case POINT_TYPE_NONE:
		case POINT_TYPE_NODE_PAIR_LIST:
		default:
			return NULL;
		break;
	}
	return NULL;
}
