home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / nead / neadea.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-05  |  43.0 KB  |  1,257 lines

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