Posts Tagged ‘source code’

DOS: Get the directory name from a file path

Monday, June 28th, 2010

If you need to write a DOS batch file that takes a file path as an input parameter and needs to do something to other files in the same directory as the input file then you’ll find there is no easy way to get the file’s directory name into a variable.

dos path from file

You could pass in the directory name as a separate parameter but that seems like cheating. I sometimes find answers to problems like these on Rob van der Woude’s scripting site or Google, but no luck this time.

I had to figure this one out from scratch. Here’s what I do. Let me know if you have a better (shorter) way of doing this.

  • Output the result of running ‘dir’ on the file path into a temporary file.
  • Loop through the lines in the temporary file, skipping the first three, and then taking the third token.
  • Assign that token to a variable.

If all has worked the variable which I’ve called ‘thedirectory’ should now contain the file path.

I’ve tested this on Windows 7 and I’m guessing it will work on other versions of Windows, but I’ll make no promises.

Here is the code:

goto :skip_functions

:setDir
if not %thedirectory% == "" goto :EOF
set thedirectory=%1
goto :EOF

:getDirectory
del %TEMP%\getdir.tmp
dir %1 > %TEMP%\getdir.tmp
for /f "skip=3 tokens=3" %%i in (%temp%\getdir.tmp) do call :setDir %%i
goto :EOF

:skip_functions

set thedirectory=""
call :getDirectory %1

@echo off
echo thefile =%1
echo thedirectory=%thedirectory%

And if you want to know what I needed it for have a look at my post about stitching together photos using ImageMagick.

Writing WordPress posts offline in Word with the help of VBA macros

Monday, February 15th, 2010

If you want to write your WordPress posts offline (i.e. in a separate editor to the WordPress editor), then you may find you have to spend a fair bit of time reformatting the blog post to add any required WordPress formatting before you can publish.

There are lots of reasons for wanting to write your WordPress blog posts offline. You may not have access to the internet at the time you are writing. You may find the WordPress editor to be a pain, or maybe you have another editor that you’d much rather write with.

I like writing using Word 2007 so I created some VBA macros which allow me to add bits of formatting to the post (titles, links, photos) faster than I could do manually.

wordpress word 2007 macros

These macros help you format posts which are meant to be pasted into the WordPress non-WYSIWYG post editor. I don’t know what would happen if you pasted posts formatted with these macros into the WordPress WYSIWYG editor.

Description of WordPress macros

Here’s a description of the macros from the source code at the end of this post. I’m only describing the main macros, not the other supporting functions in the code that these macros need.

BoldForWordPress – Adds ‘Strong’ tags around the highlighted text and also makes the text bold in Microsoft Word to make the titles easier to see when you are editing your blog posts.

BoldForWordPress

Will be turned into:

<strong>BoldForWordPress</strong>

PhotoLinkSite1 / PhotoLinkSite2

Changes the image name into an image link with just a few bits for you to fill in to complete the HTML. It will try to auto generate an ALT tag from the image name by turning any hyphens ‘-‘ into spaces. Highlight an image name such as ‘myimage.jpg’ and click the image button.

wordpress-blog.jpg

Will be changed into:

<img src="http://www.????.co.uk/data/2010/xxxx/wordpress-blog.jpg"
 width="" height="" alt="wordpress blog" />

If you have multiple sites then you can use the template code in PhotoLinkSite1 / PhotoLinkSite2 to allow you to create links which already contain each of your sites URLs. If you only have one site then just delete PhotoLinkSite2.

Listify

Listify will convert a number of lines of text into a HTML list.

Item 1
Item 2
Item 3

Will become:

<ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li></li>
</ul>

The code will give you an extra list element at the end in case you want to add more items to your list. If you don’t want it just delete it.

Link

Highlight some text or a URL and this will create your <A HREF… link. If you highlight text beginning with ‘http’ then it will put the text into the link section, otherwise it will put it into the description section.

This is some text

Will become:

<a href="">This is some text</a>

And:

http://www.advancedhtml.co.uk/

Will become:

<a href="http://www.advancedhtml.co.uk/"></a>

SpacingTable

This will insert a piece of fixed HTML which can be used to add extra spacing to images or Amazon iframes. See my post Adding spacing round an iframe in WordPress for more information. If you select the iframe HTML the spacing table will be put around it. If you have nothing selected then the spacing table will just be inserted straight where the cursor is. This is what will be inserted:

<table border="0" cellspacing="10" align="right">
 <tr><td></td></tr></table>

AdSense

This macro is useful if you use the Adsense Injection plugin. Press it once and it will insert a tag to disable AdSense in the current post. Press it again and you will get the tag to start the AdSense from a certain point in your post. Here are the two tags it will insert.

<!--noadsense-->
<!--adsensestart-->

Splitter

This inserts a line of hashes and asterisks into the text. This isn’t useful for the WordPress blog post, but I use it to split up sections in the Word document when I’m writing multiple posts. This is what this macro outputs:

*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#

How to create and configure the toolbar buttons

Here are some brief instructions for how to setup these macros. You’ll need the source code below.

First click on the ‘View’ tab and then the ‘Macros’ button on the right hand side of the ribbon.

