Annotation of os232sdk/toolkt20/c/samples/nead/neadea.c, revision 1.1

1.1     ! root        1: /*************************************************************
        !             2: 
        !             3:  This module contains subroutines for nead.c that specifically
        !             4:  deal with the manipulation of EAs.
        !             5: 
        !             6:  Procedures in this file:
        !             7:    AddEA()             Handles the Add button press
        !             8:    QueryEAs()          Reads in all the EAs associated with a file
        !             9:    CheckEAIntegrity()  Checks an EA buffer to see if it is valid
        !            10:    Free_FEAList()      Deallocates memory associated with EA list
        !            11:    LookupEAType()      Gets an offset into table for an EA type
        !            12:    DeleteCurEA()       Deletes the highlighted EA
        !            13:    CurEAType()         Returns EA Type given a HoldFEA ptr
        !            14:    GetUSHORT()         Returns nth USHORT in ->aValue
        !            15:    WriteEAs()          Updates EAs state on the disk
        !            16:    EditEAValues()      Handles editing a given EA (also m-m EAs)
        !            17:    EAExists()          Determines if the given EA Name exists
        !            18:    ChangeName()        Handles the change of an EA's name
        !            19:    MultiTypeIndex()    Gets a specific field in a m-m structure
        !            20:    EAValueString()     Returns a representational string for an EA
        !            21:    MultiAdd()          Handles addition of a field for m-m
        !            22: 
        !            23: **************************************************************/
        !            24: 
        !            25: #include "nead.h"
        !            26: 
        !            27: /************ External GLOBALS *******************************/
        !            28: 
        !            29: extern CHAR szFileName[CCHMAXPATH];
        !            30: extern CHAR szEAName[MAXEANAME+1];
        !            31: extern USHORT usRetEAType;
        !            32: extern BOOL FILE_ISOPEN;
        !            33: extern BOOL FILE_CHANGED;
        !            34: extern BOOL COMMAND_LINE_FILE;
        !            35: extern CHAR *pAlloc,*szEditBuf,*szAscii,*szScratch;
        !            36: extern HOLDFEA *pHoldFEA;
        !            37: extern DELETELIST *pDelList;
        !            38: extern EADATA ConvTable[EATABLESIZE];
        !            39: 
        !            40: /*************************************************************/
        !            41: 
        !            42: 
        !            43: /*
        !            44:  * Function name: AddEA()
        !            45:  *
        !            46:  * Parameters:  hwnd which is the current window handle.
        !            47:  *
        !            48:  * Returns: TRUE iff the EA is successfully added.
        !            49:  *
        !            50:  * Purpose: This routine handles the addition of a new EA to the linked list.
        !            51:  *
        !            52:  * Usage/Warnings:  Routine does NOT do full memory error trapping and the
        !            53:  *                  insert message to the l-box is not error checked.
        !            54:  *
        !            55:  * Calls: EditEAValue()
        !            56:  */
        !            57: 
        !            58: BOOL AddEA(HWND hwnd)
        !            59: {
        !            60:    HOLDFEA  *pFEA=pHoldFEA;  /* Points to the beginning of the EA list */
        !            61:    HOLDFEA  *pNewFEA;        /* Used to temporarily hold the new EA    */
        !            62:    PASSDATA PData;
        !            63: 
        !            64:    if(!FILE_ISOPEN)
        !            65:       return(FALSE);
        !            66: 
        !            67:    if(!WinDlgBox(HWND_DESKTOP,         /* get new EA name and type */
        !            68:                  hwnd,
        !            69:                  AddEAProc,
        !            70:                  NULL,
        !            71:                  IDD_ADDEA,
        !            72:                  NULL))
        !            73:       return(FALSE);                   /* they said cancel */
        !            74: 
        !            75:    GetMem((PPVOID)&pNewFEA, sizeof(HOLDFEA));   /* Allocate space for new EA struct */
        !            76: 
        !            77:    pNewFEA->cbName = (CHAR) strlen(szEAName);  /* Fill in new structure */
        !            78:    pNewFEA->cbValue= 0;
        !            79:    pNewFEA->fEA    = 0; /* Need bit NOT set */
        !            80: 
        !            81:    GetMem((PPVOID)&pNewFEA->szName, pNewFEA->cbName+1);  /* Name returned in szEAName */
        !            82:    strcpy(pNewFEA->szName,strupr(szEAName));
        !            83:    pNewFEA->aValue = NULL;
        !            84:    pNewFEA->next   = NULL;
        !            85: 
        !            86:    if(pHoldFEA == NULL)           /* It's the first EA for the file */
        !            87:    {
        !            88:       pHoldFEA = pNewFEA;
        !            89:    }
        !            90:    else                           /* Add EA to the end of the linked list */
        !            91:    {
        !            92:       while(pFEA->next)
        !            93:          pFEA = pFEA->next;
        !            94:       pFEA->next = pNewFEA;
        !            95:    }
        !            96:    PData.Point         = (CHAR *) pNewFEA;  /* Setup user data for call */
        !            97:    PData.cbMulti       = 0;                 /* to edit of the name and  */
        !            98:    PData.usMultiOffset = 0;                 /* EA Value                 */
        !            99: 
        !           100:    if(!EditEAValue(hwnd,&PData)) /* They canceled the edit */
        !           101:    {
        !           102:       if(pFEA)               /* It's not the only EA          */
        !           103:          pFEA->next = NULL;  /* Disconnect the partial new EA */
        !           104:       else
        !           105:          pHoldFEA = NULL;    /* The new EA was the first one  */
        !           106: 
        !           107:       FreeMem(pNewFEA->szName);
        !           108:       FreeMem(pNewFEA);
        !           109: 
        !           110:       return(FALSE);
        !           111:    }
        !           112: 
        !           113:    WinSendDlgItemMsg(hwnd, IDD_LBOX, LM_INSERTITEM, /* Insert name in L-Box */
        !           114:                      MPFROM2SHORT(LIT_END,0),
        !           115:                      MPFROMP(pNewFEA->szName));
        !           116: 
        !           117:    return(TRUE);
        !           118: }
        !           119: 
        !           120: 
        !           121: /*
        !           122:  * Function name: QueryEAs()
        !           123:  *
        !           124:  * Parameters:  hwnd which is the current window handle.
        !           125:  *              pszPath points to the path of the file to grab EAs from.
        !           126:  *
        !           127:  * Returns: TRUE iff it successfully reads in the EAs.  Upon exit, global
        !           128:  *          pHoldFEA points to a linked list of the EAs for the current file.
        !           129:  *
        !           130:  * Purpose: Call DOS to Query a file's EA names and values.
        !           131:  *
        !           132:  * Usage/Warnings:  Routine does NOT do full memory error trapping.
        !           133:  *                  NOTE:  This routine does NOT prevent other processes
        !           134:  *                  from accessing the file's EAs while it is reading them
        !           135:  *                  in, or while the program is editing them.
        !           136:  *
        !           137:  * Calls: Free_FEAList(), CheckEAIntegrity()
        !           138:  */
        !           139: 
        !           140: BOOL QueryEAs(CHAR *pszPath)
        !           141: {
        !           142:    CHAR *pAlloc;       /* Holds the FEA struct returned by DosEnumAttribute */
        !           143:                        /* also used to create the GEALIST for DosQPathInfo  */
        !           144:    CHAR *pBigAlloc;    /* Temp buffer to hold each EA as it is read in      */
        !           145:    USHORT cbBigAlloc;  /* Size of buffer                                    */
        !           146: 
        !           147:    ULONG ulEntryNum = 1; /* count of current EA to read (1-relative)        */
        !           148:    ULONG ulEnumCnt;      /* Number of EAs for Enum to return, always 1      */
        !           149: 
        !           150:    HOLDFEA *pLastIn;     /* Points to last EA added, so new EA can link     */
        !           151:    HOLDFEA *pNewFEA;     /* Struct to build the new EA in                   */
        !           152: 
        !           153:    FEA *pFEA;            /* Used to read from Enum's return buffer          */
        !           154:    GEALIST *pGEAList;    /* Ptr used to set up buffer for DosQPathInfo call */
        !           155:    EAOP eaopGet;         /* Used to call DosQPathInfo                       */
        !           156: 
        !           157:    GetMem((PPVOID)&pAlloc, MAX_GEA);     /* Allocate enough room for any GEA List     */
        !           158:    pFEA = (FEA *) pAlloc;      /* pFEA always uses pAlloc buffer            */
        !           159: 
        !           160:    pHoldFEA = NULL;            /* Reset the pointer for the EA linked list  */
        !           161: 
        !           162:    while(TRUE) /* Loop continues until there are no more EAs */
        !           163:    {
        !           164:       ulEnumCnt = 1;                 /* Only want to get one EA at a time */
        !           165:       if(DosEnumAttribute(Ref_ASCIIZ,          /* Read into pAlloc Buffer */
        !           166:                           pszPath,             /* Note that this does not */
        !           167:                           ulEntryNum,          /* get the aValue field,   */
        !           168:                           pAlloc,              /* so DosQPathInfo must be */
        !           169:                           MAX_GEA,             /* called to get it.       */
        !           170:                           &ulEnumCnt,
        !           171:                           (LONG) GetInfoLevel1))
        !           172:         break;                         /* There was some sort of error    */
        !           173: 
        !           174:       if(ulEnumCnt != 1)               /* All the EAs have been read      */
        !           175:          break;
        !           176: 
        !           177:       ulEntryNum++;
        !           178: 
        !           179:       GetMem((PPVOID)&pNewFEA, sizeof(HOLDFEA));
        !           180: 
        !           181:       if (pNewFEA == NULL)             /* Out of memory */
        !           182:       {
        !           183:          FreeMem(pAlloc);
        !           184:          Free_FEAList(pHoldFEA,pDelList);
        !           185:          return (FALSE);
        !           186:       }
        !           187: 
        !           188:       pNewFEA->cbName = pFEA->cbName;  /* Fill in the HoldFEA structure   */
        !           189:       pNewFEA->cbValue= pFEA->cbValue;
        !           190:       pNewFEA->fEA    = pFEA->fEA;
        !           191:       pNewFEA->next = NULL;
        !           192: 
        !           193:       GetMem((PPVOID)&pNewFEA->szName, pFEA->cbName +1); /* Allocate for 2 arrays   */
        !           194:       GetMem((PPVOID)&pNewFEA->aValue, pFEA->cbValue);
        !           195: 
        !           196:       if (!pNewFEA->szName || !pNewFEA->aValue) /* Out of memory */
        !           197:       {
        !           198:          if(pNewFEA->szName)
        !           199:             FreeMem(pNewFEA->szName);
        !           200:          if(pNewFEA->aValue)
        !           201:             FreeMem(pNewFEA->aValue);
        !           202: 
        !           203:          FreeMem(pAlloc);
        !           204:          FreeMem(pNewFEA);
        !           205: 
        !           206:          Free_FEAList(pHoldFEA,pDelList);
        !           207:          return (FALSE);
        !           208:       }
        !           209:       strcpy(pNewFEA->szName,pAlloc+sizeof(FEA));      /* Copy in EA Name */
        !           210: 
        !           211:       cbBigAlloc = sizeof(FEALIST) + pNewFEA->cbName+1 + pNewFEA->cbValue;
        !           212:       GetMem((PPVOID)&pBigAlloc, cbBigAlloc);
        !           213:       if (pBigAlloc == NULL)
        !           214:       {
        !           215:          FreeMem(pNewFEA->szName);
        !           216:          FreeMem(pNewFEA->aValue);
        !           217:          FreeMem(pAlloc);
        !           218:          FreeMem(pNewFEA);
        !           219:          Free_FEAList(pHoldFEA,pDelList);
        !           220:          return (FALSE);
        !           221:       }
        !           222: 
        !           223:       pGEAList = (GEALIST *) pAlloc;   /* Set up GEAList structure */
        !           224: 
        !           225:       pGEAList->cbList = sizeof(GEALIST) + pNewFEA->cbName; /* +1 for NULL */
        !           226:       pGEAList->list[0].cbName = pNewFEA->cbName;
        !           227:       strcpy(pGEAList->list[0].szName,pNewFEA->szName);
        !           228: 
        !           229:       eaopGet.fpGEAList = (GEALIST FAR *) pAlloc;
        !           230:       eaopGet.fpFEAList = (FEALIST FAR *) pBigAlloc;
        !           231: 
        !           232:       eaopGet.fpFEAList->cbList = cbBigAlloc;
        !           233: 
        !           234:       DosQPathInfo(pszPath,            /* Get the complete EA info        */
        !           235:                    GetInfoLevel3,
        !           236:                    (PVOID) &eaopGet,
        !           237:                    sizeof(EAOP));
        !           238:       memcpy(pNewFEA->aValue,          /* Copy the value to HoldFEA       */
        !           239:              pBigAlloc+sizeof(FEALIST)+pNewFEA->cbName+1,
        !           240:              pNewFEA->cbValue);
        !           241: 
        !           242:       FreeMem(pBigAlloc);   /* Release the temp Enum buffer    */
        !           243: 
        !           244:       if(!CheckEAIntegrity(pNewFEA->aValue,pNewFEA->cbValue)) /* Bad EA   */
        !           245:       {
        !           246:          FreeMem(pNewFEA->szName);
        !           247:          FreeMem(pNewFEA->aValue);
        !           248:          FreeMem(pNewFEA);
        !           249:          continue;                    /* Don't add this EA to linked list */
        !           250:       }
        !           251: 
        !           252:       if(pHoldFEA == NULL)             /* If first EA, set pHoldFEA       */
        !           253:          pHoldFEA = pNewFEA;
        !           254:       else                             /* Otherwise, add to end of list   */
        !           255:          pLastIn->next = pNewFEA;
        !           256: 
        !           257:       pLastIn = pNewFEA;               /* Update the end of the list      */
        !           258:    }
        !           259:    FreeMem(pAlloc);  /* Free up the GEA buf for DosEnum */
        !           260:    return (TRUE);
        !           261: }
        !           262: 
        !           263: 
        !           264: /*
        !           265:  * Function name: CheckEAIntegrity()
        !           266:  *
        !           267:  * Parameters:  aBuf points to the buffer to check for a valid EA.
        !           268:  *              cbBuf is the allocated length of aBuf.
        !           269:  *
        !           270:  * Returns: TRUE iff the buffer is a valid EA structure.
        !           271:  *
        !           272:  * Purpose: This routine checks the integrity of the passed EA buffer by
        !           273:  *          seeing if there are any non-standard EA types, or bad data that
        !           274:  *          isn't sized correctly.
        !           275:  *
        !           276:  * Usage/Warnings:  Routine uses MultiTypeIndex() to check m-m type EAs
        !           277:  *                  since they are potentially recursive.  However, this
        !           278:  *                  may not be a good idea if the m-m EA is severly
        !           279:  *                  corrupted because it may cause MTI() to attempt a read
        !           280:  *                  from protected memory.  Routine does NOT modify the
        !           281:  *                  buffer under any circumstance.
        !           282:  *
        !           283:  * Calls: MultiTypeIndex()
        !           284:  */
        !           285: 
        !           286: BOOL CheckEAIntegrity(CHAR *aBuf,USHORT cbBuf)
        !           287: {
        !           288:    USHORT *pusPtr = (USHORT *) aBuf;
        !           289:    USHORT usOffset;
        !           290:    CHAR   *aEndPtr;
        !           291: 
        !           292:    usOffset = LookupEAType(*pusPtr);  /* Get the EA type */
        !           293: 
        !           294:    switch(ConvTable[usOffset].usFldType)
        !           295:    {
        !           296:       case IDD_LPDATA:
        !           297:          pusPtr++;
        !           298:          if(*pusPtr + 2*sizeof(USHORT) == cbBuf)
        !           299:             return TRUE;
        !           300:          else
        !           301:             return FALSE;
        !           302: 
        !           303:       case IDD_MULTILIST:
        !           304:          if(*pusPtr == EA_MVMT)
        !           305:          {
        !           306:             pusPtr += 2;
        !           307: 
        !           308:             /* This checks where the end of the m-m list ends to determine
        !           309:                the size of the EA.  This is probably not good if the EA is
        !           310:                badly corrupted and it points to protected memory */
        !           311: 
        !           312:             aEndPtr = MultiTypeIndex(aBuf,*pusPtr);
        !           313:             if(aEndPtr - aBuf == cbBuf)
        !           314:                return TRUE;
        !           315:             else
        !           316:                return FALSE;
        !           317:          }
        !           318:          else /* Single type, multi-value is not yet implemented */
        !           319:          {
        !           320:             return TRUE;
        !           321:          }
        !           322:       default:
        !           323:          return FALSE;
        !           324:    }
        !           325:    return TRUE;
        !           326: }
        !           327: 
        !           328: 
        !           329: /*
        !           330:  * Function name: Free_FEAList()
        !           331:  *
        !           332:  * Parameters:  pFEA points to the beginning of the linked list to be freed.
        !           333:  *              pDList points to the beginning of the deleted linked list.
        !           334:  *
        !           335:  * Returns: VOID.  The two linked lists passed in are cleaned out though.
        !           336:  *
        !           337:  * Purpose: This routine frees up the current list of EAs by deallocating
        !           338:  *          the space used by the szName and aValue fields, then deallocating
        !           339:  *          the HoldFEA struct.  Next, it deletes the EAName space, then the
        !           340:  *          DeleteList structure.
        !           341:  *
        !           342:  * Usage/Warnings:  Note that NEAD always passes in pHoldFEA and pDelList
        !           343:  *                  which is unnecessary since they are global pointers;
        !           344:  *                  however, this is done to make the routine more flexible
        !           345:  *                  by allowing multiple linked lists to exist.
        !           346:  *
        !           347:  * Calls:
        !           348:  */
        !           349: 
        !           350: VOID Free_FEAList(HOLDFEA *pFEA,DELETELIST *pDList)
        !           351: {
        !           352:    HOLDFEA *next;  /* Holds the next field since we free the structure */
        !           353:                    /* before reading the current next field            */
        !           354:    DELETELIST *Dnext; /* Same purpose as *next */
        !           355: 
        !           356:    while(pFEA)
        !           357:    {
        !           358:       next = pFEA->next;
        !           359:       if(pFEA->szName)                         /* Free if non-NULL name  */
        !           360:          FreeMem(pFEA->szName);
        !           361:       if(pFEA->aValue)                         /* Free if non-NULL value */
        !           362:          FreeMem(pFEA->aValue);
        !           363: 
        !           364:       FreeMem(pFEA);           /* Free HoldFEA struct    */
        !           365:       pFEA = next;
        !           366:    }
        !           367: 
        !           368:    while(pDList)
        !           369:    {
        !           370:       Dnext = pDList->next;
        !           371:       if(pDList->EAName)
        !           372:          FreeMem(pDList->EAName);
        !           373:       FreeMem(pDList);
        !           374:       pDList = Dnext;
        !           375:    }
        !           376: }
        !           377: 
        !           378: 
        !           379: /*
        !           380:  * Function name: LookupEAType()
        !           381:  *
        !           382:  * Parameters:  usType is tye EA type to be looked up.
        !           383:  *
        !           384:  * Returns: An offset into the ConvTable to the appropriate entry.  If no
        !           385:  *          match is found, the return value points to the last entry,
        !           386:  *          non-conventional format.
        !           387:  *
        !           388:  * Purpose: This routine takes EA type and returns an offset into ConvTable
        !           389:  *          which points to an entry that describes the type passed in.
        !           390:  *
        !           391:  * Usage/Warnings:
        !           392:  *
        !           393:  * Calls:
        !           394:  */
        !           395: 
        !           396: USHORT LookupEAType(USHORT usType)
        !           397: {
        !           398:    USHORT cnt;
        !           399: 
        !           400:    for(cnt=0;cnt<EATABLESIZE-1;cnt++)
        !           401:       if(ConvTable[cnt].usPrefix == usType)
        !           402:          return(cnt);
        !           403:    return(cnt);
        !           404: }
        !           405: 
        !           406: 
        !           407: /*
        !           408:  * Function name: DeleteCurEA()
        !           409:  *
        !           410:  * Parameters:  hwnd is the current window handle.
        !           411:  *
        !           412:  * Returns: VOID.  Removes one item from global pHoldFEA list and adds one
        !           413:  *          to global pDelList.
        !           414:  *
        !           415:  * Purpose: This routine removes in memory the currently highlighted EA from
        !           416:  *          the EA list.  It places the deleted EA in the global pDelList
        !           417:  *          linked list.
        !           418:  *
        !           419:  * Usage/Warnings:  The memory allocation routines are NOT fully error trapped.
        !           420:  *
        !           421:  * Calls: GetCurFEA()
        !           422:  */
        !           423: 
        !           424: VOID DeleteCurEA(HWND hwnd)
        !           425: {
        !           426:    HOLDFEA *pFEA,*pFEAPrev;
        !           427:    DELETELIST *pDL,*pDLcnt;  /* Utility ptrs for manipulating the Del list */
        !           428:    LONG lOffset;
        !           429: 
        !           430:    pFEA = GetCurFEA(hwnd,pHoldFEA);    /* Gets a pointer to item to delete */
        !           431:    if (pFEA == NULL)
        !           432:       return;
        !           433: 
        !           434:    /* These two allocations should be checked for out of memory */
        !           435:    GetMem((PPVOID)&pDL, sizeof(DELETELIST));     /* Add Name to Delete List */
        !           436:    GetMem((PPVOID)&pDL->EAName, pFEA->cbName+1);
        !           437:    strcpy(pDL->EAName,pFEA->szName);
        !           438:    pDL->next = NULL;
        !           439: 
        !           440:    if(pDelList == NULL)        /* The del list was previously empty  */
        !           441:       pDelList = pDL;
        !           442:    else                        /* tack name onto the end of the list */
        !           443:    {
        !           444:       pDLcnt = pDelList;
        !           445:       while(pDLcnt->next)
        !           446:          pDLcnt = pDLcnt->next;
        !           447:       pDLcnt->next = pDL;
        !           448:    }
        !           449: 
        !           450:    lOffset = (LONG) WinSendDlgItemMsg(hwnd, IDD_LBOX,
        !           451:                                      LM_QUERYSELECTION,0,0);
        !           452:    WinSendDlgItemMsg(hwnd, IDD_LBOX,
        !           453:                      LM_DELETEITEM,MPFROMSHORT((SHORT) lOffset),0L);
        !           454: 
        !           455:    if(lOffset<1)               /* Remove pFEA from the linked list */
        !           456:    {
        !           457:       pHoldFEA = pFEA->next;
        !           458:    }
        !           459:    else
        !           460:    {
        !           461:       pFEAPrev = pHoldFEA;
        !           462: 
        !           463:       while(--lOffset)              /* Find previous EA */
        !           464:          pFEAPrev = pFEAPrev->next;
        !           465: 
        !           466:       pFEAPrev->next = pFEA->next;
        !           467:    }
        !           468: 
        !           469:    FreeMem(pFEA->szName);  /* Release the memory */
        !           470:    FreeMem(pFEA->aValue);
        !           471:    FreeMem(pFEA);
        !           472: 
        !           473:    FILE_CHANGED = TRUE;
        !           474: }
        !           475: 
        !           476: 
        !           477: /*
        !           478:  * Function name: CurEAType()
        !           479:  *
        !           480:  * Parameters:  pFEA points to the FEA struct to use.
        !           481:  *
        !           482:  * Returns: The EA type.
        !           483:  *
        !           484:  * Purpose: Given an EA structure, this routine returns the Type of the EA
        !           485:  *          which resides in the first USHORT of the aValue member.
        !           486:  *          This function is the same as GetUSHORT(pFEA,0)
        !           487:  *
        !           488:  * Usage/Warnings:  Assumes a valid HoldFEA struct.
        !           489:  *
        !           490:  * Calls:
        !           491:  */
        !           492: 
        !           493: USHORT CurEAType(HOLDFEA *pFEA)   /* Same as GetUSHORT(,0); */
        !           494: {
        !           495:    USHORT *pusType;    /* EA Type is stored in first USHORT of aValue field */
        !           496: 
        !           497:    pusType = (USHORT *) pFEA->aValue;
        !           498:    return(*pusType);
        !           499: }
        !           500: 
        !           501: 
        !           502: /*
        !           503:  * Function name: GetUSHORT()
        !           504:  *
        !           505:  * Parameters:  pFEA points to the FEA struct to use.
        !           506:  *              index is an offset of the USHORT to be returned
        !           507:  *
        !           508:  * Returns: The appropriate USHORT from the aValue field
        !           509:  *
        !           510:  * Purpose: This routine returns the nth USHORT value in the aValue member
        !           511:  *          of pFEA using index as the offset.
        !           512:  *
        !           513:  * Usage/Warnings:  Assumes a valid HoldFEA struct and that index doesn't
        !           514:  *                  point outside the aValue buffer.
        !           515:  *
        !           516:  * Calls:
        !           517:  */
        !           518: 
        !           519: USHORT GetUSHORT(HOLDFEA *pFEA,USHORT index)
        !           520: {
        !           521:    USHORT *pusType;
        !           522: 
        !           523:    pusType = (USHORT *) pFEA->aValue;
        !           524:    while(index-- > 0)
        !           525:       pusType++;
        !           526:    return(*pusType);
        !           527: }
        !           528: 
        !           529: 
        !           530: /*
        !           531:  * Function name: WriteEAs()
        !           532:  *
        !           533:  * Parameters:  hwnd is the current window handle used only by memory
        !           534:  *              allocation error handling.
        !           535:  *
        !           536:  * Returns: VOID.  But cleans out the pDelList linked list.
        !           537:  *
        !           538:  * Purpose: This routine updates the EAs on disk to reflect their current
        !           539:  *          condition in memory.  First, all EAs in the delete list are
        !           540:  *          removed from the disk, then all EAs in the pHoldFEA list are
        !           541:  *          written out to disk.
        !           542:  *
        !           543:  * Usage/Warnings:  NOTE:  This routine is not bulletproof as it does not get
        !           544:  *                  exclusive access to the file EAs, nor does it handle out
        !           545:  *                  of disk space sort of errors. Also, memory fetches are
        !           546:  *                  not fully error trapped.
        !           547:  *
        !           548:  * Calls:
        !           549:  */
        !           550: 
        !           551: VOID WriteEAs()
        !           552: {
        !           553:    DELETELIST *pDL = pDelList,*pDLnext;
        !           554:    HOLDFEA    *pHFEA= pHoldFEA;
        !           555:    EAOP       eaopWrite;
        !           556:    CHAR       aBuf[MAX_GEA],*aPtr;
        !           557:    FEA        *pFEA = (FEA *) &aBuf[sizeof(ULONG)];
        !           558:    USHORT     usRet,usMemNeeded;
        !           559:    ULONG      *pulPtr=(ULONG *) aBuf; /* Initally points to top of FEALIST */
        !           560: 
        !           561:    if(!FILE_ISOPEN || !FILE_CHANGED) /* Don't write unless it's necessary */
        !           562:       return;
        !           563: 
        !           564:    eaopWrite.fpFEAList = (FEALIST FAR *) aBuf; /* Setup fields that won't */
        !           565:    pFEA->fEA     = 0;                          /* change for the delete   */
        !           566:    pFEA->cbValue = 0;                          /* calls to DosSetPathInfo */
        !           567: 
        !           568:    while(pDL)                       /* Clean out all the deleted EA names */
        !           569:    {
        !           570:       pFEA->cbName = (UCHAR) strlen(pDL->EAName);
        !           571:       *pulPtr      = sizeof(FEALIST) + pFEA->cbName+1; /* +1 for NULL */
        !           572:       strcpy(aBuf+sizeof(FEALIST),pDL->EAName);
        !           573: 
        !           574:       usRet=DosSetPathInfo(szFileName,    /* Delete EA's by saying cbValue=0 */
        !           575:                            SetInfoLevel2,
        !           576:                            (PVOID) &eaopWrite,
        !           577:                            (USHORT) sizeof(EAOP),
        !           578:                            DSPI_WRTTHRU);
        !           579: 
        !           580:       pDLnext = pDL->next;                   /* Temp hold next pDL         */
        !           581:       FreeMem(pDL->EAName);  /* Free up current Del struct */
        !           582:       FreeMem(pDL);
        !           583:       pDL = pDLnext;                         /* Set pDL to saved value     */
        !           584:    }
        !           585:    pDelList = NULL;                          /* DelList is now empty       */
        !           586: 
        !           587:    while(pHFEA)   /* Go through each HoldFEA */
        !           588:    {
        !           589:       usMemNeeded = sizeof(FEALIST) + pHFEA->cbName+1 + pHFEA->cbValue;
        !           590:       GetMem((PPVOID)&aPtr, usMemNeeded);
        !           591: 
        !           592:       eaopWrite.fpFEAList = (FEALIST FAR *) aPtr; /* Fill in eaop struct */
        !           593:       eaopWrite.fpFEAList->cbList = usMemNeeded;
        !           594: 
        !           595:       eaopWrite.fpFEAList->list[0].fEA     = pHFEA->fEA;
        !           596:       eaopWrite.fpFEAList->list[0].cbName  = pHFEA->cbName;
        !           597:       eaopWrite.fpFEAList->list[0].cbValue = pHFEA->cbValue;
        !           598: 
        !           599:       strcpy(aPtr + sizeof(FEALIST),  pHFEA->szName);
        !           600:       memcpy(aPtr + sizeof(FEALIST) + pHFEA->cbName+1,
        !           601:              pHFEA->aValue, pHFEA->cbValue);
        !           602: 
        !           603:       usRet=DosSetPathInfo(szFileName,             /* Write out the EA */
        !           604:                            SetInfoLevel2,
        !           605:                            (PVOID) &eaopWrite,
        !           606:                            (USHORT) sizeof(EAOP),
        !           607:                            DSPI_WRTTHRU);
        !           608: 
        !           609:       FreeMem(aPtr);       /* Free up the FEALIST struct */
        !           610: 
        !           611:       pHFEA = pHFEA->next;
        !           612:    }
        !           613: 
        !           614:    FILE_CHANGED = FALSE;
        !           615: }
        !           616: 
        !           617: 
        !           618: /*
        !           619:  * Function name: EditEAValue()
        !           620:  *
        !           621:  * Parameters:  hwnd is the current window handle.
        !           622:  *              pPDat is a pointer to PassData which contains Edit EA info.
        !           623:  *
        !           624:  * Returns: TRUE iff the edit was successful.
        !           625:  *
        !           626:  * Purpose: This routine allows the entry/edit of an EA value.
        !           627:  *          condition in memory.  First, all EAs in the delete list are
        !           628:  *          removed from the disk, then all EAs in the pHoldFEA list are
        !           629:  *          written out to disk.
        !           630:  *
        !           631:  * Usage/Warnings:  Expects the PassData structure to tell it the HoldFEA
        !           632:  *                  to edit, and if it is a subfield of a multi-multi EA,
        !           633:  *                  the rest of the PassData structure will be filled in
        !           634:  *                  to indicated which m-m is being edited.  Note that if
        !           635:  *                  this is a new edit, usRetEAType is expected to be set
        !           636:  *                  to the proper EA type upon entry.  NOTE:  memory sizing
        !           637:  *                  requests are not fully error trapped.
        !           638:  *
        !           639:  * Calls: MultiTypeIndex(), ChangeName(), AsciiEditProc() (thru PM),
        !           640:  *        MultiTypeProc() (thru PM).
        !           641:  */
        !           642: 
        !           643: BOOL EditEAValue(HWND hwnd, PASSDATA *pPDat)
        !           644: {
        !           645:    USHORT usEAType; /* Holds the field type to be edited */
        !           646:    USHORT *pusPtr;
        !           647:    USHORT usSize;   /* Holds the delta difference of the old and new buffers */
        !           648:    CHAR   *szNew,*szTrash;     /* Temporary pointers */
        !           649:    PASSDATA PDat;
        !           650:    HOLDFEA *pFEA = (HOLDFEA *) pPDat->Point;   /* The EA to be edited */
        !           651: 
        !           652:    /* Determine the type of EA that will be edited */
        !           653:    if(pPDat->cbMulti)                  /* It's a multi-type job  */
        !           654:    {
        !           655:       pusPtr = (USHORT *) MultiTypeIndex(pFEA->aValue+pPDat->usMultiOffset,
        !           656:                                          pPDat->usIndex);
        !           657:       usEAType = *pusPtr;
        !           658:    }
        !           659:    else if(pFEA->cbValue) /* It isn't a new EA name */
        !           660:    {
        !           661:       pusPtr   = (USHORT *) pFEA->aValue;
        !           662:       usEAType = *pusPtr;
        !           663:    }
        !           664:    else    /* It's a new EA */
        !           665:    {
        !           666:       usEAType = ConvTable[usRetEAType].usPrefix;
        !           667:    }
        !           668: 
        !           669:    PDat.Point   = pFEA->szName;        /* General setup for AsciiEditProc */
        !           670:    PDat.usIndex = pPDat->cbMulti ? 1 : 0;   /* =1 if there is a multi  */
        !           671:    PDat.fFlag   = (BYTE) ((pFEA->fEA & 0x80) ? TRUE : FALSE);
        !           672: 
        !           673:    switch(usEAType)
        !           674:    {
        !           675:       case EA_ASCIIZ:
        !           676:       case EA_ASCIIZFN:
        !           677:       case EA_ASCIIZEA:
        !           678:       case EA_ASN1:
        !           679:          if(pPDat->cbMulti)            /* It is a multi-type field */
        !           680:             szAscii=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
        !           681:                                    pPDat->usIndex)
        !           682:                     +sizeof(USHORT);
        !           683:          else if(pFEA->cbValue)        /* There is a current value */
        !           684:             szAscii=pFEA->aValue+sizeof(USHORT);
        !           685:          else                                     /* It's a new EA */
        !           686:             szAscii=NULL;
        !           687: 
        !           688: 
        !           689:          if(!WinDlgBox(HWND_DESKTOP,        /* Do an ascii text edit */
        !           690:                        hwnd,
        !           691:                        AsciiEditProc,
        !           692:                        NULL,
        !           693:                        IDD_ASCIIEDIT,
        !           694:                        &PDat))
        !           695:             return(FALSE);                  /* They said cancel */
        !           696: 
        !           697:          if(PDat.fFlag)            /* Handle the need/nice bit */
        !           698:             PDat.fFlag = 0x80;
        !           699:          if(PDat.fFlag != (PDat.fFlag & 0x80))
        !           700:             FILE_CHANGED = TRUE;
        !           701:          pFEA->fEA = (pFEA->fEA & 0x7f) | PDat.fFlag;
        !           702: 
        !           703:          if(stricmp(strupr(szEAName),pFEA->szName)) /* The name changed */
        !           704:             ChangeName(pFEA,szEAName);
        !           705: 
        !           706:          if(pFEA->cbValue) /* There is a current value */
        !           707:          {
        !           708:             if(!strcmp(szAscii,szScratch))  /* It hasn't changed */
        !           709:                return(TRUE);
        !           710: 
        !           711:             if(pPDat->cbMulti) /* Do the whole thing here if m-m */
        !           712:             {
        !           713:                usSize = strlen(szScratch)-strlen(szAscii); /* Change in size */
        !           714: 
        !           715:                if(usSize > 0) /* The new string is longer */
        !           716:                {
        !           717:                   ResizeMem(pFEA->aValue,          /* Enlarge the EA size */
        !           718:                             pFEA->cbValue,
        !           719:                             pFEA->cbValue+usSize);
        !           720:                   szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
        !           721:                                          pPDat->usIndex+1);
        !           722:                   memmove(szTrash+usSize,  /* Move end of EA to make room */
        !           723:                           szTrash,
        !           724:                           pFEA->cbValue-(szTrash-pFEA->aValue));
        !           725:                }
        !           726:                else if(usSize < 0) /* The new string is shorter */
        !           727:                {
        !           728:                   szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
        !           729:                                          pPDat->usIndex+1);
        !           730:                   memmove(szTrash+usSize, /* Move back the end of the EA */
        !           731:                           szTrash,
        !           732:                           pFEA->cbValue-(szTrash-pFEA->aValue));
        !           733:                   DosSetMem(pFEA->aValue, pFEA->cbValue+usSize, fPERM|PAG_COMMIT);
        !           734:                }
        !           735:                szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
        !           736:                                       pPDat->usIndex);
        !           737:                strcpy(szTrash+sizeof(USHORT),szScratch); /* Copy in new val */
        !           738:                pFEA->cbValue+=usSize;              /* Change buffer count   */
        !           739: 
        !           740:                return(FILE_CHANGED = TRUE);  /* Done with m-m edit */
        !           741:             }
        !           742:             else
        !           743:             {
        !           744:                FreeMem(pFEA->aValue); /* Release old Value mem */
        !           745:             }
        !           746:          }
        !           747:          GetMem((PPVOID)&szNew, strlen(szScratch)+3);  /* +3 for Type & NULL */
        !           748:          pusPtr = (USHORT *) szNew;
        !           749:          *pusPtr= usEAType;                  /* Set type in new buffer       */
        !           750:          strcpy(szNew+2,szScratch);          /* Copy in the new value        */
        !           751:          pFEA->aValue = szNew;               /* Fix up the structure         */
        !           752:          pFEA->cbValue= strlen(szScratch)+3;
        !           753: 
        !           754:          return(FILE_CHANGED = TRUE);
        !           755: 
        !           756:       case EA_LPBINARY:
        !           757:       case EA_LPASCII:
        !           758:       case EA_LPMETAFILE:
        !           759:          if(pPDat->cbMulti)            /* It is a multi-type field */
        !           760:          {  /* szTrash points to field to edit, pusPtr to the field length */
        !           761:             szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
        !           762:                                    pPDat->usIndex);
        !           763:             pusPtr = (USHORT *) ((CHAR *) szTrash + sizeof(USHORT));
        !           764:             usSize = *pusPtr;
        !           765:             if(usSize)  /* It isn't a new EA */
        !           766:             {
        !           767:                GetMem((PPVOID)&szAscii, usSize+1); /* Set up inital value for edit */
        !           768:                memcpy(szAscii,szTrash+2*sizeof(USHORT),usSize);
        !           769:                szAscii[usSize]=NULL;
        !           770:             }
        !           771:             else                       /* No inital value */
        !           772:                szAscii = NULL;
        !           773:          }
        !           774:          else if(pFEA->cbValue)
        !           775:          {
        !           776:             usSize=GetUSHORT(pFEA,1);  /* Get size and set inital value */
        !           777:             if(usSize)
        !           778:             {
        !           779:                GetMem((PPVOID)&szTrash, usSize+1); /* +1 for null */
        !           780:                memcpy(szTrash,pFEA->aValue+4,usSize);
        !           781:                szTrash[usSize]=NULL;
        !           782:                szAscii=szTrash;
        !           783:             }
        !           784:             else
        !           785:                szAscii = NULL;
        !           786:          }
        !           787:          else
        !           788:             szAscii = NULL;
        !           789: 
        !           790:          if(!WinDlgBox(HWND_DESKTOP,        /* Do an ascii text edit */
        !           791:                        hwnd,
        !           792:                        AsciiEditProc,
        !           793:                        NULL,
        !           794:                        IDD_ASCIIEDIT,
        !           795:                        &PDat))
        !           796:          {  /* Cancel, but check if memory needs to be freed before exit */
        !           797:             if(pPDat->cbMulti || pFEA->cbValue)
        !           798:                if(szAscii) /* It's not NULL */
        !           799:                   FreeMem(szAscii); /* +1 for NULL */
        !           800: 
        !           801:             return(FALSE);
        !           802:          }
        !           803: 
        !           804:          if(PDat.fFlag)              /* Handle the need/nice bit */
        !           805:             PDat.fFlag = 0x80;
        !           806:          if(PDat.fFlag != (PDat.fFlag & 0x80))
        !           807:             FILE_CHANGED = TRUE;
        !           808:          pFEA->fEA = (pFEA->fEA & 0x7f) | PDat.fFlag;
        !           809: 
        !           810:          if(stricmp(strupr(szEAName),pFEA->szName)) /* The name changed */
        !           811:             ChangeName(pFEA,szEAName);
        !           812: 
        !           813:          if(pFEA->cbValue) /* There is a current value */
        !           814:          {
        !           815:             if(!strcmp(szAscii,szScratch))  /* It hasn't changed */
        !           816:             {
        !           817:                if(szAscii)
        !           818:                   FreeMem(szAscii);
        !           819:                return(TRUE);
        !           820:             }
        !           821:             if(szAscii)                  /* Free default value buffer */
        !           822:                FreeMem(szAscii);
        !           823: 
        !           824:             if(pPDat->cbMulti)   /* Do the whole thing here is multi-type */
        !           825:             {
        !           826:                USHORT usDelta = strlen(szScratch) - usSize; /* Change in len */
        !           827:                if(usDelta > 0) /* The new string is longer, resize first */
        !           828:                {
        !           829:                   ResizeMem(pFEA->aValue, pFEA->cbValue, pFEA->cbValue+usDelta);
        !           830:                   szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
        !           831:                                          pPDat->usIndex+1);
        !           832:                   memmove(szTrash+usDelta,szTrash,
        !           833:                           pFEA->cbValue-(szTrash-pFEA->aValue));
        !           834:                }
        !           835:                else if(usDelta < 0) /* move first, resize afterwards */
        !           836:                {
        !           837:                   szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
        !           838:                                          pPDat->usIndex+1);
        !           839:                   memmove(szTrash+usDelta,szTrash,
        !           840:                           pFEA->cbValue-(szTrash-pFEA->aValue));
        !           841:                   ResizeMem(pFEA->aValue, pFEA->cbValue+usDelta, fPERM|PAG_COMMIT);
        !           842:                }
        !           843:                szTrash=MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
        !           844:                                       pPDat->usIndex);
        !           845:                memmove(szTrash+2*sizeof(USHORT),szScratch,strlen(szScratch));
        !           846:                pusPtr = (USHORT *) ((CHAR *) szTrash + sizeof(USHORT));
        !           847:                *pusPtr= strlen(szScratch);   /* Set the length field */
        !           848: 
        !           849: 
        !           850:                pFEA->cbValue += usDelta;     /* Adjust struct len field */
        !           851: 
        !           852:               return(FILE_CHANGED = TRUE);
        !           853:             }
        !           854: 
        !           855:             FreeMem(pFEA->aValue); /* Free up old value */
        !           856:          }
        !           857:          GetMem((PPVOID)&szNew, strlen(szScratch)+4);    /* Get space for new value */
        !           858:          pusPtr = (USHORT *) szNew;
        !           859:          *pusPtr= usEAType;                    /* Set type field */
        !           860:          pusPtr++;
        !           861:          *pusPtr= strlen(szScratch);           /* Set length field */
        !           862:          memcpy(szNew+4,szScratch,*pusPtr);    /* Copy in new value */
        !           863:          pFEA->aValue = szNew;                 /* Adjust pointers */
        !           864:          pFEA->cbValue= strlen(szScratch)+4;   /* +4 for type and LP cnt */
        !           865: 
        !           866:          return(FILE_CHANGED = TRUE);
        !           867: 
        !           868:       case EA_MVMT:                    /* It's multi-value multi-type */
        !           869:          if(pFEA->cbValue == 0) /* It's a new EA */
        !           870:          {
        !           871:             GetMem((PPVOID)&pFEA->aValue, 3*sizeof(USHORT)); /* Allocate empty m-m EA */
        !           872:             pFEA->cbValue = 3*sizeof(USHORT);
        !           873:             pusPtr      = (USHORT *) pFEA->aValue;
        !           874:             *pusPtr = 0xffdf;                 /* Multi-value, multi-type */
        !           875:             pusPtr+=2;                        /* Skip type, codepage */
        !           876:             *pusPtr = 0;                      /* No fields initially     */
        !           877:             FILE_CHANGED = TRUE;
        !           878:          }
        !           879: 
        !           880:          /* Set up passed in data */
        !           881:          if(pPDat->cbMulti) /* It's a multi-type job  */
        !           882:          {
        !           883:             szNew   = MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
        !           884:                                      pPDat->usIndex);
        !           885:             szTrash = MultiTypeIndex(pFEA->aValue + pPDat->usMultiOffset,
        !           886:                                      pPDat->usIndex+1);
        !           887:             PDat.usMultiOffset = szNew - pFEA->aValue;
        !           888:             PDat.cbMulti       = szTrash - szNew;
        !           889:          }
        !           890:          else
        !           891:          {
        !           892:             PDat.usMultiOffset = 0;
        !           893:             PDat.cbMulti       = pFEA->cbValue;
        !           894:          }
        !           895:          PDat.Point         = (CHAR *) pFEA;
        !           896: 
        !           897:          WinDlgBox(HWND_DESKTOP,           /* Do the Multi-type edit */
        !           898:                    hwnd,
        !           899:                    MultiTypeProc,
        !           900:                    NULL,
        !           901:                    IDD_MULTIBOX,
        !           902:                    &PDat);
        !           903:          return(TRUE);
        !           904: 
        !           905:    }
        !           906: }
        !           907: 
        !           908: 
        !           909: /*
        !           910:  * Function name: EAExists()
        !           911:  *
        !           912:  * Parameters:  szEAName points to the EA Name to check for.
        !           913:  *
        !           914:  * Returns: TRUE iff an EA with a name matching szEAName exists.
        !           915:  *
        !           916:  * Purpose: This routine goes through the linked list pointed to by global
        !           917:  *          pHoldFEA and determines whether or not an EA of the passed name
        !           918:  *          already exists.
        !           919:  *
        !           920:  * Usage/Warnings:  The comparison is NOT case sensitive.
        !           921:  *
        !           922:  * Calls:
        !           923:  *
        !           924:  */
        !           925: 
        !           926: BOOL EAExists(CHAR *szEAName)
        !           927: {
        !           928:    HOLDFEA *phFEA=pHoldFEA;
        !           929: 
        !           930:    while(phFEA)
        !           931:    {
        !           932:       if(!stricmp(szEAName,phFEA->szName))
        !           933:          return(TRUE);
        !           934:       phFEA=phFEA->next;
        !           935:    }
        !           936:    return(FALSE);
        !           937: }
        !           938: 
        !           939: 
        !           940: /*
        !           941:  * Function name: ChangeName()
        !           942:  *
        !           943:  * Parameters:  hwnd is the current window used for error messages.
        !           944:  *              pFEA points to the current FEA.
        !           945:  *              szName points to the new EA name.
        !           946:  *
        !           947:  * Returns: VOID.  Fixes up the pFEA structure and global pDelList.
        !           948:  *
        !           949:  * Purpose: This routine copies the current EA Name to the delete list, then
        !           950:  *          allocates a new space, copies the new name into it, and sets the
        !           951:  *          FEA pointer to it.
        !           952:  *
        !           953:  * Usage/Warnings:  NOTE:  Not all the memory allocations are fully error
        !           954:  *                         trapped.
        !           955:  *
        !           956:  * Calls:
        !           957:  *
        !           958:  */
        !           959: 
        !           960: VOID ChangeName(HOLDFEA *pFEA,CHAR *szName)
        !           961: {
        !           962:    CHAR *szTemp;
        !           963:    DELETELIST *pDL;
        !           964: 
        !           965:    GetMem((PPVOID)&szTemp, strlen(szName+1));  /* Allocate space for new name */
        !           966:    if(!szTemp)
        !           967:       return;
        !           968: 
        !           969:    GetMem((PPVOID)&pDL, (USHORT) sizeof(DELETELIST)); /* Allocate a new delete struct  */
        !           970:    pDL->EAName = pFEA->szName;              /* Fill in DeleteList struct     */
        !           971:    pDL->next   = pDelList;
        !           972:    pDelList    = pDL;
        !           973: 
        !           974:    strcpy(szTemp,szName);                   /* Copy name to permanent buffer */
        !           975:    pFEA->szName = szTemp;                   /* Fix up struct                 */
        !           976:    pFEA->cbName = (CHAR) strlen(szName);
        !           977: 
        !           978:    FILE_CHANGED = TRUE;
        !           979: }
        !           980: 
        !           981: 
        !           982: /*
        !           983:  * Function name: MultiTypeIndex()
        !           984:  *
        !           985:  * Parameters:  pMulti points to the current m-m field.
        !           986:  *              usIndex is the field the caller is interested in.
        !           987:  *
        !           988:  * Returns: a pointer to the field specified by the usIndex param.
        !           989:  *
        !           990:  * Purpose: This routine takes a pointer to a Multi-Multi data field and
        !           991:  *          returns a pointer to the nth data field in this buffer.
        !           992:  *
        !           993:  * Usage/Warnings:  NOTE:  Memory bounds are not checked and a corrupt
        !           994:  *                         EA field could cause unspecified results.
        !           995:  *                  Recursively calls itself to handle nesting. Does not
        !           996:  *                  support multi-value single type fields.
        !           997:  *
        !           998:  * Calls: LookupEAType, MultiTypeIndex()
        !           999:  *
        !          1000:  */
        !          1001: 
        !          1002: CHAR *MultiTypeIndex(CHAR *pMulti, USHORT usIndex)
        !          1003: {
        !          1004:    USHORT *pusPtr;
        !          1005:    USHORT usOffset;
        !          1006: 
        !          1007:    pMulti += 3*sizeof(USHORT);  /* skip over 0xffdf, codepage, and field cnt */
        !          1008: 
        !          1009:    while(usIndex--)             /* loop to skip over correct # of flds  */
        !          1010:    {
        !          1011:       pusPtr   = (USHORT *) pMulti;
        !          1012:       usOffset = LookupEAType(*pusPtr);    /* Get offset of field type */
        !          1013: 
        !          1014:       pMulti += sizeof(USHORT);            /* Skip over the type field */
        !          1015: 
        !          1016:       switch(ConvTable[usOffset].usFldType)
        !          1017:       {
        !          1018:          case IDD_ASCIIZ:
        !          1019:             while(*pMulti++);              /* Increment to point after NULL */
        !          1020:             break;
        !          1021: 
        !          1022:          case IDD_LPDATA:
        !          1023:             pusPtr = (USHORT *) pMulti;                /* Get the length */
        !          1024:             pMulti += *pusPtr + sizeof(USHORT);        /* skip to end */
        !          1025:             break;
        !          1026: 
        !          1027:          case IDD_MULTILIST:
        !          1028:             if(*pusPtr == EA_MVMT) /* m-m, do a recursive call to skip fld */
        !          1029:             {
        !          1030:                pusPtr = (USHORT *) pMulti; /* points to field cnt */
        !          1031:                pMulti = MultiTypeIndex(pMulti-sizeof(USHORT),*pusPtr);
        !          1032:                break;
        !          1033:             }
        !          1034:             /* Not yet implemented for Multi-valued single-type stuff... */
        !          1035:             break;
        !          1036:       }
        !          1037:    }
        !          1038:    return(pMulti);
        !          1039: }
        !          1040: 
        !          1041: 
        !          1042: /*
        !          1043:  * Function name: EAValueString()
        !          1044:  *
        !          1045:  * Parameters:  hwnd is the current window handle.
        !          1046:  *              aEAVal is a pointer to an EA value field.
        !          1047:  *
        !          1048:  * Returns: a pointer to an ASCII description of the field value.
        !          1049:  *
        !          1050:  * Purpose: This routine takes a pointer to an EA Value (i.e. starting with
        !          1051:  *          with $ffxx) and returns a pointer to a string representing the
        !          1052:  *          value of the EA.  This string must be Freed by the user when
        !          1053:  *          finished with it.
        !          1054:  *
        !          1055:  * Usage/Warnings:  NOTE:  Not all GetMem's are totally error trapped.
        !          1056:  *                  The string returned is allocated in this procedure,
        !          1057:  *                  but it is the caller's responsibility to free the buffer.
        !          1058:  *
        !          1059:  * Calls:
        !          1060:  *
        !          1061:  */
        !          1062: 
        !          1063: CHAR *EAValueString(CHAR *aEAVal)
        !          1064: {
        !          1065:    USHORT *pusPtr= (USHORT *) aEAVal;  /* Points to EA Type     */
        !          1066:    CHAR *szRet,*szTemp;        /* szRet points to return string */
        !          1067: 
        !          1068:    switch(*pusPtr)
        !          1069:    {
        !          1070:       case EA_ASCIIZ:    /* For asciiz strings, return MAXSHOWSIZE-1 chars */
        !          1071:       case EA_ASCIIZFN:
        !          1072:       case EA_ASCIIZEA:
        !          1073:       case EA_ASN1:
        !          1074:          aEAVal += sizeof(USHORT);
        !          1075:          if(strlen(aEAVal)<MAXSHOWSIZE)
        !          1076:          {
        !          1077:             GetMem((PPVOID)&szRet, strlen(aEAVal)+1);
        !          1078:             strcpy(szRet,aEAVal);
        !          1079:          }
        !          1080:          else
        !          1081:          {
        !          1082:             GetMem((PPVOID)&szRet, MAXSHOWSIZE);
        !          1083:             strncpy(szRet,aEAVal,MAXSHOWSIZE-4);
        !          1084:             strcpy (szRet+MAXSHOWSIZE-4,"...");
        !          1085:             szRet[MAXSHOWSIZE-1]=NULL;
        !          1086:          }
        !          1087:          return(szRet);
        !          1088: 
        !          1089:       case EA_LPASCII:   /* Display up to first MAXSHOWSIZE-1 chars */
        !          1090:       case EA_LPMETAFILE:
        !          1091:          pusPtr++;
        !          1092:          aEAVal += 2*sizeof(USHORT);
        !          1093:          if(*pusPtr < MAXSHOWSIZE)
        !          1094:          {
        !          1095:             GetMem((PPVOID)&szRet, *pusPtr +1);
        !          1096:             strncpy(szRet,aEAVal,*pusPtr);
        !          1097:             szRet[*pusPtr]=NULL;
        !          1098:          }
        !          1099:          else
        !          1100:          {
        !          1101:             GetMem((PPVOID)&szRet, MAXSHOWSIZE);
        !          1102:             strncpy(szRet,aEAVal,MAXSHOWSIZE-4);
        !          1103:             strcpy (szRet+MAXSHOWSIZE-4,"...");
        !          1104:             szRet[MAXSHOWSIZE-1]=NULL;
        !          1105:          }
        !          1106:          return(szRet);
        !          1107: 
        !          1108:       /* For the rest of the types, just display the field type */
        !          1109: 
        !          1110:       case EA_LPBINARY:
        !          1111:          szTemp = "*** LP Binary ***";
        !          1112:          break;
        !          1113: 
        !          1114:       case EA_LPBITMAP:
        !          1115:          szTemp = "*** LP Bitmap ***";
        !          1116:          break;
        !          1117: 
        !          1118:       case EA_LPICON:
        !          1119:          szTemp = "*** LP Icon ***";
        !          1120:          break;
        !          1121: 
        !          1122:       case EA_MVMT:
        !          1123:          szTemp = "*** Multi-value Multi-type ***";
        !          1124:          break;
        !          1125: 
        !          1126:       case EA_MVST:
        !          1127:          szTemp = "*** Multi-value Single-type ***";
        !          1128:          break;
        !          1129: 
        !          1130:       default:
        !          1131:          szTemp = "*** Unknown EA type ***";
        !          1132:          break;
        !          1133: 
        !          1134:    }
        !          1135:    GetMem((PPVOID)&szRet, strlen(szTemp)+1); /* Copy string from static to dynamic */
        !          1136:    strcpy(szRet,szTemp);
        !          1137:    return(szRet);
        !          1138: }
        !          1139: 
        !          1140: 
        !          1141: /*
        !          1142:  * Function name: MultiAdd()
        !          1143:  *
        !          1144:  * Parameters:  hwnd is the current window handle.
        !          1145:  *              pFEA points to the current FEA.
        !          1146:  *              pPDat gives the current m-m data.
        !          1147:  *
        !          1148:  * Returns: VOID.  Modifies the current pFEA.
        !          1149:  *
        !          1150:  * Purpose: This routine is called by MultiTypeProc and handles the addition
        !          1151:  *          of a subvalue to a multi-value, multi-type EA.
        !          1152:  *
        !          1153:  * Usage/Warnings:  NOTE:  Not all GetMem's are totally error trapped.
        !          1154:  *                  It is also possible that the add to the listbox could fail.
        !          1155:  *
        !          1156:  * Calls: AddEAProc() (thru PM), MultiTypeIndex()
        !          1157:  *
        !          1158:  */
        !          1159: 
        !          1160: VOID MultiAdd(HWND hwnd, HOLDFEA *pFEA,PASSDATA FAR *pPDat)
        !          1161: {
        !          1162:    USHORT   usSize;
        !          1163:    USHORT   *pusPtr;
        !          1164:    CHAR     aUtility[6];      /* Used to hold the header for all EA types */
        !          1165:    CHAR     *pInsert,*pValue;
        !          1166:    PASSDATA PDat;
        !          1167: 
        !          1168:    PDat.Point = pFEA->szName;
        !          1169: 
        !          1170:    if(!WinDlgBox(HWND_DESKTOP,        /* Get the name and type */
        !          1171:                  hwnd,
        !          1172:                  AddEAProc,
        !          1173:                  NULL,
        !          1174:                  IDD_ADDEA,
        !          1175:                  &PDat))
        !          1176:       return;                         /* They said cancel */
        !          1177: 
        !          1178:    pusPtr = (USHORT *) aUtility;
        !          1179:    *pusPtr= ConvTable[usRetEAType].usPrefix;   /* Set the type in header buf */
        !          1180: 
        !          1181:    switch(ConvTable[usRetEAType].usFldType)
        !          1182:    {
        !          1183:       case IDD_ASCIIZ:     /* make buffer look like: xx FF 00, size 3 */
        !          1184:          usSize = 3;
        !          1185:          aUtility[2]=0;
        !          1186:          break;
        !          1187: 
        !          1188:       case IDD_LPDATA:     /* make the buffer look like: xx FF 00 00, size 4 */
        !          1189:          usSize = 4;
        !          1190:          pusPtr = (USHORT *) &aUtility[2];
        !          1191:          *pusPtr= 0;
        !          1192:          break;
        !          1193: 
        !          1194:       case IDD_MULTILIST:
        !          1195:          usSize = 6;
        !          1196:          pusPtr = (USHORT *) &aUtility[2];
        !          1197:          *pusPtr= 0; /* Zero out codepage */
        !          1198:          pusPtr++;
        !          1199:          *pusPtr= 0; /* Zero out fld cnt */
        !          1200:          break;
        !          1201:    }
        !          1202:    /* Increase EA size to accomodate the header */
        !          1203:    ResizeMem(pFEA->aValue, pFEA->cbValue, pFEA->cbValue+usSize);
        !          1204: 
        !          1205:    pusPtr  = (USHORT *) ((CHAR *) pFEA->aValue + pPDat->usMultiOffset);
        !          1206:    pusPtr+=2;    /* Point to the current number of m-m fields */
        !          1207: 
        !          1208:    /* Get ptr to beginning of current EA, scoot the rest down and insert
        !          1209:       the 3-4 byte header at the end of the list.                        */
        !          1210:    pInsert = MultiTypeIndex(pFEA->aValue+pPDat->usMultiOffset, *pusPtr);
        !          1211:    memmove(pInsert+usSize,pInsert, pFEA->cbValue-(pInsert-pFEA->aValue));
        !          1212:    memcpy(pInsert,aUtility,usSize);
        !          1213: 
        !          1214:    pFEA->cbValue += usSize;   /* Fix up the counts */
        !          1215:    pPDat->cbMulti+= usSize;
        !          1216:                                                   /* Set the PDat for call */
        !          1217:    PDat.Point         = (CHAR *) pFEA;
        !          1218:    PDat.cbMulti       = pPDat->cbMulti;
        !          1219:    PDat.usMultiOffset = pPDat->usMultiOffset;
        !          1220:    PDat.usIndex       = *pusPtr;
        !          1221: 
        !          1222:    if(!EditEAValue(hwnd,&PDat)) /* They canceled the edit */
        !          1223:    {  /* Move the EA's back to effectively kill the inserted header */
        !          1224:       memmove(pInsert,pInsert+usSize,pFEA->cbValue-(pInsert-pFEA->aValue));
        !          1225:       DosSetMem(pFEA->aValue, pFEA->cbValue-usSize, fPERM|PAG_COMMIT);
        !          1226:       pFEA->cbValue -= usSize;   /* Adjust counters */
        !          1227:       pPDat->cbMulti-= usSize;
        !          1228: 
        !          1229:       return;
        !          1230:    }
        !          1231: 
        !          1232:    /* Reset pusPtr since EditEAValue could have moved the base address */
        !          1233:    pusPtr  = (USHORT *) ((CHAR *) pFEA->aValue + pPDat->usMultiOffset);
        !          1234:    pusPtr+=2;
        !          1235: 
        !          1236:    pInsert = MultiTypeIndex(pFEA->aValue+pPDat->usMultiOffset, *pusPtr);
        !          1237: 
        !          1238:    *pusPtr += 1; /* Field cnt incremented AFTER call to Edit */
        !          1239: 
        !          1240:    pValue = EAValueString(pInsert);   /* Add new field to the list box */
        !          1241: 
        !          1242:    WinSendDlgItemMsg(hwnd, IDD_LBOX, LM_INSERTITEM,
        !          1243:                      MPFROM2SHORT(LIT_END,0),
        !          1244:                      MPFROMP(pValue));
        !          1245:    FreeMem(pValue);
        !          1246: 
        !          1247:    FILE_CHANGED = TRUE;
        !          1248: }
        !          1249: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.