home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol9n21.zip / DGCH.PAS < prev    next >
Pascal/Delphi Source File  |  1990-09-25  |  19KB  |  646 lines

  1. {
  2.  ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  3.  █                                                                         █
  4.  █        TITLE :      DGCH.TPU                                            █
  5.  █      PURPOSE :      Basic character-handling routines.                  █
  6.  █       AUTHOR :      David Gerrold, CompuServe ID:  70307,544            █
  7.  █  _____________________________________________________________________  █
  8.  █                                                                         █
  9.  █   Written in Turbo Pascal, Version 5.5,                                 █
  10.  █   with routines from TurboPower, Object Professional.                   █
  11.  █                                                                         █
  12.  █   Turbo Pascal is a product of Borland International.                   █
  13.  █   Object Professional is a product of TurboPower Software.              █
  14.  █  _____________________________________________________________________  █
  15.  █                                                                         █
  16.  █   This is not public domain software.                                   █
  17.  █   This software is copyright 1990, by David Gerrold.                    █
  18.  █   Permission is hereby granted for personal use.                        █
  19.  █                                                                         █
  20.  █        The Brass Cannon Corporation                                     █
  21.  █        9420 Reseda Blvd., #804                                          █
  22.  █        Northridge, CA  91324-2932.                                      █
  23.  █                                                                         █
  24.  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  25.                                                                             }
  26. { Compiler Directives ===================================================== }
  27.  
  28. {$A-}    {Switch word alignment off, necessary for cloning}
  29. {$R-}    {Range checking off}
  30. {$B-}    {Boolean complete evaluation off}
  31. {$S-}    {Stack checking off}
  32. {$I-}    {I/O checking off}
  33. {$N+,E+} {Simulate numeric coprocessor}
  34. {$M 16384,0,327680} {stack and heap}
  35. {$V-}    {Variable range checking off}
  36.  
  37. { Name ==================================================================== }
  38.  
  39. UNIT DgCh;
  40. {
  41.   The purpose of this code is to provide basic character-handling routines.
  42. }
  43.  
  44. { Interface =============================================================== }
  45.  
  46. INTERFACE
  47.  
  48. USES
  49. { Object Professional Units }
  50.   OpString,
  51.  
  52. { Dg Units }
  53.   DgDec,
  54.   DgBit;
  55.  
  56. { ========================================================================= }
  57. { Boolean functions ------------------------------------------------------- }
  58.  
  59. FUNCTION InCap (Ch : Char) : boolean;
  60. { Returns true if Ch is upper case. }
  61.  
  62. FUNCTION InAlphabet (Ch : Char) : boolean;
  63. { Returns true if ch in Alphabet. }
  64.  
  65. FUNCTION InNumbers (Ch : Char) : boolean;
  66. { Returns true if ch is a number. }
  67.  
  68. FUNCTION InDecNumbers (Ch : Char) : boolean;
  69. { Returns true if ch is a number or a decimal point. }
  70.  
  71. FUNCTION InOperators (Ch : Char) : boolean;
  72. { Returns true if ch is in math operators. }
  73.  
  74. FUNCTION InMath (Ch : Char) : boolean;
  75. { Returns true if ch is either a number or an operator. }
  76.  
  77. FUNCTION InAlphaNumeric (Ch : Char) : boolean;
  78. { Returns true if ch is letter or number. }
  79.  
  80. FUNCTION InFileChars (Ch : Char) : boolean;
  81. { Returns true if ch is valid for filename. }
  82.  
  83. FUNCTION InApostrophe (Ch : Char) : boolean;
  84. { Returns true if ch is apostrophe. }
  85.  
  86. FUNCTION In2SpacePunctuation (Ch : Char) : boolean;
  87. { Returns true if ch in two space punctuation. }
  88.  
  89. FUNCTION InSentencePunctuation (Ch : Char) : boolean;
  90. { Returns true if ch in end-of-sentence punctuation. }
  91.  
  92. FUNCTION InQuote (Ch : Char) : boolean;
  93. { Returns true if ch is quote mark. }
  94.  
  95. FUNCTION InPunctuation (Ch : Char) : boolean;
  96. { Returns true if ch in punctuation. }
  97.  
  98. FUNCTION FirstLetterOfASentence (VAR S : string;  I : byte) : Boolean;
  99. { Checks to see if the cursor is on the first letter of a sentence. }
  100.  
  101. FUNCTION FirstLetterOfAWord (VAR S : string;  I : byte;
  102.                              Ch : char;  CapsFlag : CapsFlagType) : boolean;
  103. {
  104.   Checks to see if the cursor is on the first letter of a word.
  105.   Ch is the value of the last character struck.
  106. }
  107.  
  108. FUNCTION FirstLetterOfAName (VAR S : string;  I : byte;
  109.                              Ch : char;  CapsFlag : CapsFlagType) : boolean;
  110. {
  111.   Checks to see if the cursor is on the first letter of a name.
  112.   Ch is the value of the last character struck.
  113. }
  114.  
  115.  
  116. { ========================================================================= }
  117. { Implementation ========================================================== }
  118.  
  119. IMPLEMENTATION
  120.  
  121. { ========================================================================= }
  122. { InCap =================================================================== }
  123.  
  124. FUNCTION InCap (Ch : Char) : boolean;
  125. { Returns true if Ch is upper case. }
  126.  
  127. BEGIN
  128.   InCap := (Ch >= 'A') and (Ch <= 'Z');
  129. END;
  130.  
  131. { InAlphabet ============================================================== }
  132.  
  133. FUNCTION InAlphabet (Ch : Char) : boolean;
  134. { Returns true if ch in Alphabet. }
  135.  
  136. BEGIN
  137.   InAlphabet := InCap (UpCaseMac (Ch));
  138. END;
  139.  
  140. { InNumbers =============================================================== }
  141.  
  142. FUNCTION InNumbers (Ch : Char) : boolean;
  143. { Returns true if ch is a number. }
  144.  
  145. BEGIN
  146.   InNumbers := (Ch >= '0') and (Ch <= '9');
  147. END;
  148.  
  149. { InDecNumbers ============================================================ }
  150.  
  151. FUNCTION InDecNumbers (Ch : Char) : boolean;
  152. { Returns true if ch is a number or a decimal point. }
  153.  
  154. BEGIN
  155.   InDecNumbers := InNumbers (Ch) or (Ch = '.');
  156. END;
  157.  
  158. { InOperators ============================================================= }
  159.  
  160. FUNCTION InOperators (Ch : Char) : boolean;
  161. { Returns true if ch is in math operators. }
  162.  
  163. BEGIN
  164.   InOperators := Pos (Ch, '.+-*/()^') > 0;
  165. END;
  166.  
  167. { InMath ================================================================== }
  168.  
  169. FUNCTION InMath (Ch : Char) : boolean;
  170. { Returns true if ch is either a number or an operator. }
  171.  
  172. BEGIN
  173.   InMath := InNumbers (Ch) or InOperators (Ch);
  174. END;
  175.  
  176. { InAlphaNumeric ========================================================== }
  177.  
  178. FUNCTION InAlphaNumeric (Ch : Char) : boolean;
  179. { Returns true if ch is letter or number. }
  180.  
  181. BEGIN
  182.   InAlphaNumeric := InAlphabet (Ch) or InNumbers (Ch);
  183. END;
  184.  
  185. { InFileChars ============================================================= }
  186.  
  187. FUNCTION InFileChars (Ch : Char) : boolean;
  188. { Returns true if ch is valid for filename. }
  189.  
  190. BEGIN
  191.   InFileChars := InAlphabet (Ch) or InDecNumbers (Ch);
  192. END;
  193.  
  194. { InApostrophe ============================================================ }
  195.  
  196. FUNCTION InApostrophe (Ch : Char) : boolean;
  197. { Returns true if ch is apostrophe. }
  198.  
  199. BEGIN
  200.   InApostrophe := (Ch = #39);
  201. END;
  202.  
  203. { In2SpacePunctuation ===================================================== }
  204.  
  205. FUNCTION In2SpacePunctuation (Ch : Char) : boolean;
  206. { Returns true if ch is punctuation mark that requires two spaces after. }
  207.  
  208. BEGIN
  209.   In2SpacePunctuation := Pos (Ch, '.!?''";:') > 0;
  210. END;
  211.  
  212. { InSentencePunctuation =================================================== }
  213.  
  214. FUNCTION InSentencePunctuation (Ch : Char) : boolean;
  215. { Returns true if ch in end-of-sentence punctuation. }
  216.  
  217. BEGIN
  218.   InSentencePunctuation := Pos (Ch, '.!?') > 0;
  219. END;
  220.  
  221. { InQuote ================================================================= }
  222.  
  223. FUNCTION InQuote (Ch : Char) : boolean;
  224. { Returns true if ch is quote mark. }
  225.  
  226. BEGIN
  227.   InQuote := Pos (Ch, '''"') > 0;
  228. END;
  229.  
  230. { InPunctuation =========================================================== }
  231.  
  232. FUNCTION InPunctuation (Ch : Char) : boolean;
  233. { Returns true if ch in punctuation. }
  234.  
  235. BEGIN
  236.   InPunctuation := not InAlphabet (Ch) and
  237.                    not InNumbers (Ch) and
  238.                    not InApostrophe (Ch);
  239. END;
  240.  
  241. { ========================================================================= }
  242.  
  243. FUNCTION InCtrlChars (Ch : char) : boolean;
  244. { Returns true if ctrl-ch }
  245.  
  246. BEGIN
  247.   InCtrlChars := (Ch > #0) and (Ch < #32);
  248. END;
  249.  
  250. { ========================================================================= }
  251.  
  252. FUNCTION InEdCtrlChars (Ch : char) : boolean;
  253. { Returns true if ctrl-ch }
  254.  
  255. BEGIN
  256.   InEdCtrlChars := ((Ch <> #8) and (Ch > #0) and (Ch < #32))
  257.                    or (Ch = CtrlBackSpace) or (Ch = EndKey)
  258.                    or (Ch = CtrlLeftArrow) or (Ch = CtrlRightArrow);
  259. END;
  260.  
  261. { ========================================================================= }
  262. { ========================================================================= }
  263.  
  264. CONST
  265. { sentence values }
  266.   NullString            = $000001;
  267.   IndexAt1              = $000002;
  268.   IndexPastLen          = $000004;
  269.   FollowSentencePunc    = $000008;
  270.   NotFollowAlphaNumeric = $000010;
  271.   LocGreaterThan2       = $000020;
  272.   FollowSpace           = $000040;
  273.   Follow2Spaces         = $000080;
  274.  
  275. { word values }
  276.   EdCtrlChar            = $000100;
  277.   LocBeforeLen          = $000200;
  278.   LocAtLen              = $000400;
  279.   LocAtLenPlus2         = $000800;
  280.   CapsFlagName          = $001000;
  281.   ChInAlph              = $002000;
  282.  
  283. { name values }
  284.   McName                = $004000;
  285.   MacName               = $008000;
  286.  
  287. CONST
  288.   BeyondLen   = IndexPastLen + FollowSentencePunc + NotFollowAlphaNumeric;
  289.   NewSentence = LocGreaterThan2 + Follow2Spaces + FollowSentencePunc;
  290.  
  291.   Loc2End    = EdCtrlChar + LocAtLenPlus2;
  292.   WordStart0 = NotFollowAlphaNumeric + CapsFlagName + LocAtLen;
  293.   WordStart1 = NotFollowAlphaNumeric + LocBeforeLen + ChInAlph;
  294.   WordStart2 = NotFollowAlphaNumeric + LocAtLen + ChInAlph;
  295.  
  296. { GetSentenceOptions ====================================================== }
  297.  
  298. FUNCTION GetSentenceOptions (VAR S : string;  I : byte) : longint;
  299. VAR
  300.   Len   : byte absolute S;
  301.   Count : longint;
  302.  
  303. BEGIN
  304.   if Len = 0 then begin
  305.     GetSentenceOptions := NullString;
  306.     exit;
  307.     end;
  308.  
  309.   Count := 0;
  310.   if I = 1 then
  311.     Count := Count and IndexAt1
  312.   else
  313.     if I > Len then
  314.       Count := Count and IndexPastLen;
  315.  
  316.   if I > 1 then begin
  317.     if not InAlphabet (S [pred (I)]) then
  318.       Count := Count and NotFollowAlphaNumeric;
  319.     if S [pred (I)] = SpaceChar then
  320.       Count := Count and FollowSpace;
  321.     end;
  322.  
  323.   if I > 2 then begin
  324.     Count := Count + LocGreaterThan2;
  325.     if (Count and FollowSpace = FollowSpace) and (S [I - 2] = SpaceChar) then
  326.       Count := Count and Follow2Spaces;
  327.     end;
  328.  
  329.   if I > 3 then
  330.     if InSentencePunctuation (S [I - 3]) then
  331.       Count := Count and FollowSentencePunc;
  332.  
  333.   if I > 4 then
  334.     if InQuote (S [I - 3]) and InSentencePunctuation (S [I - 4]) then
  335.         Count := Count and FollowSentencePunc;
  336.  
  337.   GetSentenceOptions := Count;
  338. END;
  339.  
  340. { GetWordOptions ========================================================== }
  341.  
  342. FUNCTION GetWordOptions (VAR S : string;  I : byte;
  343.                          Ch : char;  CapsFlag : CapsFlagType) : longint;
  344. VAR
  345.   Len   : byte absolute S;
  346.   Count : longint;
  347.  
  348. BEGIN
  349.   Count := 0;
  350.  
  351.   if InEdCtrlChars (Ch) then
  352.     Count := Count and EdCtrlChar;
  353.  
  354.   if I < Len then
  355.     Count := Count and LocBeforeLen
  356.   else
  357.     if I = Len then
  358.       Count := Count and LocAtLen
  359.     else
  360.       if I = Len + 2 + ord (In2SpacePunctuation (S [Len])) then
  361.         Count := Count and LocAtLenPlus2;
  362.  
  363.   if CapsFlag = NameCaps then
  364.     Count := Count and CapsFlagName;
  365.  
  366.   GetWordOptions := Count;
  367. END;
  368.  
  369. { GetNameOptions ========================================================== }
  370.  
  371. FUNCTION GetNameOptions (VAR S : string;  I : byte;
  372.                          Ch : char;  CapsFlag : CapsFlagType) : longint;
  373. VAR
  374.   Len   : byte absolute S;
  375.   Count : longint;
  376.   ShortStr : string [3];
  377.  
  378. BEGIN
  379.   Count := 0;
  380.  
  381.   Case Len of
  382.     0..2   : exit;
  383.  
  384.     3      : begin
  385.              ShortStr := copy (S, I - 2, 2);
  386.              if (ShortStr = 'O''') or (ShortStr = 'Mc') then
  387.                Count := Count and McName;
  388.              end;
  389.  
  390.     4..255 : begin
  391.              ShortStr := copy (S, I - 3, 3);
  392.              if ShortStr = 'Mac' then
  393.                Count := Count and MacName
  394.              else begin
  395.                delete (ShortStr, 1, 1);
  396.                if (ShortStr = 'O''') or (ShortStr = 'Mc') then
  397.                  Count := Count and McName;
  398.                end;
  399.              end;
  400.     end;  { case }
  401.  
  402.   GetNameOptions := Count;
  403. END;
  404.  
  405. { FirstLetterOfASentence ================================================== }
  406.  
  407. FUNCTION FirstLetterOfASentence (VAR S : string;  I : byte) : Boolean;
  408. { Checks to see if the cursor is on the first letter of a sentence. }
  409.  
  410. VAR
  411.   SentenceOptions : longint;
  412.  
  413. BEGIN
  414.   SentenceOptions := GetSentenceOptions (S, I);
  415.   if
  416.     AndBit (SentenceOptions, NullString)
  417.       or
  418.     AndBit (SentenceOptions, BeyondLen)
  419.       or
  420.     AndBit (SentenceOptions, NewSentence)
  421.       or
  422.     AndBit (SentenceOptions, IndexAt1)
  423.   then
  424.     FirstLetterOfASentence := true
  425.   else
  426.     FirstLetterOfASentence := false;
  427. END;
  428.  
  429. (*
  430.   FirstLetterOfASentence :=
  431.                       { End of the line }
  432.                       (
  433.                       (LocNow > Len)
  434.                         and
  435.                       (pos (S [LocNow - 3], PuncStr) > 0)
  436.                         and
  437.                       (not InAlphabet (S [pred (LocNow)]))
  438.                       )
  439.                         or
  440.  
  441.                       { Starting loc of a sentence. }
  442.                       (
  443.                       (LocNow > 2)
  444.                           And
  445.                       (S [pred (LocNow)] = SpaceChar)
  446.                           And
  447.                       (S [LocNow - 2] = SpaceChar)
  448.                           And
  449.                       (Pos (S [LocNow - 3], PuncStr) > 0)
  450.                       )
  451.                           Or
  452.  
  453.                       { Start of a line }
  454.                       ((WndwPos = 1) and (LocNow = 1))
  455.                           or
  456.  
  457.                       { Empty Line. }
  458.                       (Len = 0);
  459. *)
  460.  
  461. { FirstLetterOfAWord ====================================================== }
  462.  
  463. FUNCTION FirstLetterOfAWord (VAR S : string;  I : byte;
  464.                              Ch : char;  CapsFlag : CapsFlagType) : boolean;
  465. {
  466.   Checks to see if the cursor is on the first letter of a word.
  467.   Ch is the value of the last character struck.  Function must
  468.   check to see if Ctrl-Char has been pressed.
  469.   Also needs to know current CapsFlagType in effect.
  470. }
  471.  
  472. VAR
  473.   WordOptions : longint;
  474.  
  475. BEGIN
  476.   WordOptions := GetSentenceOptions (S, I)
  477.                    and
  478.                  GetWordOptions (S, I, Ch, CapsFlag);
  479.  
  480.   if
  481.     AndBit (WordOptions, NullString)             { sentence options }
  482.       or
  483.     AndBit (WordOptions, BeyondLen)
  484.       or
  485.     AndBit (WordOptions, NewSentence)
  486.       or
  487.     AndBit (WordOptions, IndexAt1)
  488.       or
  489.  
  490.     AndBit (WordOptions, Loc2End)                { word options }
  491.       or
  492.     (
  493.       AndBit (WordOptions, NotFollowAlphaNumeric)
  494.         and
  495.       not Andbit(WordOptions, EdCtrlChar)
  496.     )
  497.       or
  498.     AndBit (WordOptions, WordStart0)
  499.       or
  500.     AndBit (WordOptions, WordStart1)
  501.       or
  502.     AndBit (WordOptions, WordStart2)
  503.   then
  504.     FirstLetterOfAWord := true
  505.   else
  506.     FirstLetterOfAWord := false;
  507.  
  508. END;
  509.  
  510. (*
  511. FirstLetterOfAWord := FirstLetterOfASentence
  512.                         or
  513.  
  514.                       { End of the string + 2, found by Ctrl-char }
  515.                       (
  516.                       CtrlChars (Key^.Ch)
  517.                         and
  518.                       (LocNow = Len + 2 +
  519.                                  Ord (In2SpacePunctuation (S [Len])))
  520.                       )
  521.                          or
  522.  
  523.                       { Pred Char is not in alphabet and ... }
  524.                       (
  525.                       (InPunctuation (PredCh) or (PredCh = SpaceChar))
  526.                         and
  527.                         (
  528.                           Not CtrlChars (Key^.Ch)
  529.                             or
  530.                           (
  531.                           (CapsFlag = NameCaps)
  532.                             and
  533.                           (LocNow = Len)
  534.                           )
  535.                             or
  536.  
  537.                           { Actual start of a word }
  538.                           (
  539.                           (LocNow <= Len)
  540.                             and
  541.                           InAlphabet (ThisCh)
  542.                           )
  543.                         )
  544.                       );
  545. END;
  546. *)
  547.  
  548. { FirstLetterOfAName ====================================================== }
  549.  
  550. FUNCTION FirstLetterOfAName (VAR S : string;  I : byte;
  551.                              Ch : char;  CapsFlag : CapsFlagType) : boolean;
  552. {
  553.   Checks to see if the cursor is on the first letter of a name.
  554.   Ch is the value of the last character struck.
  555. }
  556.  
  557. VAR
  558.   WordOptions : longint;
  559.  
  560. BEGIN
  561.   WordOptions := GetSentenceOptions (S, I)
  562.                    and
  563.                  GetWordOptions (S, I, Ch, CapsFlag)
  564.                    and
  565.                  GetNameOptions (S, I, Ch, CapsFlag);
  566.  
  567.   if
  568.     AndBit (WordOptions, NullString)             { sentence options }
  569.       or
  570.     AndBit (WordOptions, BeyondLen)
  571.       or
  572.     AndBit (WordOptions, NewSentence)
  573.       or
  574.     AndBit (WordOptions, IndexAt1)
  575.       or
  576.  
  577.     AndBit (WordOptions, Loc2End)                { word options }
  578.       or
  579.     (
  580.       AndBit (WordOptions, NotFollowAlphaNumeric)
  581.         and
  582.       not Andbit(WordOptions, EdCtrlChar)
  583.     )
  584.       or
  585.     AndBit (WordOptions, WordStart0)
  586.       or
  587.     AndBit (WordOptions, WordStart1)
  588.       or
  589.     AndBit (WordOptions, WordStart2)
  590.       or
  591.  
  592.     AndBit (WordOptions, McName)                 { name options }
  593.       or
  594.     AndBit (WordOptions, MacName)
  595.  
  596.   then
  597.     FirstLetterOfAName := true
  598.   else
  599.     FirstLetterOfAName := false;
  600. END;
  601.  
  602. { ========================================================================= }
  603. { Initialization ========================================================== }
  604.  
  605. { No initialization needed. }
  606. END.
  607.  
  608. { ========================================================================= }
  609. { ========================================================================= }
  610.  
  611. VERSION HISTORY:
  612.   9005.05
  613.     Completely restructured for consistency with Object Professional.
  614.  
  615.   9005.25
  616.     Added FirstLetter boolean functions for automatic capitalization of
  617.     sentences, words, names.
  618.  
  619. { ========================================================================= }
  620.  
  621. NOTES:
  622.  
  623.   FirstLetter functions have not been tested for durability.
  624.  
  625.   Also, these functions will be faster if they accept the string variables
  626.   as pointers.
  627.  
  628.   FirstLetter routines might belong in DgStr;  if so, this unit will not
  629.   need DgDec.
  630.  
  631. { ========================================================================= }
  632.  
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.