word 2007 macros button

If you haven’t added any macros before you’ll need to create a dummy one so you can access the Visual Basic macro editor. Type in ‘Dummy’ as the macro name and press ‘Create’. You’ll be taken straight to the editor.

create dummy word 97 macro

Paste all the macro VBA source code below into the editor. Save the macros by going to the File menu and pressing ‘Save Normal’.

Now you need to create some buttons and link them to the macros. Click on the little down arrow (pictured below) to get the Customize Quick Access Toolbar menu. Press ‘More Commands’.

customize quick access toolbar

In the ‘Choose commands from’ pull down list select ‘Macros’.

choose commands from menu

Now click on each of the macros and then press ‘Add’.

adding macros to the quick access toolbar

To give each macro a unique icon, click on each on in turn, press ‘Modify’, and then choose your icon.

add icons to macros

You should now have your macro buttons setup and it will look something like this.

wordpress word 2007 macros

Visual Basic (VBA) WordPress macro source code

Here is the VBA macro code – it’s not pretty but it works. It has been tested on Word 2007. You should be able to get it working on other versions of Word as well, but it might require minor modifications if it doesn’t work as expected.

You might want to customise the URLs in PhotoLinkSite1 / PhotoLinkSite2 to fit your own blog.

Sub BoldForWordpress()
    'Wordpress bold title
    Dim TitleStr
    TitleStr = Selection.Text
    Dim HasNewLine As Boolean
    If Right(TitleStr, 1) = Chr(13) Then
        HasNewLine = True
    End If
    TitleStr = TrimNewLine(TitleStr)
    With Selection
    .Delete
    .Font.Bold = wdToggle
    .TypeText ("<strong>")
    .TypeText (TitleStr)
    .TypeText ("</strong>")
    .Font.Bold = wdToggle
    End With
    If HasNewLine Then
        Selection.TypeText (Chr(13))
        Selection.MoveLeft
        Selection.Font.Bold = wdToggle
    End If
End Sub
Function TrimNewLine(Str) As String
    'Remove newline from string
    If Right(Str, 1) = Chr(13) Then
    TrimNewLine = Left(Str, Len(Str) - 1)
    Else
    TrimNewLine = Str
    End If
End Function
Function TrimPlus(TheString) As String
    'Trim space and newline
    TheString = Trim(TheString)
    TrimPlus = TrimNewLine(TheString)
End Function
Sub Replace(FromStr, ToStr)
'Replace text in the current selection
    With Selection.Find
    .ClearFormatting
    .Replacement.ClearFormatting
    .Text = FromStr
    .Replacement.Text = ToStr
    .Forward = False
    .Wrap = wdFindStop
    .Format = False
    .MatchCase = False
    .MatchWholeWord = False
    .MatchWildcards = False
    .MatchSoundsLike = False
    .MatchAllWordForms = False
    .Execute Replace:=wdReplaceAll
    End With
End Sub
Sub PhotoLinkSite1()
Call PhotoLink("http://www.????.co.uk/2010/xxxx/")
End Sub
Sub PhotoLinkSite2()
Call PhotoLink("http://www.????.co.uk/2010/xxxx/")
End Sub
Sub PhotoLink(LinkBase As String)
    'Turn the image name into a link
    Dim PicString, AltString
    PicString = Selection.Text
    ' Remember newline
    Dim HasNewLine As Boolean
    If Right(PicString, 1) = Chr(13) Then
        HasNewLine = True
    End If
    PicString = TrimPlus(PicString)
    'Create alt text
    Call Replace("-", " ")
    Call Replace(".jpg", vbNullString)
    Call Replace(".png", vbNullString)
    Call Replace(".gif", vbNullString)
    AltString = Selection.Text
    AltString = TrimPlus(AltString)
    'Write HTML
    With Selection
    .Delete
    .TypeText ("<img src=""")
    .TypeText (LinkBase + PicString)
    .TypeText (""" width="""" height="""" ")
    .TypeText ("alt=""" + AltString + """ />")
    End With
    ' Re-add new line
    If HasNewLine Then
        Selection.TypeText (Chr(13))
    End If
End Sub
Sub Listify()
    'Add list tags to a plain text list
    Dim ListString
    Call Replace(Chr(13), "</li>" + Chr(13) + "    <li>")
    ListString = Selection.Text
    Selection.Delete
    Selection.TypeText ("<ul>" + Chr(13) + "    <li>")
    Selection.TypeText (ListString)
    Selection.TypeText ("</li>" + Chr(13) + "</ul>")
End Sub
Sub SpacingTable()
    'Add a table which puts space around Amazon
    'product links
    Dim TableString
    TableString = Selection.Text
    TableString = TrimPlus(TableString)
    With Selection
    .Delete
    .TypeText ("<table border=""0"" cellspacing=""10""")
    .TypeText (" align=""right""><tr><td>")
    .TypeText (TableString)
    .TypeText ("</td></tr></table>")
    End With
