Brandon's Notepad

June 5, 2015

Playing WAV Files In PERL

Filed under: Perl,Programming — Brandon @ 3:42 pm
Tags: , , , , ,

Home > My Lists > Programming Notes > PERL > Playing WAV Files In PERL


I don’t remember why exactly, but a few years ago I wrote a countdown timer that would sound a chime when it reached zero. I decided to keep the code that plays the sound for future reference. Note, this works using ActiveState PERL on Windows.



use Win32::Sound;

$wav = 'C:\path\to\file.wav';

Win32::Sound::Play($wav);


June 10, 2013

Interactive PERL Shell Environment

Home > My Lists > Programming Notes > PERL > Interactive PERL Shell Environment


Our first family computer was the IBM PCjr, and as i recall, we had two boot options: DOS 2.1 on 5.25″ floppy or BASIC A on cartridge. That’s right, depending on what we needed to do, we could use BASIC as an operating system, more or less. Bill Joy’s C shell (csh) was written to resemble the C programming language and can be used interactively or as a script interpreter. In more modern times, Python too can be run in either mode. Since I program a lot in PERL, it sure would be nice to have the ability to “live” inside a program, especially for debugging and testing purposes.


The Basis

Actually, it is quite possible to run PERL in an interactive mode. Consider the basic two-liner below that I picked up here from Asim Jalis of MetaProse:

#!/usr/bin/env perl
do{print("perl> ");$_x=<>;chomp $_x;print(eval($_x)."\n")}while($_x ne "q")

In a loop, this program presents a prompt, accepts input, strips off the newline at the end, and then executes (evaluates) the code block, that is until it encounters an input string consisting simply of ‘q’.

I reluctantly included the word ‘shell‘ in the title of this post, since this PERL environment isn’t really a user-interface between the user and the OS kernel, but it does resemble what most of us think of when we hear the word in this context. Moreover, this should not be confused with the Perl Shell, psh.

Of course, I can’t be satisfied with the bare minimum. There are a few bells and whistles I’d like to have. To make room for some additions, I expanded the script as follows:

  1. #!usr/bin/env perl
  2. do {
  3.    print("perl> ");
  4.    $_x=<>;
  5.    chomp $_x;
  6.    print(eval($_x)."\n")
  7. } while($_x ne "q")

Customizations

Recreating History. It’s always helpful to have a listing of the last actions performed. Unix shells usually include two methods for recalling and re-executing commands with or without editing. The first is the use of the up and down arrow keys to cycle through previous commands. This is the same functionality provided by the old DOSKEY command in DOS, which was later built into the command prompt in Windows. While this is a really cool feature, the programming is a bit involved for me to tackle at this time; besides, it would be a wasted effort since running this interactive environment in ActivePERL on Windows (where I actually do the majority of my scripting) magically makes this feature available. I’ve tried this in bash and ksh (set -o vi) on Linux but it did not work.

The second is a ‘history‘ command that simply lists the previous n commands on the screen. The list is usually numbered and a command can be re-executed by typing !n, where n is the line number of the desired command. I doubt I will get that fancy, but I would like to implement a basic history command.

Lazy Line Endings. I thought it might be nice to eliminate the need to end each line in a semicolon, just to make the environment more user-friendly. This too proved to be unnecessary, as the eval() command makes the semicolon optional by default (unless, of course, if multiple lines of code are being stacked end-to-end on the same command line).

I will update the section with more ideas and implementations as they come to pass.


January 30, 2012

Getting Google Maps

Filed under: How-To,Online Tools,Perl,Programming — Brandon @ 4:08 pm
Tags: , , , , , , , , ,

So, I’d like to have a current traffic map delivered to my e-mail at the precise moment I’m leaving work for the day. Call me lazy, but this is the sort of thing that can be automated pretty easily and I don’t want to go look it up, I want it delivered. Someday, I’ll get around to setting this up, but as they say, a journey begins with a single step. In this case, the step is to find a way a good to download Google Maps with a script. For now, that is the scope of this post.


Here’s some initial research to plow through:
Mapki: Google Map Parameters Best reference so far!
Google Static Maps API*
A PERL/Wget solution
A Python script
MapTileCacher in PERL
In Bash
Discussion on Google blocking tile downloads

