/******************************************************************************\ * This is a part of the Microsoft Source Code Samples. * Copyright (C) 1993-1997 Microsoft Corporation. * All rights reserved. * This source code is only intended as a supplement to * Microsoft Development Tools and/or WinHelp documentation. * See these sources for detailed information regarding the * Microsoft samples programs. \******************************************************************************/ /****************************** Module Header ******************************* * Module Name: LINE.C * * Functions that handle lines of text to be output. * * Functions: * * line_new() * line_delete() * line_reset() * line_gettext() * line_gettabbedlength() * line_getlink() * line_getlinenr() * line_compare() * line_link() * line_isblank() * * Comments: * * LINE is a data type representing a string of ascii text along with * a line number. * * A LINE can compare itself to another line, and maintain a link if the * lines are similar. * * Comparisons between lines take note of the global option flag * ignore_blanks, defined elsewhere. If this is true, we ignore * differences in spaces and tabs when comparing lines, and when * generating hashcodes. * * Links and are only generated once. To clear the link call line_reset. * * Lines can be allocated on a list. If a null list handle is passed, the * line will be allocated using gmem_get() from the hHeap defined and * initialised elsewhere. * ****************************************************************************/ #include #include #include #include "gutils.h" #include "windiff.h" /* defines hHeap and ignore_blanks */ #include "list.h" #include "line.h" struct fileline { UINT flags; /* see below */ LPSTR text; /* null-terminated copy of line text */ DWORD hash; /* hashcode for line */ LINE link; /* handle for linked line */ UINT linenr; /* line number (any arbitrary value) */ }; /* flag values (or-ed) */ #define LF_DISCARD 1 /* if true, alloced from gmem heap */ #define LF_HASHVALID 2 /* if true, hashcode need not be recalced */ /*************************************************************************** * Function: line_new * * Purpose: * * Creates a new line and makes a copy of the text. * * If the list is non-null, allocate on the list. If null, alloc from * gmem_get. * ***************************************************************************/ LINE line_new(LPSTR text, int linelength, UINT linenr, LIST list) { LINE line; /* alloc a line. from the list if there is a list */ if (list) { line = List_NewLast(list, sizeof(struct fileline)); if (line == NULL) { return(NULL); } line->flags = 0; } else { line = (LINE) gmem_get(hHeap, sizeof(struct fileline)); if (line == NULL) { return(NULL); } line->flags = LF_DISCARD; } /* alloc space for the text. remember the null character */ line->text = gmem_get(hHeap, linelength + 1); strncpy(line->text, text, linelength); line->text[linelength] = '\0'; line->link = NULL; line->linenr = linenr; return(line); } /*************************************************************************** * Function: line_delete * * Purpose: * * Deletes a line and frees up all associated memory and if the line * was not alloc-ed from a list, frees up the line struct itself * ***************************************************************************/ void line_delete(LINE line) { if (line == NULL) { return; } /* free up text space */ gmem_free(hHeap, line->text, lstrlen(line->text)+1); /* free up line itself only if not on list */ if (line->flags & LF_DISCARD) { gmem_free(hHeap, (LPSTR) line, sizeof(struct fileline)); } } /*************************************************************************** * Function: line_reset * * Purpose: * * Clears the link and force recalc of the hash code. * ***************************************************************************/ void line_reset(LINE line) { if (line == NULL) { return; } line->link = NULL; line->flags &= ~LF_HASHVALID; } /*************************************************************************** * Function: line_gettext * * Purpose: * * Returns a pointer to the line text * ***************************************************************************/ LPSTR line_gettext(LINE line) { if (line == NULL) { return(NULL); } return (line->text); } /*************************************************************************** * Function: line_gettabbedlength * * Purpose: * * Returns the length of line in characters, expanding tabs. * ***************************************************************************/ int line_gettabbedlength(LINE line, int tabstops) { int length; LPSTR chp; if (line == NULL) { return(0); } for (length = 0, chp = line->text; *chp != '\0'; chp++) { if (*chp == '\t') { length = (length + tabstops) / tabstops * tabstops; } else { length++; } } return(length); } /*************************************************************************** * Function: line_gethashcode * * Purpose: * * Returns the hashcode for this line * ***************************************************************************/ DWORD line_gethashcode(LINE line) { if (line == NULL) { return(0); } if (! (line->flags & LF_HASHVALID)) { /* hashcode needs to be recalced */ line->hash = hash_string(line->text, ignore_blanks); line->flags |= LF_HASHVALID; } return (line->hash); } /*************************************************************************** * Function: line_getlink * * Purpose: * * Returns the handle for the line that is linked to this line (the * result of a successful line_link() operation). This line is * identical in text to the linked line (allowing for ignore_blanks). * ***************************************************************************/ LINE line_getlink(LINE line) { if (line == NULL) { return(NULL); } return(line->link); } /*************************************************************************** * Function: line_getlinenr * * Purpose: * * Returns the line number associated with this line * ***************************************************************************/ UINT line_getlinenr(LINE line) { if (line == NULL) { return(0); } return(line->linenr); } /*************************************************************************** * Function: line_compare * * Purpose: * * Compares two lines and returns TRUE if they are the same. * ***************************************************************************/ BOOL line_compare(LINE line1, LINE line2) { LPSTR p1, p2; /* Assert: At least one of them is not null ??? */ if ((line1 == NULL) || (line2 == NULL)) { /* null line handles do not compare */ return(FALSE); } /* check that the hashcodes match */ if (line_gethashcode(line1) != line_gethashcode(line2)) { return(FALSE); } /* hashcodes match - are the lines really the same ? */ /* note that this is coupled to gutils\utils.c in definition of blank */ p1 = line_gettext(line1); p2 = line_gettext(line2); // Japanese friendy do { if (ignore_blanks) { while ( (*p1 == ' ') || (*p1 == '\t')) { p1 = CharNext(p1); } while ( (*p2 == ' ') || (*p2 == '\t')) { p2 = CharNext(p2); } } if (IsDBCSLeadByte(*p1) && *(p1+1) != '\0' && IsDBCSLeadByte(*p2) && *(p2+1) != '\0') { if (*p1 != *p2 || *(p1+1) != *(p2+1)) { return(FALSE); } p1 += 2; p2 += 2; } else { if (*p1 != *p2) { return(FALSE); } p1++; p2++; } } while ( (*p1 != '\0') && (*p2 != '\0')); return(TRUE); } /*************************************************************************** * Function: line_link * * Purpose: * * Attempts to link two lines and returns TRUE if succesful. * * This will fail if either line is NULL, or already linked, or if * they differ. * ***************************************************************************/ BOOL line_link(LINE line1, LINE line2) { if ( (line1 == NULL) || (line2 == NULL)) { return(FALSE); } if ( (line1->link != NULL) || (line2->link != NULL)) { return(FALSE); } if (line_compare(line1, line2)) { line1->link = line2; line2->link = line1; return(TRUE); } else { return(FALSE); } } /*************************************************************************** * Function: line_isblank * * Purpose: * * Returns TRUE iff line is blank. NULL => return FALSE * ***************************************************************************/ BOOL line_isblank(LINE line) { return line!=NULL && utils_isblank(line->text); }