End Sub
Sub Link()
    'You can either select some plain text or a
    'URL to be turned into a link
    Dim LinkString
    LinkString = Selection.Text
    Dim HasNewLine As Boolean
    If Right(LinkString, 1) = Chr(13) Then
        HasNewLine = True
    End If
    LinkString = TrimPlus(LinkString)
    Selection.Delete
    If Left(LinkString, 4) = "http" Then
        Selection.TypeText ("<a href=""")
        Selection.TypeText (LinkString)
        Selection.TypeText ("""></a>")
    Else
        Selection.TypeText ("<a href="""">")
        Selection.TypeText (LinkString)
        Selection.TypeText ("</a>")
    End If
    'Fix up the new line
    If HasNewLine Then
        Selection.TypeText (Chr(13))
    Else
        Selection.TypeText (" ")
    End If
    Selection.MoveLeft
    'Put the cursor in the correct place so you
    'can complete the link
    Selection.MoveLeft Unit:=wdCharacter, Count:=4
    If Not Left(LinkString, 4) = "http" Then
        MoveCount = 2 + Len(LinkString)
        Selection.MoveLeft Count:=MoveCount
    End If
End Sub
Sub Splitter()
'Easily visible line for dividing posts
Sp = "*#*#*#*#*#*#*#*#*#*#"
Selection.TypeText (Sp + Sp + Sp + "*#*#" + Chr(13))
End Sub
Sub Adsense()
'For use with Adsense Injection plugin
NoAdsense = "<!--noadsense-->"
If Selection.Text = NoAdsense Then
    Selection.TypeText ("<!--adsensestart-->")
Else
    Selection.TypeText (NoAdsense)
    With Selection
    .MoveLeft Unit:=wdCharacter, Count:=16, Extend:=wdExtend
    End With
End If
End Sub


Triangle Identification – C++ solution and test code

Tuesday, September 23rd, 2008

Here is another interview coding question that I have heard of.

You have to write a function to identify the triangle type. You have to return a number between 1 or 4 to identify either a valid triangle type or an error.

The solution is very simple requiring only one condensed line of code to identify each triangle type. Two lines of code identify error cases. One of the error cases identifies input with 0 or negative lengths. The other error case identifies line lengths that don’t make a triangle or which make a segment (thanks to Yabba for pointing out these error cases).

As an exercise you could try to extend the solution to identify right-angled triangles as well.

const int SCALENE = 1;
const int ISOSCELES = 2;
const int EQUILATERAL = 3;
const int ERROR = 4;
int TriangleType(int x, int y, int z)
{
	if ((x + y <= z) || (x + z <= y) || (z + y <= x)) return ERROR;
	if (x<=0 || y<=0 || z<=0) return ERROR;
	if (x == y && y == z) return EQUILATERAL;
	if (x == y || y == z || z == x) return ISOSCELES;
	return SCALENE;
}

The more interesting code comes from testing the function. To test the function I pass in a series of triangle side lengths. I also pass in the expected result. If the actual result matches the expected result then the test passes.

The test data is written in a way that allows each test to be defined in a single line of code which makes it very easy to extend.

This easy extendibility was fortunate as my original version of this solution missed out the cases where the line lengths don’t make a triangle (e.g. 1, 1, 5), and where the line lengths make a segment (e.g. 2, 2, 4).

void TriangleTest()
{
const int testDataSize = 14;
int testData[testDataSize][4] = {
	{9, 9, 9, EQUILATERAL},
	{4, 5, 5, ISOSCELES},
	{5, 4, 5, ISOSCELES},
	{5, 3, 3, ISOSCELES},
	{0, 0, 0, ERROR}, // 0 number checks
	{0, 1, 2, ERROR},
	{1, 0, 2, ERROR},
	{1, 2, 0, ERROR},
	{-1, -1, -1, ERROR}, // negative number checks
	{-1, 1, 2, ERROR},
	{1, -1, 2, ERROR},
	{1, 2, -1, ERROR},
	{2, 2, 4, ERROR}, // line segment not a triangle
	{1, 1, 5, ERROR} // not a triangle
};
for (int i=0; i<testDataSize; ++i)
{
	int result = TriangleType(
		testData[i][0], testData[i][1], testData[i][2]);
	if (result == testData[i][3])
	{
		cout << " Pass: triangleType("
			<< testData[i][0] << ", "
			<< testData[i][1] << ", "
			<< testData[i][2] << ")==" << result << endl;
	}
	else
	{
		cout << "!Fail: triangleType("
			<< testData[i][0] << ", "
			<< testData[i][1] << ", "
			<< testData[i][2] << ")==" << result
			<< " Expected: " << testData[i][3] << endl;
	}
}
}


Reverse the words in a sentence – C++ solution and test code

Tuesday, September 16th, 2008

Here is a solution to the standard interview questions of reversing the letters in the words of a sentence. It is a more complex version of the even more common “reverse a string” question. I also include my test code.

There are two main parts to this. The first identifies where the word boundaries are. The second reverses the letters between two positions in the array.

The wordStart and wordEnd variables keep track of the word boundaries. We first look for the start of the word and then the end and store the positions. These values are then passed to ReverseWord along with the character array. ReverseWord does some simple character swapping to reverse the word.

