home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / AP / JED / JED097-1.TAR / jed / src / os2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-12  |  22.4 KB  |  956 lines

  1. #if !defined (_MSC_VER) && !defined (__EMX__)
  2. # include <dir.h>
  3. #endif
  4.  
  5. #define INCL_BASE
  6. #define INCL_NOPM
  7. #define INCL_VIO
  8. #define INCL_KBD
  9. #define INCL_DOS
  10. #if 0
  11. # define INCL_DOSSEMAPHORES
  12. #endif
  13. #ifdef LONG
  14. #undef LONG
  15. #endif
  16. #include <os2.h>
  17.  
  18. #include <signal.h>
  19. #include <string.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <process.h>
  23. #include <dos.h>
  24. #include <errno.h>
  25.  
  26. #include "config.h"
  27. #include "sysdep.h"
  28. #include "screen.h"
  29. #include "buffer.h"
  30. #include "misc.h"
  31. #include "hooks.h"
  32.  
  33. int Abort_Char = 7;               /* scan code for G (control) */
  34.  
  35. #include "dos_os2.c"
  36.  
  37. extern char *get_cwd (void);
  38. void delay (int time);
  39.  
  40. void set_kbd (void);
  41. void thread_getkey (void);
  42.  
  43. #define lowercase strlwr
  44.  
  45. KBDINFO    initialKbdInfo;    /* keyboard info        */
  46.  
  47. /* Code to read keystrokes in a separate thread */
  48.  
  49. typedef struct kbdcodes {
  50.   UCHAR ascii;
  51.   UCHAR scan;
  52.   USHORT shift;
  53. } KBDCODES;
  54.  
  55. #define BUFFER_LEN 4096
  56. static KBDCODES *threadKeys;
  57. static int atEnd = 0;
  58. static int startBuf;
  59. static int endBuf;
  60.  
  61. /* Original code used semaphores to control access to threadKeys.
  62.  * It is expected that the semaphore code will be deleted after 0.97.
  63. */
  64. #if 0
  65.  
  66. #ifdef __os2_16__
  67.  
  68. typedef USHORT APIRET;
  69. static HSEM Hmtx;
  70.  
  71. #define DosRequestMutexSem(hmtx,timeout) DosSemRequest(hmtx,timeout)
  72. #define DosReleaseMutexSem(hmtx) DosSemClear(hmtx)
  73. #define DosCloseMutexSem(hmtx) DosCloseSem(hmtx)
  74.  
  75. #else /* !defined(__os2_16__) */
  76.  
  77. static HMTX Hmtx;     /* Mutex Semaphore */
  78.  
  79. #endif
  80.  
  81.  
  82. APIRET CreateSem(void)
  83. {
  84. #ifdef __os2_16__
  85.   char SemName[32];
  86.   sprintf(SemName, "\\SEM\\jed\\%u", getpid());
  87.   return ( DosCreateSem (0, &Hmtx, SemName) );
  88. #else
  89.   return ( DosCreateMutexSem (NULL, &Hmtx, 0, 0) );
  90. #endif
  91. }
  92.  
  93. APIRET RequestSem(void)
  94. {
  95.   return ( DosRequestMutexSem (Hmtx, -1) );
  96. }
  97.  
  98. APIRET ReleaseSem(void)
  99. {
  100.   return ( DosReleaseMutexSem (Hmtx) );
  101. }
  102.  
  103. APIRET CloseSem(void)
  104. {
  105.   return( DosCloseMutexSem (Hmtx) );
  106. }
  107.  
  108. #else
  109.  
  110. #define CreateSem()
  111. #define RequestSem()
  112. #define ReleaseSem()
  113. #define CloseSem()
  114.  
  115. #endif
  116.  
  117.  
  118. void thread_getkey ()
  119. {
  120.    KBDKEYINFO keyInfo;
  121.    int n;
  122.  
  123.    while (!atEnd) {     /* at end is a flag */
  124.       set_kbd();
  125.       KbdCharIn(&keyInfo, IO_NOWAIT, 0);       /* get a character    */
  126.       if (keyInfo.fbStatus & 0x040) {          /* found a char process it */
  127.     if (keyInfo.chChar == Abort_Char) {
  128.       SLang_Error = 2;
  129.       SLKeyBoard_Quit = 1;
  130.     }
  131.     n = (endBuf + 1) % BUFFER_LEN;
  132.     if (n == startBuf) {
  133.       DosBeep (500, 20);
  134.       KbdFlushBuffer(0);
  135.       continue;
  136.     }
  137.     RequestSem();
  138.     threadKeys [n].ascii = keyInfo.chChar;
  139.     threadKeys [n].scan = keyInfo.chScan;
  140.     threadKeys [n].shift = keyInfo.fsState;
  141.     endBuf = n;
  142.     ReleaseSem();
  143.       } else                    /* no char available*/
  144.     DosSleep (20);
  145.    }
  146. }
  147.  
  148. void thread_code (void *Args)
  149. {
  150.   (void) Args;
  151.   startBuf = -1;      /* initialize the buffer pointers */
  152.   endBuf = -1;
  153.   thread_getkey ();
  154.   atEnd = 0;          /* reset the flag */
  155.   _endthread();
  156. }
  157.  
  158.  
  159. /* The code below is in the main thread */
  160.  
  161. void set_kbd()
  162. {
  163.   KBDINFO kbdInfo;
  164.  
  165.   kbdInfo = initialKbdInfo;
  166.   kbdInfo.fsMask &= ~0x0001;        /* not echo on        */
  167.   kbdInfo.fsMask |= 0x0002;        /* echo off        */
  168.   kbdInfo.fsMask &= ~0x0008;        /* cooked mode off    */
  169.   kbdInfo.fsMask |= 0x0004;        /* raw mode        */
  170.   kbdInfo.fsMask &= ~0x0100;        /* shift report    off    */
  171.   KbdSetStatus(&kbdInfo, 0);
  172. }
  173.  
  174. static int enhancedKeyboard;
  175.  
  176. void init_tty ()
  177. {
  178.   VIOCURSORINFO cursorInfo, OldcursorInfo;
  179.  
  180.   /*  set ^C off */
  181.   signal (SIGINT, SIG_IGN);
  182.   signal (SIGBREAK, SIG_IGN);
  183.  
  184.   /* set up the keyboard */
  185.  
  186.    if (threadKeys == NULL)
  187.      {
  188.     if (NULL == (threadKeys = SLCALLOC (sizeof(KBDCODES), BUFFER_LEN)))
  189.       {
  190.          exit_error ("init_tty: Malloc error.", 0);
  191.       }
  192.      }
  193.  
  194.   initialKbdInfo.cb = sizeof(initialKbdInfo);
  195.   KbdGetStatus(&initialKbdInfo, 0);
  196.   set_kbd();
  197.   enhancedKeyboard = 1;
  198.  
  199.   /* open a semaphore */
  200.   CreateSem();
  201.  
  202.   /* start a separate to read the keyboard */
  203. #if defined(__BORLANDC__)
  204.   _beginthread (thread_code, 8096, NULL);
  205. #else
  206.   _beginthread (thread_code, NULL,  8096, NULL);
  207. #endif
  208.  
  209.   VioGetCurType (&OldcursorInfo, 0);
  210.   cursorInfo.yStart = 1;
  211.   cursorInfo.cEnd = 15;
  212.   cursorInfo.cx = 1;
  213.   cursorInfo.attr = 1;
  214.   if (VioSetCurType (&cursorInfo, 0))
  215.     VioSetCurType (&OldcursorInfo, 0);   /* reset to previous value */
  216. }
  217.  
  218.  
  219. void reset_tty ()
  220. {
  221.   atEnd = 1;                      /* set flag and wait until thread ends */
  222.   while (atEnd) {DosSleep (0);}
  223.  
  224.   CloseSem();
  225.  
  226.   /* close the keyboard */
  227.   KbdSetStatus(&initialKbdInfo, 0); /* restore original state    */
  228. }
  229.  
  230. unsigned char sys_getkey ()
  231. {
  232.    char *keypad_scan =
  233.       "\x4e\x53\x52\x4f\x50\x51\x4b\x4c\x4d\x47\x48\x49\x37\x4a";
  234.    char *normal = "!@#$%^&*()-=\t*\0177QWERTYUIOP[]\r*ASDFGHJKL;'`*\\ZXCVBNM<>/";
  235.    char *edt_chars = "lnpqrstuvwxyRS";
  236.    int bra = 'O', P = 'P', keypad, weird;
  237.    char *p;
  238.    unsigned int c, c1, shft, shift, i;
  239.  
  240.    weird = 300;
  241.  
  242.    while (!sys_input_pending(&weird))
  243.      {
  244.     if (Display_Time)
  245.       {
  246.          JWindow->trashed = 1;
  247.          update((Line *) NULL, 0, 1);
  248.       }
  249.      }
  250.  
  251.    /* read codes from buffer */
  252.    RequestSem();
  253.    startBuf = (startBuf + 1) % BUFFER_LEN;
  254.    c = threadKeys [startBuf].ascii;
  255.    c1 = threadKeys [startBuf].scan;
  256.    shift = threadKeys [startBuf].shift;
  257.    ReleaseSem();
  258.  
  259.    shft = shift & 0xF;
  260.  
  261.    keypad = (c1 > 0x36) && NumLock_Is_Gold && (enhancedKeyboard);
  262. /*   keypad = (c == 0) && (c1 > 0x36); */
  263.    /* allow Shift-keypad to give non edt keypad chars */
  264.    keypad = keypad && !(shft & 0x3);
  265.  
  266.    /* This is for the damned enter and slash keys */
  267.    weird = keypad && ((c1 == 0xE0) && ((c == 0xD) || (c == 0x2F)));
  268.  
  269.    keypad = keypad && (c != 0xE0);  /* excludes small keypad */
  270.  
  271.    if ((c == 8) && ((c1) == 0x0e)) c =127;
  272.    else if ((c == 32) && (shft & 0x04))    /* ^ space = ^@ */
  273.      {
  274.     c = 3;
  275.     ungetkey ((int*) &c);
  276.     c = 0;
  277.      }
  278.    else if (weird || (keypad && (NULL != (p = strchr(keypad_scan, c1)))))
  279.      {
  280.     if (c1 == 0xE0) if (c == 0x2f) c = 'Q'; else c = 'M';
  281.     else c = (unsigned int) edt_chars[(int) (p - keypad_scan)];
  282.     ungetkey ((int*) &c);
  283.     ungetkey ((int*) &bra);
  284.     c = 27;
  285.      }
  286.    else if ((!c) || ((c == 0xe0) && (enhancedKeyboard) && (c1 > 0x43)))
  287.      {
  288.     if (NumLock_Is_Gold && (c1 == 0x3B))
  289.       {
  290.          ungetkey((int*)&P); ungetkey((int*) &bra); c = 27;
  291.       }
  292.     /* if key is 5 of keypad, get another char */
  293.     else if ((c1 == 'L') && enhancedKeyboard && (c == 0)) return(sys_getkey());
  294.     else
  295.       {
  296.          if ((shft == 0x8) && (c == 0) && PC_Alt_Char)
  297.            {
  298.           if ((c1 >= 14) && (c1 <= 53))
  299.             {
  300.                c1 = (unsigned int) normal[c1];
  301.                c = PC_Alt_Char;
  302.             }
  303.           else if ((c1 >= 120) && (c1 <= 131))
  304.             {
  305.                c1 = (unsigned int) normal[c1 - 120];
  306.                c = PC_Alt_Char;
  307.             }
  308.           else if (c1 == 165) /* tab */
  309.             {
  310.                c1 = (unsigned int) normal[c1 - 165 + 12];
  311.                c = PC_Alt_Char;
  312.             }
  313.            }
  314.          else c = 0;
  315.          ungetkey((int*) &c1);
  316.       }
  317.      }
  318.    return(c);
  319. }
  320.  
  321. void sys_flush_input()
  322. {
  323.   KbdFlushBuffer(0);
  324.   endBuf = startBuf;
  325. }
  326.  
  327. #define keyWaiting() (endBuf != startBuf)
  328.  
  329. /* sleep for *tsecs tenths of a sec waiting for input */
  330. static int sys_input_pending(int *tsecs)
  331. {
  332.    int count = *tsecs * 5;
  333.  
  334.    if (Batch || Input_Buffer_Len) return(Input_Buffer_Len);
  335.  
  336.    if (count)
  337.      {
  338.     while(count > 0)
  339.       {
  340.          delay(20);               /* 20 ms or 1/50 sec */
  341.          if (keyWaiting ()) break;
  342.          count--;
  343.       }
  344.     return(count);
  345.      }
  346.    else return(keyWaiting ());
  347. }
  348.  
  349.  
  350. void get_term_dimensions(int *w, int *h)
  351. {
  352.   VIOMODEINFO vioModeInfo;
  353.  
  354.   vioModeInfo.cb = sizeof(vioModeInfo);
  355.   VioGetMode (&vioModeInfo, 0);
  356.   *w = vioModeInfo.col;
  357.   *h = vioModeInfo.row;
  358. }
  359.  
  360. #if defined(_MSC_VER) || defined (__EMX__)
  361. int sys_chmod(char *file, int what, int *mode, short *uid, short *gid)
  362. {
  363.    struct stat buf;
  364.    int m;
  365.  
  366. #ifdef _MSC_VER 
  367.    /* MSC stat() is broken on directory names ending with a slash */
  368.    char path[_MAX_PATH];
  369.    strcpy(path, file); 
  370.    deslash(file = path);
  371. #endif
  372.  
  373.    if (what)
  374.      {
  375.     chmod(file, *mode);
  376.     return(0);
  377.      }
  378.  
  379.    if (stat(file, &buf) < 0) switch (errno)
  380.      {
  381.     case EACCES: return(-1); /* es = "Access denied."; break; */
  382.     case ENOENT: return(0);  /* ms = "File does not exist."; */
  383.     case ENOTDIR: return(-2); /* es = "Invalid Path."; */
  384.     default: return(-3); /* "stat: unknown error."; break;*/
  385.      }
  386.  
  387.    m = buf.st_mode;
  388.  
  389.    *mode = m & 0777;
  390.  
  391.    if (m & S_IFDIR) return (2);
  392.    return(1);
  393. }
  394.  
  395. #else
  396.  
  397. int sys_chmod(char *file, int what, int *mode, short *dum1, short *dum2)
  398. {
  399.   FILESTATUS3 fileInfo;
  400.   USHORT Result;
  401.   (void) dum1; (void) dum2;
  402.   Result = DosQueryPathInfo (file, FIL_STANDARD, &fileInfo, sizeof (fileInfo));
  403.   if (Result == ERROR_FILE_NOT_FOUND) return 0;
  404.   else if (Result == ERROR_ACCESS_DENIED) return -1;
  405.   else if (Result == ERROR_INVALID_PATH) return -2;
  406.   else if (Result != NO_ERROR) return -3;
  407.  
  408.   *mode = fileInfo.attrFile;
  409.  
  410.   if (what) {
  411.     fileInfo.attrFile = *mode;
  412.     DosSetPathInfo (file, FIL_STANDARD, &fileInfo, sizeof (fileInfo), 0);
  413.   }
  414.  
  415.   if (*mode & 0x10) return(2);
  416.   else return (1);
  417. }
  418.  
  419. #endif
  420.  
  421. static char Found_Dir[256];
  422.  
  423. #ifdef __os2_16__
  424. #define DosFindFirst(FileName, DirHandle, Attribute, ResultBuf, \
  425.              ResultBufLen, SearchCount, Reserved) \
  426.     DosFindFirst(FileName, DirHandle, Attribute, ResultBuf, \
  427.              ResultBufLen, SearchCount, 0)
  428. #endif
  429.  
  430. int sys_findfirst(char *theFile)
  431. {
  432.    char *f, the_path[CCHMAXPATH], *file, *f1;
  433.    char *pat;
  434.  
  435. #if defined(__os2_16__)
  436.   FILEFINDBUF FindBuffer;
  437.   USHORT FindCount;
  438.   USHORT File_Attr;
  439. #else
  440.   FILEFINDBUF3 FindBuffer;
  441.   ULONG FindCount;
  442.   ULONG File_Attr;
  443. #endif
  444.  
  445.   HDIR FindHandle;
  446.   File_Attr = FILE_READONLY | FILE_DIRECTORY;
  447.  
  448.   file = expand_filename(theFile);
  449.   f1 = f = extract_file(file);
  450.   strcpy (Found_Dir, file);
  451.  
  452.    Found_Dir[(int) (f - file)] = 0;
  453.  
  454.   strcpy(the_path, file);
  455.  
  456.   while (*f1 && (*f1 != '*')) f1++;
  457.   if (! *f1)
  458.     {
  459.     while (*f && (*f != '.')) f++;
  460.     if (*f) strcat(the_path, "*"); else strcat(the_path, "*.*");
  461.     }
  462.   pat = the_path;
  463.  
  464.   FindHandle = 1;
  465.   FindCount = 1;
  466.   if (DosFindFirst(pat, &FindHandle, File_Attr, &FindBuffer,
  467.     sizeof (FindBuffer), &FindCount, FIL_STANDARD) != NO_ERROR)
  468.     return 0;
  469.   strcpy (theFile, Found_Dir);
  470.   strcat (theFile, FindBuffer.achName);
  471.   if (FindBuffer.attrFile & FILE_DIRECTORY) fixup_dir (theFile);
  472.   return 1;
  473. }
  474.  
  475. int sys_findnext(char *file)
  476. {
  477. #ifdef __os2_16__
  478.   FILEFINDBUF FindBuffer;
  479.   USHORT FileCount;
  480. #else
  481.   FILEFINDBUF3 FindBuffer;
  482.   ULONG FileCount;
  483. #endif
  484.  
  485.   FileCount = 1;
  486.  
  487.   if (DosFindNext(1, &FindBuffer, sizeof (FindBuffer), &FileCount))
  488.     return 0;
  489.   else {
  490.     strcpy (file, Found_Dir);
  491.     strcat (file, FindBuffer.achName);
  492.     if (FindBuffer.attrFile & FILE_DIRECTORY) fixup_dir (file);
  493.     return 1;
  494.   }
  495. }
  496.  
  497.  
  498.  
  499. /* Here we do a find first followed by calling routine to conver time */
  500. #if defined(_MSC_VER) || defined(__EMX__)
  501.  
  502. unsigned long sys_file_mod_time(char *file)
  503. {
  504.    struct stat buf;
  505.  
  506.    if (stat(file, &buf) < 0) return(0);
  507.    return((unsigned long) buf.st_mtime);
  508. }
  509.  
  510. #else
  511.  
  512. unsigned long sys_file_mod_time(char *file)
  513. {
  514.    FILESTATUS3 fileInfo;
  515.    struct time t;
  516.    struct date d;
  517.  
  518.    if (DosQueryPathInfo (file, FIL_STANDARD, &fileInfo, sizeof (fileInfo))
  519.        != NO_ERROR)
  520.        return 0;
  521.    t.ti_min = fileInfo.ftimeLastWrite.minutes;
  522.    t.ti_hour = fileInfo.ftimeLastWrite.hours;
  523.    t.ti_hund = 0;
  524.    t.ti_sec = fileInfo.ftimeLastWrite.twosecs;
  525.    d.da_day = fileInfo.fdateLastWrite.day;
  526.    d.da_mon = fileInfo.fdateLastWrite.month;
  527.    d.da_year = fileInfo.fdateLastWrite.year;
  528.    return dostounix(&d, &t);
  529. }
  530.  
  531. #endif
  532.  
  533. void delay (int time)
  534. {
  535.   DosSleep (time);
  536. }
  537.  
  538. int IsHPFSFileSystem (char *directory)
  539. {
  540.     ULONG        lMap;
  541.     BYTE        bData[128];
  542.     BYTE        bName[3];
  543.     int            i;
  544.     char        *FName;
  545. #if defined (__os2_16__)
  546.     USHORT        cbData;
  547.     USHORT        nDrive;
  548. #define DosQueryCurrentDisk DosQCurDisk
  549. #else
  550.     ULONG        cbData;
  551.     ULONG        nDrive;
  552.     PFSQBUFFER2        pFSQ = (PFSQBUFFER2)bData;
  553. #endif
  554.  
  555.     if ( _osmode == DOS_MODE )
  556.     return FALSE;
  557.  
  558.     if (isalpha (directory[0]) && (directory[1] == ':'))
  559.     nDrive = toupper (directory[0]) - '@';
  560.     else
  561.     DosQueryCurrentDisk (&nDrive, &lMap);
  562.  
  563. /* Set up the drive name */
  564.  
  565.     bName[0] = (char) (nDrive + '@');
  566.     bName[1] = ':';
  567.     bName[2] = 0;
  568.  
  569.     cbData = sizeof (bData);
  570.  
  571. #if defined(__os2_16__)
  572.     if (DosQFSAttach (bName, 0, FSAIL_QUERYNAME, bData, &cbData, 0L))
  573. #else
  574.     if (DosQueryFSAttach (bName, 0, FSAIL_QUERYNAME, pFSQ, &cbData))
  575. #endif
  576.       return FALSE;
  577.  
  578. #if defined(__os2_16__)
  579.     FName = bData + (*((USHORT *) (bData + 2)) + 7);
  580. #else
  581.     FName = pFSQ->szName + pFSQ->cbName + 1;
  582. #endif
  583.  
  584.     if (strcmp(FName, "HPFS"))
  585.       return FALSE;
  586.     return(TRUE);
  587. }
  588.  
  589.  
  590. /* Code for EAs */
  591.  
  592. #if defined(__os2_16__)
  593. /* Variables and data structures used for handling EA's, these are
  594.    defined in the 32 BIT API, so these will be included in os2.h */
  595.  
  596. typedef USHORT APIRET;
  597. typedef struct _FEA2         /* fea2 */
  598.         {
  599. #if 0            /* This field is in the 32 bit structure */
  600.         ULONG oNextEntryOffset;        /* New field */
  601. #endif
  602.         BYTE fEA;
  603.         BYTE cbName;
  604.         USHORT cbValue;
  605.         CHAR szName[1];                /* New field */
  606.         } FEA2;
  607. typedef FEA2 *PFEA2;
  608.  
  609. typedef struct _FEA2LIST        /* fea2l */
  610.         {
  611.         ULONG cbList;
  612.         FEA2 list[ 1 ];
  613.         } FEA2LIST;
  614.  
  615. typedef FEA2LIST *PFEA2LIST;
  616.  
  617. typedef struct _GEA2            /* gea2 */
  618.         {
  619. #if 0
  620.         /* New field - in the 32 bit structure */
  621.         ULONG oNextEntryOffset;
  622. #endif /* OS2_32 */
  623.         BYTE cbName;
  624.         CHAR szName[ 1 ];        /* New field */
  625.         } GEA2;
  626.  
  627. typedef GEA2 *PGEA2;
  628.  
  629. typedef struct _GEA2LIST        /* gea2l */
  630.         {
  631.         ULONG cbList;
  632.         GEA2 list[ 1 ];
  633.         } GEA2LIST;
  634.  
  635. typedef GEA2LIST *PGEA2LIST;
  636.  
  637. typedef struct _EAOP2            /* eaop2 */
  638.         {
  639.         PGEA2LIST fpGEA2List;    /* GEA set */
  640.         PFEA2LIST fpFEA2List;    /* FEA set */
  641.         ULONG oError;            /* Offset of FEA error */
  642.         } EAOP2;
  643.  
  644. /* typedef EAOP2 *PEAOP2; */
  645.  
  646. #define DosSetPathInfo(PathName, PathInfoLevel, PathInfoBuf, \
  647.                PathInfoBufSize, PathInfoFlags) \
  648.         DosSetPathInfo(PathName, PathInfoLevel, PathInfoBuf, \
  649.                PathInfoBufSize, PathInfoFlags, 0)
  650. #define DosQueryPathInfo(PathName, PathInfoLevel, PathInfoBuf, \
  651.              PathInfoBufSize) \
  652.         DosQPathInfo(PathName, PathInfoLevel, PathInfoBuf, PathInfoBufSize, 0)
  653. #define DosEnumAttribute(RefType, FileRef, EntryNum, EnumBuf, \
  654.              EnumBufSize, EnumCnt, InfoLevel) \
  655.         DosEnumAttribute(RefType, FileRef, EntryNum, EnumBuf, \
  656.              EnumBufSize, EnumCnt, InfoLevel, 0)
  657. #endif
  658.  
  659. /* The HoldFEA is used to hold individual EAs.  The member names correspond
  660.    directly to those of the FEA structure.  Note however, that both szName
  661.    and aValue are pointers to the values.  An additional field, next, is
  662.    used to link the HoldFEA's together to form a linked list. */
  663.  
  664. struct _HoldFEA
  665.     {
  666.     BYTE fEA;                    /* Flag byte */
  667.     BYTE cbName;
  668.     USHORT cbValue;
  669.     CHAR *szName;
  670.     BYTE *aValue;
  671.     struct _HoldFEA *next;
  672.     };
  673.  
  674. typedef struct _HoldFEA HOLDFEA;
  675.  
  676. #define MAX_GEA                500L /* Max size for a GEA List */
  677. #define REF_ASCIIZ            1    /* Reference type for DosEnumAttribute */
  678.  
  679. #define GET_INFO_LEVEL1        1    /* Get info from SFT */
  680. #define GET_INFO_LEVEL2        2    /* Get size of FEAlist */
  681. #define GET_INFO_LEVEL3        3    /* Get FEAlist given the GEAlist */
  682. #define GET_INFO_LEVEL4        4    /* Get whole FEAlist */
  683. #define GET_INFO_LEVEL5        5    /* Get FSDname */
  684.  
  685. #define SET_INFO_LEVEL1        1    /* Set info in SFT */
  686. #define SET_INFO_LEVEL2        2    /* Set FEAlist */
  687.  
  688.  
  689. /* #define BufferSize 1024
  690. static char FileBuffer [BufferSize]; */
  691. static HOLDFEA *pHoldFEA;            /* EA linked-list pointer */
  692.  
  693. /* Free_FEAList (pFEA)
  694.    Frees the memory used by the linked list of HOLDFEA's pointed to by pFEA */
  695.  
  696. void Free_FEAList( HOLDFEA *pFEA )
  697.     {
  698.     HOLDFEA *next;    /* Holds the next field since we free the structure
  699.                        before reading the current next field */
  700.  
  701.     /* Step through the list freeing all the fields */
  702.     while( pFEA )
  703.         {
  704.         /* Free the fields of the struct */
  705.         next = pFEA->next;
  706.         if( pFEA->szName != NULL )
  707.             /* Free if non-NULL name */
  708.             free(pFEA->szName);
  709.         if( pFEA->aValue != NULL )
  710.             /* Free if non-NULL value */
  711.             free(pFEA->aValue);
  712.  
  713.         /* Free the pFEA struct itself and move on to the next field */
  714.         free(pFEA);
  715.         pFEA = next;
  716.         }
  717.     }
  718.  
  719. #if 0
  720. /* Read the EA type, this is stored at the start of the EA value */
  721.  
  722. ULONG getEAType( const CHAR *Value )
  723.     {
  724.     USHORT Type = *( USHORT * ) Value;
  725.  
  726.     return( Type );
  727.     }
  728.  
  729. /* Return the EA length, stored in pFEA, this done so that it is calculated
  730.    in only one place */
  731.  
  732. ULONG getEALength( const HOLDFEA *pFEA )
  733.     {
  734.     return( sizeof( FEA2 )
  735.             - sizeof( CHAR )    /* Don't include the first element of aValue */
  736.             + pFEA->cbName + 1    /* Length of ASCIIZ name */
  737.             + pFEA->cbValue );    /* The value length */
  738.     }
  739.  
  740. /* Set the first two words of the EA value, this is usually the
  741.    EA type and EA size in pFEA, from the values Type and Size */
  742.  
  743. void setEATypeSize( const HOLDFEA *pFEA, const USHORT Type, const USHORT Size )
  744.     {
  745.     USHORT *valPtr = ( USHORT * ) pFEA->aValue;
  746.     valPtr[ 0 ] = Type;
  747.     valPtr[ 1 ] = Size;
  748.     }
  749.  
  750. /* Read the first two words of the EA value, this is usually the
  751.    EA type and EA size in pFEA, into the Type and Size */
  752.  
  753. void getEATypeSize( const HOLDFEA *pFEA, USHORT *Type, USHORT *Size )
  754.     {
  755.     USHORT *valPtr = ( USHORT * ) pFEA->aValue;
  756.     *Type = valPtr[ 0 ];
  757.     *Size = valPtr[ 1 ];
  758.     }
  759.  
  760. /* Get the address of the EA value in pFEA, ie skip over the Type and Size */
  761.  
  762. void* getEADataVal (const HOLDFEA *pFEA)
  763.     {
  764.     /* Skip over the type and size */
  765.     return pFEA->aValue + 2 * sizeof ( USHORT );
  766.     }
  767. #endif
  768.  
  769. /* QueryEAs (szFileName)
  770.       find all EAs that file szFileName has
  771.       return these in the linked list of HOLDFEAs
  772.       if no EAs exist or the linked list cannot be created then
  773.       return NULL
  774.   This function is modelled after code from IBM's Toolkit */
  775.  
  776. HOLDFEA *QueryEAs( const CHAR *szFileName )
  777.     {
  778.     HOLDFEA *pHoldFEA;        /* The start of the linked list */
  779.  
  780.     CHAR *pAllocc = NULL;    /* Temp buffer used with DosEnumAttribute */
  781.     CHAR *pBigAlloc = NULL;    /* Temp buffer to hold each EA as it is read in */
  782.     USHORT cbBigAlloc = 0;
  783.  
  784.     ULONG ulEntryNum = 1;    /* Count of current EA to read (1-relative) */
  785.     ULONG ulEnumCnt;        /* Number of EAs for Enum to return, always 1 */
  786.  
  787.     HOLDFEA *pLastIn = 0;    /* Points to last EA added, so new EA can link    */
  788.     HOLDFEA *pNewFEA = NULL; /* Struct to build the new EA in                  */
  789.  
  790.     FEA2 *pFEA;                /* Used to read from Enum's return buffer */
  791.     GEA2LIST *pGEAList;        /* Ptr used to set up buffer for DosQueryPathInfo() */
  792.     EAOP2 eaopGet;            /* Used to call DosQueryPathInfo() */
  793.  
  794.     pAllocc = malloc( MAX_GEA );    /* Allocate room for a GEA list */
  795.     pFEA = ( FEA2 * ) pAllocc;
  796.     pHoldFEA = NULL;        /* Initialize the linked list */
  797.  
  798.     /* Loop through all the EA's adding them to the list */
  799.     while( TRUE )
  800.         {
  801.         ulEnumCnt = 1;        /* No of EAs to retrieve */
  802.         if( DosEnumAttribute( REF_ASCIIZ,    /* Read into EA name into */
  803.                               szFileName,    /* pAlloc Buffer */
  804.                               ulEntryNum, pAllocc, MAX_GEA, &ulEnumCnt,
  805.                               ( LONG ) GET_INFO_LEVEL1 ) )
  806.             break;    /* An error */
  807.  
  808.         /* Exit if all the EA's have been read */
  809.         if( ulEnumCnt != 1 )
  810.             break;
  811.  
  812.         /* Move on to next EA */
  813.         ulEntryNum++;
  814.  
  815.         /* Try and allocate the HoldFEA structure */
  816.         if( ( pNewFEA = malloc( sizeof( HOLDFEA ) ) ) == NULL )
  817.             {
  818.             free( pAllocc );
  819.             Free_FEAList( pHoldFEA );
  820.             return( NULL );
  821.             }
  822.  
  823.         /* Fill in the HoldFEA structure */
  824.         pNewFEA->cbName = pFEA->cbName;
  825.         pNewFEA->cbValue= pFEA->cbValue;
  826.         pNewFEA->fEA = pFEA->fEA;
  827.         pNewFEA->next = '\0'; 
  828. /*        pNewFEA->next = NULL; */
  829.  
  830.         /* Allocate the two arrays */
  831.         if( ( pNewFEA->szName = malloc( pFEA->cbName + 1 ) ) == NULL || \
  832.             ( pNewFEA->aValue = malloc( pFEA->cbValue ) ) == NULL )
  833.             {
  834.             /* Out of memory, clean up and exit */
  835.             if( pNewFEA->szName )
  836.                 free( pNewFEA->szName );
  837.             if( pNewFEA->aValue )
  838.                 free( pNewFEA->aValue );
  839.  
  840.             free( pAllocc );
  841.             free( pNewFEA );
  842.  
  843.             Free_FEAList( pHoldFEA );
  844.             return( NULL );
  845.             }
  846.  
  847.         /* Copy EA name across */
  848.         strcpy( pNewFEA->szName, pFEA->szName );
  849.         cbBigAlloc = sizeof( FEA2LIST ) + pNewFEA->cbName + 1 + pNewFEA->cbValue;
  850.                             /* +1 is for '\0' */
  851.         if( ( pBigAlloc = malloc( cbBigAlloc ) ) == NULL )
  852.             {
  853.             free( pNewFEA->szName );
  854.             free( pNewFEA->aValue );
  855.             free( pAllocc );
  856.             free( pNewFEA );
  857.             Free_FEAList( pHoldFEA );
  858.             return( NULL );
  859.             }
  860.  
  861.         /* Set up GEAlist structure */
  862.         pGEAList = ( GEA2LIST * ) pAllocc;
  863.         pGEAList->cbList = sizeof( GEA2LIST ) + pNewFEA->cbName;    /* + 1 for NULL */
  864. #ifndef __os2_16__
  865.         pGEAList->list[ 0 ].oNextEntryOffset = 0L;
  866. #endif
  867.         pGEAList->list[ 0 ].cbName = pNewFEA->cbName;
  868.         strcpy( pGEAList->list[ 0 ].szName, pNewFEA->szName );
  869.  
  870.         eaopGet.fpGEA2List = ( GEA2LIST FAR * ) pAllocc;
  871.         eaopGet.fpFEA2List = ( FEA2LIST FAR * ) pBigAlloc;
  872.  
  873.         eaopGet.fpFEA2List->cbList = cbBigAlloc;
  874.  
  875.         /* Get the complete EA info and copy the EA value */
  876.         DosQueryPathInfo( szFileName, FIL_QUERYEASFROMLIST, ( PVOID ) &eaopGet, \
  877.                           sizeof( EAOP2 ) );
  878.         memcpy( pNewFEA->aValue, \
  879.                 pBigAlloc + sizeof( FEA2LIST ) + pNewFEA->cbName, \
  880.                 pNewFEA->cbValue );
  881.  
  882.         /* Release the temp. Enum buffer */
  883.         free( pBigAlloc );
  884.  
  885.         /* Add to the list */
  886.         if( pHoldFEA == NULL )
  887.             pHoldFEA = pNewFEA;
  888.         else
  889.             pLastIn->next = pNewFEA;
  890.         pLastIn = pNewFEA;
  891.         }
  892.  
  893.     /* Free up the GEA buffer for DosEnum() */
  894.     free( pAllocc );
  895.  
  896.     return pHoldFEA;
  897.     }
  898.  
  899.  
  900. /* WriteEAs(szFileName, pHoldFEA)
  901.  
  902.    Write the EAs contained in the linked list pointed to by pHoldFEA
  903.    to the file szFileName.
  904.  
  905.    Returns TRUE if the write was successful, FALSE otherwise */
  906.  
  907. int WriteEAs( const char *szFileName, HOLDFEA *pHoldFEA )
  908. {
  909.   HOLDFEA *pHFEA = pHoldFEA;
  910.   EAOP2 eaopWrite;
  911.   CHAR *aPtr = NULL;
  912.   USHORT usMemNeeded;
  913.   APIRET rc;
  914.  
  915.   eaopWrite.fpGEA2List = NULL;
  916.   while( pHFEA )                                  /* Go through each HoldFEA */
  917.     {
  918.       usMemNeeded = sizeof( FEA2LIST ) + pHFEA->cbName + 1 + pHFEA->cbValue;
  919.  
  920.       if( ( aPtr = malloc( usMemNeeded ) ) == NULL )
  921.     return FALSE;
  922.       
  923.       /* Fill in eaop structure */
  924.       eaopWrite.fpFEA2List = ( FEA2LIST FAR * ) aPtr;
  925.       eaopWrite.fpFEA2List->cbList = usMemNeeded;
  926. #ifdef __os2_16__  /* ugly hack for difference in 16-bit FEA struct */
  927.       eaopWrite.fpFEA2List->cbList -= ( sizeof(FEA2LIST) - sizeof(FEALIST) );
  928. #else
  929.       eaopWrite.fpFEA2List->list[ 0 ].oNextEntryOffset = 0L;
  930. #endif
  931.       eaopWrite.fpFEA2List->list[ 0 ].fEA = pHFEA->fEA;
  932.       eaopWrite.fpFEA2List->list[ 0 ].cbName = pHFEA->cbName;
  933.       eaopWrite.fpFEA2List->list[ 0 ].cbValue = pHFEA->cbValue;
  934.       strcpy( eaopWrite.fpFEA2List->list[ 0 ].szName, pHFEA->szName );
  935.       memcpy( eaopWrite.fpFEA2List->list[ 0 ].szName + pHFEA->cbName + 1, \
  936.          pHFEA->aValue, pHFEA->cbValue );
  937.  
  938.       /* Write out the EA */
  939.       rc = DosSetPathInfo( szFileName, FIL_QUERYEASIZE,
  940.                  ( PVOID ) &eaopWrite, sizeof( EAOP2 ),
  941.                  DSPI_WRTTHRU );
  942.  
  943.       /* Free up the FEALIST struct */
  944.       free( aPtr );
  945.       
  946.       /* If the write failed, leave now */
  947.       if( rc )
  948.     return FALSE;
  949.       
  950.       pHFEA = pHFEA->next;
  951.     }
  952.   
  953.   return( TRUE );
  954. }
  955.  
  956.