Annotation of os232sdk/toolkt20/c/samples/nead/neadea.c, revision 1.1.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.