void ReverseWords(char string[])
{
	int length = StringLength(string);
	int wordStart = -1;
	int wordEnd = -1;
	for (int i=0; i<length; ++i)
	{
		if (string[i] == ' ' && wordStart == -1)
		{
			continue;
		}
		else if (wordStart == -1)
		{
			wordStart = i;
		}
		if (wordStart != -1 && string[i] == ' ')
		{
			wordEnd = i-1;
			ReverseWord(string, wordStart, wordEnd);
			wordStart = -1;
			wordEnd = -1;
		}
	}
	if (wordStart != -1)
	{
		wordEnd = length-1;
		ReverseWord(string, wordStart, wordEnd);
	}
}
void ReverseWord(char string[], int wordStart, int wordEnd)
{
	int midPoint = (wordStart+wordEnd)/2;
	for (int l=wordStart, r=wordEnd; l<=midPoint; ++l, --r)
	{
		char tmp = string[l];
		string[l] = string[r];
		string[r] = tmp;
	}
}

Here is the test code. For each test a character array is passed to the word reversing function. The result is then compared against the expected result. If they match the test passes. If they don’t match then the test fails. I’ve tried to test the obvious cases. You could easily find flaws in the word reversal function but it is probably good enough to get you onto the next question.

void ReverseWordsTest()
{
	char test1[] = "cat and dog";
	char expected1[] = "tac dna god";
	ReverseAndCheck(test1, expected1);
	char test2[] = "cat and dog ";
	char expected2[] = "tac dna god ";
	ReverseAndCheck(test2, expected2);
	char test3[] = " cat and dog";
	char expected3[] = " tac dna god";
	ReverseAndCheck(test3, expected3);
	char test4[] = " cat and dog ";
	char expected4[] = " tac dna god ";
	ReverseAndCheck(test4, expected4);
	char test5[] = "cat  and dog";
	char expected5[] = "tac  dna god";
	ReverseAndCheck(test5, expected5);
	char test6[] = "catanddog";
	char expected6[] = "goddnatac";
	ReverseAndCheck(test6, expected6);
	char test7[] = "";
	char expected7[] = "";
	ReverseAndCheck(test7, expected7);
}
void ReverseAndCheck(char string[], char expected[])
{
	ReverseWords(string);
	if (MatchingStrings(string, expected))
	{
	cout << " Pass: " << string << endl;
	}
	else
	{
	cout << "!Fail: " << string << " != " << expected << endl;
	}
}
bool MatchingStrings(char string1[], char string2[])
{
	int length = StringLength(string1);
	if (length != StringLength(string2))
	{
		return false;
	}
	for (int i=0; i<length; ++i)
	{
		if (string1[i] != string2[i])
		{
			return false;
		}
	}
	return true;
}
int StringLength(char string[])
{
	int index = 0;
	char s = string[index];
	while (s)
	{
		++index;
		s = string[index];
	}
	return index;
}


Picking the 5th from last element in a singly linked list

Monday, August 18th, 2008

Here’s another of those fun coding interview puzzles. The kind that companies like Microsoft or Google might ask you. Given a singly linked list, select the 5th from last element. I’m writing the solution in C++ but the solution in Java would be almost identical. I’m also putting up my test code.

The restrictions are – you can only make one pass of the list, and you don’t know the length of the list.

First we need to define our linked list element. All it needs is to store a value, and a pointer to the next element in the list.

class Element
{
public:
	Element(int valueArg) : value(valueArg), next(NULL) {}
public:
	int value;
	Element* next;
};

Here is the actual solution. As we are only allowed one pass of the list we use two pointers. The second pointer trails 5 places behind the first pointer. When the first pointer reaches the end of the list we simply return whichever element the second pointer is pointing to.

We need to take care of the special case where the list has less than 5 elements – including the case where the list has 0 elements!

Element* FifthFromLast(Element* root)
{
	Element* current = root;
	int fromLast = 5;
	while (fromLast > 0 && current)
	{
		current = current->next;
		--fromLast;
	}
	if (fromLast != 0)
	{
		return NULL; // less than 5 items in list
	}
	Element* fifthFromLast = root;
	while (current)
	{
		current = current->next;
		fifthFromLast = fifthFromLast->next;
	}
	return fifthFromLast;
}

Here is the test code which tests the most common cases for this problem. As the parameter to FifthFromLast is the root element we can simulate a shorter list by passing in one of the middle elements.

void LinkedListTest()
{
	Element* one = new Element(1);
	Element* two = new Element(2);
	Element* three = new Element(3);
	Element* four = new Element(4);
	Element* five = new Element(5);
	Element* six = new Element(6);
	Element* seven = new Element(7);
	Element* eight = new Element(8);
	Element* nine = new Element(9);
	Element* ten = new Element(10);
	one->next = two;
	two->next = three;
	three->next = four;
	four->next = five;
	five->next = six;
	six->next = seven;
	seven->next = eight;
	eight->next = nine;
	nine->next = ten;
	cout << "Test: find 5th from last in 10 item list" << endl;
	Element* fifthFromLast = FifthFromLast(one);
	if (fifthFromLast == six)
	{
		cout << " Pass" << endl;
	}
	else
	{
		cout << "!Fail" << endl;
	}
	cout << "Test: with 4 item list - expect NULL" << endl;
	Element* nullReturnCheck = FifthFromLast(seven);
	if (nullReturnCheck == NULL)
	{
		cout << " Pass" << endl;
	}
	else
	{
		cout << "!Fail" << endl;
	}
	cout << "Test: FifthFromLast(NULL) - expect NULL" << endl;
	nullReturnCheck = FifthFromLast(NULL);
	if (nullReturnCheck == NULL)
	{
		cout << " Pass" << endl;
	}
	else
	{
		cout << "!Fail" << endl;
	}
	// clean up
	Element* current = one;
	while (current)
	{
		Element* next = current->next;
		delete current;
		current = next;
	}
}

