home *** CD-ROM | disk | FTP | other *** search
/ Languages Around the World / LanguageWorld.iso / language / japanese / win_prog / win_jwp / search.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-31  |  43.9 KB  |  1,538 lines

  1. /* Copyright (C) Stephen Chung, 1991-1993.  All rights reserved. */
  2.  
  3. #include "jwp.h"
  4.  
  5.  
  6. #define EXPBLOCKSIZE        10
  7. #define CURLYINDICATOR      0xff
  8.  
  9.  
  10. typedef enum {
  11.     T_ERROR = 0, T_TEXT, T_ESCAPE,
  12.     T_SOFTRETURN, T_HARDRETURN, T_TAB,
  13.     T_MATCHALL, T_MATCHONE, T_MATCHKANJI, T_MATCHASCII, T_MATCHKANA,
  14.     T_COMMA, T_NOT, T_BOL, T_EOL, T_DASH,
  15.     T_OPENPAREN, T_CLOSEPAREN, T_OPENBRACKET, T_CLOSEBRACKET,
  16.     T_OPENCURLY, T_CLOSECURLY
  17. } TOKEN;
  18.  
  19. static struct { char ascii; TOKEN token; } tokens[] = {
  20.     { ',',      T_COMMA },
  21.     { '!',      T_NOT },
  22.     { '^',      T_BOL },
  23.     { '$',      T_EOL },
  24.     { '-',      T_DASH },
  25.     { '*',      T_MATCHALL },
  26.     { '?',      T_MATCHONE },
  27.     { '(',      T_OPENPAREN },
  28.     { ')',      T_CLOSEPAREN },
  29.     { '[',      T_OPENBRACKET },
  30.     { '[',      T_OPENBRACKET },
  31.     { ']',      T_CLOSEBRACKET },
  32.     { ']',      T_CLOSEBRACKET },
  33.     { '{',      T_OPENCURLY },
  34.     { '}',      T_CLOSECURLY },
  35.     { '\\',     T_ESCAPE },
  36.     { 0,        T_ERROR }
  37. };
  38.  
  39. static struct { char esc; TOKEN token; } escapes[] = {
  40.     { 'n',      T_SOFTRETURN },     /* \n */
  41.     { 'p',      T_HARDRETURN },     /* \p */
  42.     { 't',      T_TAB },            /* \t */
  43.     { 'x',      T_MATCHKANA },      /* \x */
  44.     { 'k',      T_MATCHKANJI },     /* \k */
  45.     { 'a',      T_MATCHASCII },     /* \a */
  46.     { '\0',     T_ERROR }
  47. };
  48.  
  49. static char *CompileErrors[] = {
  50.     /* 0 */     "The character after the escape character is missing",
  51.     /* 1 */     "Special characters (\p, \n etc.) cannot be placed within square brackets",
  52.     /* 2 */     "You can only put a NOT symbol right AFTER the open bracket",
  53.     /* 3 */     "The closing bracket is missing",
  54.     /* 4 */     "You must enter something to search for",
  55.     /* 5 */     "The range is not correct",
  56.     /* 6 */     "There must be character(s) inside a pair of brackets",
  57.     /* 7 */     "Curly brackets must enclose the digit 1 - 9",
  58.     /* 8 */     "",
  59.     /* 9 */     "Internal Error.  Life is tough."
  60. };
  61.  
  62.  
  63. typedef struct RegexStruct {
  64.     TOKEN action;
  65.     LONG data;
  66.     POSITION startpos, endpos;
  67.     struct RegexStruct far *prev, far *next;
  68. } REGEX;
  69.  
  70. static REGEX far *Expression = NULL;
  71. static KANJI far *ExpText = NULL;
  72.  
  73. static KANJI far *ReplaceExp = NULL;
  74. static KANJI far *ReplaceText = NULL;
  75.  
  76. static struct {
  77.     int IgnoreCase:1;
  78.     int Regex:1;
  79.     int JASCII:1;
  80.     int WrapAround:1;
  81.     int WholeFile:1;
  82.     int NoConfirm:1;
  83. } SearchOptions = { 1, 0, 1, 0, 0, 0 };
  84.  
  85. BOOL FAR PASCAL SearchProc (HWND, WORD, WORD, LONG);
  86. BOOL FAR PASCAL ReplaceProc (HWND, WORD, WORD, LONG);
  87. BOOL FAR PASCAL ReplaceDlgProc (HWND, WORD, WORD, LONG);
  88. BOOL FAR PASCAL EditReplacementProc (HWND, WORD, WORD, LONG);
  89.  
  90. static KANJI far *Replacement = NULL;
  91.  
  92.  
  93.  
  94. static int FindToken (KANJI token)
  95. {
  96.     int i;
  97.     char ch;
  98.  
  99.     token &= 0x7f7f;
  100.  
  101.     if (ISKANJI(token)) {
  102.         ch = LOBYTE(TranslateJAscii(token, TRUE));
  103.         if (!ch) return (-1);
  104.     } else {
  105.         ch = LOBYTE(token);
  106.     }
  107.  
  108.     for (i = 0; tokens[i].token != T_ERROR; i++) {
  109.         if (tokens[i].ascii == ch) return (i);
  110.     }
  111.     return (-1);
  112. }
  113.  
  114.  
  115. static int FindEscape (KANJI escape)
  116. {
  117.     int i;
  118.  
  119.     if ('A' <= escape && escape <= 'Z') escape += 32;
  120.  
  121.     for (i = 0; escapes[i].token != T_ERROR; i++) {
  122.         if (escapes[i].esc == escape) return (i);
  123.     }
  124.     return (-1);
  125. }
  126.  
  127.  
  128. static void FreeRegex (REGEX far *rp)
  129. {
  130.     REGEX far *rp2;
  131.  
  132.     if (rp == NULL) return;
  133.  
  134.     for (; rp != NULL; ) {
  135.         switch (rp->action) {
  136.             case T_TEXT:
  137.                 FreeBlock(rp->data);
  138.                 break;
  139.  
  140.             case T_NOT:
  141.             case T_OPENBRACKET:
  142.             case T_OPENPAREN:
  143.             case T_OPENCURLY:
  144.                 FreeRegex((REGEX far *) rp->data);
  145.                 break;
  146.  
  147.             default:
  148.                 break;
  149.         }
  150.  
  151.         rp2 = rp->next;
  152.         FreeBlock(rp);
  153.         rp = rp2;
  154.     }
  155. }
  156.  
  157.  
  158.  
  159. #define RETURN_WITH_ERROR(x,y)  { FreeRegex(RegexChain); RegexChain = NULL; *OutStr = InStr + (x); *ErrorNum = (y); return (NULL); }
  160.  
  161.  
  162. static REGEX far *CompileBracketedString (UNIT far *InStr, UNIT far **OutStr, int *ErrorNum, BOOL not)
  163. {
  164.     int i, j, k, errornum;
  165.     KANJI kch;
  166.     KANJI far *kp;
  167.     REGEX far *RegexChain = NULL, far *rp;
  168.  
  169.     for (i = 0; InStr[i].kanji; i++) {
  170.         kch = InStr[i].kanji;
  171.         j = FindToken(kch);
  172.         if (j >= 0) {
  173.             switch (tokens[j].token) {
  174.                 case T_CLOSEBRACKET:
  175.                     if (RegexChain == NULL) RETURN_WITH_ERROR(i, 6);
  176.  
  177.                     *OutStr = InStr + i;
  178.                     return (RegexChain);
  179.  
  180.                 case T_ESCAPE:
  181.                     kch = InStr[++i].kanji;
  182.                     if (!kch) RETURN_WITH_ERROR(i, 0);
  183.                     k = FindEscape(kch);
  184.                     if (k >= 0) RETURN_WITH_ERROR(i, 1);
  185.                     break;
  186.  
  187.                 case T_NOT: {
  188.                     REGEX far *rpx;
  189.                     UNIT far *up;
  190.  
  191.                     if (!not) RETURN_WITH_ERROR(i, 2);
  192.                     rpx = CompileBracketedString(InStr + i + 1, &up, &errornum, FALSE);
  193.                     i = up - InStr;
  194.                     if (rpx == NULL) RETURN_WITH_ERROR(i, errornum);
  195.  
  196.                     /* Adds to it */
  197.  
  198.                     if (RegexChain == NULL) {
  199.                         RegexChain = rp = StructAlloc(REGEX);
  200.                         rp->action = T_NOT;
  201.                         rp->data = (LONG) rpx;
  202.                         rp->next = rp->prev = NULL;
  203.                     } else {
  204.                         rp->next = StructAlloc(REGEX);
  205.                         rp->next->prev = rp;
  206.                         rp = rp->next;
  207.                         rp->next = NULL;
  208.                         rp->action = T_NOT;
  209.                         rp->data = (LONG) rpx;
  210.                     }
  211.  
  212.                     *OutStr = up;
  213.                     return (RegexChain);        /* Success! */
  214.                 }
  215.             }
  216.         }
  217.  
  218.         not = FALSE;
  219.  
  220.         if (j < 0 || tokens[j].token != T_DASH) {
  221.             j = FindToken(InStr[i+1].kanji);
  222.         } else {
  223.             kch = 0;
  224.             i--;    /* Because it is i += 2 later on */
  225.             goto ItIsADash;
  226.         }
  227.  
  228.         if (j >= 0) {
  229.             switch (tokens[j].token) {
  230.                 ItIsADash:
  231.                 case T_DASH: {
  232.                     KANJI start, stop;
  233.  
  234.                     start = kch;
  235.                     i += 2;
  236.                     stop = InStr[i].kanji;
  237.                     if (!stop) RETURN_WITH_ERROR(i, 3);
  238.  
  239.                     j = FindToken(stop);
  240.                     if (j >= 0 && tokens[j].token == T_CLOSEBRACKET) {
  241.                         stop = 0xffff;  /* Maximum value */
  242.                         i--;
  243.                     } else if (j >= 0 && tokens[j].token == T_ESCAPE) {
  244.                         stop = InStr[++i].kanji;
  245.                         if (!stop) RETURN_WITH_ERROR(i, 3);
  246.                         k = FindEscape(stop);
  247.                         if (k >= 0) RETURN_WITH_ERROR(i, 1);
  248.                     }
  249.  
  250.                     //if (ISKANJI(start) && !ISKANJI(stop)) RETURN_WITH_ERROR(i, ?);
  251.                     //if (!ISKANJI(start) && ISKANJI(stop)) RETURN_WITH_ERROR(i, ?);
  252.  
  253.                     if (start > stop) RETURN_WITH_ERROR(i, 5);
  254.                     if (start == stop) {
  255.                         kch = start;
  256.                         goto StraightText;
  257.                     }
  258.  
  259.  
  260.                     /* Adds to it */
  261.  
  262.                     if (RegexChain == NULL) {
  263.                         RegexChain = rp = StructAlloc(REGEX);
  264.                         rp->action = T_DASH;
  265.                         rp->data = MAKELONG(start,stop);
  266.                         rp->next = rp->prev = NULL;
  267.                     } else {
  268.                         rp->next = StructAlloc(REGEX);
  269.                         rp->next->prev = rp;
  270.                         rp = rp->next;
  271.                         rp->next = NULL;
  272.                         rp->action = T_DASH;
  273.                         rp->data = MAKELONG(start,stop);
  274.                     }
  275.                     continue;
  276.                 }
  277.  
  278.             }
  279.         }
  280.  
  281.         /* Now, just a normal character */
  282.  
  283. StraightText:
  284.  
  285.         if (RegexChain == NULL) {
  286.             RegexChain = rp = StructAlloc(REGEX);
  287.             rp->action = T_TEXT;
  288.             kp = BlockAlloc(EXPBLOCKSIZE * sizeof(KANJI));
  289.             kp[0] = kch;
  290.             kp[1] = 0;
  291.             rp->data = (LONG) kp;
  292.             rp->next = rp->prev = NULL;
  293.         } else if (rp->action != T_TEXT) {
  294.             rp->next = StructAlloc(REGEX);
  295.             rp->next->prev = rp;
  296.             rp = rp->next;
  297.             rp->next = NULL;
  298.             rp->action = T_TEXT;
  299.             kp = BlockAlloc(EXPBLOCKSIZE * sizeof(KANJI));
  300.             kp[0] = kch;
  301.             kp[1] = 0;
  302.             rp->data = (LONG) kp;
  303.         } else {
  304.             kp = (KANJI far *) rp->data;
  305.             j = kanjilen(kp);
  306.             k = SegHeapGetSize(kp) / sizeof(KANJI);
  307.             if (j + 2 >= k) {
  308.                 kp = (KANJI far *) BlockRealloc(kp, (k + EXPBLOCKSIZE) * sizeof(KANJI));
  309.                 rp->data = (LONG) kp;
  310.             }
  311.             kp[j] = kch;
  312.             kp[j+1] = 0;
  313.         }
  314.     }
  315.  
  316.     RETURN_WITH_ERROR(i, 3);
  317. }
  318.  
  319.  
  320.  
  321. static BOOL CharInBracketed (KANJI ch, REGEX far *rp)
  322. {
  323.     int i;
  324.     KANJI far *kp;
  325.     KANJI start, stop;
  326.  
  327.     for (; rp != NULL; rp = rp->next) {
  328.         switch (rp->action) {
  329.             case T_TEXT:
  330.                 kp = (KANJI far *) rp->data;
  331.                 for (i = 0; kp[i]; i++) if (ch == kp[i]) return (TRUE);
  332.                 break;
  333.  
  334.             case T_NOT:
  335.                 return (!CharInBracketed(ch, (REGEX far *) rp->data));
  336.  
  337.             case T_DASH:
  338.                 start = LOWORD(rp->data);
  339.                 stop = HIWORD(rp->data);
  340.                 if (start <= ch && ch <= stop) return (TRUE);
  341.                 break;
  342.         }
  343.     }
  344.  
  345.     return (FALSE);
  346. }
  347.  
  348.  
  349.  
  350. static REGEX far *CompileText (UNIT far *InStr)
  351. {
  352.     int i, len;
  353.     REGEX far *rp;
  354.     KANJI far *kp;
  355.  
  356.     len = unitlen(InStr);
  357.  
  358.     if (len <= 0) return (NULL);
  359.  
  360.     rp = StructAlloc(REGEX);
  361.     rp->action = T_TEXT;
  362.  
  363.     kp = (KANJI far *) BlockAlloc((len + 5) * sizeof(KANJI));
  364.  
  365.     for (i = 0; i < len; i++) kp[i] = InStr[i].kanji;
  366.     kp[len] = 0;
  367.  
  368.     rp->data = (LONG) kp;
  369.     rp->prev = rp->next = NULL;
  370.  
  371.     return (rp);
  372. }
  373.  
  374.  
  375.  
  376. static REGEX far *CompileRegex (TOKEN action, UNIT far *InStr, UNIT far **OutStr, int *ErrorNum)
  377. {
  378.     int i, j, k, errornum;
  379.     KANJI kch;
  380.     REGEX far *RegexChain = NULL;
  381.     REGEX far *rp;
  382.     REGEX far *SubRegex;
  383.     KANJI far *kp;
  384.     UNIT far *up;
  385.     TOKEN token;
  386.  
  387.  
  388.     /* Now process the string */
  389.  
  390.     *OutStr = InStr;
  391.  
  392.     for (i = 0; ; i++) {
  393.         kch = InStr[i].kanji;
  394.         if (!kch) {
  395.             if (action != T_ERROR) RETURN_WITH_ERROR(i, 3) else break;
  396.         }
  397.  
  398.         j = FindToken(kch);
  399.  
  400.  
  401.         if (j < 0) {
  402.             /* Not a special character */
  403. TextMatch:  if (RegexChain == NULL) {
  404.                 RegexChain = rp = StructAlloc(REGEX);
  405.                 rp->action = T_TEXT;
  406.                 kp = BlockAlloc(EXPBLOCKSIZE * sizeof(KANJI));
  407.                 kp[0] = kch;
  408.                 kp[1] = 0;
  409.                 rp->data = (LONG) kp;
  410.                 rp->next = rp->prev = NULL;
  411.             } else if (rp->action != T_TEXT) {
  412.                 rp->next = StructAlloc(REGEX);
  413.                 rp->next->prev = rp;
  414.                 rp = rp->next;
  415.                 rp->next = NULL;
  416.                 rp->action = T_TEXT;
  417.                 kp = BlockAlloc(EXPBLOCKSIZE * sizeof(KANJI));
  418.                 kp[0] = kch;
  419.                 kp[1] = 0;
  420.                 rp->data = (LONG) kp;
  421.             } else {
  422.                 kp = (KANJI far *) rp->data;
  423.                 j = kanjilen(kp);
  424.                 k = SegHeapGetSize(kp) / sizeof(KANJI);
  425.                 if (j + 2 >= k) {
  426.                     kp = (KANJI far *) BlockRealloc(kp, (k + EXPBLOCKSIZE) * sizeof(KANJI));
  427.                     rp->data = (LONG) kp;
  428.                 }
  429.                 kp[j] = kch;
  430.                 kp[j+1] = 0;
  431.             }
  432.             continue;
  433.         }
  434.  
  435.         /* Now, it is a special character */
  436.  
  437.         if (action == T_OPENPAREN) {
  438.             if (tokens[j].token == T_CLOSEPAREN || tokens[j].token == T_COMMA) break;
  439.         } else if (action == T_OPENBRACKET) {
  440.             if (tokens[j].token == T_CLOSEBRACKET) break;
  441.         } else if (action == T_OPENCURLY) {
  442.             if (tokens[j].token == T_CLOSECURLY) break;
  443.         }
  444.  
  445.  
  446.         /* Process the special character */
  447.  
  448.         switch (tokens[j].token) {
  449.             case T_ESCAPE:
  450.                 kch = InStr[++i].kanji;
  451.                 if (!kch) RETURN_WITH_ERROR(i, 0);
  452.                 k = FindEscape(kch);
  453.                 if (k < 0) goto TextMatch;
  454.                 token = escapes[k].token;
  455.                 SubRegex = NULL;
  456.                 break;
  457.  
  458.             case T_OPENCURLY:
  459.                 SubRegex = CompileRegex(tokens[j].token, InStr + i + 1, &up, &errornum);
  460.                 i = up - InStr;
  461.                 if (SubRegex == NULL) RETURN_WITH_ERROR(i, errornum);
  462.                 token = T_OPENCURLY;
  463.                 break;
  464.  
  465.             case T_OPENPAREN: {
  466.                 int x;
  467.                 REGEX far *SubExp = NULL, far *rpx;
  468.  
  469.                 for (;;) {      /* Wait till a close paren */
  470.                     SubRegex = CompileRegex(tokens[j].token, InStr + i + 1, &up, &errornum);
  471.                     i = up - InStr;
  472.                     if (SubRegex == NULL) RETURN_WITH_ERROR(i, errornum);
  473.  
  474.                     /* Insert a new block */
  475.  
  476.                     if (SubExp == NULL) {
  477.                         SubExp = rpx = SubRegex;
  478.                     } else {
  479.                         rpx->next = SubRegex;
  480.                         SubRegex->prev = rpx;
  481.                         rpx = SubRegex;
  482.                     }
  483.  
  484.                     x = FindToken(up->kanji);
  485.                     if (x >= 0 && tokens[x].token == T_CLOSEPAREN) break;
  486.                 }
  487.                 token = T_OPENPAREN;
  488.                 SubRegex = SubExp;
  489.                 break;
  490.             }
  491.  
  492.             case T_OPENBRACKET:
  493.                 SubRegex = CompileBracketedString(InStr + i + 1, &up, &errornum, TRUE);
  494.                 i = up - InStr;
  495.                 if (SubRegex == NULL) RETURN_WITH_ERROR(i, errornum);
  496.                 token = T_OPENBRACKET;
  497.                 break;
  498.  
  499.             case T_BOL:
  500.             case T_EOL:
  501.             case T_MATCHALL:
  502.             case T_MATCHONE:
  503.             case T_MATCHKANJI:
  504.             case T_MATCHASCII:
  505.             case T_MATCHKANA:
  506.             case T_SOFTRETURN:
  507.             case T_HARDRETURN:
  508.             case T_TAB:
  509.                 SubRegex = NULL;
  510.                 token = tokens[j].token;
  511.                 break;
  512.  
  513.             default:
  514.                 RETURN_WITH_ERROR(i, 9);
  515.         }
  516.  
  517.         /* Insert a new block */
  518.  
  519.         if (RegexChain == NULL) {
  520.             RegexChain = rp = StructAlloc(REGEX);
  521.             rp->prev = NULL;
  522.         } else {
  523.             rp->next = StructAlloc(REGEX);
  524.             rp->next->prev = rp;
  525.             rp = rp->next;
  526.         }
  527.         rp->next = NULL;
  528.         rp->action = token;
  529.         rp->data = (LONG) SubRegex;
  530.     }
  531.  
  532.     if (RegexChain == NULL) {
  533.         if (action == T_ERROR) { RETURN_WITH_ERROR(i, 4); }
  534.         else { RETURN_WITH_ERROR(i, 6); }
  535.     }
  536.  
  537.     *OutStr = InStr + i;
  538.     return (RegexChain);
  539. }
  540.  
  541.  
  542.  
  543. #define REPLACE_ERROR(x,y)  { if (kp != NULL) FreeBlock(kp); *OutStr = InStr + (x); *ErrorNum = (y); return (NULL); }
  544.  
  545. static KANJI far *CompileReplaceString (BOOL Regex, UNIT far *InStr, UNIT far **OutStr, int *ErrorNum)
  546. {
  547.     int i, j, len;
  548.     KANJI kch;
  549.     KANJI far *kp = NULL;
  550.  
  551.  
  552.     *OutStr = InStr;
  553.  
  554.     if (!Regex) {
  555.         len = unitlen(InStr);
  556.         kp = BlockAlloc((len + 5) * sizeof(KANJI));
  557.         for (i = 0; i < len; i++) kp[i] = InStr[i].kanji;
  558.         kp[len] = 0;
  559.         *OutStr = NULL;
  560.         *ErrorNum = 0;
  561.         return (kp);
  562.     }
  563.  
  564.  
  565.     for (i = 0; InStr[i].kanji; i++) {
  566.         kch = InStr[i].kanji;
  567.  
  568.         j = FindToken(kch);
  569.  
  570.         switch (tokens[j].token) {
  571.             case T_ESCAPE:
  572.                 kch = InStr[++i].kanji;
  573.                 if (!kch) REPLACE_ERROR(i,0);
  574.                 j = FindEscape(kch);
  575.                 if (j >= 0) {
  576.                     switch (escapes[j].token) {
  577.                         case T_SOFTRETURN:  kch = '\n'; break;
  578.                         case T_HARDRETURN:  kch = '\r'; break;
  579.                         case T_TAB:         kch = '\t'; break;
  580.                         default:            break;
  581.                     }
  582.                 }
  583.                 break;
  584.  
  585.             case T_OPENCURLY:
  586.                 kch = InStr[i+1].kanji;
  587.                 if (ISKANJI(kch)) kch = TranslateJAscii(kch, TRUE);
  588.                 if (!kch) REPLACE_ERROR(i + 1, 7);
  589.  
  590.                 if ('1' > kch || kch > '9') REPLACE_ERROR(i + 1, 7);
  591.                 j = FindToken(InStr[i+2].kanji);
  592.                 if (tokens[j].token != T_CLOSECURLY) REPLACE_ERROR(i + 2, 7);
  593.  
  594.                 kch = (CURLYINDICATOR << 8) | (kch - '1');
  595.                 i += 2;
  596.                 break;
  597.         }
  598.  
  599.         if (kp == NULL) {
  600.             kp = BlockAlloc(EXPBLOCKSIZE * sizeof(KANJI));
  601.             len = 0;
  602.             kp[0] = kch;
  603.             kp[1] = 0;
  604.         } else {
  605.             len = kanjilen(kp);
  606.             j = SegHeapGetSize(kp);
  607.  
  608.             if ((len + 5) * sizeof(KANJI) >= j) {
  609.                 kp = BlockRealloc(kp, j + EXPBLOCKSIZE);
  610.             }
  611.             kp[len] = kch;
  612.             kp[len + 1] = 0;
  613.         }
  614.     }
  615.  
  616.     *ErrorNum = 0;
  617.     return (kp);
  618. }
  619.  
  620.  
  621.  
  622. static BOOL CharComp (KANJI c1, KANJI c2, BOOL JASCII, BOOL nocase)
  623. {
  624.     c1 &= 0x7f7f;
  625.     c2 &= 0x7f7f;
  626.  
  627.     if (JASCII) {
  628.         if (/* A */ 0x2341 <= c1 && c1 <= 0x235a /* Z */) c1 = 'A' + (c1 - 0x2341);
  629.         if (/* a */ 0x2361 <= c1 && c1 <= 0x237a /* z */) c1 = 'a' + (c1 - 0x2361);
  630.         if (/* A */ 0x2341 <= c2 && c2 <= 0x235a /* Z */) c2 = 'A' + (c2 - 0x2341);
  631.         if (/* a */ 0x2361 <= c2 && c2 <= 0x237a /* z */) c2 = 'a' + (c2 - 0x2361);
  632.     }
  633.     if (nocase) {
  634.         if ('A' <= c1 && c1 <= 'Z') c1 += 32;
  635.         if ('A' <= c2 && c2 <= 'Z') c2 += 32;
  636.     }
  637.     return (c1 - c2);
  638. }
  639.  
  640.  
  641.  
  642. static BOOL MatchRegex (REGEX far *regex, POSITION *StartPos, BOOL JASCII, BOOL nocase)
  643. {
  644.     int i, j;
  645.     int LineLength;
  646.     UNIT far *up;
  647.     KANJI far *kp;
  648.     REGEX far *rp;
  649.     POSITION pos, TempPos;
  650.  
  651.  
  652.     rp = regex;
  653.     pos = *StartPos;
  654.  
  655.     for (;;) {
  656.         if (rp == NULL) break;
  657.  
  658.         up = PARAOF(pos)->text;
  659.         LineLength = unitlen(up);
  660.  
  661.         for (i = POSOF(pos); i <= LineLength; i++) {
  662.             POSOF(pos) = i;
  663.  
  664.             if (i == LineLength) {
  665.                 if (rp->action != T_EOL && rp->action != T_HARDRETURN) return (FALSE);
  666.             }
  667.  
  668.             switch (rp->action) {
  669.                 case T_TEXT:
  670.                     kp = (KANJI far *) rp->data;
  671.                     for (j = 0; up[i + j].kanji; j++) {
  672.                         if (!kp[j]) break;
  673.                         if (CharComp(kp[j], up[i + j].kanji, JASCII, nocase)) break;
  674.                     }
  675.                     if (kp[j]) return (FALSE); /* Not matched */
  676.  
  677.                     /* Matched... */
  678.                     PARAOF(rp->startpos) = PARAOF(rp->endpos) = PARAOF(pos);
  679.                     POSOF(rp->startpos) = i;
  680.                     POSOF(rp->endpos) = i + j - 1;
  681.  
  682.                     i += (j - 1);
  683.                     rp = rp->next;
  684.                     break;
  685.  
  686.                 case T_BOL:
  687.                     if (i > 0) return (FALSE);    /* Not matched */
  688.  
  689.                     rp->startpos = rp->endpos = pos;
  690.                     i--;
  691.                     rp = rp->next;
  692.                     break;
  693.  
  694.                 case T_EOL:
  695.                 case T_HARDRETURN:
  696.                     if (i != LineLength) return (FALSE);
  697.  
  698.                     rp->startpos = rp->endpos = pos;
  699.                     rp = rp->next;
  700.                     break;
  701.  
  702.                 case T_SOFTRETURN:
  703.                     if (up[i].kanji != '\n') return (FALSE);
  704.                     rp->startpos = rp->endpos = pos;
  705.                     rp = rp->next;
  706.                     break;
  707.  
  708.                 case T_TAB:
  709.                     if (up[i].kanji != '\t') return (FALSE);
  710.                     rp->startpos = rp->endpos = pos;
  711.                     rp = rp->next;
  712.                     break;
  713.  
  714.                 case T_MATCHONE:
  715.                     if (up[i].kanji == 0) return (FALSE);
  716.                     rp->startpos = rp->endpos = pos;
  717.                     rp = rp->next;
  718.                     break;
  719.  
  720.                 case T_MATCHKANA:
  721.                     if (!ISKANJI(up[i].kanji)) return (FALSE);
  722.                     if (HIBYTE(up[i].kanji) != 0x24 && HIBYTE(up[i].kanji) != 0x25)
  723.                         return (FALSE);
  724.  
  725.                     rp->startpos = rp->endpos = pos;
  726.                     rp = rp->next;
  727.                     break;
  728.  
  729.                 case T_MATCHKANJI:
  730.                     if (!ISKANJI(up[i].kanji)) return (FALSE);
  731.                     if (up[i].kanji < 0x3021) return (FALSE);
  732.  
  733.                     rp->startpos = rp->endpos = pos;
  734.                     rp = rp->next;
  735.                     break;
  736.  
  737.                 case T_MATCHASCII:
  738.                     if (ISKANJI(up[i].kanji)) return (FALSE);
  739.                     rp->startpos = rp->endpos = pos;
  740.                     rp = rp->next;
  741.                     break;
  742.  
  743.                 case T_OPENCURLY:
  744.                     rp->startpos = TempPos = pos;
  745.  
  746.                     if (!MatchRegex((REGEX far *) rp->data, &TempPos, JASCII, nocase))
  747.                         return (FALSE);
  748.  
  749.                     /* Matched... */
  750.                     pos = rp->endpos = TempPos;
  751.                     i = POSOF(pos);
  752.                     rp = rp->next;
  753.                     break;
  754.  
  755.                 case T_MATCHALL: {
  756.                     BOOL Matched = FALSE;
  757.                     int len;
  758.  
  759.                     rp->startpos = TempPos = pos;
  760.                     len = unitlen(PARAOF(TempPos)->text);
  761.                     POSOF(TempPos) = i;
  762.  
  763.                     for (;;) {
  764.                         if (POSOF(TempPos) >= len) {
  765.                             if (PARAOF(TempPos)->next == NULL) return (FALSE);
  766.                             PARAOF(TempPos) = PARAOF(TempPos)->next;
  767.                             POSOF(TempPos) = i = 0;
  768.                             len = unitlen(PARAOF(TempPos)->text);
  769.                         }
  770.                         if (MatchRegex(rp->next, &TempPos, JASCII, nocase)) {
  771.                             Matched = TRUE;
  772.                             break;
  773.                         }
  774.                         POSOF(TempPos)++;
  775.                     }
  776.  
  777.                     if (!Matched) return (FALSE);
  778.  
  779.                     pos = rp->endpos = TempPos;
  780.                     *StartPos = pos;
  781.                     return (TRUE);
  782.                 }
  783.  
  784.                 case T_OPENPAREN: {
  785.                     REGEX far *rpx;
  786.                     REGEX far *rpnext;
  787.  
  788.                     for (rpx = (REGEX far *) rp->data; rpx != NULL; rpx = rpx->next) {
  789.                         rp->startpos = TempPos = pos;
  790.                         /* Must unlink */
  791.                         rpnext = rpx->next;
  792.                         rpx->next = NULL;
  793.                         if (MatchRegex(rpx, &TempPos, JASCII, nocase)) break;
  794.                         rpx->next = rpnext;
  795.                     }
  796.                     if (rpx == NULL) return (FALSE);
  797.  
  798.                     /* Matched... */
  799.                     pos = rp->endpos = TempPos;
  800.                     i = POSOF(pos);
  801.                     rp = rp->next;
  802.                     break;
  803.                 }
  804.  
  805.                 case T_OPENBRACKET:
  806.                     if (!CharInBracketed(up[i].kanji, (REGEX far *) rp->data))
  807.                         return (FALSE);
  808.  
  809.                     rp->startpos = rp->endpos = pos;
  810.                     rp = rp->next;
  811.                     break;
  812.             }
  813.  
  814.             POSOF(pos) = i;
  815.  
  816.             if (rp == NULL) {
  817.                 *StartPos = pos;
  818.                 return (TRUE);
  819.             }
  820.         }
  821.  
  822.         if (PARAOF(pos)->next == NULL) break;
  823.  
  824.         PARAOF(pos) = PARAOF(pos)->next;
  825.         POSOF(pos) = 0;
  826.     }
  827.  
  828.     if (rp == NULL) {
  829.         *StartPos = pos;
  830.         return (TRUE);
  831.     } else {
  832.         return (FALSE);
  833.     }
  834. }
  835.  
  836.  
  837.  
  838. static REGEX far *GetCurlyString (REGEX far *regex, int *num, KANJI far *buffer)
  839. {
  840.     int i, j;
  841.     KANJI kch;
  842.     REGEX far *rp, far *rp1;
  843.     POSITION p;
  844.  
  845.     for (rp = regex; rp != NULL; rp = rp->next) {
  846.         if (rp->action != T_OPENCURLY) continue;
  847.  
  848.         if (*num == 0) {
  849.             p = rp->startpos;
  850.             i = POSOF(p);
  851.             j = 0;
  852.  
  853.             for(;;) {
  854.                 if (PARAOF(p) == NULL) break;
  855.                 if (PARAOF(p) == PARAOF(rp->endpos) && i > POSOF(rp->endpos)) break;
  856.                 kch = PARAOF(p)->text[i].kanji;
  857.  
  858.                 if (!kch) {
  859.                     buffer[j++] = '\r';
  860.                     PARAOF(p) = PARAOF(p)->next;
  861.                     POSOF(p) = i = 0;
  862.                 } else {
  863.                     buffer[j++] = kch;
  864.                     i++;
  865.                 }
  866.             }
  867.  
  868.             buffer[j] = 0;
  869.             return (rp);
  870.         } else {
  871.             (*num)--;
  872.             rp1 = GetCurlyString((REGEX far *) rp->data, num, buffer);
  873.             if (rp1 != NULL) return (rp1);
  874.         }
  875.     }
  876.  
  877.     buffer[0] = 0;
  878.     return (NULL);
  879. }
  880.  
  881.  
  882.  
  883. static void ConstructReplacement (REGEX far *exp, KANJI far *rp, KANJI far *buffer)
  884. {
  885.     int i, j;
  886.     int level;
  887.  
  888.     for (i = j = 0; rp[i]; i++) {
  889.         if (HIBYTE(rp[i]) != CURLYINDICATOR) {
  890.             buffer[j++] = rp[i];
  891.             continue;
  892.         }
  893.  
  894.         level = LOBYTE(rp[i]);
  895.  
  896.         if (GetCurlyString(exp, &level, buffer + j) == NULL) continue;
  897.  
  898.         j = kanjilen(buffer);
  899.     }
  900.     buffer[j] = 0;
  901. }
  902.  
  903.  
  904.  
  905. void DoSearch (void)
  906. {
  907.     FILEOPTIONS *f;
  908.     int i, len;
  909.     KANJI FirstChar;
  910.     BOOL Matched = FALSE;
  911.     BOOL Wrapped = FALSE;
  912.     HCURSOR hcursor;
  913.     POSITION p;
  914.  
  915.  
  916.     if (Expression == NULL) {
  917.         i = DialogBox (hInstance, "Search", global.hwnd, SearchProc);
  918.         if (!i) return;
  919.     }
  920.  
  921.     /* Set up the first character - for speed */
  922.  
  923.     if (Expression->action == T_TEXT) {
  924.         FirstChar = ((KANJI far *) Expression->data)[0];
  925.     } else {
  926.         FirstChar = 0;
  927.     }
  928.  
  929.  
  930.     /* Now do the search */
  931.  
  932.     hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  933.     ShowCursor(TRUE);
  934.  
  935.     f = global.active;
  936.  
  937.     if (SearchOptions.WholeFile) {
  938.         PARAOF(p) = f->paragraph;
  939.         POSOF(p) = 0;
  940.     } else {
  941.         PARAOF(p) = CURPARA(f);
  942.         POSOF(p) = POS2ABS(f->current);
  943.     }
  944.     len = unitlen(PARAOF(p)->text);
  945.  
  946.     for (;;) {
  947.         if (POSOF(p) >= len) {
  948.             if (PARAOF(p)->next == NULL) {
  949.                 if (!SearchOptions.WrapAround || Wrapped) break;
  950.                 PARAOF(p) = f->paragraph;
  951.                 POSOF(p) = 0;
  952.                 Wrapped = TRUE;
  953.             } else {
  954.                 PARAOF(p) = PARAOF(p)->next;
  955.                 POSOF(p) = 0;
  956.             }
  957.             len = unitlen(PARAOF(p)->text);
  958.         }
  959.  
  960.         if (FirstChar > 0 && FirstChar != PARAOF(p)->text[POSOF(p)].kanji) {
  961.             POSOF(p)++;
  962.             continue;
  963.         }
  964.  
  965.         if (MatchRegex(Expression, &p, SearchOptions.JASCII, SearchOptions.IgnoreCase)) {
  966.             Matched = TRUE;
  967.             break;
  968.         }
  969.         POSOF(p)++;
  970.     }
  971.  
  972.     ShowCursor(FALSE);
  973.     SetCursor(hcursor);
  974.  
  975.     if (!Matched) {
  976.         TurnOffSelection(f);
  977.         ErrorMessage(global.hwnd, "Search String Not Found.");
  978.     } else {
  979.         POSITION endrel;
  980.  
  981.         if (SELPARA1(f) != NULL) FlipHighlight(f);
  982.         SEL1(f) = Expression->startpos;
  983.         SEL2(f) = p;
  984.         SELTYPE(f) = SEL_SELECTION;
  985.  
  986.         /* Set the cursor */
  987.         if (POSOF(p) >= unitlen(PARAOF(p)->text)) {
  988.             if (PARAOF(p)->next != NULL) {
  989.                 PARAOF(p) = PARAOF(p)->next;
  990.                 POSOF(p) = 0;
  991.             }
  992.         } else {
  993.             POSOF(p)++;
  994.         }
  995.  
  996.         AbsoluteToPosition(p, &endrel);
  997.         f->current = endrel;
  998.  
  999.         if (CURPARA(f) != global.cpospara) FillCPos(f, CURPARA(f), 0, -1);
  1000.  
  1001.         if (!FindCaret(f, FALSE)) {
  1002.             MoveIntoWindow(f);
  1003.             InvalidateRect(f->hwnd, NULL, TRUE);
  1004.             UpdateWindow(f->hwnd);
  1005.         } else {
  1006.             FlipHighlight(f);
  1007.         }
  1008.         f->pseudo = f->cursor;
  1009.         DoCaret(f, CURX(f), CURY(f) - CURLINE(f)->height, TRUE);
  1010.         Triangles(f);
  1011.     }
  1012. }
  1013.  
  1014.  
  1015.  
  1016. void DoReplace (void)
  1017. {
  1018.     FILEOPTIONS *f;
  1019.     int i, len, nr_matched;
  1020.     KANJI FirstChar;
  1021.     BOOL Matched;
  1022.     BOOL Wrapped = FALSE;
  1023.     BOOL KeepGoing = TRUE;
  1024.     BOOL NeedConfirm;
  1025.     HCURSOR hcursor;
  1026.     POSITION p;
  1027.     KANJI buffer[MAXLINELEN];
  1028.  
  1029.  
  1030.     if (ReplaceExp == NULL || Expression == NULL) {
  1031.         i = DialogBox (hInstance, "Replace", global.hwnd, ReplaceProc);
  1032.         if (!i) return;
  1033.     }
  1034.  
  1035.  
  1036.     /* Set up the first character - for speed */
  1037.  
  1038.     if (Expression->action == T_TEXT) {
  1039.         FirstChar = ((KANJI far *) Expression->data)[0];
  1040.     } else {
  1041.         FirstChar = 0;
  1042.     }
  1043.  
  1044.  
  1045.     /* Now do the search */
  1046.  
  1047.     hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1048.     ShowCursor(TRUE);
  1049.  
  1050.     f = global.active;
  1051.  
  1052.     NeedConfirm = !SearchOptions.NoConfirm;
  1053.     nr_matched = 0;
  1054.  
  1055.     if (NeedConfirm) {
  1056.         PARAOF(p) = f->paragraph;
  1057.         POSOF(p) = 0;
  1058.     } else {
  1059.         PARAOF(p) = CURPARA(f);
  1060.         POSOF(p) = POS2ABS(f->current);
  1061.     }
  1062.     len = unitlen(PARAOF(p)->text);
  1063.  
  1064. Loop:
  1065.  
  1066.     Matched = FALSE;
  1067.  
  1068.     for (;;) {
  1069.         if (POSOF(p) >= len) {
  1070.             if (PARAOF(p)->next == NULL) {
  1071.                 if (Wrapped) break;
  1072.                 PARAOF(p) = f->paragraph;
  1073.                 POSOF(p) = 0;
  1074.                 Wrapped = TRUE;
  1075.             } else {
  1076.                 PARAOF(p) = PARAOF(p)->next;
  1077.                 POSOF(p) = 0;
  1078.             }
  1079.             len = unitlen(PARAOF(p)->text);
  1080.         }
  1081.  
  1082.         if (FirstChar > 0 && FirstChar != PARAOF(p)->text[POSOF(p)].kanji) {
  1083.             POSOF(p)++;
  1084.             continue;
  1085.         }
  1086.  
  1087.         if (MatchRegex(Expression, &p, SearchOptions.JASCII, SearchOptions.IgnoreCase)) {
  1088.             Matched = TRUE;
  1089.             nr_matched++;
  1090.             break;
  1091.         }
  1092.         POSOF(p)++;
  1093.     }
  1094.  
  1095.     if (!Matched) {
  1096.         ShowCursor(FALSE);
  1097.         SetCursor(hcursor);
  1098.         TurnOffSelection(f);
  1099.         if (nr_matched > 0) {
  1100.             char buf[50];
  1101.  
  1102.             sprintf(buf, "%d changes made", nr_matched);
  1103.             StatusMessage(buf);
  1104.         } else {
  1105.             ErrorMessage(global.hwnd, "Search String Not Found.");
  1106.         }
  1107.         KeepGoing = FALSE;
  1108.     } else {
  1109.         POSITION startrel, endrel;
  1110.  
  1111.         TurnOffSelection(f);
  1112.         SEL1(f) = Expression->startpos;
  1113.         SEL2(f) = p;
  1114.         SELTYPE(f) = SEL_SELECTION;
  1115.  
  1116.         /* Set the cursor */
  1117.         if (POSOF(p) >= unitlen(PARAOF(p)->text)) {
  1118.             if (PARAOF(p)->next != NULL) {
  1119.                 PARAOF(p) = PARAOF(p)->next;
  1120.                 POSOF(p) = 0;
  1121.             }
  1122.         } else {
  1123.             POSOF(p)++;
  1124.         }
  1125.  
  1126.         AbsoluteToPosition(p, &endrel);
  1127.         f->current = endrel;
  1128.  
  1129.         if (CURPARA(f) != global.cpospara) FillCPos(f, CURPARA(f), 0, -1);
  1130.  
  1131.         if (!FindCaret(f, FALSE)) {
  1132.             MoveIntoWindow(f);
  1133.             InvalidateRect(f->hwnd, NULL, TRUE);
  1134.             UpdateWindow(f->hwnd);
  1135.         } else {
  1136.             FlipHighlight(f);
  1137.         }
  1138.         f->pseudo = f->cursor;
  1139.         DoCaret(f, CURX(f), CURY(f) - CURLINE(f)->height, TRUE);
  1140.         Triangles(f);
  1141.  
  1142.         ConstructReplacement(Expression, ReplaceExp, buffer);
  1143.  
  1144.         if (NeedConfirm) {
  1145.             /* Put up the dialog box */
  1146.  
  1147.             ShowCursor(FALSE);
  1148.             SetCursor(hcursor);
  1149.  
  1150.             Replacement = buffer;
  1151.  
  1152.             i = DialogBox (hInstance, "ReplaceDlg", global.hwnd, ReplaceProc);
  1153.  
  1154.             hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1155.             ShowCursor(TRUE);
  1156.  
  1157.             switch (i) {
  1158.                 case 4203:  /* All */
  1159.                     NeedConfirm = FALSE;
  1160.                     /* ... falls into the next case */
  1161.  
  1162.                 case 1:     /* Yes */
  1163.                     TurnOffSelection(f);
  1164.                     AbsoluteToPosition(Expression->startpos, &startrel);
  1165.                     if (POSOF(p) > 0) POSOF(p)--;
  1166.                     AbsoluteToPosition(p, &endrel);
  1167.                     BlockReplace(f, startrel, endrel, (KANJI far *) buffer);
  1168.                     break;
  1169.  
  1170.                 case 2:     /* Stop */
  1171.                     KeepGoing = FALSE;
  1172.                     ShowCursor(FALSE);
  1173.                     SetCursor(hcursor);
  1174.                     break;
  1175.  
  1176.                 case 4201:  /* No*/
  1177.                     break;
  1178.             }
  1179.         } else {
  1180.             TurnOffSelection(f);
  1181.             AbsoluteToPosition(Expression->startpos, &startrel);
  1182.             if (POSOF(p) > 0) POSOF(p)--;
  1183.             AbsoluteToPosition(p, &endrel);
  1184.             BlockReplace(f, startrel, endrel, (KANJI far *) buffer);
  1185.         }
  1186.     }
  1187.  
  1188.     if (KeepGoing) goto Loop;
  1189. }
  1190.  
  1191.  
  1192.  
  1193. BOOL FAR PASCAL SearchProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
  1194. {
  1195.     switch (message) {
  1196.         case WM_INITDIALOG: {
  1197.             FILEOPTIONS *f;
  1198.  
  1199.             /* Set the type and mode-change icon */
  1200.             SendDlgItemMessage(hwnd, 4201, EM_SETMODIFY, FN_CONTROL, 0L);
  1201.             SendDlgItemMessage(hwnd, 4201, EM_SETRECT, GetDlgItem(hwnd, 4241), 0L);
  1202.  
  1203.             //SendDlgItemMessage(hwnd, 4202, EM_SETMODIFY, FN_CONTROL, 0L);
  1204.             //SendDlgItemMessage(hwnd, 4202, EM_SETRECT, GetDlgItem(hwnd, 4241), 0L);
  1205.  
  1206.             f = (FILEOPTIONS *) SendDlgItemMessage(hwnd, 4201, EM_GETHANDLE, 0, 0L);
  1207.             SendDlgItemMessage(hwnd, 4241, EM_SETHANDLE, f->hwnd, 0L);  /* mode-change icon */
  1208.  
  1209.             if (ExpText != NULL) {
  1210.                 int len;
  1211.  
  1212.                 SendDlgItemMessage(hwnd, 4201, EM_REPLACESEL, 0, (LONG) ExpText);
  1213.                 len = kanjilen(ExpText);
  1214.                 if (len > 0) {
  1215.                     SendDlgItemMessage(hwnd, 4201, EM_SETSEL, len, MAKELONG(0, len - 1));
  1216.                 }
  1217.             }
  1218.  
  1219.             CheckDlgButton (hwnd, 4221, SearchOptions.IgnoreCase);
  1220.             CheckDlgButton (hwnd, 4222, SearchOptions.Regex);
  1221.             CheckDlgButton (hwnd, 4223, SearchOptions.JASCII);
  1222.             CheckDlgButton (hwnd, 4224, SearchOptions.WrapAround);
  1223.             CheckDlgButton (hwnd, 4225, SearchOptions.WholeFile);
  1224.             //CheckDlgButton (hwnd, 4226, SearchOptions.NoConfirm);
  1225.  
  1226.             CenterDialogBox(hwnd);
  1227.             return (TRUE);
  1228.         }
  1229.  
  1230.         case WM_PAINT: {
  1231.             HDC hdc;
  1232.             PAINTSTRUCT ps;
  1233.  
  1234.             hdc = BeginPaint(hwnd, &ps);
  1235.  
  1236.             DrawBoundingBox(hwnd, hdc, 4201);
  1237.             //DrawBoundingBox(hwnd, hdc, 4202);
  1238.  
  1239.             EndPaint(hwnd, &ps);
  1240.             return (TRUE);
  1241.         }
  1242.  
  1243.         case WM_COMMAND:
  1244.             switch (wParam) {
  1245.                 case IDOK: {
  1246.                     int i, len, errornum;
  1247.                     UNIT far *up, far *up1;
  1248.                     REGEX far *rp;
  1249.  
  1250.                     SearchOptions.IgnoreCase = IsDlgButtonChecked(hwnd, 4221);
  1251.                     SearchOptions.Regex = IsDlgButtonChecked(hwnd, 4222);
  1252.                     SearchOptions.JASCII = IsDlgButtonChecked(hwnd, 4223);
  1253.                     SearchOptions.WrapAround = IsDlgButtonChecked(hwnd, 4224);
  1254.                     SearchOptions.WholeFile = IsDlgButtonChecked(hwnd, 4225);
  1255.                     //SearchOptions.NoConfirm = IsDlgButtonChecked(hwnd, 4226);
  1256.  
  1257.                     up = (UNIT far *) SendDlgItemMessage(hwnd, 4201, EM_GETLINE, 0, 0L);
  1258.  
  1259.                     if (SearchOptions.Regex) {
  1260.                         rp = CompileRegex(0, up, &up1, &errornum);
  1261.                         if (rp == NULL) {
  1262.                             ErrorMessage(hwnd, "Error in Regular Expression: %s.\n\n"
  1263.                                                   "Please correct the regular expression and try again.",
  1264.                                                   CompileErrors[errornum]);
  1265.                             SendDlgItemMessage(hwnd, 4201, EM_SETSEL, up1 - up, 0L);
  1266.                             SetFocus(GetDlgItem(hwnd, 4201));
  1267.                             return (TRUE);
  1268.                         }
  1269.                     } else {
  1270.                         rp = CompileText(up);
  1271.                         if (rp == NULL) {
  1272.                             ErrorMessage(hwnd, "You must enter something to search for!");
  1273.                             SetFocus(GetDlgItem(hwnd, 4201));
  1274.                             return (TRUE);
  1275.                         }
  1276.                     }
  1277.  
  1278.                     if (Expression != NULL) FreeRegex(Expression);
  1279.                     Expression = rp;
  1280.  
  1281.                     if (ExpText != NULL) FreeBlock(ExpText);
  1282.  
  1283.                     len = unitlen(up);
  1284.                     ExpText = (KANJI far *) BlockAlloc((len + 5) * sizeof(KANJI));
  1285.                     for (i = 0; i < len; i++) ExpText[i] = up[i].kanji;
  1286.                     ExpText[len] = 0;
  1287.  
  1288.                     EndDialog(hwnd, TRUE);
  1289.                     return (TRUE);
  1290.                 }
  1291.  
  1292.                 case IDCANCEL:
  1293.                     EndDialog(hwnd, FALSE);
  1294.                     return (TRUE);
  1295.             }
  1296.     }
  1297.     return (FALSE);
  1298. }
  1299.  
  1300.  
  1301. BOOL FAR PASCAL ReplaceProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
  1302. {
  1303.     switch (message) {
  1304.         case WM_INITDIALOG: {
  1305.             int len;
  1306.             FILEOPTIONS *f;
  1307.  
  1308.             /* Set the type and mode-change icon */
  1309.             SendDlgItemMessage(hwnd, 4201, EM_SETMODIFY, FN_CONTROL, 0L);
  1310.             SendDlgItemMessage(hwnd, 4201, EM_SETRECT, GetDlgItem(hwnd, 4241), 0L);
  1311.  
  1312.             SendDlgItemMessage(hwnd, 4202, EM_SETMODIFY, FN_CONTROL, 0L);
  1313.             SendDlgItemMessage(hwnd, 4202, EM_SETRECT, GetDlgItem(hwnd, 4241), 0L);
  1314.  
  1315.             f = (FILEOPTIONS *) SendDlgItemMessage(hwnd, 4201, EM_GETHANDLE, 0, 0L);
  1316.             SendDlgItemMessage(hwnd, 4241, EM_SETHANDLE, f->hwnd, 0L);  /* mode-change icon */
  1317.  
  1318.             if (ExpText != NULL) {
  1319.                 SendDlgItemMessage(hwnd, 4201, EM_REPLACESEL, 0, (LONG) ExpText);
  1320.                 len = kanjilen(ExpText);
  1321.                 if (len > 0) {
  1322.                     SendDlgItemMessage(hwnd, 4201, EM_SETSEL, len, MAKELONG(0, len - 1));
  1323.                 }
  1324.             }
  1325.             if (ReplaceText != NULL) {
  1326.                 SendDlgItemMessage(hwnd, 4202, EM_REPLACESEL, 0, (LONG) ReplaceText);
  1327.                 len = kanjilen(ReplaceText);
  1328.             }
  1329.  
  1330.             CheckDlgButton (hwnd, 4221, SearchOptions.IgnoreCase);
  1331.             CheckDlgButton (hwnd, 4222, SearchOptions.Regex);
  1332.             CheckDlgButton (hwnd, 4223, SearchOptions.JASCII);
  1333.             //CheckDlgButton (hwnd, 4224, SearchOptions.WrapAround);
  1334.             //CheckDlgButton (hwnd, 4225, SearchOptions.WholeFile);
  1335.             CheckDlgButton (hwnd, 4226, SearchOptions.NoConfirm);
  1336.  
  1337.             CenterDialogBox(hwnd);
  1338.             return (TRUE);
  1339.         }
  1340.  
  1341.         case WM_PAINT: {
  1342.             HDC hdc;
  1343.             PAINTSTRUCT ps;
  1344.  
  1345.             hdc = BeginPaint(hwnd, &ps);
  1346.  
  1347.             DrawBoundingBox(hwnd, hdc, 4201);
  1348.             DrawBoundingBox(hwnd, hdc, 4202);
  1349.  
  1350.             EndPaint(hwnd, &ps);
  1351.             return (TRUE);
  1352.         }
  1353.  
  1354.         case WM_COMMAND:
  1355.             switch (wParam) {
  1356.                 case IDOK: {
  1357.                     int i, len, errornum;
  1358.                     KANJI far *kp;
  1359.                     UNIT far *up, far *up1;
  1360.                     REGEX far *rp;
  1361.  
  1362.                     SearchOptions.IgnoreCase = IsDlgButtonChecked(hwnd, 4221);
  1363.                     SearchOptions.Regex = IsDlgButtonChecked(hwnd, 4222);
  1364.                     SearchOptions.JASCII = IsDlgButtonChecked(hwnd, 4223);
  1365.                     //SearchOptions.WrapAround = IsDlgButtonChecked(hwnd, 4224);
  1366.                     //SearchOptions.WholeFile = IsDlgButtonChecked(hwnd, 4225);
  1367.                     SearchOptions.NoConfirm = IsDlgButtonChecked(hwnd, 4226);
  1368.  
  1369.                     up = (UNIT far *) SendDlgItemMessage(hwnd, 4201, EM_GETLINE, 0, 0L);
  1370.  
  1371.                     /* Compile the Search Text */
  1372.  
  1373.                     if (SearchOptions.Regex) {
  1374.                         rp = CompileRegex(0, up, &up1, &errornum);
  1375.                         if (rp == NULL) {
  1376.                             ErrorMessage(hwnd, "Error in Regular Expression: %s.\n\n"
  1377.                                                   "Please correct the regular expression and try again.",
  1378.                                                   CompileErrors[errornum]);
  1379.                             SendDlgItemMessage(hwnd, 4201, EM_SETSEL, up1 - up, 0L);
  1380.                             SetFocus(GetDlgItem(hwnd, 4201));
  1381.                             return (TRUE);
  1382.                         }
  1383.                     } else {
  1384.                         rp = CompileText(up);
  1385.                         if (rp == NULL) {
  1386.                             ErrorMessage(hwnd, "You must enter something to search for!");
  1387.                             SetFocus(GetDlgItem(hwnd, 4201));
  1388.                             return (TRUE);
  1389.                         }
  1390.                     }
  1391.  
  1392.                     if (Expression != NULL) FreeRegex(Expression);
  1393.                     Expression = rp;
  1394.  
  1395.                     if (ExpText != NULL) FreeBlock(ExpText);
  1396.  
  1397.                     len = unitlen(up);
  1398.                     ExpText = (KANJI far *) BlockAlloc((len + 5) * sizeof(KANJI));
  1399.                     for (i = 0; i < len; i++) ExpText[i] = up[i].kanji;
  1400.                     ExpText[len] = 0;
  1401.  
  1402.                     /* Compile the replace text */
  1403.  
  1404.                     up = (UNIT far *) SendDlgItemMessage(hwnd, 4202, EM_GETLINE, 0, 0L);
  1405.  
  1406.                     if (SearchOptions.Regex) {
  1407.                         kp = CompileReplaceString(TRUE, up, &up1, &errornum);
  1408.                         if (kp == NULL) {
  1409.                             ErrorMessage(hwnd, "Error in the replacement text: %s.\n\n"
  1410.                                                   "Please correct the expression and try again.",
  1411.                                                   CompileErrors[errornum]);
  1412.                             SendDlgItemMessage(hwnd, 4202, EM_SETSEL, up1 - up, 0L);
  1413.                             SetFocus(GetDlgItem(hwnd, 4202));
  1414.                             return (TRUE);
  1415.                         }
  1416.                     } else {
  1417.                         kp = CompileReplaceString(FALSE, up, &up1, &errornum);
  1418.                     }
  1419.  
  1420.                     if (ReplaceExp != NULL) FreeBlock(ReplaceExp);
  1421.                     ReplaceExp = kp;
  1422.  
  1423.                     if (ReplaceText != NULL) FreeBlock(ReplaceText);
  1424.  
  1425.                     len = unitlen(up);
  1426.                     ReplaceText = (KANJI far *) BlockAlloc((len + 5) * sizeof(KANJI));
  1427.                     for (i = 0; i < len; i++) ReplaceText[i] = up[i].kanji;
  1428.                     ReplaceText[len] = 0;
  1429.  
  1430.                     EndDialog(hwnd, TRUE);
  1431.                     return (TRUE);
  1432.                 }
  1433.  
  1434.                 case IDCANCEL:
  1435.                     EndDialog(hwnd, FALSE);
  1436.                     return (TRUE);
  1437.             }
  1438.     }
  1439.     return (FALSE);
  1440. }
  1441.  
  1442.  
  1443.  
  1444. BOOL FAR PASCAL ReplaceDlgProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
  1445. {
  1446.     switch (message) {
  1447.         case WM_INITDIALOG:
  1448.             if (Replacement != NULL) {
  1449.                 SendDlgItemMessage(hwnd, 4211, EM_REPLACESEL, 0, (LONG) Replacement);
  1450.             }
  1451.             break;
  1452.  
  1453.         case WM_COMMAND:
  1454.             switch (wParam) {
  1455.                 case IDOK:      /* Yes */
  1456.                 case IDCANCEL:  /* Stop */
  1457.                 case 4201:      /* No */
  1458.                 case 4203:      /* All */
  1459.                     EndDialog(hwnd, wParam);
  1460.                     return (TRUE);
  1461.  
  1462.                 case 4202:      /* Change */
  1463.                     if (DialogBox (hInstance, "EditReplacement", hwnd, EditReplacementProc)) {
  1464.                         SendDlgItemMessage(hwnd, 4211, EM_REPLACESEL, 0, (LONG) Replacement);
  1465.                         InvalidateRect(GetDlgItem(hwnd, 4211), NULL, TRUE);
  1466.                     }
  1467.                     return (TRUE);
  1468.             }
  1469.             break;
  1470.     }
  1471.     return (FALSE);
  1472. }
  1473.  
  1474.  
  1475.  
  1476. BOOL FAR PASCAL EditReplacementProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
  1477. {
  1478.     switch (message) {
  1479.         case WM_INITDIALOG: {
  1480.             int len;
  1481.             FILEOPTIONS *f;
  1482.  
  1483.             /* Set the type and mode-change icon of the Jedit control */
  1484.             SendDlgItemMessage(hwnd, 4201, EM_SETMODIFY, FN_CONTROL, 0L);
  1485.             SendDlgItemMessage(hwnd, 4201, EM_SETRECT, GetDlgItem(hwnd, 4202), 0L);
  1486.  
  1487.             f = (FILEOPTIONS *) SendDlgItemMessage(hwnd, 4201, EM_GETHANDLE, 0, 0L);
  1488.             SendDlgItemMessage(hwnd, 4202, EM_SETHANDLE, f->hwnd, 0L);  /* icon-change */
  1489.  
  1490.             len = kanjilen(Replacement);
  1491.             if (len > 0) {
  1492.                 SendDlgItemMessage(hwnd, 4201, EM_REPLACESEL, 0, (LONG) Replacement);
  1493.                 SendDlgItemMessage(hwnd, 4201, EM_SETSEL, len, MAKELONG(0, len - 1));
  1494.             }
  1495.  
  1496.             SetFocus(GetDlgItem(hwnd, 4201));
  1497.  
  1498.             CenterDialogBox(hwnd);
  1499.  
  1500.             return (TRUE);
  1501.         }
  1502.  
  1503.         case WM_PAINT: {
  1504.             HDC hdc;
  1505.             PAINTSTRUCT ps;
  1506.  
  1507.             hdc = BeginPaint(hwnd, &ps);
  1508.  
  1509.             DrawBoundingBox(hwnd, hdc, 4201);
  1510.  
  1511.             EndPaint(hwnd, &ps);
  1512.             return (TRUE);
  1513.         }
  1514.  
  1515.         case WM_COMMAND:
  1516.             switch (wParam) {
  1517.                 case IDOK: {
  1518.                     int i;
  1519.                     UNIT far *up;
  1520.  
  1521.                     /* Now replace the replacement string */
  1522.  
  1523.                     up = (UNIT far *) SendDlgItemMessage(hwnd, 4201, EM_GETLINE, 0, 0L);
  1524.                     for (i = 0; up[i].kanji; i++) Replacement[i] = up[i].kanji;
  1525.                     Replacement[i] = 0;
  1526.                     EndDialog(hwnd, TRUE);
  1527.                     return (TRUE);
  1528.                 }
  1529.  
  1530.                 case IDCANCEL:
  1531.                     EndDialog(hwnd, FALSE);
  1532.                     return (TRUE);
  1533.             }
  1534.             break;
  1535.     }
  1536.     return (FALSE);
  1537. }
  1538.