* On 2/7/2012, I tried using the Google Static Maps API and received Error 400 (malformed or illegal request) when using the URL described therein. I have had more luck using Google Maps directly to frame the map, getting the (perma)link, and tweaking the parameters.


January 13, 2012

Single Keystroke Menu Using Term::ReadKey

Filed under: Perl — Brandon @ 11:55 am
Tags: ,

Home > My Lists > Programming Notes > PERL > Single Keystroke Menu


Using Term::ReadKey, you can implement a console menu/prompt that accepts a single keystroke. There are many similar implementations of ReadKey available on the Web. This one is in the form of a reusable subroutine. Only valid options are accepted and the choice is returned to the calling script for futher use. It does not convert the choice to upper- or lower-case, because sometimes it is nice to have both options available.



The Subroutine

This code can be placed in a script or in a separate module.

 1: use Term::ReadKey;
 2:
 3: sub getPromptOption ($$)
 4: {
 5: 	my $prompt  = shift;
 6:	my $options = shift;
 7:	my $choice;
 8:
 9:	ReadMode 'cbreak';
10:	print $prompt;
11:	$choice = ReadKey(0) until $choice =~ m/[$options]/;
12:	ReadMode 'normal';
13:	return $choice;
14: }

Obviously, the Term::ReadKey must be loaded first (line 1). The getPromptOption() subroutine accepts two mandatory parameters as indicated by the declared prototype (line 3). Additional field-validation logic may be desired, but is omitted here for brevity. The terminal’s “read” mode is changed to cbreak, which accepts a single character as input (line 9). The prompt that was passed into the subroutine is printed on the screen (line 10) and then the program enters a loop that reads characters from keyboard input until one of the valid options is entered (line 11). Once a valid key has been pressed, the read mode is returned to normal mode (input accepted until the Enter key is pressed; line 12) and the chosen option is returned to the calling logic (line 13).

Usage

This is a very contrived routine that illustrates the use of the subroutine described above. It allows the user to increment or decrement a current value.

 1. my $i = 0;
 2. my $action = '';
 3. print "Current value: $i\n\n";
 4. until ( $action =~ m/[Xx]/ ) {
 5.	$action = getPromptOption(
 6.		"Select Action: [I]ncr, [D]ecr, or E[X]it",
 7.		"IiDdXx"
 8.	);
 9.	$i++ if ( $action =~ m/[Ii]/ );
10.	$i-- if ( $action =~ m/[Dd]/ );
11.	print "\n\nCurrent value: $i\n\n";
12. }

The iterator (“$i”) is set to an initial value of zero (line 1) and the next action flag (“$action”) set to null (line 2). The current value is printed on the screen (line 3) so that the user knows what it is. Next, the user is prompted to increment or decrement the value, or to exit the program (lines 5-8). If the user chooses to change the value by pressing the “i” key (line 9) or the “d” key (line 10), then the value is printed again on the screen for the benefit of the user (line 11). If the user presses the “x” key, the loop ends (line 4) and process control flows out to the end of the script. Please notice that both the upper- and lower-cases are valid options (line 7), but that the program is indifferent to which is used (lines 4, 9, 10).


January 10, 2012

Tie::File Examples

Filed under: Perl — Brandon @ 3:07 pm
Tags: ,

Home > My Lists > Programming Notes > PERL > Tie::File Examples


Using Tie::File, you can operate directly on a text file as an array. This provides random access to lines in a file and allows for speedy manipulation of very large files since the file itself is not loaded into memory. The following are some examples with explanation as to how they work. (Yes, these examples are extremely rudimentary and a bit redundant at that; this is because I like to have complete examples at my fingertips to use as base templates when I need them for real programming work.)


The Data File

Any ASCII text file can be used with the following examples. I use “myfile.txt” for illustrative purposes, and for me, it is a twenty-line file that contains consecutive numbers on each line (line 1 is “1”, line 2 is “2”, etc.). The following code creates this data file and quickly resets it as needed.

1: open (OUT,">myfile.txt");
2: print OUT join("\n",1..20);
3: close OUT;

Basic Example

This is a very basic example for using Tie::File. It just prints the contents of an array on the screen.

1: use Tie::File;
2: my @records;
3: tie @records, 'Tie::File', "myfile.txt";
4: print join ( "\n", @records );
5: untie @records;