This is the output from running the tests.

Test: find 5th from last in 10 item list
 Pass
Test: with 4 item list - expect NULL
 Pass
Test: FifthFromLast(NULL) - expect NULL
 Pass


Batch processing photos with DOS and ImageMagick

Thursday, August 7th, 2008

For my recent walking project I knew I was going to be taking lots of photos. I wanted a DOS script which would batch process the JPEG photos from my camera into the ‘full sized images’ (which are much smaller than the raw camera images), and the poloroid-like thumbnails.

The excellent ImageMagick tool provides a way to generate poloroid-like thumbnails automatically. I also wanted the thumbnails to be rotated at random angles which ImageMagick can do as well.

However the ImageMagick instructions were missing a few things 1) they seem to be aimed at people using Unix / Linux scripts whereas I’m using DOS scripts and 2) they show how to do this processing on single images rather than on a whole directory of them.

Poloroid rotation with ImageMagick Poloroid rotation with ImageMagick

It is quite easy to generate a random rotation angle with a simple bit of perl. The below line will generate a random floating point number between -7 and +7. I want both negative and positive numbers so that some of the poloroids will be tilted to the left, and others to the right.

perl -e "print rand() * 14 - 7"

I wanted to do all the processing through a DOS batch file so the next problem was how to get the random number into a DOS environmental variable. The answer is to use the ‘for /f‘ command to assign the output of a command into a variable:

for /f %%i in ('perl -e "print rand() * 14 - 7"') do set ANGLE=%%i

At the time when I wrote this script generating a poloroid involved a whole sequence of commands. Something like below!

-bordercolor white -border 6 -bordercolor grey60 -border 1 -background none -rotate %ANGLE% -background black ( +clone -shadow 60x4+4+4 ) +swap -background white -flatten

My script still uses this long poloroid command, but you might want to use the new one word ‘poloroid‘ command which is built straight into the latest versions of ImageMagick instead.

As well as generating the poloroid thumbnails it will also generate the full size website friendly images which are tagged with the website URL.

Prerequisites:
Your JPEG images are in an ‘images’ directory.

Usage:
ProcessPhotos.bat [path of directory that contains ‘images’ directory]

Output:
A new directory called ‘generated’ in the input directory containing a full size image (which has been tagged with the website URL), and a poloroid thumbnail.

Notes:
In order to use this script you will have to customise 1) the location of the ImageMagick executable 2) the reference to the drive – it is assuming a ‘f:’ drive here and 3) the website URL.

setlocal
pushd .
goto :skip_functions
:makeThumb
	echo %1
	set jpg=%1
	set jpg=%jpg:~0,-4%
	echo %jpg%
	for /f %%i in ('perl -e "print rand() * 14 - 7"') do set ANGLE=%%i
	set ANNOTATE=-gravity south -stroke "#000C" -strokewidth 2 -annotate +0+20 "www.advancedhtml.co.uk" -stroke none -fill white -annotate +0+20 "www.advancedhtml.co.uk"
	set POLOROID=-bordercolor white -border 6 -bordercolor grey60 -border 1 -background none -rotate %ANGLE% -background black ( +clone -shadow 60x4+4+4 ) +swap -background white -flatten
	D:appsImageMagick-6.3.6-Q16convert %1 ( +clone -resize 600x -auto-orient %ANNOTATE% -compress JPEG -quality 70 -write %jpg%_full.jpg +delete ) -resize 180x -auto-orient %POLOROID% -compress JPEG -quality 80 -sampling-factor 2x1 -strip %jpg%_th.jpg
goto :EOF
:skip_functions
f:
cd %1images
for /f %%i in ('dir /b *.jpg') do call :makeThumb %%i
md %1generated
move *_full.jpg ..generated
move *_th.jpg ..generated
popd
endlocal


AdSense Injection WordPress plugin tweaks

Thursday, July 24th, 2008

Update 7th December 2010: Use the new Ad Injection plugin for WordPress instead as it will do what these tweaks do, and more.

On this blog I use the Adsense Injection plugin to automatically add Google’s targeted AdSense adverts to my posts. The plugin is excellent and has helped to make more money for this site but there are a few tweaks that I have done.

First, I’ve made a modification so that if a individual post page is shorter than a certain number of characters then the number of adverts is limited to one.

