/* hl7_api.c * Functions for HL7ImEx. * * Copyright (C) 1993 Igor Chernizer. Columbia University. * Columbia-Presbyterian Medical Center. * * This file is part of HL7ImEx * * Use and copying of this software and preparation of derivative works * based upon this software are permitted. However, any distribution of * this software or derivative works must include the above copyright * notice. * * This software is made available AS IS , and neither the * Columbia-Presbyterian Medical Center or the Columbia University make * any warranty about the software, its performance or its conformity to * any specification. * * Modified by Allen Rueter, Mallinckrodt Institute of Radiology, * Washingtion University Medical Center. May 1994 */ /* Change history * *$Log: hl7_api.c,v $ * Revision 1.3 1993/03/26 02:56:55 cherniz * add BSD implementation of memchr, because AIX optimize * code too much :-) * HL7GetField -> HL7GetFld * * Revision 1.1 1993/03/01 22:01:16 cherniz * Initial revision * Revision 2 1994 may Allen Rueter * Added hl7init, and new structures to allow reading in segment definitions * and rules. Replaced hard coded rules, with recursive routines. Replaced * HL7xYYY constant with pointer/function HL7pYYY that return a pointer to a * structure defining the Segment. */ #ifndef lint static char rcsid[] = "$Id: hl7_api.c,v 1.3 1993/03/26 02:56:55 cherniz Exp $"; #endif #include #include #include /* isalnum */ #ifdef VMS #include #else #include #endif #include /*#include */ #define API 1 #include "hl7_api.h" #ifdef min #undef min #endif #define min(A,B) ((A)<(B)? (A):(B)) /* is needed by aix, not VMS or Ultrix */ #ifdef AIX #undef memchr #define memchr Memchr /* implementation of memchar to make AIX happy */ /* Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. */ void * Memchr(void *s, int c, size_t n) { if (n != 0) { register const unsigned char *p = s; do { if (*p++ == c) return ((void *)(p - 1)); } while (--n != 0); } return (NULL); } #endif #ifdef DEBUG # undef NDEBUG /* turn assertion on */ # define DB if(1) #else # define NDEBUG /* disable assert */ # define DB if(0) #endif # define DB1 if(0) #include static int UnmarshallSeg(HL7MSG *, HL7SegRule *, SIZE *); static int UnmarshallSep(HL7MSG *, char *); static int UnmarshallRep(HL7MSG *, char *); static int UnmarshallComp(HL7MSG *, char *); static int UnmarshallSub(HL7MSG *, char *); static int MarshallSeg (HL7MSG *, HL7SegRule *); static int HL7Parse (HL7MSG *); static int AppendToBuffer(HL7MSG *, char *); static void MsgType2Ecode (HL7MSG *); static int PoolToWire(HL7MSG *, char *, SIZE); /* resolve segment name to ptr to rule/desc. */ HL7SegRule *pSegRule( char *segNm) { /* resolve a segment name ("MSH") to a ptr to rule By Allen Rueter */ HL7SegRule *pSR = p1SegR; while ( strncmp( pSR->azNam, segNm, HL7_SEG_NAME_LEN) !=0) { pSR = pSR->nxt; if (pSR==0) {fprintf( stderr, "pSegRule couldn't find %s\n",segNm);exit(0);} } return pSR; } void HL7savLet( char *seg, int *segi, int c) { /* by Allen Rueter */ *(seg+(*segi)++) = c; /* save letter, bump index */ *(seg+*segi) = 0; /* keep string terminated */ } MSGrule *pCurRule; MSGterm *pCurTerm; void HL7savSeg( char *seg, int *segNamI) { /* Save a Segment def. by Allen Rueter */ MSGterm *pTmpTerm; DB printf("%s ", seg); pTmpTerm = (MSGterm *)malloc( sizeof( MSGterm)); pTmpTerm->typ = 0; /* set type to seg (not []{}()<>) */ pTmpTerm->pSegR = pSegRule( seg); /* point to type of segment */ pTmpTerm->nxt = 0; /* current end of rule */ if ( pCurRule->p1term == 0) /* 1st rule? */ pCurRule->p1term = pTmpTerm; /* save start up rule list */ else pCurTerm->nxt = pTmpTerm; /* add to end of rule list */ pCurTerm = pTmpTerm; *segNamI = 0; } char ocstack[20], *pocs; /* stack to match open close */ void HL7savOpn( char opn) { /* Save starting delem [{<( By Allen Rueter */ MSGterm *pTmpTerm; DB printf("%c", opn); pTmpTerm = (MSGterm *)malloc( sizeof( MSGterm)); pTmpTerm->typ = opn; pTmpTerm->pSegR = 0; pTmpTerm->nxt = 0; if ( pCurRule->p1term == 0) pCurRule->p1term = pTmpTerm; else pCurTerm->nxt = pTmpTerm; pCurTerm = pTmpTerm; *++pocs = opn; /* push open [{<( on to stack */ } void HL7savCls( char cls) { /* Save closing delem. ]}>) By Allen Rueter */ MSGterm *pTmpTerm; /* printf("%c", cls); */ pTmpTerm = (MSGterm *)malloc( sizeof( MSGterm)); pTmpTerm->typ = cls; pTmpTerm->pSegR = 0; pTmpTerm->nxt = 0; if (pCurRule->p1term == 0) pCurRule->p1term = pTmpTerm; else pCurTerm->nxt = pTmpTerm; pCurTerm = pTmpTerm; if ( *pocs == '{' && cls == '}') { pocs--; return; } if ( *pocs == '[' && cls == ']') { pocs--; return; } if ( *pocs == '<' && cls == '>') { pocs--; return; } if ( *pocs == '(' && cls == ')') { pocs--; return; } fprintf( stderr, "ERROR %c doesn't match %c\n",*pocs, cls); exit(-1); } int HL7Init ( char *tblPath, char *tblVrsn ) { /* read in parsing table(s) */ /* This function reads in two files, segDefs and msgRules. The tblPath arg. is a prefix to the filenames and tblVrsn is a suffix. side effects files are closed By Allen Rueter */ FILE *stfd; /* segment types file descriptor */ char tmp[510], *pC; char *segDefs="segDefs"; char *msgRules="msgRules", evnt[10], cln[2], rule[510], eol[2], c; char segNam[10]; int sni; char filename[256]; char *opn = "[{<("; /* delemiters */ char *cls = "]}>)"; char *wht = " ,\t"; int i, state, s; char segTypes[256], typ[10],ro[10],nr[20]; int sto=0, fldLen, n =0; HL7SegRule *pSegR,*pCurSegR; HL7FldRule *pFldR,*pCurFldR; FILE *mrfd; /* message rules file descriptor */ MSGterm *pCurTerm, *pTmpTerm; MSGrule *pTmpRule; strcpy( filename, tblPath); /* build file name to open */ strcat( filename, segDefs); strcat( filename, tblVrsn); stfd = fopen( filename,"r"); if (stfd==0) { fprintf(stderr,"FAILED TO OPEN: %s\n",filename); exit(-1);} p1SegR = (HL7SegRule *)malloc( sizeof( HL7SegRule)); pCurSegR = p1SegR; pCurSegR->azNam[0] = 0; pCurSegR->p1fld = 0; while ( n>=0) { /* get field length, type, req/opt, #repeats */ while ( (n=fscanf( stfd, "%d%s%s%s", &fldLen, typ, ro, nr)) > 0) { fgets( tmp, 509, stfd); /* suck up comments */ pFldR = (HL7FldRule *)malloc( sizeof( HL7FldRule)); /* tack field rule on to seg or prev. field */ if (pCurSegR->p1fld==0) pCurSegR->p1fld = pFldR; else pCurFldR->nxt = pFldR; pCurFldR = pFldR; pCurFldR->nxt = 0; pCurSegR->nmbrFlds += 1; pFldR->len = fldLen; pC = strstr( sFldTypes, typ); /* decode field type */ if (pC==0) pFldR->typ = 0; else pFldR->typ = 1+( pC-sFldTypes)/3; /* decode required / optional */ if (ro[0]=='R' && ro[1]=='E') pFldR->reqOpt = 1; else if (ro[0]=='O' && ro[1]=='P') pFldR->reqOpt = 0; else pFldR->reqOpt = -1; /* decode repeat */ if (nr[0]=='N' && nr[1]=='O') { if (nr[3]=='M') pFldR->nmbrRep = 100; /* NO_MAX (yeah, right) */ if (nr[3]=='R') pFldR->nmbrRep = 0; /* NO_RPT */ } else if (isdigit(nr[0])) pFldR->nmbrRep = atoi(nr); else { fprintf(stderr, "BAD repeat specified %s\n", nr); exit(0); } DB printf("read: %d %d %s %s %s\n",n,fldLen,typ,ro,nr); } n = fscanf( stfd, "%s", &segTypes[sto]); if ( n>=0) { DB printf("segtype: %s\n", &segTypes[sto]); memcpy( pCurSegR->azNam, &segTypes[sto], 4); /* save where MSH is defined */ if (strcmp( "MSH",pCurSegR->azNam)==0) { HL7pMSH = pCurSegR; } else if(strcmp( "MSA",pCurSegR->azNam)==0) { HL7pMSA = pCurSegR; } else if(strcmp( "EVN",pCurSegR->azNam)==0) { HL7pEVN = pCurSegR; } else if(strcmp( "PID",pCurSegR->azNam)==0) { HL7pPID = pCurSegR; } else if(strcmp( "PV1",pCurSegR->azNam)==0) { HL7pPV1 = pCurSegR; } else if(strcmp( "GT1",pCurSegR->azNam)==0) { HL7pGT1 = pCurSegR; } else if(strcmp( "IN1",pCurSegR->azNam)==0) { HL7pIN1 = pCurSegR; } else if(strcmp( "DSC",pCurSegR->azNam)==0) { HL7pDSC = pCurSegR; } else if(strcmp( "DSP",pCurSegR->azNam)==0) { HL7pDSP = pCurSegR; } else if(strcmp( "QRD",pCurSegR->azNam)==0) { HL7pQRD = pCurSegR; } sto+=4; pSegR = (HL7SegRule *)malloc( sizeof( HL7SegRule)); pCurSegR->nxt = pSegR; pCurSegR = pSegR; pCurSegR->azNam[0] = 0; pCurSegR->p1fld = 0; } } fclose( stfd); pCurSegR = p1SegR; DB { printf("Segs:"); while ( pCurSegR->azNam[0]!=0) { printf("%s ", pCurSegR->azNam); pCurSegR = pCurSegR->nxt; } printf("\n"); } /* read in Rules */ strcpy( filename, tblPath); strcat( filename, msgRules); strcat( filename, tblVrsn); mrfd = fopen( filename,"r"); if (mrfd==0) { fprintf(stderr,"FAILED TO OPEN: %s\n",filename); exit(0);} while ( (s = fscanf( mrfd, "%[^:]%c%[^\n]%c", evnt, cln, rule,eol))>2) { state=1; pocs = &ocstack[0]; /* setup stack to match open close */ pTmpRule = (MSGrule *)malloc( sizeof( MSGrule)); if (p1Rule == 0) p1Rule = pCurRule = pTmpRule; /* very 1st ? */ else pCurRule->nxt = pTmpRule; pCurRule = pTmpRule; strcpy( pCurRule->evnt, evnt); pCurRule->p1term = 0; pCurRule->nxt = 0; pCurTerm = 0; sni = 0; segNam[3]=0; for ( i=0; rule[i]!=0;i++) { s = rule[i]; if (state==1) { /* building Seg */ if ( isalnum(s) ) HL7savLet(segNam, &sni, s) ; else if ( strchr( opn,s)) { HL7savSeg(segNam,&sni); HL7savOpn(s); state=2;} else if ( strchr( cls,s)) { HL7savSeg(segNam,&sni); HL7savCls(s); state=3;} else if ( strchr( wht,s)) { HL7savSeg(segNam,&sni); state=4;} else { fprintf(stderr,"Bad char %c (%d)\n", s, s); exit(0);} } else if (state==2) { /* just got [{<( */ if ( isalnum(s) ) { HL7savLet(segNam, &sni, s) ; state=1; } else if ( strchr( opn,s)) { HL7savOpn(s); state=2;} else if ( strchr( cls,s)) { fprintf(stderr,"ERROR messing seg\n"); exit(0);} else if ( strchr( wht,s)) state=4; else { fprintf(stderr,"Bad char %c (%d)\n", s, s); exit(0);} } else if (state==3) { /* just got ]}>) */ if ( isalnum(s) ) { HL7savLet(segNam, &sni, s) ; state=1; } else if ( strchr( opn,s)) { HL7savOpn(s); state=2;} else if ( strchr( cls,s)) { HL7savCls(s); state=3;} else if ( strchr( wht,s)) state=4; else { fprintf(stderr,"Bad char %c (%d)\n", s, s); exit(0);} } else if (state==4) { /* just got white space */ if ( isalnum(s) ) { HL7savLet(segNam, &sni, s) ; state=1; } else if ( strchr( opn,s)) { HL7savOpn(s); state=2;} else if ( strchr( cls,s)) { HL7savCls(s); state=3;} else if ( strchr( wht,s)) state=4; else { fprintf(stderr,"Bad char %c (%d)\n", s, s); exit(0);} } else { fprintf(stderr, "Ugly state=%d\n",state); exit(0); } } if ( pocs != &ocstack[0]) { fprintf( stderr, "unmatched paren. %c in %s\n", *pocs,evnt); exit(0); } } fclose( mrfd); } HL7MSG * HL7Alloc(void) { HL7MSG *pMsg; /* Allocate initial structure, and initialize it. */ DB { printf("\n Create message handle"); fflush(stdout); } if ((pMsg = (HL7MSG *)malloc(sizeof(HL7MSG))) == NULL) { return(NULL); /* no available memory */ } /* clean it up */ pMsg->cMsgType[0] = 0; pMsg->cMsgEcode[0] = 0; pMsg->pSegList = 0; pMsg->pCurrSeg = 0; pMsg->iCurrFldI0b = 0; pMsg->pCurrRep = 0; pMsg->pCurrCom = 0; pMsg->pCurrSub = 0; pMsg->FldSep = HL7FLDSEP; pMsg->CmpSep = HL7CMPSEP; pMsg->RepSep = HL7REPSEP; pMsg->EscSep = HL7ESCSEP; pMsg->SubSep = HL7SUBSEP; pMsg->pWireCursor = 0; pMsg->fDirection = 0; pMsg->pWire = 0; pMsg->WireLen = 0; pMsg->MaxWireLen = 0; pMsg->pGetBuffer = 0; pMsg->GetBufferSize = 0; return(pMsg); /* pointer to handle */ } int HL7InsSeg(HL7MSG *pMsg, HL7SegRule *pSegR) { HL7SEG *pL; /* insert new list item into structure */ DB { printf("\n Insert new segment %s", pSegR->azNam); fflush(stdout); } /* alloc space for new seg */ if (( pL = (HL7SEG *) calloc (sizeof(HL7SEG),1)) == 0) return (HL7_NO_MEMORY); /* set list link */ if (pMsg->pCurrSeg == 0) { /* first segment-node */ if (pMsg->pSegList != 0) return(HL7_NO_CURRENT_SEG); pMsg->pSegList = pL; /* keep list head */ pL->pNextSeg = 0; /* set list terminator */ } else { pL->pNextSeg = pMsg->pCurrSeg->pNextSeg; pMsg->pCurrSeg->pNextSeg = pL; /* set link */ } pMsg->pCurrSeg = pL; pMsg->pCurrSeg->pSegRul = pSegR; /* put seg type in new node */ /* Change current pointer to new one */ return (HL7_OK); } int HL7WriteMsg(HL7MSG *pMsg, char *pzWire , SIZE MaxWireLen, SIZE *pWireLen) { int i; /* convert structure to wire */ pMsg->fDirection = HL7_STRUCT_TO_WIRE; /* global direction */ pMsg->pWire = pzWire; pMsg->pWireCursor = pzWire; /* global wire ptr, space */ pMsg->iCurrFldI0b=0; /* iCurrFldI0b is zero based not 1 like the segdefs */ if ((pMsg->pCurrSeg = pMsg->pSegList) == 0) return(HL7_EMPTY_STRUCT); pMsg->MaxWireLen = MaxWireLen; /* max length of wire */ pMsg->WireLen = 0; /* set wire len var */ if ((i = HL7Parse (pMsg)) != HL7_OK) return (i); /* do the parse */ *pWireLen = pMsg->WireLen;; return (HL7_OK); } int HL7Eat(HL7MSG *pMsg, HL7SegRule *pSegR) { int i; SIZE SegLen = 0; HL7SEG *pSeg = 0; HL7SEG *pPrevSeg = pMsg->pCurrSeg; /* in case Eat fails, which happens when parsing nested []{}<> */ switch (pMsg->fDirection) { case HL7_WIRE_TO_STRUCT: DB { printf("\n Allocate new segment - %s", pSegR->azNam); fflush(stdout); } /* allocate next segment entry */ if ((pSeg = (HL7SEG *) calloc (sizeof(HL7SEG), 1)) == 0) return (HL7_NO_MEMORY); if (pMsg->pSegList == 0) /* this is first segment */ /* should be MSH */ /* or FHS */ pMsg->pSegList = pSeg; /* init segment list */ else /* append to segment list */ pMsg->pCurrSeg->pNextSeg = pSeg; /* point from prev to new */ pMsg->pCurrSeg = pSeg; /* make it current segment */ pMsg->pCurrSeg->pNextSeg = 0; /* null terminator for last entry*/ /* get segment name from table */ pMsg->pCurrSeg->pSegRul = pSegR; /* FLDAMT = 0 init number of fields */ pMsg->pCurrRep = 0; pMsg->pCurrCom=0; pMsg->pCurrSub=0; if ((i = UnmarshallSeg (pMsg, pSegR, &SegLen)) != HL7_OK) { /* need to undo */ free(pSeg); if (pPrevSeg==0) pMsg->pSegList=0; else pPrevSeg->pNextSeg = 0; pMsg->pCurrSeg = pPrevSeg; return (i); } pMsg->pWireCursor += SegLen; /* Move wire cursor forward */ break; case HL7_STRUCT_TO_WIRE: DB { printf("\nFrom struct to wire segment -'%s'",pSegR->azNam); fflush(stdout); } if (pSegR != HL7pMSH) { /* or FHS ? */ if ((pSeg = pMsg->pCurrSeg->pNextSeg) == 0) return (HL7_MSG_INCOMPLETE); if ( pMsg->pCurrSeg->pNextSeg->pSegRul != pSegR) { fprintf( stderr,"\n Seg out of order, found %s, expecting %s\n", pMsg->pCurrSeg->pNextSeg->pSegRul, pSegR); return HL7_SEG_OUTOF_ORDER; } pMsg->pCurrSeg = pSeg; } if ((i = MarshallSeg (pMsg, pSegR)) != HL7_OK) return (i); /* return (HL7_OK); */ break; default: return (HL7_BAD_DIRECTION); break; } return(HL7_OK); } static int UnmarshallSeg (HL7MSG *pMsg, HL7SegRule *pSegRule, SIZE *pSegLen) { /* break wire up into structure */ /* segments are made up of fields */ int fEOWire; /* TRUE if EOF or End of Seg occur*/ int fFldEnd; /* TRUE if num of fiels = max */ SIZE i; SIZE FldLen; char *pc, *pcT; char aDelims[3]; char msgtype[8]; pcT = pMsg->pWireCursor; *pSegLen = 0; if (strncmp(pcT, pSegRule->azNam, HL7_SEG_NAME_LEN) != 0) { return(HL7_BAD_SEG_NAME); } pcT += HL7_SEG_NAME_LEN; if (pSegRule == HL7pMSH) { /* or FHS? */ pMsg->FldSep = *(pcT); pMsg->CmpSep = *(pcT+1); pMsg->RepSep = *(pcT+2); pMsg->EscSep = *(pcT+3); pMsg->SubSep = *(pcT+4); } else if (*pcT != pMsg->FldSep) return(HL7_BAD_FLD_SEP); aDelims[0] = pMsg->FldSep; aDelims[1] = HL7_SEG_SEP; aDelims[2] = '\0'; pcT++; pMsg->pWireCursor = pcT; fEOWire = FALSE; fFldEnd = FALSE; pMsg->iCurrFldI0b = 0; (pMsg->pCurrSeg)->pFldLst[pMsg->iCurrFldI0b] = 0; if (pSegRule == HL7pMSH) { /* take care of FHS? */ if ((i = UnmarshallSep(pMsg, pMsg->pWireCursor)) != HL7_OK) /* first MSH field */ return (i); pcT = pcT+6; pMsg->pWireCursor = pcT; pMsg->iCurrFldI0b++; /* change field numb to next */ pMsg->iCurrFldI0b++; /* MSH fix up */ } do { /* till numbers of fields exceed over max or EndOfWire */ if ((pc = strpbrk(pcT,aDelims)) == NULL) return(HL7_SEG_TOO_LONG); /* each segment should have */ /* SEG_SEP as teminator */ (pMsg->pCurrSeg)->pFldLst[pMsg->iCurrFldI0b] = 0; /* init ptr to curent field */ /* value can be changed inside */ /* UnmarshallRep */ pMsg->pCurrCom=0; pMsg->pCurrSub=0; if (pSegRule != HL7pMSH) /* or FHS ? */ pMsg->pCurrRep = 0; if ((FldLen = (pc - pcT)) != 0) { /* field is empty */ if ((i = UnmarshallRep(pMsg, pc)) != HL7_OK) return (i); if ( (pSegRule == HL7pMSH) && (pMsg->iCurrFldI0b == 9-1)) { i = min(HL7_MSGTYPE_LEN,FldLen); /* pick up & save ADT^A01 */ strncpy(pMsg->cMsgType, pcT, i); pMsg->cMsgType[i]='\0'; MsgType2Ecode( pMsg); } } if (*pc == HL7_SEG_SEP) fEOWire = TRUE; /* end of segment */ else if (pMsg->iCurrFldI0b == pSegRule->nmbrFlds) fFldEnd = TRUE; /* CURRFLD == max */ else { pcT = pc +1; /* move forward to next field*/ pMsg->pWireCursor = pcT; pMsg->iCurrFldI0b++; /* next field */ } } while (!fEOWire && !fFldEnd); /* if actual amount af fields more than max - ignore rest */ if (fFldEnd) if ((pc = strchr(pcT, HL7_SEG_SEP)) == 0) return(HL7_SEG_TOO_LONG); pMsg->pCurrSeg->NumFld = pMsg->iCurrFldI0b; *pSegLen = pc - pMsg->pWireCursor + 1; return (HL7_OK); } static int UnmarshallRep(HL7MSG *pMsg, char *pRight) { HL7REP *pRep; char *pLeft; /* first char in repetition */ char *pL, *pR; /* float left and right bounds*/ char *pT; int i; pLeft = pMsg->pWireCursor; pL = pLeft; do { /* until repetition scanning is over */ pMsg->pCurrCom=0; pMsg->pCurrSub=0; if ((pT = memchr(pL, pMsg->RepSep, (SIZE)(pRight-pL))) != NULL) pR = pT; /* set new right bound */ else pR = pRight; if ((pR - pL) != 0) { /* non-empty rep */ DB { printf("\n allocate new repetition "); fflush(stdout); } if ((pRep = (HL7REP *) malloc(sizeof(HL7REP))) == 0) return (HL7_NO_MEMORY); if ((pMsg->pCurrSeg)->pFldLst[pMsg->iCurrFldI0b] == 0) { /* first occur */ (pMsg->pCurrSeg)->pFldLst[pMsg->iCurrFldI0b] = pRep; pRep->RepNum = 1; } else { /* last occur */ pRep->RepNum = pMsg->pCurrRep->RepNum + 1; /* incr rep # */ pMsg->pCurrRep->pRepNext = pRep; /* append to list */ } pMsg->pCurrRep = pRep; /* make it current rep */ pRep->pRepNext = 0; /* put end-of-list */ pRep->CompNum = 0; pRep->pComp = 0; pMsg->pWireCursor = pL; /* cursor points to left bound */ DB { printf("\nUnmarshallRep field %d:",(pMsg->iCurrFldI0b)+1); for(i=0; i < (pR-pL); i++) printf("%c",*(pL+i)); fflush(stdout); } if ((i = UnmarshallComp(pMsg, pR)) != HL7_OK) return (i); } if (pT != 0) pL= pT + 1; } while (pT); pMsg->pWireCursor = pRight; return(HL7_OK); } static int UnmarshallComp(HL7MSG *pMsg, char *pRight) { HL7COMP *pComp; char *pLeft; /* first char in component */ char *pL, *pR; char *pT; int i; int CompCount; pLeft = pMsg->pWireCursor; pL = pLeft; CompCount = 0; do { /* until component scanning is over */ pMsg->pCurrSub =0; if ((pT = memchr(pL, pMsg->CmpSep, (SIZE)(pRight-pL))) != NULL) pR = pT; else pR = pRight; CompCount++; if ((pR - pL) != 0) { /* non-empty component*/ DB { printf("\n allocate new component"); fflush(stdout); } if ((pComp = (HL7COMP *) malloc(sizeof(HL7COMP))) == 0) return (HL7_NO_MEMORY); if (pMsg->pCurrCom == 0) { /* first entry in list */ pMsg->pCurrRep->pComp = pComp; pMsg->pCurrRep->CompNum = 1; } else { /* add to comp list */ pMsg->pCurrCom->pCompNext = pComp; /* attach to list */ pMsg->pCurrRep->CompNum = CompCount; } pMsg->pCurrCom = pComp; pComp->pCompNext = 0; pComp->pSCompLst = 0; pComp->CompIndex = CompCount; /* set index component index */ pMsg->pWireCursor = pL; DB { printf("\nUnmarshallComp:"); for(i=0; i < (pR-pL); i++) printf("%c",*(pL+i)); fflush(stdout); } if ((i = UnmarshallSub(pMsg, pR)) != HL7_OK) return (i); } if (pT !=0) pL = pT +1; } while (pT); pMsg->pWireCursor = pRight; return(HL7_OK); } static int UnmarshallSub(HL7MSG *pMsg, char *pRight) { HL7SUBCOMP *pSub; char *pLeft; /* first char in subcomponent */ char *pL, *pR; char *pT; char SubCount; int i; pLeft = pMsg->pWireCursor; pL = pLeft; SubCount = 0; do { /* until subcomponent scanning is over */ if ((pT = memchr(pL, pMsg->SubSep, (SIZE)(pRight-pL))) != NULL) pR = pT; else pR = pRight; SubCount++; if ((pR - pL) != 0) { /* non-emty subcomponent */ DB { printf("\n allocate new subcomponent"); fflush(stdout); } if ((pSub = (HL7SUBCOMP *) malloc(sizeof(HL7SUBCOMP))) == 0) return (HL7_NO_MEMORY); if (pMsg->pCurrSub == 0) /* first subcomponent */ pMsg->pCurrCom->pSCompLst = pSub; else pMsg->pCurrSub->pSubNext = pSub; pMsg->pCurrSub = pSub; pMsg->pCurrCom->SubCompNum = SubCount; pMsg->pCurrSub->SubCompIndex = SubCount; pMsg->pCurrSub->pSubNext = 0; pMsg->pWireCursor = pL; DB { printf("\n allocate new data"); fflush(stdout); } if ((pSub->pzDataStr = (char *)malloc((SIZE)(pR-pL+1))) == NULL) return (HL7_NO_MEMORY); DB { printf("\nUnmarshallSub :"); for(i=0; i < (pR-pL); i++) printf("%c",*(pL+i)); fflush(stdout); } strncpy(pSub->pzDataStr, pL, (SIZE)(pR-pL)); pSub->SubLen = pR-pL; *(pSub->pzDataStr + pSub->SubLen) = '\0'; } if (pT != 0) pL = pT +1; /* goto to next subcomp */ } while (pT); pMsg->pWireCursor = pRight; return(HL7_OK); } static int UnmarshallSep(HL7MSG *pMsg, char *pString) { HL7REP *pRep; HL7COMP *pComp; HL7SUBCOMP *pSubComp; if ((pRep = (HL7REP *) malloc(sizeof(HL7REP))) == 0) return (HL7_NO_MEMORY); pMsg->pCurrRep = pRep; (pMsg->pCurrSeg)->pFldLst[pMsg->iCurrFldI0b] = pRep; pRep->RepNum = 1; pRep->CompNum = 1; pRep->pRepNext = 0; if ((pComp = (HL7COMP *) malloc(sizeof(HL7COMP))) == 0) return (HL7_NO_MEMORY); pMsg->pCurrCom = pComp; pRep->pComp = pComp; pComp->CompIndex = 1; pComp->pCompNext = 0; if ((pSubComp = (HL7SUBCOMP *) malloc(sizeof(HL7SUBCOMP))) == 0) return (HL7_NO_MEMORY); pMsg->pCurrSub = pSubComp; pComp->pSCompLst = pSubComp; pSubComp->SubLen = 4; /* length (exclude null-terminator) */ pSubComp->SubCompIndex = 1; pSubComp->pSubNext = 0; if ((pSubComp->pzDataStr = (char *) malloc(5)) == 0) return (HL7_NO_MEMORY); strncpy(pSubComp->pzDataStr, pString,4); return(HL7_OK); } char * HL7GetSub(HL7MSG *pMsg, int FieldNum, int RepNum, int CompNum, int SubNum) { /* pick out a subcomponnet */ HL7SEG *pSegT; HL7REP *pRepT; HL7COMP *pCompT; HL7SUBCOMP *pSubT; char azFldDel[2]; /* chech handle */ if (pMsg == NULL) return(NULL); if (pMsg->pGetBuffer != 0) *pMsg->pGetBuffer = '\0'; /* check current segment */ if ((pSegT = pMsg->pCurrSeg) == NULL) return(NULL); /* arguments validation */ if ((FieldNum < 1) || (RepNum < 1) || (CompNum < 1) || (SubNum < 1)) return(NULL); if (pSegT->pSegRul == HL7pMSH) if (FieldNum != 1) --FieldNum; else { if (pMsg->pGetBuffer != 0) *pMsg->pGetBuffer = '\0'; azFldDel[0] = pMsg->FldSep; azFldDel[1] = '\0'; if (AppendToBuffer(pMsg, azFldDel) != HL7_OK) return(NULL); return(pMsg->pGetBuffer); } if ((pRepT = pSegT->pFldLst[FieldNum-1]) == NULL) return(NULL); /* traverse reprtition list */ do { if (pRepT->RepNum == RepNum) break; } while (pRepT = pRepT->pRepNext); if (pRepT == 0) return(NULL); /* Not that many repeats */ if (pRepT->RepNum != RepNum) return(NULL); if ((pCompT = pRepT->pComp) == NULL) return(NULL); /* traverse component list */ do { if (pCompT->CompIndex == CompNum) break; } while(pCompT = pCompT->pCompNext); if (pCompT->CompIndex != CompNum) return(NULL); if ((pSubT = pCompT->pSCompLst) == NULL) return(NULL); /* traverse subcomponent list */ do { if (pSubT->SubCompIndex == SubNum) break; } while (pSubT = pSubT->pSubNext); if (pSubT->SubCompIndex != SubNum) return(NULL); if (pSubT->pzDataStr == NULL) return(NULL); /* no data */ /* get data */ AppendToBuffer(pMsg, pSubT->pzDataStr); return(pMsg->pGetBuffer); } char * HL7GetComp(HL7MSG *pMsg, int FieldNum, int RepNum, int CompNum) { /* pick out a componnet */ HL7SEG *pSegT; HL7REP *pRepT; HL7COMP *pCompT; HL7SUBCOMP *pSubT; int i,j; char azSubDel[2]; char azFldDel[2]; /* chech handle */ if (pMsg == NULL) return(NULL); azSubDel[0] = pMsg->SubSep; azSubDel[1] = '\0'; /* check current segment */ if ((pSegT = pMsg->pCurrSeg) == NULL) return(NULL); /* arguments validation */ if ((FieldNum < 1) || (RepNum < 1) || (CompNum < 1)) return(NULL); if (pSegT->pSegRul == HL7pMSH) if (FieldNum != 1) --FieldNum; else { if (pMsg->pGetBuffer != 0) *pMsg->pGetBuffer = '\0'; azFldDel[0] = pMsg->FldSep; azFldDel[1] = '\0'; if (AppendToBuffer(pMsg, azFldDel) != HL7_OK) return(NULL); return(pMsg->pGetBuffer); } if ((pRepT = pSegT->pFldLst[FieldNum-1]) == NULL) return(NULL); /* traverse reprtition list */ do { if (pRepT->RepNum == RepNum) break; } while(pRepT = pRepT->pRepNext); if (pRepT == 0) return(NULL); /* Not that many repeats */ if (pRepT->RepNum != RepNum) return(NULL); if ((pCompT = pRepT->pComp) == NULL) return(NULL); /* traverse component list */ do { if (pCompT->CompIndex == CompNum) break; } while(pCompT = pCompT->pCompNext); if (pCompT->CompIndex != CompNum) return(NULL); /* build component from all existing subcomponents */ /* write output in io buffer */ if ((pSubT = pCompT->pSCompLst) == NULL) return(NULL); if (pMsg->pGetBuffer != 0) *pMsg->pGetBuffer = '\0'; /* prepare buffer */ /* traverse subcomponent list */ i=0; do { i++; /* number of sub component */ if (pSubT->pzDataStr != NULL) { if (pSubT->SubCompIndex > i) { for (j=0; j<(pSubT->SubCompIndex - i);j++) if (AppendToBuffer(pMsg, azSubDel) != HL7_OK) return(NULL); i = pSubT->SubCompIndex; } if (i != 1) if (AppendToBuffer(pMsg, azSubDel) != HL7_OK) return(NULL); if (AppendToBuffer(pMsg, pSubT->pzDataStr) != HL7_OK) return(NULL); } } while(pSubT=pSubT->pSubNext); return(pMsg->pGetBuffer); } char * HL7GetRep(HL7MSG *pMsg, int FieldNum, int RepNum) { /* pick put a repeated field */ HL7SEG *pSegT; HL7REP *pRepT; HL7COMP *pCompT; HL7SUBCOMP *pSubT; int i,j,k; char azCmpDel[2]; char azSubDel[2]; char azFldDel[2]; /* chech handle */ if (pMsg == NULL) return(NULL); azCmpDel[0] = pMsg->CmpSep; azCmpDel[1] = '\0'; azSubDel[0] = pMsg->SubSep; azSubDel[1] = '\0'; /* check current segment */ if ((pSegT = pMsg->pCurrSeg) == NULL) return(NULL); /* arguments validation */ if ((FieldNum < 1) || (RepNum < 1)) return(NULL); if (pSegT->pSegRul == HL7pMSH) if (FieldNum > 1) --FieldNum; else { if (pMsg->pGetBuffer != 0) *pMsg->pGetBuffer = '\0'; azFldDel[0] = pMsg->FldSep; azFldDel[1] = '\0'; if (AppendToBuffer(pMsg, azFldDel) != HL7_OK) return(NULL); return(pMsg->pGetBuffer); } if ((pRepT = pSegT->pFldLst[FieldNum-1]) == NULL) return(NULL); /* traverse repetition list */ for(i=1;(pRepT->pRepNext != NULL) && (i < RepNum); pRepT=pRepT->pRepNext, i++); if (i != RepNum) return(NULL); if ((pCompT = pRepT->pComp) == NULL) return(NULL); if (pMsg->pGetBuffer != 0) *pMsg->pGetBuffer = '\0'; /* prepare buffer */ /* traverse component list */ k=0; /* component counter */ do { k++; if ((pSubT = pCompT->pSCompLst) != NULL) { if (pCompT->CompIndex > k) { for (j=0; j<(pCompT->CompIndex - k);j++) if (AppendToBuffer(pMsg, azCmpDel) != HL7_OK) return(NULL); k = pCompT->CompIndex; } if (k!=1) if (AppendToBuffer(pMsg, azCmpDel) != HL7_OK) return(NULL); i=0; /* subcomp counter */ do { i++; /* number of sub component */ if (pSubT->pzDataStr != NULL) { if (pSubT->SubCompIndex > i) { for (j=0; j<(pSubT->SubCompIndex - i);j++) if (AppendToBuffer(pMsg, azSubDel) != HL7_OK) return(NULL); i = pSubT->SubCompIndex; } if (i != 1) if (AppendToBuffer(pMsg, azSubDel) != HL7_OK) return(NULL); if (AppendToBuffer(pMsg, pSubT->pzDataStr) != HL7_OK) return(NULL); } } while(pSubT=pSubT->pSubNext); } } while(pCompT=pCompT->pCompNext); return(pMsg->pGetBuffer); } char * HL7GetFld(HL7MSG *pMsg, int FieldNum) { /* get a nonrepeated field */ HL7SEG *pSegT; HL7REP *pRepT; HL7COMP *pCompT; HL7SUBCOMP *pSubT; int i,j,k,l; char azRepDel[2]; char azCmpDel[2]; char azSubDel[2]; char azFldDel[2]; /* chech handle */ if (pMsg == NULL) return(NULL); azRepDel[0] = pMsg->RepSep; azRepDel[1] = '\0'; azCmpDel[0] = pMsg->CmpSep; azCmpDel[1] = '\0'; azSubDel[0] = pMsg->SubSep; azSubDel[1] = '\0'; /* check current segment */ if ((pSegT = pMsg->pCurrSeg) == NULL) return(NULL); /* arguments validation */ if (FieldNum < 1) return(NULL); if (pSegT->pSegRul == HL7pMSH) if (FieldNum == 1) { if (pMsg->pGetBuffer != 0) *pMsg->pGetBuffer = '\0'; azFldDel[0] = pMsg->FldSep; azFldDel[1] = '\0'; if (AppendToBuffer(pMsg, azFldDel) != HL7_OK) return(NULL); return(pMsg->pGetBuffer); } if ((pRepT = pSegT->pFldLst[FieldNum-1]) == NULL) return(NULL); /* traverse repetition list */ l=0; /* repetition counter */ if (pMsg->pGetBuffer != 0) *pMsg->pGetBuffer = '\0'; do { l++; if ((pCompT = pRepT->pComp) != NULL) { if (pRepT->RepNum >l) { for (j=0; j<(pRepT->RepNum - l);j++) if (AppendToBuffer(pMsg, azRepDel) != HL7_OK) return(NULL); l = pRepT->RepNum; } if (l!=1) if (AppendToBuffer(pMsg, azRepDel) != HL7_OK) return(NULL); /* traverse component list */ k=0; /* component counter */ do { k++; if ((pSubT = pCompT->pSCompLst) != NULL) { if (pCompT->CompIndex > k) { for (j=0; j<(pCompT->CompIndex - k);j++) if (AppendToBuffer(pMsg, azCmpDel) != HL7_OK) return(NULL); k = pCompT->CompIndex; } if (k!=1) if (AppendToBuffer(pMsg, azCmpDel) != HL7_OK) return(NULL); i=0; /* subcomp counter */ do { i++; /* number of sub component */ if (pSubT->pzDataStr != NULL) { if (pSubT->SubCompIndex > i) { for (j=0; j<(pSubT->SubCompIndex - i);j++) if (AppendToBuffer(pMsg, azSubDel) != HL7_OK) return(NULL); i = pSubT->SubCompIndex; } if (i != 1) if (AppendToBuffer(pMsg, azSubDel) != HL7_OK) return(NULL); if (AppendToBuffer(pMsg, pSubT->pzDataStr) != HL7_OK) return(NULL); } } while(pSubT=pSubT->pSubNext); } } while(pCompT=pCompT->pCompNext); } } while(pRepT=pRepT->pRepNext); return(pMsg->pGetBuffer); } static int AppendToBuffer(HL7MSG *pMsg, char *pSource) { SIZE Len, ExpLen; Len = strlen(pSource); /* + pMsg->pGetBuffer; expected string length */ if (pMsg->pGetBuffer == 0) { /* init allocation */ if ((pMsg->pGetBuffer = malloc(Len +1)) == 0) return(HL7_NO_MEMORY); *pMsg->pGetBuffer = '\0'; pMsg->GetBufferSize = Len +1; } else { ExpLen = strlen(pMsg->pGetBuffer)+Len+1; /* expected size of buffer */ if (ExpLen > pMsg->GetBufferSize) { /* needs extentension */ if ((pMsg->pGetBuffer = realloc(pMsg->pGetBuffer,ExpLen)) == NULL) return(HL7_NO_MEMORY); pMsg->GetBufferSize = ExpLen; } } strcat(pMsg->pGetBuffer, pSource); return(HL7_OK); } int HL7ReadMsg(HL7MSG *pMsg, char *pzWire) { int i; DB printf("\n Read message"); if (pMsg == NULL) return(HL7_EMPTY_STRUCT); /* HL7MSG was not allocated*/ pMsg->fDirection = HL7_WIRE_TO_STRUCT; /* global flag */ pMsg->pWire = pzWire; pMsg->pWireCursor = pzWire; if ((i = HL7Parse (pMsg)) != HL7_OK) return (i); /* do the parse */ DB printf("\n Parsing finish"); pMsg->pCurrSeg = pMsg->pSegList; return (HL7_OK); } int skipTo(char clsParen, MSGterm **pCurTerm) { int s; MSGterm *pLclTerm = *pCurTerm; /* resolve/deref */ while ( (pLclTerm = pLclTerm->nxt)) { /* assumes no <> or {} */ if (pLclTerm->typ == clsParen) { *pCurTerm = pLclTerm; return HL7_OK; } switch ( clsParen) { case ']' : if ( pLclTerm->typ == '[') { s = skipTo( clsParen, &pLclTerm); *pCurTerm = pLclTerm->nxt; /* when recursive skip over */ return s; } break; case '>' : if ( pLclTerm->typ == '<') { s =skipTo( clsParen, &pLclTerm); *pCurTerm = pLclTerm->nxt; /* when recursive skip over */ return s; } break; case '}' : if ( pLclTerm->typ == '{') { s = skipTo( clsParen, &pLclTerm); *pCurTerm = pLclTerm->nxt; /* when recursive skip over */ return s; } break; case ')' : if ( pLclTerm->typ == '(') return skipTo( clsParen, &pLclTerm); break; } } return HL7_END_OF_STRUCT; } int doSquareB( HL7MSG *pMsg, MSGterm **pCurTerm) { /* [ 0 or 1 ] */ /* This function parses thru a pair of [] we will be matching zero or one returns number of matches or an error, errors are > 255 pCurTerm is left pointing at ] pMsg->pCurrSeg may change By Allen Rueter */ int s, m, mtchd = 0; MSGterm *pLclTerm = *pCurTerm; /* resolve/deref */ pLclTerm = pLclTerm->nxt; /* move past [ */ DB printf("\n In doSquareB"); while (1) { if (pLclTerm->typ == 0) { if (mtchd == 0) { if ((s=HL7IsNextSeg( pMsg, pLclTerm->pSegR))==HL7_OK) { EAT(pLclTerm->pSegR,s); mtchd=1; } else { skipTo( ']', &pLclTerm); *pCurTerm = pLclTerm; /* step over & return */ return 0; } } else EAT(pLclTerm->pSegR,s); /* 1st matched, rest must match */ } else { switch ( pLclTerm->typ) { case '[' : m=doSquareB( pMsg, &pLclTerm); break; case '{' : m=doCurlyB( pMsg, &pLclTerm, 1); break; case '<' : m=doAngleB( pMsg, &pLclTerm, 1); break; case '(' : m=doParen( pMsg, &pLclTerm); break; case ']' : *pCurTerm = pLclTerm; /* return number of matches */ return mtchd; default : return HL7_PARSE_NESTING; } if (m>255) return m; if (m>0) mtchd = 1; } pLclTerm= pLclTerm->nxt; } } int doParen( HL7MSG *pMsg, MSGterm **pCurTerm) { /* ( one of ) */ /* This function parses thru a pair of () we will be matching one of them returns number of matches or an error, errors are > 255 pCurTerm is left pointing at ) pMsg->pCurrSeg may change By Allen Rueter */ int s, m, mtchd = 0; MSGterm *pLclTerm = *pCurTerm; /* resolve/deref */ pLclTerm = pLclTerm->nxt; /* move past ( */ DB printf("\n In doParen"); while (1) { if (pLclTerm->typ == 0) { if (mtchd == 0) { if ((s=HL7IsNextSeg( pMsg, pLclTerm->pSegR))==HL7_OK) { EAT(pLclTerm->pSegR,s); mtchd=1; } } else ; /* matched 1, skip rest */ } else { switch ( pLclTerm->typ) { case '[' : m=doSquareB( pMsg, &pLclTerm); break; case '{' : m=doCurlyB( pMsg, &pLclTerm, 1); break; case '<' : m=doAngleB( pMsg, &pLclTerm, 1); break; case '(' : m=doParen( pMsg, &pLclTerm); break; case ')' : *pCurTerm = pLclTerm; /* return number of matches */ return mtchd; default : return HL7_PARSE_NESTING; } if (m>255) return m; /* error */ if (m>0) mtchd = 1; } pLclTerm=pLclTerm->nxt; } } /* { 1 or more } */ int doCurlyB( HL7MSG *pMsg, MSGterm **pCurTerm, int iter) { /* This function parses thru a pair of {} we will be matching one or more returns number of matches or an error, errors are > 255 pCurTerm is left pointing at } pMsg->pCurrSeg may change By Allen Rueter */ int s, m, mtchd = 0; MSGterm *pLclTerm = *pCurTerm; /* resolve/deref */ MSGterm *pMarkCT = *pCurTerm; /* recursive loop back */ pLclTerm = pLclTerm->nxt; /* move past [ */ DB printf("\n In doCurlyB"); while (1) { if (pLclTerm->typ == 0) { if (mtchd == 0) { if (iter == 1) { EAT(pLclTerm->pSegR,s); mtchd=1; } else if ((s=HL7IsNextSeg( pMsg, pLclTerm->pSegR))==HL7_OK) { EAT(pLclTerm->pSegR,s); /* mtch 1, match rest */ mtchd=1; } else if (s == HL7_SEG_MISMATCH) { skipTo( '}', &pLclTerm); *pCurTerm = pLclTerm; return 0; /* nth interation, nomatch, rtn ok */ } } else EAT(pLclTerm->pSegR,s); /* 1st matched, rest must match */ } else { switch ( pLclTerm->typ) { case '[' : m=doSquareB( pMsg, &pLclTerm); break; case '{' : m=doCurlyB( pMsg, &pLclTerm, 1); break; case '<' : m=doAngleB( pMsg, &pLclTerm, 1); break; case '(' : m=doParen( pMsg, &pLclTerm); break; case '}' : if (mtchd) if ( (m=doCurlyB( pMsg, &pMarkCT, iter+1))>255) return m; *pCurTerm = pLclTerm; /* move up & return */ return mtchd; break; default : return HL7_PARSE_NESTING; break; } if (m>255) { if (iter>1 && mtchd==0) m = 0; else return m; /* error */ } if (m>0) mtchd = 1; } pLclTerm=pLclTerm->nxt; } } /* < 0 or more > */ int doAngleB( HL7MSG *pMsg, MSGterm **pCurTerm, int iter) { /* This function parses thru a pair of <> we will be matching zero or more returns number of matches or an error, errors are > 255 pCurTerm is left pointing at > pMsg->pCurrSeg may change By Allen Rueter */ int s, m, mtchd = 0; MSGterm *pLclTerm = *pCurTerm; /* resolve/deref */ MSGterm *pMarkCT = *pCurTerm; /* recursive loop back */ pLclTerm = pLclTerm->nxt; /* move past < */ DB printf("\n In doAngleB"); while (1) { if (pLclTerm->typ == 0) { if (mtchd == 0) { if ((s=HL7IsNextSeg( pMsg, pLclTerm->pSegR))==HL7_OK) { EAT(pLclTerm->pSegR,s); /* mtch 1, match rest */ mtchd=1; } else if ( s==HL7_SEG_MISMATCH) { /* HL7_END_OF_STRUCT? */ skipTo('>',&pLclTerm); *pCurTerm = pLclTerm; return 0; /* nomatchs, return */ } } else EAT(pLclTerm->pSegR,s); /* 1st matched, rest must match */ } else { switch ( pLclTerm->typ) { case '[' : m=doSquareB( pMsg, &pLclTerm); break; case '{' : m=doCurlyB( pMsg, &pLclTerm, 1); break; case '<' : m=doAngleB( pMsg, &pLclTerm, 1); break; case '(' : m=doParen( pMsg, &pLclTerm); break; case '>' : if (mtchd) if ( (s=doAngleB( pMsg, &pMarkCT, iter+1))>255) return s; *pCurTerm = pLclTerm; /* move up & return */ return mtchd; default : return HL7_PARSE_NESTING; break; } if (m>255) return m; /* error */ if (m>1) mtchd = 1; } pLclTerm=pLclTerm->nxt; } } static int HL7Parse (HL7MSG *pMsg) { int i, m ; int s; /* status for EAT */ MSGterm *pCurTerm; DB printf("\n HL7Parse start"); EAT (HL7pMSH, s); /* MSH is always present in HL7. */ /* Message Type decides parse rules, */ /* & pMsg should point correctly */ /* init error message var */ pMsg->pRule = p1Rule; /* find Rule */ while (strcmp( pMsg->pRule->evnt, pMsg->cMsgType) !=0) { pMsg->pRule = pMsg->pRule->nxt; if (pMsg->pRule==0) { fprintf(stderr,"Rule not found for %.7s\n",pMsg->cMsgType); return (HL7_BAD_MSG_TYPE); } } foundRule: /* Found Rule, start validating */ pCurTerm = pMsg->pRule->p1term; pCurTerm = pCurTerm->nxt; /* skip over MSH term */ while ( pCurTerm) { if (pCurTerm->typ==0) { /* Seg def? */ EAT(pCurTerm->pSegR,s); } else { /* new parse rule */ switch ( pCurTerm->typ) { case '[' : m=doSquareB( pMsg, &pCurTerm); break; case '{' : m=doCurlyB( pMsg, &pCurTerm, 1); if (m==0) return HL7_SEG_MISSING; break; case '<' : m=doAngleB( pMsg, &pCurTerm, 1); break; case '(' : m=doParen( pMsg, &pCurTerm); if (m!=1) return HL7_SEG_MISSING; break; default : fprintf( stderr, "\n Hmm Parse error\n"); return HL7_PARSE_NESTING; } s= (m>=1&&m<=255) ? 0 : m; } if (s==HL7_END_OF_STRUCT) if (pCurTerm==0) return HL7_OK; if (s!=HL7_OK) return s; pCurTerm = pCurTerm->nxt; } return HL7_OK; } static void MsgType2Ecode (HL7MSG *pmsg) { int i; i = strlen(pmsg->cMsgType); switch(i) { case HL7_MSGTYPE_LEFT: /* case XXX */ case HL7_MSGTYPE_LEFT+1: /* case XXX^ */ strncpy( pmsg->cMsgEcode, pmsg->cMsgType, HL7_MSGTYPE_RIGHT); break; case HL7_MSGTYPE_LEN: /* case XXX^YNN */ strncpy( pmsg->cMsgEcode, &pmsg->cMsgType[HL7_MSGTYPE_LEN-HL7_MSGTYPE_RIGHT], HL7_MSGTYPE_RIGHT); break; default: /* uknown type */ fprintf( stderr, "Bad MsgType %s with length %d\n", pmsg->cMsgType, i); exit(0); } } static int MarshallSeg (HL7MSG *pMsg, HL7SegRule *pSegR) { int iResult; HL7SEG *pSegT; HL7REP *pRepT; HL7COMP *pCompT; HL7SUBCOMP *pSubT; int i,j,k,l,f; int FieldAmt; char azSegDel[2]; azSegDel[0] = HL7_SEG_SEP; azSegDel[1] = '\0'; pSegT = pMsg->pCurrSeg; /* printf("\n Marshall -%s", pSegR->azNam; fflush(stdout); */ if ((iResult = PoolToWire(pMsg, pSegR->azNam, HL7_SEG_NAME_LEN)) != HL7_OK) return (!HL7_OK); if ((iResult = PoolToWire(pMsg, &pMsg->FldSep, 1)) != HL7_OK) return (!HL7_OK); FieldAmt = pSegR->nmbrFlds; for ( f= (pSegR!=HL7pMSH) ? 0 : 1 ; fpFldLst[f]) != 0) { pMsg->iCurrFldI0b = f; /* traverse repetition list */ l=0; /* repetition counter */ do { l++; if ((pCompT = pRepT->pComp) != NULL) { if (pRepT->RepNum >l) { for (j=0; j<(pRepT->RepNum - l);j++) if (PoolToWire(pMsg,&pMsg->RepSep,1) != HL7_OK) return(!HL7_OK); l = pRepT->RepNum; } if (l!=1) if (PoolToWire(pMsg,&pMsg->RepSep,1) != HL7_OK) return(!HL7_OK); /* traverse component list */ k=0; /* component counter */ do { k++; if ((pSubT = pCompT->pSCompLst) != NULL) { if (pCompT->CompIndex > k) { for (j=0; j<(pCompT->CompIndex - k);j++) if (PoolToWire(pMsg, &pMsg->CmpSep,1) != HL7_OK) return(!HL7_OK); k = pCompT->CompIndex; } if (k!=1) if (PoolToWire(pMsg, &pMsg->CmpSep,1) != HL7_OK) return(!HL7_OK); i=0; /* subcomp counter */ do { i++; /* number of sub component */ if (pSubT->pzDataStr != NULL) { if (pSubT->SubCompIndex > i) { for (j=0; j<(pSubT->SubCompIndex - i);j++) if (PoolToWire(pMsg, &pMsg->SubSep,1) != HL7_OK) return(!HL7_OK); i = pSubT->SubCompIndex; } if (i != 1) if (PoolToWire(pMsg, &pMsg->SubSep,1) != HL7_OK) return(!HL7_OK); if (PoolToWire(pMsg, pSubT->pzDataStr, strlen(pSubT->pzDataStr)) != HL7_OK) return(!HL7_OK); } } while(pSubT = pSubT->pSubNext); } } while(pCompT = pCompT->pCompNext); } } while(pRepT = pRepT->pRepNext); } if (f < (FieldAmt - 1)) /* don't print field delimeter for */ /* last field in segment */ if ((iResult = PoolToWire(pMsg, &pMsg->FldSep, 1)) != HL7_OK) return (!HL7_OK); } if ((iResult = PoolToWire(pMsg, azSegDel, 1)) != HL7_OK) return (!HL7_OK); return(HL7_OK); } static int PoolToWire(HL7MSG *pMsg, char *pChar, SIZE Len) { if (pMsg->WireLen + Len > pMsg->MaxWireLen) return(!HL7_OK); strncpy(pMsg->pWireCursor, pChar, Len); pMsg->pWireCursor +=Len; *pMsg->pWireCursor = '\0'; pMsg->WireLen += Len; return(HL7_OK); } int HL7IsNextSeg (HL7MSG *pMsg, HL7SegRule *pSegR) { int iResult; HL7SEG *pSeg; switch (pMsg->fDirection) { case HL7_WIRE_TO_STRUCT: DB printf("\n Looking for %s, found %.3s", pSegR->azNam,pMsg->pWireCursor); iResult = strncmp (pMsg->pWireCursor, pSegR->azNam, HL7_SEG_NAME_LEN); break; case HL7_STRUCT_TO_WIRE: if (pMsg == 0) return (HL7_EMPTY_STRUCT); if ((pSeg = pMsg->pCurrSeg->pNextSeg) == 0) return (HL7_END_OF_STRUCT); iResult = ((pSeg->pSegRul == pSegR) ? HL7_OK : !HL7_OK); break; default: return (HL7_BAD_DIRECTION); break; } if (iResult == 0) return (HL7_OK); else return (HL7_SEG_MISMATCH); } int HL7FirstSeg(HL7MSG *pMsg, HL7SegRule **pSegR) { if (pMsg == 0) return (HL7_EMPTY_STRUCT); if (pMsg->pSegList == 0) return (HL7_EMPTY_STRUCT); pMsg->pCurrSeg = pMsg->pSegList; *pSegR = pMsg->pCurrSeg->pSegRul; return(HL7_OK); } int HL7LastSeg(HL7MSG *pMsg, HL7SegRule **pSegR) { if (pMsg == 0) return (HL7_EMPTY_STRUCT); if (pMsg->pSegList == 0) return (HL7_EMPTY_STRUCT); for (pMsg->pCurrSeg = pMsg->pSegList; pMsg->pCurrSeg->pNextSeg; pMsg->pCurrSeg=pMsg->pCurrSeg->pNextSeg); *pSegR = pMsg->pCurrSeg->pSegRul; return(HL7_OK); } int HL7NextSeg(HL7MSG *pMsg, HL7SegRule **pSegR) { if (pMsg == 0) return (HL7_EMPTY_STRUCT); if (pMsg->pSegList == 0) return (HL7_EMPTY_STRUCT); if (pMsg->pCurrSeg->pNextSeg == 0) return(HL7_END_OF_STRUCT); pMsg->pCurrSeg=pMsg->pCurrSeg->pNextSeg; *pSegR = pMsg->pCurrSeg->pSegRul; return(HL7_OK); } int HL7FindSeg(HL7MSG *pMsg, HL7SegRule *pSegR) { HL7SEG *pSegT; if (pMsg == 0) return (HL7_EMPTY_STRUCT); if (pMsg->pSegList == 0) return (HL7_EMPTY_STRUCT); if (pMsg->pCurrSeg == 0) pSegT = pMsg->pSegList; /* start from the beginning */ else pSegT = pMsg->pCurrSeg; if (pSegT->pSegRul == pSegR) pSegT = pSegT->pNextSeg; do { if (pSegT->pSegRul == pSegR) { pMsg->pCurrSeg = pSegT; return(HL7_OK); } } while(pSegT = pSegT->pNextSeg); return(HL7_END_OF_STRUCT); } int HL7Free(HL7MSG *pMsg) { HL7SEG *pSegT, *pSegN; HL7REP *pRepT, *pRepN; HL7COMP *pCompT, *pCompN; HL7SUBCOMP *pSubT, *pSubN; int i; if (pMsg == NULL) return(HL7_EMPTY_STRUCT); /* free buffers */ if (pMsg->pGetBuffer != 0) free (pMsg->pGetBuffer); if ((pSegT = pMsg->pSegList) != 0) /* segment list exist list */ do { for (i =0; i < HL7_MAX_FLD_IN_SEG; i++) /* for each field */ if ((pRepT = pSegT->pFldLst[i]) != 0) do { if ((pCompT = pRepT->pComp) != 0) do { if ((pSubT = pCompT->pSCompLst) != 0) do { if (pSubT->pzDataStr != 0) free(pSubT->pzDataStr); /* free data */ pSubN = pSubT->pSubNext; free(pSubT); } while(pSubT = pSubN); pCompN = pCompT->pCompNext; free(pCompT); } while(pCompT = pCompN); pRepN = pRepT->pRepNext; /* keep next repetition */ free(pRepT); /* free current repetition */ } while(pRepT = pRepN); /* till last repetition */ pSegN = pSegT->pNextSeg; /* keep next segment */ free(pSegT); /* free current segment */ } while (pSegT = pSegN); /* till last segment */ free(pMsg); return(HL7_OK); } int HL7PutFld(HL7MSG *pMsg, char *pString, int FieldNum) { HL7SEG *pSegT; HL7REP *pRepT, *pRepN; HL7COMP *pCompT, *pCompN; HL7SUBCOMP *pSubT, *pSubN; int i; if (pMsg == 0) return(HL7_EMPTY_STRUCT); if ((pSegT = pMsg->pCurrSeg) == 0) return(HL7_NO_CURRENT_SEG); if ((FieldNum < 1) || (FieldNum > pSegT->pSegRul->nmbrFlds)) return(HL7_BAD_FLDNUM); /* special MSH treatment */ if (pMsg->pCurrSeg->pSegRul == HL7pMSH) { if (FieldNum == 1) { /* this is just Field Separator - don't keep as a data */ pMsg->FldSep = *pString; return(HL7_OK); } else if (FieldNum == 2) { pMsg->iCurrFldI0b = FieldNum-1; if ((i = UnmarshallSep(pMsg, pString)) != HL7_OK) return (i); return(HL7_OK); } } if (pSegT->pFldLst[FieldNum-1] != 0) { /* field already exists */ pRepT = pSegT->pFldLst[FieldNum-1]; do { if ((pCompT = pRepT->pComp) != 0) do { if ((pSubT = pCompT->pSCompLst) != 0) do { if (pSubT->pzDataStr != 0) free(pSubT->pzDataStr); /* free data */ pSubN = pSubT->pSubNext; free(pSubT); } while(pSubT = pSubN); pCompN = pCompT->pCompNext; free(pCompT); } while(pCompT = pCompN); pRepN = pRepT->pRepNext; /* keep next repetition */ free(pRepT); /* free current repetition */ } while(pRepT = pRepN); } pSegT->pFldLst[FieldNum-1] = 0; if (strcmp(pString,HL7_NULL_FLD) && (strlen(pString) !=0)) { /* regular field */ pMsg->pWireCursor = pString; pMsg->iCurrFldI0b = FieldNum -1; if ((i = UnmarshallRep(pMsg, pString + strlen(pString))) != HL7_OK) return (i); } /* update message type */ if ((pMsg->pCurrSeg->pSegRul == HL7pMSH) && (pMsg->iCurrFldI0b == 9-1)) { strcpy(pMsg->cMsgType, HL7GetFld(pMsg, 9)); MsgType2Ecode( pMsg); } return(HL7_OK); } int HL7PutRep(HL7MSG *pMsg, char *pString, int FieldNum) { HL7SEG *pSegT; HL7REP *pRepT, *pRepN; int i; if (pMsg == 0) return(HL7_EMPTY_STRUCT); if ((pSegT = pMsg->pCurrSeg) == 0) return(HL7_NO_CURRENT_SEG); if ((FieldNum < 1) || (FieldNum > pSegT->pSegRul->nmbrFlds)) return(HL7_BAD_FLDNUM); if (pString == 0) return (HL7_OK); if (strlen(pString) == 0) return (HL7_OK); if (pMsg->pCurrSeg->pSegRul == HL7pMSH) if (FieldNum == 1) { /* this is just Field Separator - don't keep as a data */ pMsg->FldSep = *pString; return(HL7_OK); } pMsg->iCurrFldI0b = FieldNum-1; pMsg->pCurrCom=0; pMsg->pCurrSub=0; /* allocate new repetition*/ if ((pRepN = (HL7REP *) malloc(sizeof(HL7REP))) == 0) return (HL7_NO_MEMORY); if ((pRepT = pSegT->pFldLst[FieldNum-1]) != 0) { /* field already exists */ /* traverse to last repetition */ for (;pRepT->pRepNext;pRepT=pRepT->pRepNext); pRepN->RepNum = pRepT->RepNum + 1; pRepT->pRepNext = pRepN; /* append to list */ } else { (pMsg->pCurrSeg)->pFldLst[pMsg->iCurrFldI0b] = pRepN; pRepN->RepNum = 1; } pMsg->pCurrRep = pRepN; pRepN->pRepNext = 0; pMsg->pWireCursor=pString; if ((i = UnmarshallComp(pMsg, pString +strlen(pString))) != HL7_OK) return (i); return(HL7_OK); } int HL7PutComp(HL7MSG *pMsg, char *pString, int FieldNum) { HL7SEG *pSegT; HL7REP *pRepT; HL7COMP *pCompT, *pCompN; int i; if (pMsg == 0) return(HL7_EMPTY_STRUCT); if ((pSegT = pMsg->pCurrSeg) == 0) return(HL7_NO_CURRENT_SEG); if ((FieldNum < 1) || (FieldNum > pSegT->pSegRul->nmbrFlds)) return(HL7_BAD_FLDNUM); if (pString == 0) return (HL7_OK); if (strlen(pString) == 0) return (HL7_OK); if (pMsg->pCurrSeg->pSegRul == HL7pMSH) if (FieldNum == 1) { /* this is just Field Separator - don't keep as a data */ pMsg->FldSep = *pString; return(HL7_OK); } pMsg->iCurrFldI0b = FieldNum-1; pMsg->pCurrSub=0; /* allocate new repetition*/ if ((pRepT = pSegT->pFldLst[FieldNum-1]) != 0) { /* field already exists */ /* traverse to last repetition */ for (;pRepT->pRepNext;pRepT=pRepT->pRepNext); } else { if ((pRepT = (HL7REP *) malloc(sizeof(HL7REP))) == 0) return (HL7_NO_MEMORY); (pMsg->pCurrSeg)->pFldLst[pMsg->iCurrFldI0b] = pRepT; pRepT->RepNum = 1; pRepT->pRepNext = 0; } pMsg->pCurrRep = pRepT; if ((pCompN = (HL7COMP *) malloc(sizeof(HL7COMP))) == 0) return (HL7_NO_MEMORY); if ((pCompT = pRepT->pComp) == 0) { pMsg->pCurrRep->pComp = pCompN; pMsg->pCurrRep->CompNum = 1; pCompN->CompIndex = 1; } else { /* traverse component list */ for(;pCompT->pCompNext;pCompT=pCompT->pCompNext); pCompT->pCompNext = pCompN; pCompN->CompIndex = pCompT->CompIndex +1; pMsg->pCurrRep->CompNum =pCompN->CompIndex; } pMsg->pCurrCom = pCompN; pCompN->pCompNext = 0; pCompN->pSCompLst = 0; pMsg->pWireCursor=pString; if ((i = UnmarshallSub(pMsg, pString +strlen(pString))) != HL7_OK) return (i); /* update message type */ if ((pMsg->pCurrSeg->pSegRul == HL7pMSH) && (pMsg->iCurrFldI0b == 9-1)) { strcpy( pMsg->cMsgType, HL7GetFld( pMsg, 9)); MsgType2Ecode( pMsg ); } return(HL7_OK); } int HL7PutSub(HL7MSG *pMsg, char *pString, int FieldNum) { HL7SEG *pSegT; HL7REP *pRepT; HL7COMP *pCompT; HL7SUBCOMP *pSubT, *pSubN; if (pMsg == 0) return(HL7_EMPTY_STRUCT); if ((pSegT = pMsg->pCurrSeg) == 0) return(HL7_NO_CURRENT_SEG); if ((FieldNum < 1) || (FieldNum > pSegT->pSegRul->nmbrFlds)) return(HL7_BAD_FLDNUM); if (pString == 0) return (HL7_OK); if (strlen(pString) == 0) return (HL7_OK); if (pMsg->pCurrSeg->pSegRul == HL7pMSH) if (FieldNum == 1) { /* this is just Field Separator - don't keep as a data */ pMsg->FldSep = *pString; return(HL7_OK); } pMsg->iCurrFldI0b = FieldNum-1; if ((pRepT = pSegT->pFldLst[FieldNum-1]) != 0) { /* field already exists */ /* traverse to last repetition */ for (;pRepT->pRepNext;pRepT=pRepT->pRepNext); } else { if ((pRepT = (HL7REP *) malloc(sizeof(HL7REP))) == 0) return (HL7_NO_MEMORY); (pMsg->pCurrSeg)->pFldLst[pMsg->iCurrFldI0b] = pRepT; pRepT->RepNum = 1; pRepT->pRepNext = 0; } pMsg->pCurrRep = pRepT; if ((pCompT = pRepT->pComp) == 0) { if ((pCompT = (HL7COMP *) malloc(sizeof(HL7COMP))) == 0) return (HL7_NO_MEMORY); pMsg->pCurrRep->pComp = pCompT; pMsg->pCurrRep->CompNum = 1; pCompT->CompIndex = 1; pCompT->pCompNext = 0; pCompT->pSCompLst = 0; } else { /* traverse component list */ for(;pCompT->pCompNext;pCompT=pCompT->pCompNext); } pMsg->pCurrCom = pCompT; if ((pSubN = (HL7SUBCOMP *) malloc(sizeof(HL7SUBCOMP))) == 0) return (HL7_NO_MEMORY); if ((pSubT = pCompT->pSCompLst) == 0) { pMsg->pCurrCom->pSCompLst = pSubN; pCompT->pSCompLst=pSubT; pCompT->SubCompNum = 1; pSubN->SubCompIndex = 1; } else { /* traverse subcomponent list */ for (;pSubT->pSubNext;pSubT=pSubT->pSubNext); pSubT->pSubNext = pSubN; pSubN->SubCompIndex = pSubT->SubCompIndex +1; pCompT->SubCompNum = pSubN->SubCompIndex; } pMsg->pCurrSub = pSubN; pMsg->pCurrSub->pSubNext = 0; if ((pSubN->pzDataStr = (char *)malloc(strlen(pString)+1)) == NULL) return (HL7_NO_MEMORY); strncpy(pSubN->pzDataStr, pString, strlen(pString)); pSubN->SubLen = strlen(pString);; *(pSubN->pzDataStr + pSubN->SubLen) = '\0'; if (pMsg->pCurrSeg->pSegRul == HL7pMSH) { /* if (pMsg->iCurrFldIndex == 9-1) pMsg->cMsgEcode = MsgEvn2code(pMsg, pSubN->pzDataStr); */ if (pMsg->iCurrFldI0b == 0) { pMsg->CmpSep = *(pString); pMsg->RepSep = *(pString+1); pMsg->EscSep = *(pString+2); pMsg->SubSep = *(pString+3); } } return(HL7_OK); } char *ErrTxt(HL7MSG *pMsg, int iHL7ErrNo) { int low,high,mid; char *pMsgName; /* perform binary search in Error messages list */ low = 0; high = ERR_List_Len - 1; while (low <= high) { mid = (low + high)/2; if (iHL7ErrNo < ErrMsgList[mid].iErrIndex) high = mid -1; else if (iHL7ErrNo > ErrMsgList[mid].iErrIndex) low = mid +1; else goto found; /* found message in list */ } return(FatalError); found: switch (ErrMsgList[mid].uSevLevel) { case ERR_S: sprintf(pMsg->ErrorBuffer,ERR_PREFIX, ERR_S); break; case ERR_E: sprintf(pMsg->ErrorBuffer,ERR_PREFIX, ERR_E); break; case ERR_W: sprintf(pMsg->ErrorBuffer,ERR_PREFIX, ERR_W); break; default: sprintf(pMsg->ErrorBuffer,ERR_PREFIX, ERR_E); break; } /* */ pMsgName = (pMsg->cMsgEcode); pMsgName = (*pMsgName) ? (pMsgName) : ""; if (!(ErrMsgList[mid].uSevLevel & (MSG_ERR))) /* */ sprintf(pMsg->ErrorBuffer + strlen(pMsg->ErrorBuffer), ErrMsgList[mid].pcMsgText); else if (!(ErrMsgList[mid].uSevLevel & (MSG_ERR|SEG_ERR))) sprintf(pMsg->ErrorBuffer + strlen(pMsg->ErrorBuffer), ErrMsgList[mid].pcMsgText, pMsgName); else if (!(ErrMsgList[mid].uSevLevel & (MSG_ERR|SEG_ERR|FLD_ERR))) sprintf(pMsg->ErrorBuffer + strlen(pMsg->ErrorBuffer), ErrMsgList[mid].pcMsgText, pMsgName, pMsg->pCurrSeg->pSegRul); else if (!(ErrMsgList[mid].uSevLevel & (MSG_ERR |SEG_ERR|FLD_ERR| REP_ERR))) sprintf(pMsg->ErrorBuffer + strlen(pMsg->ErrorBuffer), ErrMsgList[mid].pcMsgText, pMsgName, pMsg->pCurrSeg->pSegRul, pMsg->iCurrFldI0b); else if (!(ErrMsgList[mid].uSevLevel & (MSG_ERR |SEG_ERR|FLD_ERR| REP_ERR|COM_ERR))) sprintf(pMsg->ErrorBuffer + strlen(pMsg->ErrorBuffer), ErrMsgList[mid].pcMsgText, pMsgName, pMsg->pCurrSeg->pSegRul, pMsg->iCurrFldI0b, pMsg->pCurrRep->RepNum); else if (!(ErrMsgList[mid].uSevLevel & (MSG_ERR |SEG_ERR|FLD_ERR| REP_ERR|COM_ERR|SUB_ERR))) sprintf(pMsg->ErrorBuffer + strlen(pMsg->ErrorBuffer), ErrMsgList[mid].pcMsgText, pMsgName, pMsg->pCurrSeg->pSegRul, pMsg->iCurrFldI0b, pMsg->pCurrRep->RepNum, pMsg->pCurrCom->CompIndex); else sprintf(pMsg->ErrorBuffer + strlen(pMsg->ErrorBuffer), ErrMsgList[mid].pcMsgText, pMsgName, pMsg->pCurrSeg->pSegRul, pMsg->iCurrFldI0b, pMsg->pCurrRep->RepNum, pMsg->pCurrCom->CompIndex, pMsg->pCurrSub->SubCompIndex); return(pMsg->ErrorBuffer); }