int CaretOffsetLine( LPCLASSDATA lpcd, int nLine, int nColumn ) { LPLINE lpLine = ArrayGetAt( lpcd->lpLines, nLine ); int nPos = 0, i; if ( lpLine && lpLine->pcText ) { /* * Iterate characters. */ for ( i = 0; i < lpLine->nLength && i < nColumn; i++ ) { /* * A tab? */ if ( lpLine->pcText[ i ] == _T( '\t' )) /* * Add number of spaces to the next tab-stop. */ nPos += Parser->nTabSize - ( nPos % Parser->nTabSize ); else /* * One more. */ nPos++; } } return nPos; }
int TextOffsetLine( LPCLASSDATA lpcd, int nLine, int nColumn, BOOL *pTruncated ) { LPLINE lpLine = ArrayGetAt( lpcd->lpLines, nLine ); int i = 0, nPos = 0; /* * Any text? */ if ( lpLine->pcText ) { /* * Iterate characters. */ for ( i = 0; i < lpLine->nLength; i++ ) { /* * Is this a tab? */ if ( lpLine->pcText[ i ] == _T( '\t' )) /* * Add number of spaces to the next tab stop. */ nPos += Parser->nTabSize - ( nPos % Parser->nTabSize ); else /* * One more. */ nPos++; /* * If we passed the requested column we can * stop here since we have reached the text * offset we are looking for. */ if ( nPos > nColumn ) break; } /* * The contents of the pTruncated pointer, if valid, * will be set to TRUE if the position computed is short * of the column requested. */ if ( pTruncated ) *pTruncated = ( BOOL )( nPos < nColumn ? TRUE : FALSE ); } return i; }
/* * Any text in the buffer? */ BOOL AnyText( LPCLASSDATA lpcd ) { if ( ArrayGetSize( lpcd->lpLines ) == 1 && (( LPLINE )ArrayGetAt( lpcd->lpLines, 0 ))->nLength == 0 ) return FALSE; return TRUE; }
static void SetSizeControls( HWND hDlg ) { LPCLASSDATA lpcd = ( LPCLASSDATA )GetWindowLong( hDlg, DWL_USER ); TCHAR szBuffer[ 256 ]; SHFILEINFO psfi; int nLines = ArrayGetSize( lpcd->lpLines ), i, nFileMode; unsigned int nBytes = 0, nLineTerm = 1; /* * Get system file type. */ SHGetFileInfo( lpcd->szFileName, 0, &psfi, sizeof( SHFILEINFO ), SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME ); SetDlgItemText( hDlg, IDC_PROP_SYSTYPE, psfi.szTypeName[ 0 ] ? psfi.szTypeName : GetString( IDS_NO_TYPENAME )); /* * Setup language name. */ SetDlgItemText( hDlg, IDC_PROP_LANGUAGE, Parser->pszTitle ); /* * Setup tab-size. */ SetDlgItemInt( hDlg, IDC_PROP_TABSIZE, Parser->nTabSize, FALSE ); /* * Setup icon. */ SendDlgItemMessage( hDlg, IDC_PROP_ICON, STM_SETICON, ( WPARAM )lpcd->hIconLarge, 0 ); /* * Setup file mode. */ SendDlgItemMessage( hDlg, IDC_PROP_TYPE, CB_SETCURSEL, Parser->nFileMode, 0 ); /* * Get file mode. */ nFileMode = SendDlgItemMessage( hDlg, IDC_PROP_TYPE, CB_GETCURSEL, 0, 0 ); /* * Compute size of the * line terminator. */ if ( nFileMode == FMODE_MSDOS || nFileMode == FMODE_UNIX ) nLineTerm = 2; /* * Compute the file size * in bytes. */ for ( i = 0; i < nLines; i++ ) { /* * Add line length. */ nBytes += (( LPLINE )ArrayGetAt( lpcd->lpLines, i ))->nLength; /* * Add line terminator bytes * if this is not the last line. */ if ( i < nLines - 1 ) nBytes += nLineTerm; } /* * Format and set size string. */ _stprintf_s( szBuffer, 256, GetString( IDS_FILE_SIZE ), nBytes, nLines ); SetDlgItemText( hDlg, IDC_PROP_SIZE, szBuffer ); }
int ParseLine( LPCLASSDATA lpcd, int nInBlock, TCHAR *pcText, int nLength, SYNTAX_COLOR *scColors, int *lpnBlocks, int nNumBlocks, int nLine ) { LPPARSER lpp = Parser; LPKEYHASH lpHash; LPBLOCK lpBlock; COLORREF crText = Parser->crColors[ CARR_TEXT ]; int nIndex = 0, nBlock = 0, nSize, i, nMatchX1 = 0, nMatchX2 = 0; BOOL bContinue = FALSE, bStartOfLine = TRUE, bHasInit = FALSE; int nHyperLength; // Modified by Stephan (2005-06-12) // To allow unquoted paths with space like c:\program files /* * Compute match columns. */ if ( lpcd->ptBracket1.y >= 0 ) nMatchX1 = CaretOffsetLine( lpcd, lpcd->ptBracket1.y, lpcd->ptBracket1.x ); if ( lpcd->ptBracket2.y >= 0 ) nMatchX2 = CaretOffsetLine( lpcd, lpcd->ptBracket2.y, lpcd->ptBracket2.x ); /* * Any text to parse? */ if ( nLength == 0 ) /* * Return the block we are in. */ return nInBlock; /* * Start with a normal text * color block... */ if ( scColors ) { /* * Enough text blocks? */ CHECK_BLOCKS; scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].crColor = crText; scColors[ nBlock ].crBgColor = CLR_DEFAULT; scColors[ nBlock ].pHash = NULL; scColors[ nBlock ].wFlags = 0; } /* * Parser active? */ if ( lpp == NULL ) { /* * A single text color block. */ *lpnBlocks = 1; return -1; } /* * Are we in a block? */ if ( nInBlock != -1 ) { /* * Get the block. */ lpBlock = ArrayGetAt( lpp->lpaBlocks, nInBlock ); /* * Setup the color. */ if ( scColors ) { /* * Enough text blocks? */ CHECK_BLOCKS; scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].crColor = lpBlock->crColor; scColors[ nBlock ].crBgColor = lpBlock->crBgColor; scColors[ nBlock ].pHash = NULL; scColors[ nBlock ].wFlags = 0; } /* * End the block with a string? */ if ( lpBlock->nEnd ) { /* * See if the terminator string occures * on the line. */ LPCTSTR pszStr = ( lpp->bCaseOn ? StrStr : StrStrI )( pcText, lpBlock->pszEnd ); /* * Terminator found? */ if( pszStr == NULL ) { /* * Are we parsing hyperlinks? */ if ( Parser->bParseHyperLinks && scColors && lpnBlocks ) { /* * Find all hyperlinks in the line starting * at offset 'nIndex'. */ *lpnBlocks = FindHyperlinksInBlock( lpcd, pcText, nIndex, nLength, 0, nNumBlocks, lpnBlocks, scColors ) + 1; scColors[ *lpnBlocks - 1 ].nColumn = nLength; } else if ( lpnBlocks ) /* * Uses a single block. */ *lpnBlocks = 1; /* * Remain in the text block. */ return nInBlock; } else if ( Parser->bParseHyperLinks && scColors && lpnBlocks ) /* * Find all hyperlinks from offset 'nIndex' * up to the block end marker. */ nBlock = FindHyperlinksInBlock( lpcd, pcText, nIndex, ( int )( pszStr - pcText ), 0, nNumBlocks, lpnBlocks, scColors ); /* * Skip to the index at which * the terminator was found. */ nIndex = ( int )( pszStr - pcText ); } } else { /* * If we are not yet inside a block we determine * if any of the block initiators occure in this * line and, if so, at which offset. */ for ( i = 0; ; i++ ) { /* * Get the block. */ lpBlock = ArrayGetAt( lpp->lpaBlocks, i ); /* * Done? */ if ( lpBlock == NULL ) break; /* * By default this block initiator is not on * this line. */ lpBlock->bInLine = FALSE; /* * Will the initiator fit at all? */ if ( lpBlock->nStart && lpBlock->nStart <= nLength ) { /* * Look up the block initiator on the line. */ LPCTSTR pszStr = ( lpp->bCaseOn ? StrStr : StrStrI )( pcText, lpBlock->pszStart ); /* * Found? */ if ( pszStr != NULL ) { /* * We have a block initializer. */ bHasInit = TRUE; /* * This block initiator is located * on this line. */ lpBlock->bInLine = TRUE; } } } } /* * First we skip the leading blanks... */ while ( _istspace( pcText[ nIndex ] ) && nIndex <= nLength ) nIndex++; /* * Iterate text. */ for ( /*nIndex = 0*/; nIndex <= nLength; nIndex++ ) { /* * Clear continue flag. */ bContinue = FALSE; /* * In a block? */ if ( nInBlock != -1 ) { /* * Get block. */ lpBlock = ArrayGetAt( lpp->lpaBlocks, nInBlock ); /* * Does the block terminate with a string? */ if ( lpBlock->nEnd ) { /* * Does the terminator occure in the text? */ LPCTSTR pszStr = ( lpp->bCaseOn ? StrStr : StrStrI )( &pcText[ nIndex ], lpBlock->pszEnd ); /* * No. Return the block number. */ if ( pszStr == NULL ) { /* * Are we parsing hyperlinks? */ if ( Parser->bParseHyperLinks && scColors && lpnBlocks ) { /* * Find the hyperlinks starting at offset 'nIndex'. */ *lpnBlocks = FindHyperlinksInBlock( lpcd, pcText, nIndex, nLength, nBlock, nNumBlocks, lpnBlocks, scColors ) + 1; scColors[ *lpnBlocks - 1 ].nColumn = nLength; } else if ( lpnBlocks ) /* * Store the block number. */ *lpnBlocks = nBlock + 1; return nInBlock; } else if ( Parser->bParseHyperLinks && scColors && lpnBlocks ) /* * Find all hyperlinks from offset 'nIndex' * up to the block end marker. */ nBlock = FindHyperlinksInBlock( lpcd, pcText, nIndex, ( int )( pszStr - pcText ), nBlock, nNumBlocks, lpnBlocks, scColors ); /* * Skip through to the index at which the * terminator was found. */ nIndex = ( int )( pszStr - pcText ); } /* * Will the terminator fit? */ if ( nLength - nIndex >= lpBlock->nEnd || lpBlock->pszEnd == END_OF_LINE ) { /* * End a block? */ if ( BlockEnd( lpcd, lpBlock, pcText, nIndex, nLength )) { /* * Color array present? */ if ( scColors ) { /* * Enough room? */ CHECK_BLOCKS; /* * Yes. Terminate current color. */ scColors[ nBlock++ ].nColumn = nIndex + lpBlock->nEnd; /* * Start a new color. */ scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].crColor = crText; scColors[ nBlock ].crBgColor = CLR_DEFAULT; scColors[ nBlock ].pHash = NULL; scColors[ nBlock ].wFlags = 0; } /* * Skip the block terminator. */ if ( lpBlock->pszEnd != END_OF_LINE ) nIndex += lpBlock->nEnd - 1; else nIndex = nLength; /* * No longer in the block. */ nInBlock = -1; /* * Continue parse... */ continue; } } } /* * Keep looking for the terminator if * we are still inside a block. */ if ( nInBlock != -1 ) { if ( scColors && nIndex >= nLength ) scColors[ nBlock ].nColumn = nIndex; continue; } /* * Do we have an initiator? */ if ( bHasInit ) { /* * Look up the block * initiators. */ for ( i = 0; ; i++ ) { /* * Valid block? */ if (( lpBlock = ArrayGetAt( lpp->lpaBlocks, i )) == NULL ) break; /* * Block initiator in this * line? */ if ( ! lpBlock->bInLine ) continue; /* * Block found? */ if ( ! BlockStart( lpcd, lpBlock, pcText, nIndex, nLength, bStartOfLine )) continue; /* * Colors present? */ if ( scColors ) { /* * Enough room? */ CHECK_BLOCKS; /* * Yes. Terminate current color. */ scColors[ nBlock++ ].nColumn = nIndex; /* * Start a new color. */ scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].crColor = lpBlock->crColor; scColors[ nBlock ].crBgColor = lpBlock->crBgColor; scColors[ nBlock ].pHash = NULL; scColors[ nBlock ].wFlags = 0; } /* * Mark us as being in the block. */ nInBlock = i; /* * Does this block terminate at eol? */ if ( lpBlock->pszEnd == END_OF_LINE ) { /* * Look at the rest of the line * for hyperlinks. */ if ( Parser->bParseHyperLinks && scColors && lpnBlocks ) nBlock = FindHyperlinksInBlock( lpcd, pcText, nIndex, nLength, nBlock, nNumBlocks, lpnBlocks, scColors ); /* * Skip everything except * the last terminator length * plus the escape character. */ nIndex = max( 0, nLength - 2 ); } else /* * Skip the block initiator. */ nIndex += lpBlock->nStart - 1; /* * Break the loop and * continue parsing. */ bContinue = TRUE; break; } } /* * No longer at the start * of the line... */ bStartOfLine = FALSE; /* * Continue? */ if ( bContinue || scColors == NULL ) continue; /* * Skip spaces. */ if ( _istspace( pcText[ nIndex ] )) { /* * Make a new block. */ if ( scColors[ nBlock ].crBgColor != CLR_DEFAULT || scColors[ nBlock ].crColor != crText || scColors[ nBlock ].wFlags ) { /* * Enough room? */ CHECK_BLOCKS; /* * Terminate current color. */ scColors[ nBlock++ ].nColumn = nIndex; /* * Setup new color. */ scColors[ nBlock ].crColor = crText; scColors[ nBlock ].crBgColor = CLR_DEFAULT; scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].pHash = NULL; scColors[ nBlock ].wFlags = 0; } continue; } if ( Parser->bParseHyperLinks && scColors ) { nHyperLength = IsHyperlink( pcText, nIndex, nLength ); // Modified by Stephan (2005-06-12) if (nHyperLength) { /* * Enough room? */ CHECK_BLOCKS; /* * Yes. Terminate current color. */ scColors[ nBlock++ ].nColumn = nIndex; /* * Start a new color. */ scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].crColor = Parser->crColors[ CARR_HYPERLINK ]; scColors[ nBlock ].crBgColor = Parser->crColors[ CARR_BACKGROUND_HYPERLINK ]; scColors[ nBlock ].pHash = NULL; scColors[ nBlock ].wFlags = SCF_HYPERLINK; /* * Is it a quoted hyperlink? */ if ( nIndex && (pcText[ nIndex - 1 ] == _T( '"' ) || pcText[ nIndex - 1 ] == _T( '\'' ))) // Modified by Stephan (2005-05-30) { /* * Look up the next quote. */ while ( nIndex < nLength && pcText[ nIndex ] != _T( '"' ) && pcText[ nIndex ] != _T( '\'' )) // Modified by Stephan (2005-05-30) nIndex++; if ( pcText[ nIndex ] == _T( '"' ) || pcText[ nIndex ] == _T( '\'' )) // Modified by Stephan (2005-05-30) nIndex--; } else { /* * Look up the next white space. */ nIndex += nHyperLength; // Modified by Stephan while ( nIndex < nLength && ! _istspace( pcText[ nIndex ] ) && pcText[ nIndex ] != _T('(') && pcText[ nIndex ] != _T(',') && pcText[ nIndex ] != _T(';') && pcText[ nIndex ] != _T(')') && pcText[ nIndex ] != _T('\'')) // Modified by Stephan (2005-05-28) nIndex++; if ( _istspace( pcText[ nIndex ] ) || pcText[ nIndex ] == _T('(') || pcText[ nIndex ] == _T(',') || pcText[ nIndex ] == _T(';') || pcText[ nIndex ] == _T(')') || pcText[ nIndex ] == _T('\'')) // Modified by Stephan (2005-05-28) nIndex--; } continue; } } /* * Delimiter? */ if ( IsDelimiter( lpcd, pcText[ nIndex ] )) { /* * Any change in color? */ if (( scColors[ nBlock ].crColor != Parser->crColors[ CARR_DELIMITER ] ) || ( scColors[ nBlock ].crBgColor != Parser->crColors[ CARR_BACKGROUND_DELIMITER ] ) || ( scColors[ nBlock ].wFlags )) { /* * Enough room? */ CHECK_BLOCKS; /* * Terminate current color. */ scColors[ nBlock++ ].nColumn = nIndex; /* * Setup delimiter color. */ scColors[ nBlock ].crColor = Parser->crColors[ CARR_DELIMITER ]; scColors[ nBlock ].crBgColor = Parser->crColors[ CARR_BACKGROUND_DELIMITER ]; scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].pHash = NULL; scColors[ nBlock ].wFlags = 0; } /* * Do we have matched brackets? */ if (( nLine == lpcd->ptBracket1.y && nIndex == nMatchX1 ) || ( nLine == lpcd->ptBracket2.y && nIndex == nMatchX2 )) { /* * Enough room? */ CHECK_BLOCKS; /* * Terminate current color. */ scColors[ nBlock++ ].nColumn = nIndex; /* * Setup match color. */ scColors[ nBlock ].crColor = scColors[ nBlock - 1 ].crColor; scColors[ nBlock ].crBgColor = lpp->crColors[ CARR_BRACKET_MATCH ]; scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].pHash = NULL; scColors[ nBlock ].wFlags = 0; } /* * Continue parsing. */ continue; } else /* * Is it a number? This check is a bit * to simple but it should not pose * any problems... */ if ( _istdigit( pcText[ nIndex ] )) { /* * Color changes? */ if (( scColors[ nBlock ].crColor != Parser->crColors[ CARR_NUMBER ] ) || ( scColors[ nBlock ].crBgColor != Parser->crColors[ CARR_BACKGROUND_NUMBER ] ) || ( scColors[ nBlock ].wFlags )) { /* * Enough room? */ CHECK_BLOCKS; /* * Terminate the current color. */ scColors[ nBlock++ ].nColumn = nIndex; /* * Setup the number colors. */ scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].crColor = Parser->crColors[ CARR_NUMBER ]; scColors[ nBlock ].crBgColor = Parser->crColors[ CARR_BACKGROUND_NUMBER ]; scColors[ nBlock ].pHash = NULL; scColors[ nBlock ].wFlags = 0; } } else { /* * Do we have bracket matches? */ if (( nLine == lpcd->ptBracket1.y && nIndex == nMatchX1 ) || ( nLine == lpcd->ptBracket2.y && nIndex == nMatchX2 )) { /* * Enough room? */ CHECK_BLOCKS; /* * Terminate current color. */ scColors[ nBlock++ ].nColumn = nIndex; /* * Setup match color. */ scColors[ nBlock ].crColor = crText; scColors[ nBlock ].crBgColor = lpp->crColors[ CARR_BRACKET_MATCH ]; scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].pHash = NULL; scColors[ nBlock ].wFlags = 0; /* * Continue parsing. */ continue; } else if ( scColors[ nBlock ].crColor != crText || scColors[ nBlock ].crBgColor != CLR_DEFAULT || scColors[ nBlock ].wFlags ) { /* * Enough room? */ CHECK_BLOCKS; /* * Terminate current color. */ scColors[ nBlock++ ].nColumn = nIndex; /* * Setup text color. */ scColors[ nBlock ].crColor = crText; scColors[ nBlock ].crBgColor = CLR_DEFAULT; scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].pHash = NULL; scColors[ nBlock ].wFlags = 0; } } /* * Count the characters up until * the next space or delimiter. */ nSize = nIndex; while ( nSize < nLength && ! _istspace( pcText[ nSize ] ) && ! IsDelimiter( lpcd, pcText[ nSize ] )) { /* * Do we have bracket matches? */ if (( nLine == lpcd->ptBracket1.y && nSize == nMatchX1 ) || ( nLine == lpcd->ptBracket2.y && nSize == nMatchX2 )) { /* * Enough room? */ CHECK_BLOCKS; /* * Terminate current color. */ scColors[ nBlock++ ].nColumn = nSize; /* * Setup match colors. */ scColors[ nBlock ].crColor = crText; scColors[ nBlock ].crBgColor = lpp->crColors[ CARR_BRACKET_MATCH ]; scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].pHash = NULL; scColors[ nBlock ].wFlags = 0; /* * Continue parsing. */ break; } nSize++; } /* * Is the previous character a space/delimiter or are * we at the start of the line? */ if ( nIndex == 0 || _istspace( pcText[ nIndex - 1 ] ) || IsDelimiter( lpcd, pcText[ nIndex - 1 ] )) { /* * Is it a keyword */ if (( lpHash = IsKeyword( lpcd, &pcText[ nIndex ], nSize - nIndex )) != NULL ) { /* * Color changes? * NOTE: Removed to accomodate case-fixing. */ /*if ( scColors[ nBlock ].crColor != lpHash->crColor )*/ { /* * Enough room? */ CHECK_BLOCKS; /* * Terminate the current color. */ scColors[ nBlock++ ].nColumn = nIndex; /* * Setup the keyword color and the hash. We use the hash * when a text line is edited to fix the casing when * case-fixing is turned on. */ scColors[ nBlock ].nColumn = nLength; scColors[ nBlock ].crColor = lpHash->crColor; scColors[ nBlock ].crBgColor = lpHash->crBkColor; scColors[ nBlock ].pHash = lpHash; scColors[ nBlock ].wFlags = 0; } } } /* * Are we at the end? */ if ( nSize >= nLength ) break; /* * Adjust the index. */ nIndex = nSize - 1; } /* * Store the number of syntax * color block that are valid. */ if ( lpnBlocks ) *lpnBlocks = nBlock + 1; return nInBlock; }
/* * Pre-parse until we reach the passed line. */ void PreParseTo( LPCLASSDATA lpcd, int nTo ) { register LPLINE lpLine; register int i, nBlock = -1, nLines = ArrayGetSize( lpcd->lpLines ); int nDummy; /* * Did the previous line end with an open block * marker? */ if ( lpcd->dwParsedUpTo == 0 ) nBlock = -1; else nBlock = (( LPLINE )ArrayGetAt( lpcd->lpLines, lpcd->dwParsedUpTo ))->nBlock; /* * Make sure we do not go past the end * of the file. */ nTo = min( nTo, nLines - 1 ); /* * Iterate the lines. */ for ( i = lpcd->dwParsedUpTo; i <= nTo; i++ ) { /* * Get line pointer. */ lpLine = ArrayGetAt( lpcd->lpLines, i ); /* * Pre-parse the line. This is done so that * the blocks found in the text are parsed * before the file is displayed the first * time. */ lpLine->nBlock = nBlock = ParseLine( lpcd, nBlock, lpLine->pcText, lpLine->nLength, NULL, &nDummy, 0, i ); } /* * Are all lines parsed? */ if ( nTo >= nLines - 1 ) { /* * Kill the timer. */ if ( lpcd->nParseTimerID ) { KillTimer( lpcd->hWnd, lpcd->nParseTimerID ); lpcd->nParseTimerID = 0; } /* * Set the counter to the maximum. */ lpcd->dwParsedUpTo = 0xFFFFFFFF; } else { /* * Is the parsing timer up? */ if ( lpcd->nParseTimerID == 0 ) lpcd->nParseTimerID = SetTimer( lpcd->hWnd, IDT_PARSETIMER, 100, NULL ); /* * Update the counter. */ lpcd->dwParsedUpTo = nTo; } }
/* * Check if the given position is over * a hyperlink. Also sets up the start * and end points if a hyperlink is * found. */ static BOOL CheckForHyperlink( LPCLASSDATA lpcd, LPPOINT lpPos, LPPOINT lpStart, LPPOINT lpEnd, BOOL bQuoted ) { LPLINE lpLine = ( LPLINE )ArrayGetAt( lpcd->lpLines, lpPos->y ); int nIndex = lpPos->x, i = 0; /* * Any text and, if so, any text on the * line? */ if ( AnyText( lpcd ) == FALSE || lpLine->pcText == NULL ) return FALSE; /* * Are we in the text of the line? */ if ( nIndex >= lpLine->nLength ) return FALSE; /* * Is the given position on a white space and * are we doing a non-quoted search? */ if ( ! bQuoted && (_istspace( lpLine->pcText[ nIndex ] ) || lpLine->pcText[ nIndex ] == _T('=') || lpLine->pcText[ nIndex ] == _T(';'))) // Modifications by Stephan (2005-05-28) { /* * Try a quoted search now. */ return CheckForHyperlink( lpcd, lpPos, lpStart, lpEnd, TRUE ); } /* * Store line numbers. */ lpStart->y = lpEnd->y = lpPos->y; /* * Search for a quoted hyperlink? */ if ( ! bQuoted ) { /* * Find the first white space or the * beginning of the line. */ while ( nIndex > 0 && ! _istspace( lpLine->pcText[ nIndex ] ) && lpLine->pcText[ nIndex ] != _T('=') && lpLine->pcText[ nIndex ] != _T(';')) nIndex--; // Support for certain Windows folders with white spaces if (nIndex >= 16 && lpLine->nLength > nIndex + 5 && !_tcsncicmp(lpLine->pcText + nIndex + 1, _T("(x86)"), 5)) nIndex -= 16; else if (nIndex >= 10 && lpLine->nLength > nIndex + 5 && !_tcsncicmp(lpLine->pcText+nIndex+1, _T("Files"), 5)) nIndex -= 10; else if (nIndex >= 16 && lpLine->nLength > nIndex + 8 && !_tcsncicmp(lpLine->pcText+nIndex+1, _T("Settings"), 8)) nIndex -= 16; else if (nIndex >= 16 && lpLine->nLength > nIndex + 13 && !_tcsncicmp(lpLine->pcText+nIndex+1, _T("Einstellungen"), 13)) nIndex -= 16; } else { /* * Find the first double quote or the * beginning of the line. */ while ( nIndex > 0 && lpLine->pcText[ nIndex ] != _T( '"' ) && lpLine->pcText[ nIndex ] != _T( '\'' )) // Modifications by Stephan (2005-05-30) nIndex--; } /* * If were looking for a quoted hyperlink and we * are not on a double quote we stop here. */ if ( bQuoted && lpLine->pcText[ nIndex ] != _T( '"' ) && lpLine->pcText[ nIndex ] != _T( '\'' )) // Modifications by Stephan (2005-05-30) return FALSE; else if ( _istspace( lpLine->pcText[ nIndex ] ) || lpLine->pcText[ nIndex ] == _T('=') || lpLine->pcText[ nIndex ] == _T(';')) // Modifications by Stephan (2005-05-28) nIndex++; /* * Store the start column. */ lpStart->x = nIndex; /* * Double or single quoted? */ if ( lpLine->pcText[ nIndex ] == _T( '"' ) || lpLine->pcText[ nIndex ] == _T( '\'' )) // Modifications by Stephan (2005-05-30) lpStart->x++; /* * Is it a hyperlink? */ for (i = 0; Hyper[ i ].pszURL; i++ ) { /* * Check if this hyperlink fits on the line * from this position. */ if ( lpLine->nLength - lpStart->x >= Hyper[ i ].nLength ) { /* * Is it this hyperlink? */ if ( ! _tcsnicmp( &lpLine->pcText[ lpStart->x ], Hyper[ i ].pszURL, Hyper[ i ].nLength )) { // Modified by Stephan (2005-06-12) // We only can specify the length of the hyperlink, if we know its identifier. // Only this makes it possible to have unquoted hyperlinks with spaces, e.g. c:\program files /* * Double or single quoted? */ if ( lpLine->pcText[ nIndex ] == _T( '"' ) || lpLine->pcText[ nIndex ] == _T( '\'' )) // Modifications by Stephan (2005-05-30) { /* * Find the next double quote or the end * of the line. */ nIndex++; while ( nIndex < lpLine->nLength && lpLine->pcText[ nIndex ] != _T( '"' ) && lpLine->pcText[ nIndex ] != _T( '\'' )) // Modifications by Stephan (2005-05-30) nIndex++; } else { nIndex += Hyper[ i ].nLength; /* * Find the next white space or the end * of the line. */ while ( nIndex < lpLine->nLength && ! _istspace( lpLine->pcText[ nIndex ] ) && lpLine->pcText[ nIndex ] != _T('(') && lpLine->pcText[ nIndex ] != _T(',') && lpLine->pcText[ nIndex ] != _T(';') && lpLine->pcText[ nIndex ] != _T(')') && lpLine->pcText[ nIndex ] != _T('\'')) // Modified by Stephan (2005-05-28) nIndex++; } /* * Store the end column. */ lpEnd->x = nIndex - 1; /* * When we are on a hyperlink we show a hand cursors. */ SetCursor( lpcd->hHand ); return TRUE; } } } /* * If we did not find a hyperlink and we are * not doing a quoted search we start one now. */ if ( ! bQuoted ) return CheckForHyperlink( lpcd, lpPos, lpStart, lpEnd, TRUE ); return FALSE; }
/* * Obtain the hyperlink located at the * mouse position. If there is no hyperlink * at the mouse position return NULL. */ TCHAR *GetHyperlink( LPCLASSDATA lpcd ) { POINT ptStart, ptEnd, ptMousePos; /* * Are we parsing hyperlinks? */ if ( Parser->bParseHyperLinks ) { /* * Get mouse position and convert * to client coordinates. */ GetCursorPos( &ptMousePos ); ScreenToClient( lpcd->hWnd, &ptMousePos ); /* * Skip selection margin. */ ptMousePos.x -= ( GetMarginWidth( lpcd ) + GetLineMarginWidth( lpcd )); /* * Convert the coordinates to the character * position. */ if ( MouseToCaret( lpcd, ptMousePos.x, ptMousePos.y, &ptMousePos )) { /* * Check if the character is located inside * a hyperlink. */ if ( CheckForHyperlink( lpcd, &ptMousePos, &ptStart, &ptEnd, FALSE )) { /* * Allocate memory to store the * hyperlink text. */ TCHAR *pszUrl = AllocPooled( lpcd->pMemPool, REAL_SIZE( ptEnd.x - ptStart.x + 2 )); if ( pszUrl ) { /* * Copy the hyperlink text into the * allocated buffer. */ LPLINE lpLine = ( LPLINE )ArrayGetAt( lpcd->lpLines, ptStart.y ); memcpy( pszUrl, &lpLine->pcText[ ptStart.x ], ptEnd.x - ptStart.x + 1 ); /* * 0-terminate to be on the safe side. */ pszUrl[ ptEnd.x - ptStart.x + 1 ] = 0; return pszUrl; } } } } /* * No hyperlink or memory failure... */ return NULL; }