home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / epm603b.zip / EPMCSAMP.ZIP / EPMCSAMP / SRC / EPMCSAMP.C < prev    next >
C/C++ Source or Header  |  1995-11-10  |  31KB  |  740 lines

  1. #define OS2VERSION 20      /* Must be 20 for 32-bit EPM */
  2. #define INCL_DOSFILEMGR   /* File Manager values */
  3. #include <EDLL.h>
  4.  
  5. #include <stdio.h>  /* Needed for sprintf() prototype */
  6.  
  7. #define DEFAULT_HIGHLIGHT_COLOR  ((DOSCOLOR_MAGENTA << 4) + DOSCOLOR_YELLOW)
  8.  
  9.    /* lstrcpy() copies one LSTRING to another */
  10. #if 0  /* Lowest overhead, but no type-checking */
  11.   #define lstrcpy(dst, src) memcpy((dst), (src), sizeofLSTRING((src)->lsLength))
  12. #else  /* Let's stick with the safer version... */
  13.   _Inline VOID lstrcpy(PLSTRING dst, PLSTRING src) {
  14.      memcpy(dst, src, sizeofLSTRING(src->lsLength));
  15.   }
  16. #endif
  17.  
  18.  
  19. typedef struct _save_pos {
  20.    ULONG  line;
  21.    ULONG  col;
  22.    ULONG  cx;
  23.    ULONG  cy;
  24. } SAVE_POS, * PSAVE_POS;
  25.  
  26.    /* Forward declarations */
  27. BOOL is_substr(PSZ word, PLSTRING line);
  28. VOID lstrupcase( PLSTRING s );
  29. VOID save_pos( HWND, PSAVE_POS );
  30. VOID restore_pos( HWND, PSAVE_POS );
  31. BOOL _Optlink lstreq_test( const PLSTRING s1, const PLSTRING s2);
  32.  
  33. /* Execute a given command against each file in the ring. */
  34. ULONG EXPENTRY Each( HWND hwndClient, PSZ command) {
  35.    ULONG start_fid, end_fid;
  36.    ULONG curr_fid = (ULONG)-1;
  37.    BOOL is_visible;
  38.    SHORT rc;
  39.  
  40.    EtkQueryFileID( hwndClient, &start_fid);
  41.    end_fid = start_fid;
  42.    EtkQueryFileField( hwndClient, VISIBLE_FIELD, 0 /*Fileid*/, (PLONG)&is_visible);
  43.    /* NB:  If initial file is not visible, we'll never get back to it,  */
  44.    /* and we'll loop forever.  Not a good idea.  So, we check the       */
  45.    /* .visible flag of the first file.                                  */
  46.    do {
  47.       rc = EtkExecuteCommand( hwndClient, command);
  48.       #ifdef DEBUG
  49.        {
  50.          unsigned char Text[256];
  51.          PLSTRING pFilename;
  52.          EtkQueryFileField( hwndClient, FILENAME_FIELD, 0 /*Fileid*/, (PLONG)&pFilename);
  53.          sprintf(Text, "Got rc %ld for file \"%.*s\"", rc, pFilename->lsLength, pFilename->Data);
  54.          WinMessageBox(HWND_DESKTOP,
  55.                        hwndClient,
  56.                        Text,
  57.                        "EPMCSAMP - Each",
  58.                        0L,
  59.                        MB_OK + MB_MOVEABLE);
  60.        }
  61.       #endif
  62.       EtkProcessEditKey( hwndClient, ETK_NEXT_FILE, 1);
  63.       /* If first file was not visible, and we've already been through */
  64.       /* the loop once, save the "curr_file" we got the last time as   */
  65.       /* the new "end_file".  Then set the "is_visible" flag to 1      */
  66.       /* so that we don't bother with this stuff again.                */
  67.       if ((!is_visible) && curr_fid != (ULONG)-1) {
  68.          end_fid = curr_fid;
  69.          is_visible = 1;
  70.       } /* endif */
  71.       EtkQueryFileID( hwndClient, &curr_fid);
  72.    } while ( end_fid != curr_fid ); /* enddo */
  73.    /* Force activation of original fileid, in case it was a hidden file. */
  74.    WinSendMsg(hwndClient, EPM_EDIT_ACTIVATEFILEID, MPFROMLONG(start_fid), 0);
  75. }
  76.  
  77. /* Query the timestamp of the current or specified file. */
  78. ULONG EXPENTRY QTS( HWND hwndClient, PSZ filename) {
  79.    UCHAR         zFileName[261];
  80.    UCHAR         edit_cmd[200];
  81.    PSZ           fn_ptr;
  82.    HDIR          FindHandle;
  83.    FILEFINDBUF3  FindBuffer;
  84.    ULONG         FindCount;
  85.    APIRET        rc;           /* Return code */
  86.  
  87.    if (strlen(filename)) {
  88.       fn_ptr = filename;
  89.    } else {
  90.       PLSTRING lstr_ptr;
  91.       EtkQueryFileField( hwndClient, FILENAME_FIELD, 0 /*Fileid*/, (PLONG)&lstr_ptr);
  92.       memcpy(zFileName, lstr_ptr->Data, lstr_ptr->lsLength);
  93.       zFileName[lstr_ptr->lsLength] = '\0';
  94.       fn_ptr = zFileName;
  95.    } /* endif */
  96.  
  97.    FindHandle = 0x0001;
  98.    FindCount = 1;
  99.  
  100.    rc = DosFindFirst(fn_ptr,                /* File pattern */
  101.                      &FindHandle,           /* Directory search handle */
  102.                      0,                     /* Search attribute */
  103.                      (PVOID) &FindBuffer,   /* Result buffer */
  104.                      sizeof(FindBuffer),    /* Result buffer length */
  105.                      &FindCount,            /* # of entries to find */
  106.                      FIL_STANDARD);         /* Return level 1 file info */
  107.  
  108.    if (rc != 0) {
  109.       sprintf(edit_cmd, "sayerror DosFindFirst error: return code = %ld", rc);
  110.    } else if (!FindBuffer.fdateCreation.month) { /* FAT file system */
  111.       sprintf(edit_cmd, "sayerror Last written %04hu/%02hu/%02hu %02hu:%02hu:%02hu",
  112.               FindBuffer.fdateLastWrite.year + 1980,
  113.               FindBuffer.fdateLastWrite.month,
  114.               FindBuffer.fdateLastWrite.day,
  115.               FindBuffer.ftimeLastWrite.hours,
  116.               FindBuffer.ftimeLastWrite.minutes,
  117.               FindBuffer.ftimeLastWrite.twosecs << 1);
  118.    } else {
  119.       sprintf(edit_cmd, "sayerror Created %04hu/%02hu/%02hu %02hu:%02hu:%02hu  Last accessed %04hu/%02hu/%02hu %02hu:%02hu:%02hu  Last written %04hu/%02hu/%02hu %02hu:%02hu:%02hu",
  120.               FindBuffer.fdateCreation.year + 1980,
  121.               FindBuffer.fdateCreation.month,
  122.               FindBuffer.fdateCreation.day,
  123.               FindBuffer.ftimeCreation.hours,
  124.               FindBuffer.ftimeCreation.minutes,
  125.               FindBuffer.ftimeCreation.twosecs << 1,
  126.               FindBuffer.fdateLastAccess.year + 1980,
  127.               FindBuffer.fdateLastAccess.month,
  128.               FindBuffer.fdateLastAccess.day,
  129.               FindBuffer.ftimeLastAccess.hours,
  130.               FindBuffer.ftimeLastAccess.minutes,
  131.               FindBuffer.ftimeLastAccess.twosecs << 1,
  132.               FindBuffer.fdateLastWrite.year + 1980,
  133.               FindBuffer.fdateLastWrite.month,
  134.               FindBuffer.fdateLastWrite.day,
  135.               FindBuffer.ftimeLastWrite.hours,
  136.               FindBuffer.ftimeLastWrite.minutes,
  137.               FindBuffer.ftimeLastWrite.twosecs << 1);
  138.    } /* endif */
  139.  
  140.    EtkExecuteCommand( hwndClient, edit_cmd);
  141. }
  142.  
  143. ULONG FindAllX( HWND hwndClient, PSZ command, BOOL case_insensitive);
  144.  
  145. /* Find the next occurrence of all of several words.  Case sensitive. */
  146. ULONG EXPENTRY FindAll( HWND hwndClient, PSZ command) {
  147.    return FindAllX( hwndClient, command, 0);
  148. }
  149. /* Find the next occurrence of all of several words.  Case-insensitive. */
  150. ULONG EXPENTRY FindAllC( HWND hwndClient, PSZ command) {
  151.    return FindAllX( hwndClient, command, 1);
  152. }
  153.  
  154. /* Find the next occurrence of all of several words.  */
  155. ULONG FindAllX( HWND hwndClient, PSZ command, BOOL case_insensitive) {
  156.    SHORT rc;
  157.    UCHAR locate_cmd[1600];
  158.    int   i, num_words=0;
  159.    PSZ   words[256];
  160.    ULONG linenum;
  161.    PLSTRING getText;
  162.    ATTRIBRECTYPE * getAttrs;
  163.    ATTRIBRECTYPE * getALAttr;
  164.    LSTRING local_copy;
  165.    BOOL success;
  166.  
  167.    words[0] = (PSZ)strtok(command, " ");
  168.    if (!words[0]) {
  169.       return 0;  /* No words?  Nothing to find... */
  170.    } /* endif */
  171.  
  172.    strcpy(locate_cmd, "xcom l \1");  /* Let's hope that ASCII 1 is a safe delimiter */
  173.    strcat(locate_cmd, words[0]);
  174.    if (case_insensitive) {
  175.       strcat(locate_cmd, "\1c");
  176.    } /* endif */
  177.  
  178.    /* We now overwrite word[0] ...  That's fine. */
  179.    while (words[num_words]=(PSZ)strtok(NULL, " ")) {
  180.       if (case_insensitive)
  181.          strupr(words[num_words]);
  182.       num_words++;
  183.    } /* endwhile */
  184.  
  185.    while (1) {
  186.       /* First do the locate, to find a line containing the first string. */
  187.       if (rc=EtkExecuteCommand( hwndClient, locate_cmd))
  188.          return rc;  /* Error; probably -273 == "String not found" */
  189.  
  190.       EtkQueryFileField( hwndClient, LINE_FIELD, 0 /*Fileid*/, (PLONG)&linenum);
  191.       EtkQueryText( hwndClient, 0 /*Fileid*/, linenum, &getText, &getAttrs, &getALAttr);
  192.       if (case_insensitive) {
  193.          /* Must make a copy, because getText points to the actual text line */
  194.          /* in the file buffer.  Can't be mucking with that!                 */
  195.          lstrcpy(&local_copy, getText);
  196.          getText = &local_copy;
  197.          lstrupcase(getText);
  198.       } /* endif */
  199.       for (i=num_words, success=1; i--; ) {      /* For each word after the first, */
  200.          if (!is_substr(words[i], getText)) {    /* if word not in this line,      */
  201.             success = 0;                         /* failure.                       */
  202.             break;                               /* So don't check the next word.  */
  203.          } /* endif */
  204.       } /* endfor */
  205.       if (success) {                             /* Did we make it through all?    */
  206.          return 0;                               /* Hurray - success!              */
  207.       } /* endif */
  208.       EtkProcessEditKey( hwndClient, ETK_END_LINE, 1);  /* Move to end of line for next search. */
  209.    } /* endwhile */
  210. }
  211.  
  212. /* Delete all lines containing a given string.  The Locate delimiters */
  213. /* and any desired options are passed as part of the argument string. */
  214. ULONG EXPENTRY Expunge( HWND hwndClient, PSZ locate_arg) {
  215.    UCHAR locate_cmd[1600];
  216.    ULONG count = 0;
  217.    SHORT rc;
  218.    SAVE_POS savepos;
  219.  
  220.    save_pos( hwndClient, &savepos );
  221.    strcpy(locate_cmd, "xcom l ");
  222.    strcat(locate_cmd, locate_arg);
  223.    if (rc=EtkExecuteCommand( hwndClient, locate_cmd))
  224.       return rc;  /* Error; probably -273 == "String not found" */
  225.    do {
  226.       EtkProcessEditKey( hwndClient, ETK_DELETE_LINE, 1);
  227.       count++;
  228.       EtkProcessEditKey( hwndClient, ETK_BEGIN_LINE, 1);
  229.    } while ( !EtkExecuteCommand( hwndClient, locate_cmd) ); /* enddo */
  230.    restore_pos( hwndClient, &savepos );
  231.    sprintf(locate_cmd, "sayerror Deleted %ld instance%s.", count, count==1 ? "" : "s");
  232.    EtkExecuteCommand( hwndClient, locate_cmd);
  233. }
  234.  
  235. /* Save a file w/o modifying the date. */
  236. ULONG EXPENTRY SaveOld( HWND hwndClient, PSZ filename) {
  237.    UCHAR         zFileName[261];
  238.    UCHAR         edit_cmd[200];
  239.    PSZ           fn_ptr;
  240.    HDIR          FindHandle;
  241.    FILEFINDBUF3  FindBuffer;
  242.    FILESTATUS    FileInfoBuf;
  243.    ULONG         FindCount;
  244.    APIRET        rc;           /* Return code */
  245.    HFILE         EPM_handle, our_handle;
  246.  
  247.    strcpy(edit_cmd, "save");
  248.    if (strlen(filename)) {
  249.       fn_ptr = filename;
  250.    } else {
  251.       PLSTRING lstr_ptr;
  252.       EtkQueryFileField( hwndClient, FILENAME_FIELD, 0 /*Fileid*/, (PLONG)&lstr_ptr);
  253.       memcpy(zFileName, lstr_ptr->Data, lstr_ptr->lsLength);
  254.       zFileName[lstr_ptr->lsLength] = '\0';
  255.       fn_ptr = zFileName;
  256.       strcat(edit_cmd, " ");
  257.       strcat(edit_cmd, fn_ptr);
  258.    } /* endif */
  259.  
  260.    FindHandle = 0x0001;
  261.    FindCount = 1;
  262.  
  263.    rc = DosFindFirst(fn_ptr,                /* File pattern */
  264.                      &FindHandle,           /* Directory search handle */
  265.                      0,                     /* Search attribute */
  266.                      (PVOID) &FindBuffer,   /* Result buffer */
  267.                      sizeof(FindBuffer),    /* Result buffer length */
  268.                      &FindCount,            /* # of entries to find */
  269.                      FIL_STANDARD);         /* Return level 1 file info */
  270.  
  271.    if (rc != 0) {
  272.       sprintf(edit_cmd, "sayerror DosFindFirst error: return code = %ld", rc);
  273.       EtkExecuteCommand( hwndClient, edit_cmd);
  274.       return rc;
  275.    } /* endif */
  276.    rc = EtkExecuteCommand( hwndClient, edit_cmd);
  277.    if (rc != 0) {  /* Error saving; don't continue. */
  278.       return rc;
  279.    } /* endif */
  280.    EtkQueryFileField( hwndClient, LOCKHANDLE_FIELD, 0 /*Fileid*/, (PLONG)&EPM_handle);
  281.    if (!EPM_handle) {  /* If file not locked (Edit /K), we need to open it. */
  282.       ULONG   Action;
  283.       rc = DosOpen(fn_ptr,                  /* File path name */
  284.                    &our_handle,             /* File handle */
  285.                    &Action,                 /* Action taken */
  286.                    0,                       /* File primary allocation */
  287.                    0,                       /* File attribute */
  288.                    OPEN_ACTION_FAIL_IF_NEW |
  289.                    OPEN_ACTION_OPEN_IF_EXISTS,  /* Open function type */
  290.                    OPEN_SHARE_DENYREADWRITE |
  291.                    OPEN_ACCESS_READWRITE,       /* Open mode of the file */
  292.                    0);                      /* No extended attributes */
  293.       if (rc != 0) {
  294.           sprintf(edit_cmd, "sayerror DosOpen error: return code = %ld", rc);
  295.           EtkExecuteCommand( hwndClient, edit_cmd);
  296.           return rc;
  297.       } /* endif */
  298.    } else {
  299.       our_handle = EPM_handle;
  300.    } /* endif */
  301.  
  302.    rc = DosQueryFileInfo(our_handle, 1, &FileInfoBuf, sizeof(FileInfoBuf) );
  303.                          /* Obtain a copy of the Level 1 */
  304.                          /*   file information           */
  305.  
  306.    if (rc != 0) {
  307.        sprintf(edit_cmd, "sayerror DosQueryFileInfo error: return code = %ld", rc);
  308.        EtkExecuteCommand( hwndClient, edit_cmd);
  309.       if (!EPM_handle) DosClose(our_handle);
  310.        return rc;
  311.    } /* endif */
  312.  
  313.    FileInfoBuf.fdateCreation.year =        FindBuffer.fdateCreation.year;
  314.    FileInfoBuf.fdateCreation.month =       FindBuffer.fdateCreation.month;
  315.    FileInfoBuf.fdateCreation.day =         FindBuffer.fdateCreation.day;
  316.    FileInfoBuf.ftimeCreation.hours =       FindBuffer.ftimeCreation.hours;
  317.    FileInfoBuf.ftimeCreation.minutes =     FindBuffer.ftimeCreation.minutes;
  318.    FileInfoBuf.ftimeCreation.twosecs =     FindBuffer.ftimeCreation.twosecs;
  319.    FileInfoBuf.fdateLastAccess.year =      FindBuffer.fdateLastAccess.year;
  320.    FileInfoBuf.fdateLastAccess.month =     FindBuffer.fdateLastAccess.month;
  321.    FileInfoBuf.fdateLastAccess.day =       FindBuffer.fdateLastAccess.day;
  322.    FileInfoBuf.ftimeLastAccess.hours =     FindBuffer.ftimeLastAccess.hours;
  323.    FileInfoBuf.ftimeLastAccess.minutes =   FindBuffer.ftimeLastAccess.minutes;
  324.    FileInfoBuf.ftimeLastAccess.twosecs =   FindBuffer.ftimeLastAccess.twosecs;
  325.    FileInfoBuf.fdateLastWrite.year =       FindBuffer.fdateLastWrite.year;
  326.    FileInfoBuf.fdateLastWrite.month =      FindBuffer.fdateLastWrite.month;
  327.    FileInfoBuf.fdateLastWrite.day =        FindBuffer.fdateLastWrite.day;
  328.    FileInfoBuf.ftimeLastWrite.hours =      FindBuffer.ftimeLastWrite.hours;
  329.    FileInfoBuf.ftimeLastWrite.minutes =    FindBuffer.ftimeLastWrite.minutes;
  330.    FileInfoBuf.ftimeLastWrite.twosecs =    FindBuffer.ftimeLastWrite.twosecs;
  331.  
  332.    rc = DosSetFileInfo(our_handle, 1, &FileInfoBuf, sizeof(FileInfoBuf) );
  333.    if (rc != 0) {
  334.        sprintf(edit_cmd, "sayerror DosSetFileInfo error: return code = %ld", rc);
  335.        EtkExecuteCommand( hwndClient, edit_cmd);
  336.    } /* endif */
  337.  
  338.    if (!EPM_handle)           /* If we opened the file ourself, */
  339.       DosClose(our_handle);   /* we must close it. */
  340.  
  341.    return rc;
  342. }
  343.  
  344. /* Simple demo using EtkAccessLowLevelData, which returns a pointer    */
  345. /* into the line array at the first line for the specified file.       */
  346. ULONG EXPENTRY test( HWND hwndClient, PSZ string) {
  347.    ULONG this_fid, last_line;
  348.    UCHAR text[200];
  349.    PLSTRING * SubLineArray;
  350.    PLSTRING firstline;
  351.    PLSTRING lastline;
  352.    EtkQueryFileID( hwndClient, &this_fid);
  353.       /* N.B.:  EtkAccessLowLevelData doesn't accept 0 to mean "current file". */
  354.    EtkAccessLowLevelData( hwndClient, this_fid, (PPVOID)&SubLineArray);
  355.    firstline = SubLineArray[0];
  356.    EtkQueryFileField( hwndClient, LAST_FIELD, 0 /*Fileid*/, (PLONG)&last_line);
  357.    lastline = SubLineArray[last_line-1];
  358.    sprintf(text, "  Line 1 = SubLineArray[0] =\n%.*s\n\n  Line %ld = SubLineArray[%ld] =\n%.*s",
  359.            min(firstline->lsLength, 40), firstline->Data,
  360.            last_line,
  361.            last_line - 1,
  362.            min(lastline->lsLength, 40), lastline->Data);
  363.    WinMessageBox(HWND_DESKTOP,
  364.                  hwndClient,
  365.                  text,
  366.                  "EPMCSAMP - test",
  367.                  0L,
  368.                  MB_OK + MB_MOVEABLE);
  369. }
  370.  
  371. /* Find the next duplicated line.                                      */
  372. LONG EXPENTRY FindDup( HWND hwndClient, PSZ string) {
  373.    ULONG this_fid, this_line, last_line;
  374.    PLSTRING * SubLineArray;
  375.    EtkQueryFileID( hwndClient, &this_fid);
  376.       /* N.B.:  EtkAccessLowLevelData doesn't accept 0 to mean "current file". */
  377.    EtkAccessLowLevelData( hwndClient, this_fid, (PPVOID)&SubLineArray);
  378.    EtkQueryFileField( hwndClient, LINE_FIELD, 0 /*Fileid*/, (PLONG)&this_line);
  379.    EtkQueryFileField( hwndClient, LAST_FIELD, 0 /*Fileid*/, (PLONG)&last_line);
  380.    /* Convert from 1-based to 0-based */
  381.    if (this_line)  this_line--;  /* Except if on line 0, don't decrement. */
  382.    last_line--;
  383.    while (this_line<last_line) {
  384.       if (lstreq_test(SubLineArray[this_line], SubLineArray[this_line+1])) {
  385.          EtkSetFileField( hwndClient, LINE_FIELD, 0 /*Fileid*/, (PVOID)(this_line+1));
  386.          return 0;
  387.       } /* endif */
  388.       this_line++;
  389.    } /* endwhile */
  390.    EtkExecuteCommand( hwndClient, "sayerror Duplicate line not found.");
  391.    return -273;  /* Return "String not found" rc. */
  392. }
  393.  
  394. /* Highlight all instances of a given string.                           */
  395. ULONG EXPENTRY Highlight( HWND hwndClient, PSZ search_str) {
  396.    SHORT rc;
  397.    UCHAR locate_cmd[1600];
  398.    UCHAR attrib_cmd[100];
  399.    int   num_hits=0;
  400.    ULONG col, len, linenum, attrib_level, modify_count;
  401.    SAVE_POS savepos;
  402.  
  403.    if (!strlen(search_str)) {  /* Nothing to find? */
  404.       EtkExecuteCommand( hwndClient, "sayerror Missing argument.");
  405.       return (ULONG) -268;  /* "Procedure needs more arguments" */
  406.    } /* endif */
  407.  
  408.    strcpy(locate_cmd, "xcom l ");
  409.    strcat(locate_cmd, search_str);
  410.  
  411.    save_pos( hwndClient, &savepos );
  412.    EtkQueryFileField( hwndClient, MODIFY_FIELD, 0 /*Fileid*/, (PLONG)&modify_count);
  413.  
  414.    while (1) {
  415.       if (rc=EtkExecuteCommand( hwndClient, locate_cmd)) {
  416.          if (num_hits) {
  417.             restore_pos( hwndClient, &savepos );
  418.             EtkQueryFileField( hwndClient, ATTRIBUTE_SUPPORT_LEVEL, 0 /*Fileid*/, (PLONG)&attrib_level);
  419.             if (!(attrib_level&EPM_DM_COLOR))  /* Make sure that color support is on */
  420.                EtkSetFileField( hwndClient, ATTRIBUTE_SUPPORT_LEVEL, 0, (PVOID)(attrib_level|EPM_DM_COLOR));
  421.             EtkSetFileField( hwndClient, MODIFY_FIELD, 0 /*Fileid*/, (PVOID)modify_count);
  422.             sprintf(locate_cmd, "sayerror %ld hit%s.", num_hits, num_hits==1 ? "" : "s");
  423.             EtkExecuteCommand( hwndClient, locate_cmd);
  424.             return num_hits;
  425.          } else {
  426.             return rc;  /* Error; probably -273 == "String not found" */
  427.          } /* endif */
  428.       } /* endif */
  429.  
  430.       num_hits++;
  431.       EtkGetPMInfo(hwndClient, SEARCHPOS, &col);
  432.       EtkGetPMInfo(hwndClient, LSLENGTH, &len);
  433.       EtkQueryFileField( hwndClient, LINE_FIELD, 0 /*Fileid*/, (PLONG)&linenum);
  434.  
  435.       sprintf(attrib_cmd, "Insert_attr_val_Pair %ld %ld %ld %ld %ld %ld",
  436.               (ULONG)COLORCLASS,                      /* Class          */
  437.               DEFAULT_HIGHLIGHT_COLOR,                /* Attrib. value  */
  438.               linenum,                                /* First line     */
  439.               linenum,                                /* Last line      */
  440.               col,                                    /* First column   */
  441.               col+len-1);                             /* Last column    */
  442.       EtkExecuteCommand( hwndClient, attrib_cmd);
  443.  
  444.    /* EtkProcessEditKey( hwndClient, ETK_REPEAT_FIND, 1);     */
  445.    /* 1.  We can't get the RC from a repeat_find op, and      */
  446.    /* 2.  If [E]GREP is used, we might get a hit on the same  */
  447.    /*     string multiple times.  Do another Locate, instead. */
  448.       EtkSetFileField( hwndClient, COL_FIELD, 0, (PVOID)(col+len));  /* Move col. past "hit" */
  449.    } /* endwhile */
  450. }
  451.  
  452. /* Remove highlighting added by Highlight command.            */
  453. ULONG EXPENTRY UnHighlight( HWND hwndClient, PSZ search_str) {
  454.    ULONG this_fid, last_line, modify_count, rc;
  455.    ULONG AttrCount;
  456.    PLSTRING sp;
  457.    ATTRIBRECTYPE * FirstAttribute;
  458.    ATTRIBRECTYPE * AfterLastAttribute;
  459.    CHAR pBuffer[2000];
  460.    PATTRSTRING pAttrString = (PATTRSTRING)pBuffer ;
  461.    ATTRIBVALUETYPE color;
  462.  
  463.  #ifdef DEBUG
  464.    UCHAR text[100];
  465.  #endif
  466.  
  467.    color = (ATTRIBVALUETYPE)atoi(search_str);
  468.    if (!color) {
  469.       color = DEFAULT_HIGHLIGHT_COLOR;
  470.    } /* endif */
  471.    EtkQueryFileField( hwndClient, MODIFY_FIELD, 0 /*Fileid*/, (PLONG)&modify_count);
  472. /* EtkQueryFileID( hwndClient, &this_fid); */
  473.    EtkQueryFileField( hwndClient, LAST_FIELD, 0 /*Fileid*/, (PLONG)&last_line);
  474.  
  475.    do {
  476.       rc = EtkQueryText(hwndClient,
  477.                         0,  /* fileid */
  478.                         last_line,
  479.                         &sp,
  480.                         &FirstAttribute,
  481.                         &AfterLastAttribute) ;
  482.       if (rc != 0 || !sp) return rc ;
  483.       AttrCount = (AfterLastAttribute - FirstAttribute) ; // Typed pointers, no need to divide by sizeof()
  484.    #ifdef DEBUG
  485.       sprintf(text, "line %ld has %ld attrib(s)\n\nFirst = 0x%lx\nLast = 0x%lx\n%.*s", last_line, AttrCount, FirstAttribute, AfterLastAttribute, sp->lsLength, sp->Data);
  486.       if (MBID_CANCEL ==
  487.           WinMessageBox(HWND_DESKTOP,
  488.                         hwndClient,
  489.                         text,
  490.                         "EPMCSAMP - UnHighlight",
  491.                         0L,
  492.                         MB_OK + MB_MOVEABLE))
  493.          break;
  494.    #endif
  495.       if (AttrCount) {
  496.          ULONG i, j ;
  497.          ULONG Found = 0;
  498.          ATTRIBRECTYPE * pattrArray = NULL ;
  499.          TERMTYPE terminator;
  500.  
  501.          /* I'm guessing that it will be cheaper to first iterate and maybe */
  502.          /* have to iterate again than to just do it once.  This is because */
  503.          /* I'm guessing that most lines either won't have any attributes,  */
  504.          /* in which case this is trivial, or will have only attributes     */
  505.          /* added by the Highlight command, in which case we'll be removing */
  506.          /* them all, so there's no need to allocate and free a buffer into */
  507.          /* which we copy the ones we want to keep.                   LAM   */
  508.          for (i=0; i<AttrCount; i++) {
  509.             if (FirstAttribute[(USHORT)i].Class == COLORCLASS &&
  510.                 FirstAttribute[(USHORT)i].Value == color)
  511.                Found++;
  512.          }
  513.          if (!Found)               /* If no matching attributes,   */
  514.             continue;              /* nothing to do for this line. */
  515.  
  516.          EtkQueryLineTerminator(hwndClient,
  517.                                 0 /* fileid */,
  518.                                 last_line,
  519.                                 &terminator);
  520.  
  521.          if (Found==AttrCount) {  /* Delete them all. */
  522.             pAttrString->Attrs  = (ATTRIBRECTYPE*)&pBuffer[0] ;
  523.             pAttrString->ALAttr = (ATTRIBRECTYPE*)&pBuffer[0] ;
  524.          } else {  /* Have to keep some and delete some... */
  525.             pattrArray = (ATTRIBRECTYPE*)malloc((int)(Found)*sizeof(ATTRIBRECTYPE)) ;
  526.             for (i=j=0; i<AttrCount; i++) {
  527.                if (FirstAttribute[(USHORT)i].Class != COLORCLASS ||
  528.                    FirstAttribute[(USHORT)i].Value != color) {
  529.                   memcpy(&pattrArray[(USHORT)j], &FirstAttribute[(USHORT)i], sizeof(ATTRIBRECTYPE)) ;
  530.                   j++ ;
  531.                } /* endif */
  532.             }
  533.             pAttrString->Attrs  = &pattrArray[0] ;
  534.             pAttrString->ALAttr = &pattrArray[j] ;
  535.          } /* endif */
  536.  
  537.          //----------------------------------------------------------------------
  538.          // Update the current line
  539.          //----------------------------------------------------------------------
  540.          pAttrString->SelfPtr= (CHAR*)&pAttrString->SelfPtr ;
  541.          pAttrString->TextLen= sp->lsLength;
  542.          memcpy(&pAttrString->Text, sp->Data, sp->lsLength);
  543.          EtkReplaceText(hwndClient, 0 /*fid*/, last_line, &pAttrString, terminator);
  544.          if (pattrArray)
  545.             free(pattrArray);
  546.       } /* endif */
  547.    } while ( --last_line ); /* enddo */
  548.    EtkSetFileField( hwndClient, MODIFY_FIELD, 0 /*Fileid*/, (PVOID)modify_count);
  549. }
  550.  
  551. /*-------------------------- Utility functions --------------------------*/
  552.  
  553. VOID save_pos( HWND hwndClient, PSAVE_POS save_pos ) {
  554.    EtkQueryFileField( hwndClient, LINE_FIELD,    0 /*Fileid*/, (PLONG)&save_pos->line);
  555.    EtkQueryFileField( hwndClient, COL_FIELD,     0 /*Fileid*/, (PLONG)&save_pos->col );
  556.    EtkQueryFileField( hwndClient, CURSORX_FIELD, 0 /*Fileid*/, (PLONG)&save_pos->cx  );
  557.    EtkQueryFileField( hwndClient, CURSORY_FIELD, 0 /*Fileid*/, (PLONG)&save_pos->cy  );
  558.    #ifdef DEBUG
  559.     {
  560.       unsigned char Text[256];
  561.       PLSTRING pFilename;
  562.       sprintf(Text, "Saved column = %ld\nSaved CX = %ld", save_pos->col, save_pos->cx );
  563.       WinMessageBox(HWND_DESKTOP,
  564.                     hwndClient,
  565.                     Text,
  566.                     "EPMCSAMP - save_pos",
  567.                     0L,
  568.                     MB_OK + MB_MOVEABLE);
  569.     }
  570.    #endif
  571. }
  572.  
  573. VOID restore_pos( HWND hwndClient, PSAVE_POS save_pos ) {
  574.    ULONG  temp;
  575.    EtkSetFileField( hwndClient, CURSORY_FIELD, 0 /*Fileid*/,  (PVOID)save_pos->cy  );
  576.    EtkQueryFileField( hwndClient, LAST_FIELD, 0 /*Fileid*/, (PLONG)&temp);
  577.    #ifdef DEBUG
  578.     {
  579.       unsigned char Text[256];
  580.       sprintf(Text, ".last = %ld\nSaved line = %ld\min = %ld", temp, save_pos->line, min(temp, save_pos->line));
  581.       WinMessageBox(HWND_DESKTOP,
  582.                     hwndClient,
  583.                     Text,
  584.                     "EPMCSAMP - restore_pos",
  585.                     0L,
  586.                     MB_OK + MB_MOVEABLE);
  587.     }
  588.    #endif
  589.    temp = min(temp, save_pos->line);
  590.    EtkSetFileField( hwndClient, LINE_FIELD,    0 /*Fileid*/,  (PVOID)temp);
  591.    temp = MAXCOL;                        /* Set left edge of window */
  592.    EtkSetFileField( hwndClient, COL_FIELD,     0 /*Fileid*/,  (PVOID)temp );
  593.    temp = save_pos->col - save_pos->cx + 1;
  594.    #ifdef DEBUG
  595.     {
  596.       unsigned char Text[256];
  597.       sprintf(Text, "Saved column = %ld\nSaved CX = %ld\nCol - cx + 1 = %ld", save_pos->col, save_pos->cx, temp);
  598.       WinMessageBox(HWND_DESKTOP,
  599.                     hwndClient,
  600.                     Text,
  601.                     "EPMCSAMP - restore_pos",
  602.                     0L,
  603.                     MB_OK + MB_MOVEABLE);
  604.     }
  605.    #endif
  606.    EtkSetFileField( hwndClient, COL_FIELD,     0 /*Fileid*/,  (PVOID)temp );
  607.                                          /* Set column */
  608.    EtkSetFileField( hwndClient, COL_FIELD,     0 /*Fileid*/,  (PVOID)save_pos->col );
  609. }
  610.  
  611.  
  612. #define Length lsLength
  613. BOOL is_substr(PSZ word, PLSTRING line)
  614. {
  615.    register SHORT  wlen;
  616.    register UCHAR  ch;
  617.    register PUCHAR ptr;
  618.    register PUCHAR end;
  619.  
  620.    if ( (line->Length) && (wlen=strlen(word)) && wlen <= line->Length) {
  621.       ptr = line->Data - 1;
  622.       end = line->Data + line->Length - wlen;
  623.       ch = word[0];
  624.       while (ptr=(PUCHAR)memchr(ptr+1, ch, end-ptr)) {  // Not end-ptr+1, since ptr is 1 below start pos
  625.          if (!memcmp(ptr, word, wlen)) {
  626.             return TRUE;
  627.          } /* endif */
  628.       } /* endwhile */
  629.    } /* endif */
  630.    return FALSE;
  631. }
  632.  
  633. VOID lstrupcase( PLSTRING s )
  634. { LSTRINGLENTYPE i;
  635.   for (i=s->Length; i; ){
  636.      i--;
  637.      s->Data[i]=toupper(s->Data[i]);
  638.   }
  639. }
  640.  
  641. BOOL _Optlink lstreq_test( const PLSTRING s1, const PLSTRING s2)
  642. {
  643. // The following checks both the length and the data, in one shot:
  644.    return(memcmp(s1,s2,s1->Length + LSTRINGLENTYPELEN)==0);
  645. }
  646.  
  647. ULONG _Optlink EtkInsertAttribute (HWND hwnd, ULONG ulFileId,
  648.                                    ULONG Line, SHORT Col,
  649.                                    ULONG ulAttributeClass, ULONG ulValue, BOOL bPush) {
  650. //------------------------------------------------------------------------------
  651. // This function inserts an attribute at the given position
  652. //------------------------------------------------------------------------------
  653.    ULONG rc ;
  654.    ATTRIBRECTYPE * pattrFirst = NULL ;
  655.    ATTRIBRECTYPE * pattrLast  = NULL ;
  656.    ATTRIBRECTYPE * pattrArray = NULL ;
  657.    ATTRIBRECTYPE * pattrNew   = NULL ;
  658.    PLSTRING pLine = (PLSTRING)0;
  659.    TERMTYPE terminator;
  660.    ULONG ulAttrCount ;
  661.    USHORT usLineLen ;
  662.  
  663.    rc = EtkQueryText(hwnd,
  664.                      ulFileId,
  665.                      Line,
  666.                      &pLine,
  667.                      &pattrFirst,
  668.                      &pattrLast) ;
  669.    if (rc != 0 || !pLine) return rc ;
  670.  
  671.    rc = EtkQueryLineTerminator(hwnd,
  672.                                ulFileId,
  673.                                Line,
  674.                                &terminator);
  675.  
  676.    usLineLen = min(pLine->lsLength, MAXCOL); // Pb in EtkReplaceText when line is too big !!
  677.  
  678.    //----------------------------------------------------------------------
  679.    // Allocate a new attribute structure containing all the current attributes
  680.    // and a an empty slot for the new attribute
  681.    //----------------------------------------------------------------------
  682.    {
  683.       // We want to know how many attributes we have before we add a new one
  684.       // Note: In a given line, all attributes are stored in pointers so that
  685.       // the following thing makes sense.
  686.       ulAttrCount = (pattrLast - pattrFirst) ; // Typed pointers, no need to divide by sizeof()
  687.       // Allocate enough memory for the existing attributes + one
  688.       pattrArray = (ATTRIBRECTYPE*)malloc((int)(ulAttrCount+1)*sizeof(ATTRIBRECTYPE)) ;
  689.       // Copy the original attributes
  690.       memcpy(pattrArray, pattrFirst, (int)ulAttrCount*sizeof(ATTRIBRECTYPE)) ;
  691.       // Initialize the 'new' attribute
  692.       pattrNew = &pattrArray[ulAttrCount] ;
  693.       // Check that there is no attribute whose column is greater than
  694.       // usCol. If there is one, we must shift a few things
  695.       {
  696.          ULONG i ;
  697.          BOOL bFound = FALSE ;
  698.          for (i=0; i<ulAttrCount; i++) {
  699.             if (pattrArray[(USHORT)i].Col > Col) { bFound = TRUE ; break ;} /* endif */
  700.          }
  701.          if (bFound) {
  702.             // Shift to the right
  703.             memmove(&pattrArray[(USHORT)i+1], &pattrArray[(USHORT)i], (ulAttrCount-i)*sizeof(ATTRIBRECTYPE)) ;
  704.             pattrNew = &pattrArray[(USHORT)i] ;
  705.          } /* endif */
  706.       }
  707.       // Zero the new attr
  708.       memset(pattrNew, 0, sizeof(ATTRIBRECTYPE)) ;
  709.    }
  710.    //----------------------------------------------------------------------
  711.    // Add a new attribute at the end
  712.    //----------------------------------------------------------------------
  713.    {
  714.       pattrNew->Col = Col ;
  715.  
  716.       pattrNew->Class  = (ATTRIBCLASSTYPE)ulAttributeClass ;
  717.       pattrNew->Value  = ulValue ;
  718.       pattrNew->IsPush = (UCHAR)(bPush) ;
  719.    }
  720.  
  721.    //----------------------------------------------------------------------
  722.    // Update the current line
  723.    //----------------------------------------------------------------------
  724.    {
  725.       CHAR pBuffer[2000];
  726.       PATTRSTRING pAttrString = (PATTRSTRING)pBuffer ;
  727.  
  728.       pAttrString->Attrs  = &pattrArray[0] ;
  729.       pAttrString->ALAttr = &pattrArray[ulAttrCount+1] ;
  730.       pAttrString->SelfPtr= (CHAR*)&pAttrString->SelfPtr ;
  731.       pAttrString->TextLen= usLineLen ;
  732.       memcpy(&pAttrString->Text, pLine->Data, usLineLen);
  733.       EtkReplaceText(hwnd, ulFileId, Line, &pAttrString, terminator);
  734.    }
  735.    // Cleanup:
  736.    //----------
  737.    free(pattrArray) ;
  738.    return 0 ;
  739. }
  740.