The module must first be loaded using the use function (line 1). Next, an array is defined that will be tied to the file (line 2). The tie command is where the magic happens (line 3). Now the lines in the file can be operated upon as though they were just elements in an array. The print/join function is a common way to print an array to the screen (line 4). The untie function releases the file (line 5), though this is often omitted due to laziness.

Direct Access

Reading a file and printing records is only so much fun. Here’s an example of how to change a single line in the file directly.

1: use Tie::File;
2: my @records;
3: tie @records, 'Tie::File', "myfile.txt";
4: $records[9] = "foo";
5: print join ( "\n", @records );
6: untie @records;

This is the same code as before, except that line 4 has been injected. It is a simple assignment that changes the tenth line of the file to “foo”. Remember that PERL arrays are zero-based, so $records[9] is actually the tenth element in the array.

Autochomp

Notice that newlines must either be chomped on input or readded for output. This is handled automatically.

Windows Newlines

Here’s an interesting trick if you are using PERL on Windows. Consider the following code.

1: use Tie::File;
2: my @records;
3: tie @records, 'Tie::File', "myfile.txt";
4: $records[9] = "foo\nbar";
5: print join ( "\n", @records );
6: untie @records;

Adding a newline character (“\n”) to the array element value will only embed it in the string. Inspect the file afterward, and find that no new line has been created in the file, even though it appears from the screen output that one had been added. Since line endings in Windows are two characters instead of one, carriage-return and linefeed, you must prepend the other character (“\r”).

1: use Tie::File;
2: my @records;
3: tie @records, 'Tie::File', "myfile.txt";
4: $records[9] = "foo\r\nbar";
5: print join ( "\n", @records );
6: untie @records;

Now the file does show an additional line. Of course, there are much better ways of doing this.

Changing Record Separators

Much like the RS and ORS variables in AWK, the record separator can be changed to any text string. This is done when the file is tied. Only this line is presented here.

1: tie @records, 'Tie::File', "myfile.txt", recsep => 'zap';

Now, the file will be separated into records on every occurrence of the string ‘zap’. I don’t want to spend the time to write and test a working example for this, as the need for this sort of thing may never arise in my work. It was just interesting to note.

Splicing

To remove one or more lines from a tied file, use the splice command.

1: use Tie::File;
2: my ( @records, @removed );
3: tie @records, 'Tie::File', "myfile.txt";
4: @removed = splice(@records,1,3);
5: print join ( "\n", @records );
6: untie @records;

Again, this is the same code we’ve been using, except an additional array has been declared (line 2) and the splice command has been introduced to remove the second, third, and fourth lines from the file (line 4). The first parameter of the splice function is the array, the second is the offset from the beginning of the array (one element), and the third is the length of the slice to be removed (three elements).

Here’s how elements can be replaced.

1: use Tie::File;
2: my ( @records, @removed );
3: tie @records, 'Tie::File', "myfile.txt";
4: @removed = splice(@records,1,3,26);
5: print join ( "\n", @records );
6: untie @records;

The same records are removed as above, but one new element has been inserted in their place with a value of 26.

Push, Pop, Shift, Unshift

All of these functions have splice equivalents, but they can be used as they normally would to manipulate the tied file.

Iteration

Random access is nice, but sometimes it is necessary to iterate through the records in a file. The following illustrates how to print the contents of the array to the screen by iteration instead of using print/join.

1. use Tie::File;
2. my ( @records, $record );
3. tie @records, 'Tie::File', "myfile.txt";
4. foreach $record ( @records ) { print "$record\n"; }
5: untie @records;

In addition to declaring the array, a record scalar is defined (line 2). The foreach iterator is used as one would expect to traverse through the array from beginning to end. A for loop could have been used just as easily.


August 23, 2011

Slurping Files In Perl

Filed under: Perl — Brandon @ 10:57 am
Tags: , ,

“Slurping” is a technical term that means to import an entire file into memory at one time. This is typically done when the data imported will not be changed, because it is static lookup data for example, or because you want to protect the contents of the file from accidental corruption. I use this technique often and was going to write a how-to post, but it seems that Uri Guttman has already posted an excellent treatment of this topic on the Perl.com blog titled Perl Slurp-Eaze.


Blog at WordPress.com.