Second, I’ve made a change so instead of looking for ‘<p’ tags to use as AdSense insertion points it looks for the full paragraph tag – ‘<p>’. The reason I did this is because I often include code in my posts in <pre> tags and the AdSense plugin code was inserting adverts in my source code snippets which looked wrong. After making this change the adverts only appear in the text of my posts.

Both sets of changes are shown in the code below. You can simply replace the ai_the_content() function in version 2.0 of the plugin with this version.

adsense-injection.php
function ai_the_content($content){
  global $doing_rss;
  if(is_feed() || $doing_rss)
    return $content;
  if(strpos($content, "<!--noadsense-->") !== false) return $content;
  if(is_home() && get_option('ai_home') == "checked=on") return $content;
  if(is_page() && get_option('ai_page') == "checked=on") return $content;
  if(is_single() && get_option('ai_post') == "checked=on") return $content;
  if(is_category() && get_option('ai_cat') == "checked=on") return $content;
  if(is_archive() && get_option('ai_archive') == "checked=on") return $content;
  global $ai_adsused, $user_level;
  if(get_option('ai_betatest') == "yes" && $user_level < 8)
    return $content;
  if(get_option('ai_notme') == "yes" && $user_level > 8)
    return $content;
  # RML: backup content
  $original_content = $content;
  $numads = get_option('ai_nads');
  if(is_single())
    $numads = get_option('ai_nadspp');
  $content_hold = "";
  if(strpos($content, "<!--adsensestart-->") !== false){
    $content_hold = substr($content, 0, strpos($content, "<!--adsensestart-->"));
    $content = substr_replace($content, "", 0, strpos($content, "<!--adsensestart-->"));
  }
  while($ai_adsused < $numads)
  {
    $poses = array();
    $lastpos = -1;
    # RML: change <p to <p> to stop ads before <pre>
    $repchar = "<p>";
    if(strpos($content, "<p>") === false)
      $repchar = "<br";
    while(strpos($content, $repchar, $lastpos+1) !== false){
      $lastpos = strpos($content, $repchar, $lastpos+1);
      $poses[] = $lastpos;
    }
    //cut the doc in half so the ads don't go past the end of the article.  It could still happen, but what the hell
    $half = sizeof($poses);
    $adsperpost = $ai_adsused+1;
    if(!is_single())
      $half = sizeof($poses)/2;
    while(sizeof($poses) > $half)
      array_pop($poses);
    $pickme = $poses[rand(0, sizeof($poses)-1)];
    $replacewith = ai_pickalign(get_option('ai_lra'));
    $replacewith .= ai_genadcode()."</div>";
    # RML: remove hardcoded length
    $content = substr_replace($content, $replacewith.$repchar, $pickme, strlen($repchar));
    $ai_adsused++;
    # RML: if content is short then limit to one advert
    if(strlen($original_content) < 2500) return $content_hold.$content;
    if(!is_single())
      break;
  }
  return $content_hold.$content;
}


Adding ‘Related Posts’ to WordPress articles and 404 error pages

Tuesday, July 22nd, 2008

Many blogs have a list of related articles after each of their posts. I wanted something similar for my WordPress blog but found it wasn’t as easy to do as I thought it would be.

At the same time I was interested in capturing any access attempts to non-existent pages (causing a 404 error), and showing a list of suggested links. This is something that is useful to do to turn people who get 404 errors into readers of your blog.

I first looked at the WASABI related post plugin. It did what I wanted with the related entries but it requires you to add a tag to each post where you want the related entries to appear. There is also a version of the plugin which can generate sensible links for any 404 errors. It does this by turning the incorrect URL into a list of terms which are then used to find related posts.

The next plugin that I read about was called ‘Aizattos Related Posts’. This plugin was originally based on WASABI but has evolved since. It inserts related links without needed to add any special tags to the posts. A lot of good feedback was given about this plugin but it seems that the author has removed it from the original download site. Fortunately someone has re-posted this plugin to this site.

I therefore have what I need in two separate plugins. I installed the Aizattos Related Posts plugins and then created a modified version of the WASABI 404 handling code. The 404 handler is in one function ‘related_posts_404’. Below is the modified version of the WASABI code which will work with the Aizattos Related Posts plugin. As well as showing the related links it also shows an extract from the post page. Just put this function in the Aizattos Related Posts plugin PHP file.

