home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / windiff / line.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  11KB  |  376 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1993-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /****************************** Module Header *******************************
  13. * Module Name: LINE.C
  14. *
  15. * Functions that handle lines of text to be output.
  16. *
  17. * Functions:
  18. *
  19. * line_new()
  20. * line_delete()
  21. * line_reset()
  22. * line_gettext()
  23. * line_gettabbedlength()
  24. * line_getlink()
  25. * line_getlinenr()
  26. * line_compare()
  27. * line_link()
  28. * line_isblank()
  29. *
  30. * Comments:
  31. *
  32. * LINE is a data type representing a string of ascii text along with 
  33. * a line number.
  34. *
  35. * A LINE can compare itself to another line, and maintain a link if the
  36. * lines are similar. 
  37. *
  38. * Comparisons between lines take note of the global option flag
  39. * ignore_blanks, defined elsewhere. If this is true, we ignore
  40. * differences in spaces and tabs when comparing lines, and when
  41. * generating hashcodes.
  42. *
  43. * Links and are only generated once. To clear the link call line_reset.
  44. *
  45. * Lines can be allocated on a list. If a null list handle is passed, the
  46. * line will be allocated using gmem_get() from the hHeap defined and
  47. * initialised elsewhere.
  48. *
  49. ****************************************************************************/
  50.  
  51. #include <windows.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54.  
  55. #include "gutils.h"
  56. #include "windiff.h"    /* defines hHeap and ignore_blanks */
  57. #include "list.h"
  58. #include "line.h"
  59.  
  60. struct fileline {
  61.  
  62.         UINT flags;     /* see below */
  63.  
  64.         LPSTR text;     /* null-terminated copy of line text */
  65.         DWORD hash;     /* hashcode for line */
  66.         LINE link;      /* handle for linked line */
  67.         UINT linenr;    /* line number (any arbitrary value) */
  68. };
  69.  
  70. /* flag values (or-ed) */
  71. #define LF_DISCARD      1       /* if true, alloced from gmem heap */
  72. #define LF_HASHVALID    2       /* if true, hashcode need not be recalced */
  73.  
  74.  
  75. /***************************************************************************
  76.  * Function: line_new
  77.  *
  78.  * Purpose:
  79.  *
  80.  * Creates a new line and makes a copy of the text.
  81.  *
  82.  * If the list is non-null, allocate on the list. If null, alloc from
  83.  * gmem_get.
  84.  *
  85.  ***************************************************************************/
  86. LINE
  87. line_new(LPSTR text, int linelength, UINT linenr, LIST list)
  88. {
  89.         LINE line;
  90.  
  91.         /* alloc a line. from the list if there is a list */
  92.         if (list) {
  93.                 line = List_NewLast(list, sizeof(struct fileline));
  94.                 if (line == NULL) {
  95.                         return(NULL);
  96.                 }
  97.                 line->flags = 0;
  98.         } else {
  99.                 line = (LINE) gmem_get(hHeap, sizeof(struct fileline));
  100.                 if (line == NULL) {
  101.                         return(NULL);
  102.                 }
  103.                 line->flags = LF_DISCARD;
  104.         }
  105.  
  106.         /* alloc space for the text. remember the null character */
  107.         line->text = gmem_get(hHeap, linelength + 1);
  108.         strncpy(line->text, text, linelength);
  109.         line->text[linelength] = '\0';
  110.  
  111.         line->link = NULL;
  112.         line->linenr = linenr;
  113.  
  114.         return(line);
  115. }
  116.  
  117. /***************************************************************************
  118.  * Function: line_delete
  119.  *
  120.  * Purpose:
  121.  *
  122.  * Deletes a line and frees up all associated memory and if the line
  123.  * was not alloc-ed from a list, frees up the line struct itself
  124.  *
  125.  ***************************************************************************/
  126. void
  127. line_delete(LINE line)
  128. {
  129.         if (line == NULL) {
  130.                 return;
  131.         }
  132.  
  133.         /* free up text space */
  134.         gmem_free(hHeap, line->text, lstrlen(line->text)+1);
  135.  
  136.         /* free up line itself only if not on list */
  137.         if (line->flags & LF_DISCARD) {
  138.                 gmem_free(hHeap, (LPSTR) line, sizeof(struct fileline));
  139.         }
  140. }
  141.  
  142. /***************************************************************************
  143.  * Function: line_reset
  144.  *
  145.  * Purpose:
  146.  *
  147.  * Clears the link and force recalc of the hash code.
  148.  *
  149.  ***************************************************************************/
  150. void
  151. line_reset(LINE line)
  152. {
  153.         if (line == NULL) {
  154.                 return;
  155.         }
  156.  
  157.         line->link = NULL;
  158.  
  159.         line->flags &= ~LF_HASHVALID;
  160. }
  161.  
  162.  
  163. /***************************************************************************
  164.  * Function: line_gettext
  165.  *
  166.  * Purpose:
  167.  *
  168.  * Returns a pointer to the line text
  169.  *
  170.  ***************************************************************************/
  171. LPSTR
  172. line_gettext(LINE line)
  173. {
  174.         if (line == NULL) {
  175.                 return(NULL);
  176.         }
  177.  
  178.         return (line->text);
  179. }
  180.  
  181. /***************************************************************************
  182.  * Function: line_gettabbedlength
  183.  *
  184.  * Purpose:
  185.  *
  186.  * Returns the length of line in characters, expanding tabs. 
  187.  *
  188.  ***************************************************************************/
  189. int
  190. line_gettabbedlength(LINE line, int tabstops)
  191. {
  192.         int length;
  193.         LPSTR chp;
  194.  
  195.         if (line == NULL) {
  196.                 return(0);
  197.         }
  198.  
  199.         for (length = 0, chp = line->text; *chp != '\0'; chp++) {
  200.                 if (*chp == '\t') {
  201.                          length = (length + tabstops) / tabstops * tabstops;
  202.                 } else {
  203.                         length++;
  204.                 }
  205.         }
  206.         return(length);
  207. }
  208.  
  209.  
  210. /***************************************************************************
  211.  * Function: line_gethashcode
  212.  *
  213.  * Purpose:
  214.  *
  215.  * Returns the hashcode for this line 
  216.  *
  217.  ***************************************************************************/
  218. DWORD
  219. line_gethashcode(LINE line)
  220. {
  221.         if (line == NULL) {
  222.                 return(0);
  223.         }
  224.  
  225.         if (! (line->flags & LF_HASHVALID)) {
  226.  
  227.  
  228.                 /* hashcode needs to be recalced */
  229.                 line->hash = hash_string(line->text, ignore_blanks);
  230.                 line->flags |= LF_HASHVALID;
  231.         }
  232.         return (line->hash);
  233. }
  234.  
  235. /***************************************************************************
  236.  * Function: line_getlink
  237.  *
  238.  * Purpose:
  239.  *
  240.  * Returns the handle for the line that is linked to this line (the
  241.  * result of a successful line_link() operation). This line is
  242.  * identical in text to the linked line (allowing for ignore_blanks).
  243.  *
  244.  ***************************************************************************/
  245. LINE
  246. line_getlink(LINE line)
  247. {
  248.         if (line == NULL) {
  249.                 return(NULL);
  250.         }
  251.  
  252.         return(line->link);
  253. }
  254.  
  255. /***************************************************************************
  256.  * Function: line_getlinenr
  257.  *
  258.  * Purpose:
  259.  *
  260.  * Returns the line number associated with this line 
  261.  *
  262.  ***************************************************************************/
  263. UINT
  264. line_getlinenr(LINE line)
  265. {
  266.         if (line == NULL) {
  267.                 return(0);
  268.         }
  269.  
  270.         return(line->linenr);
  271. }
  272.  
  273. /***************************************************************************
  274.  * Function: line_compare
  275.  *
  276.  * Purpose:
  277.  *
  278.  * Compares two lines and returns TRUE if they are the same.
  279.  *
  280.  ***************************************************************************/
  281. BOOL
  282. line_compare(LINE line1, LINE line2)
  283. {
  284.         LPSTR p1, p2;
  285.  
  286.         /* Assert: At least one of them is not null ??? */
  287.  
  288.         if ((line1 == NULL) || (line2 == NULL)) {
  289.                 /* null line handles do not compare */
  290.                 return(FALSE);
  291.         }
  292.  
  293.         /* check that the hashcodes match */
  294.         if (line_gethashcode(line1) != line_gethashcode(line2)) {
  295.                 return(FALSE);
  296.         }
  297.  
  298.         /* hashcodes match - are the lines really the same ? */
  299.         /* note that this is coupled to gutils\utils.c in definition of blank */
  300.         p1 = line_gettext(line1);
  301.         p2 = line_gettext(line2);
  302.  
  303. // Japanese friendy
  304.         do {
  305.                 if (ignore_blanks) {
  306.                         while ( (*p1 == ' ') || (*p1 == '\t')) {
  307.                                 p1 = CharNext(p1);
  308.                         }
  309.                         while ( (*p2 == ' ') || (*p2 == '\t')) {
  310.                                 p2 = CharNext(p2);
  311.                         }
  312.                 }
  313.                 if (IsDBCSLeadByte(*p1) && *(p1+1) != '\0'
  314.                 &&  IsDBCSLeadByte(*p2) && *(p2+1) != '\0') {
  315.                         if (*p1 != *p2 || *(p1+1) != *(p2+1)) {
  316.                                 return(FALSE);
  317.                         }
  318.                         p1 += 2;
  319.                         p2 += 2;
  320.                 } else {
  321.                         if (*p1 != *p2) {
  322.                                 return(FALSE);
  323.                         }
  324.                         p1++;
  325.                         p2++;
  326.                 }
  327.         } while ( (*p1 != '\0') && (*p2 != '\0'));
  328.  
  329.         return(TRUE);
  330. }
  331.  
  332. /***************************************************************************
  333.  * Function: line_link
  334.  *
  335.  * Purpose:
  336.  *
  337.  * Attempts to link two lines and returns TRUE if succesful.
  338.  *
  339.  * This will fail if either line is NULL, or already linked, or if
  340.  * they differ.
  341.  *
  342.  ***************************************************************************/
  343. BOOL
  344. line_link(LINE line1, LINE line2)
  345. {
  346.         if ( (line1 == NULL) || (line2 == NULL)) {
  347.                 return(FALSE);
  348.         }
  349.  
  350.         if ( (line1->link != NULL) || (line2->link != NULL)) {
  351.                 return(FALSE);
  352.         }
  353.  
  354.         if (line_compare(line1, line2)) {
  355.                 line1->link = line2;
  356.                 line2->link = line1;
  357.                 return(TRUE);
  358.         } else {
  359.                 return(FALSE);
  360.         }
  361. }
  362.  
  363.  
  364. /***************************************************************************
  365.  * Function: line_isblank
  366.  *
  367.  * Purpose:
  368.  *
  369.  * Returns TRUE iff line is blank.  NULL => return FALSE 
  370.  *
  371.  ***************************************************************************/
  372. BOOL line_isblank(LINE line)
  373. {
  374.         return line!=NULL && utils_isblank(line->text);
  375. }
  376.