related_posts_404()
function related_posts_404($limit=5, $len=50,
	$before_title = '', $after_title = '',
	$before_post = '', $after_post = '',
	$show_pass_post = false, $show_excerpt = true) {
    global $wpdb, $post;
    $before_title   = '<span class="aizatto_related_posts_title" >';
    $after_title    = '</span>';
    $before_excerpt = '<div class="aizatto_related_posts_excerpt">';
    $after_excerpt  = '</div><p></p>';
    $before_related = '<li>';
    $after_related  = '</li>';
    $search_term = $_SERVER['REQUEST_URI'];
    $search = array ('@[/]+@', '@(..*)@', '@[-]+@', '@[_]+@', '@[s]+@', '@archives@','@(?.*)@','/d/');
    $replace = array (' ', '', ' ', ' ', ' ', '', '','');
    $search_term = preg_replace($search, $replace, $search_term);
    $search_term = trim($search_term);
    $terms = $search_term;
    $time_difference = get_settings('gmt_offset');
    $now = gmdate("Y-m-d H:i:s",(time()+($time_difference*3600)));
    // Primary SQL query
    $sql = "SELECT ID, post_title, post_content,"
         . "MATCH (post_name, post_content) "
         . "AGAINST ('$terms') AS score "
         . "FROM $wpdb->posts WHERE "
         . "MATCH (post_name, post_content) "
         . "AGAINST ('$terms') "
		 . "AND post_date <= '$now' "
         . "AND (post_status IN ( 'publish',  'static' ) && ID != '$post->ID') ";
    if ($show_pass_post=='false') { $sql .= "AND post_password ='' "; }
    $sql .= "ORDER BY score DESC LIMIT $limit";
    $results = $wpdb->get_results($sql);
    $output = '';
    if ($results) {
        foreach ($results as $result) {
            $title = stripslashes(apply_filters('the_title', $result->post_title));
            $permalink = get_permalink($result->ID);
            $output .= $before_title
                .'<a href="'. $permalink .'" rel="bookmark" title="Permanent Link: '
		. $title . '">'
		. $title . '</a>'
		. $after_title;
            if ($show_excerpt=='true') {
                $post_content = strip_tags($result->post_content);
                $post_content = stripslashes($post_content);
                $words=split(" ",$post_content);
                $post_strip = join(" ", array_slice($words,0,$len));
                $output .= $before_excerpt . $post_strip . $after_excerpt;
                }
        }
        echo $output;
    } else {
        echo $before_title.'Fuzzy ...'.$after_title;
    }
}

Although no code modifications are needed for the related links in your normal posts, you will have to make a modification to your theme’s 404 page if you want related links for any ‘Not Found’ errors. In blue below is the modification I made to my 404.php for the default theme.

blog/wp-content/themes/default/404.php
<?php get_header(); ?>
	<div id="content" class="narrowcolumn">
		<h2 class="center">Error 404 - Not Found</h2>
		<p>We're sorry but the page you are looking
		for isn't at this location. Were you perhaps
		looking for one of these articles?</p>
		<?php related_posts_404(); ?>
	</div>
<?php get_sidebar(); ?>
<?php get_footer(); ?>


Reverse a linked list – C++ source code

Monday, July 21st, 2008

Reversing a linked list is a simple programming problem, which is often an interview question. In this case I’m referring to a singly linked list. I’ll provide the C++ solution and the C++ test code.

One of the easiest ways to reverse the linked list is to create a new head pointer, iterate through the list removing each item in turn and then inserting them at the beginning of the new list.

Here is the definition of my linked list node and the code to reverse the list.

class Node
{
public:
	Node(int value) : value(value), next(NULL) {}
public:
	int value;
	Node* next;
};
Node* reverseList(Node* head)
{
	Node* newList = NULL;
	Node* current = head;
	while (current)
	{
		Node* next = current->next;
		current->next = newList;
		newList = current;
		current = next;
	}
	return newList;
}

Below is the code I used to test this. This is what it does:

  1. It creates a simple linked list.
  2. Prints it out – output should be ‘12345’.
  3. Reverses it.
  4. Prints it out – output should be ‘54321’.
  5. Reverses it again.
  6. Prints it – output should be ‘12345’.
  7. Deletes the list.
void listTests()
{
	Node* one = new Node(1);
	Node* two = new Node(2);
	Node* three = new Node(3);
	Node* four = new Node(4);
	Node* five = new Node(5);
	one->next = two;
	two->next = three;
	three->next = four;
	four->next = five;
	Node* head = one;
	printList(head);
	head = reverseList(head);
	printList(head);
	head = reverseList(head);
	printList(head);
	// cleanup memory
	Node* current = head;
	while (current)
	{
		Node* next = current->next;
		delete current;
		current = next;
	}
}
void printList(Node* head)
{
	Node* current = head;
	while (current)
	{
		cout << current->value;
		current = current->next;
	}
	cout << endl;
}

This should be the output:

12345
54321
12345

If you are interested in other linked list related code I have a post about picking the 5th from last element from a singly linked list, and one on selecting random numbers from a stream or linked list. Both of these are based on programming interview questions.

Dijkstra’s Algorithm code in C++

Tuesday, July 15th, 2008

Dijkstra’s algorithm is a famous algorithm that calculates the routes and distances from a start node to all other nodes in a connected graph where all the distances are positive.

Here is a version which I wrote in C++. My aim here was to try to create a version that was easy to read, rather than the most efficient version. I used the excellent Introduction to Algorithms book as a reference for my version of Dijkstra’s. This version is implemented using STL vectors to store the edges and nodes. I might later modify it to use adjacency lists and priority queues to produce a more efficient implementation.

First off is my Node and Edge class. You’ll note that the objects add themselves to the nodes and edges vectors as they are constructed.

vector<Node*> nodes;
vector<Edge*> edges;
class Node
{
public:
	Node(char id)
		: id(id), previous(NULL),
		distanceFromStart(INT_MAX)
	{
		nodes.push_back(this);
	}
public:
	char id;
	Node* previous;
	int distanceFromStart;
};
class Edge
{
public:
	Edge(Node* node1, Node* node2, int distance)
		: node1(node1), node2(node2), distance(distance)
	{
		edges.push_back(this);
	}
	bool Connects(Node* node1, Node* node2)
	{
		return (
			(node1 == this->node1 &&
			node2 == this->node2) ||
			(node1 == this->node2 &&
			node2 == this->node1));
	}
public:
	Node* node1;
	Node* node2;
	int distance;
};

Next up is my code to construct a simple test graph. The starting node is initialised with a distance of 0. Dijkstra’s algorithm is then called before the results are printed out. Underneath the code is a diagram of what this graph looks like.

void DijkstrasTest()
{
	Node* a = new Node('a');
	Node* b = new Node('b');
	Node* c = new Node('c');
	Node* d = new Node('d');
	Node* e = new Node('e');
	Node* f = new Node('f');
	Node* g = new Node('g');
	Edge* e1 = new Edge(a, c, 1);
	Edge* e2 = new Edge(a, d, 2);
	Edge* e3 = new Edge(b, c, 2);
	Edge* e4 = new Edge(c, d, 1);
	Edge* e5 = new Edge(b, f, 3);
	Edge* e6 = new Edge(c, e, 3);
	Edge* e7 = new Edge(e, f, 2);
	Edge* e8 = new Edge(d, g, 1);
	Edge* e9 = new Edge(g, f, 1);
	a->distanceFromStart = 0; // set start node
	Dijkstras();
	PrintShortestRouteTo(f);
	// Node / Edge memory cleanup snipped
}

Dijkstra's algorithm

Here is the actual algorithm implementation. We remove the node with the smallest distance from the list of nodes, and then calculate all the minimum distances. We repeat until there are no more nodes left.

void Dijkstras()
{
	while (nodes.size() > 0)
	{
		Node* smallest = ExtractSmallest(nodes);
		vector<Node*>* adjacentNodes =
			AdjacentRemainingNodes(smallest);
		const int size = adjacentNodes->size();
		for (int i=0; i<size; ++i)
		{
			Node* adjacent = adjacentNodes->at(i);
			int distance = Distance(smallest, adjacent) +
				smallest->distanceFromStart;
			if (distance < adjacent->distanceFromStart)
			{
				adjacent->distanceFromStart = distance;
				adjacent->previous = smallest;
			}
		}
		delete adjacentNodes;
	}
}

Here are the supporting functions. The first function removes and returns the node with the smallest distance from the list.

The next returns a new vector containing all the nodes which are adjacent to the node that we pass in.

The third returns the distance value of an edge which directly connects the two nodes.

The final one checks if a node is in the list of nodes.

// Find the node with the smallest distance,
// remove it, and return it.
Node* ExtractSmallest(vector<Node*>& nodes)
{
	int size = nodes.size();
	if (size == 0) return NULL;
	int smallestPosition = 0;
	Node* smallest = nodes.at(0);
	for (int i=1; i<size; ++i)
	{
		Node* current = nodes.at(i);
		if (current->distanceFromStart <
			smallest->distanceFromStart)
		{
			smallest = current;
			smallestPosition = i;
		}
	}
	nodes.erase(nodes.begin() + smallestPosition);
	return smallest;
}
// Return all nodes adjacent to 'node' which are still
// in the 'nodes' collection.
vector<Node*>* AdjacentRemainingNodes(Node* node)
{
	vector<Node*>* adjacentNodes = new vector<Node*>();
	const int size = edges.size();
	for(int i=0; i<size; ++i)
	{
		Edge* edge = edges.at(i);
		Node* adjacent = NULL;
		if (edge->node1 == node)
		{
			adjacent = edge->node2;
		}
		else if (edge->node2 == node)
		{
			adjacent = edge->node1;
		}
		if (adjacent && Contains(nodes, adjacent))
		{
			adjacentNodes->push_back(adjacent);
		}
	}
	return adjacentNodes;
}
// Return distance between two connected nodes
int Distance(Node* node1, Node* node2)
{
	const int size = edges.size();
	for(int i=0; i<size; ++i)
	{
		Edge* edge = edges.at(i);
		if (edge->Connects(node1, node2))
		{
			return edge->distance;
		}
	}
	return -1; // should never happen
}
// Does the 'nodes' vector contain 'node'
bool Contains(vector<Node*>& nodes, Node* node)
{
	const int size = nodes.size();
	for(int i=0; i<size; ++i)
	{
		if (node == nodes.at(i))
		{
			return true;
		}
	}
	return false;
}

And finally here is the code which prints out the route between our start node ‘a’ and the destination node ‘f’. It starts at the destination node and then works backwards using the previous pointer in each node.

void PrintShortestRouteTo(Node* destination)
{
	Node* previous = destination;
	cout << "Distance from start: "
		<< destination->distanceFromStart << endl;
	while (previous)
	{
		cout << previous->id << " ";
		previous = previous->previous;
	}
	cout << endl;
}

Update: 7th September 2008

I have now uploaded a zip file containing the Visual C++ Express Solution file and source code for this project – Dijkstra’s Source Code (8kb).