VHDL Pre-loading RAM Memory with MIF File - vhdl

I am trying to implement memory in VHDL and when testing it on the DE2 board I want to preload the memory with generated values. I first tried doing this by reading from a text file, but that did not work because one cannot load a text file onto the FPGA board. So I turned to mif files. However, I do not know how to get vhdl/quartus ii to associate the MIF file I generated with the RAM I created.
I also tried using a 1-port RAM LPM, but because it clocks the reading as well as the writing and this causes it to not provide the data fast enough to be useful.
Below is the code for the RAM I created:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
entity instruction_memory is
port (
input_address : in std_logic_vector(31 downto 0);
opcode : out std_logic_vector(31 downto 0)
);
end instruction_memory;
architecture archInstruction_Memory of instruction_memory is
subtype word_t is std_logic_vector(31 downto 0);
type ram_t is array(0 to 4095) of Reichman_word_t;
impure function ReadMemFile(FileName : STRING) return ram_t is
file FileHandle : TEXT open READ_MODE is FileName;
variable CurrentLine : LINE;
variable TempWord : bit_vector(31 downto 0);
variable Result : ram_t := (others => (others => '0'));
begin
for i in 0 to 4095 loop
exit when endfile(FileHandle);
readline(FileHandle, CurrentLine);
read(CurrentLine, TempWord);
Result(i) := to_stdlogicvector(TempWord);
end loop;
return Result;
end function;
signal ram : ram_t := ReadMemFile("instructions_memory.txt");
attribute ram_init_file : string;
attribute ram_init_file of ram : signal is "instructions_memory.mif";
begin
opcode <= ram(to_integer(unsigned(input_address(31 downto 0))));
end archInstruction_Memory;
How can I get it preload the data in the .mif file so when I test it on the DE2 board it shows that it uses those values?

I'm using a tcl script to translate binary data (code) into a VHDL constant that can be used to generate a ROM:
package require cmdline
post_message "embed_m68k.tcl"
exec /bin/bash -c "(cd m68k; make)"
set binfile m68k/simple.bin
set fp [open $binfile r]
fconfigure $fp -translation binary
set bindata [read $fp]
close $fp
set filename simple.vhd
set date [clock format [clock seconds] -format { %a, %Y-%m-%d, %H:%M }]
set file [open $filename w]
set script [info script]
puts $file "library ieee;"
puts $file "use ieee.std_logic_1164.all;"
puts $file ""
puts $file " -- VHDL representation of $binfile"
puts $file " -- generated by $script on $date"
puts $file " -- m68k executable as preloaded RAM contents"
puts $file ""
puts $file "package m68k_binary is"
puts $file " subtype ubyte is std_logic_vector(7 downto 0);"
puts $file " type ubyte_array is array (natural range <>) of ubyte;"
puts $file ""
puts $file " constant m68k_binary : ubyte_array :="
puts $file " ("
puts -nonewline $file " "
set len [string length $bindata]
for {set i 0} {$i < $len} {incr i} {
set char [string index $bindata $i]
binary scan $char H2 byte
puts -nonewline $file "x\""
puts -nonewline $file $byte
puts -nonewline $file "\""
if { ! ([expr $i + 1] == $len) } {
puts -nonewline $file ", "
}
if { [expr ($i + 1) % 8] == 0 } {
puts $file ""
puts -nonewline $file " "
}
}
puts $file ""
puts $file " );"
puts $file "end package m68k_binary;"
close $file
You can easily include the script into your Quartus workflow using the PRE_FLOW_SCRIPT_FILE variable in your .qsf:
set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:precmd.tcl"
The PRE_FLOW_SCRIPT_FILE will then automatically be executed at the beginning of the synthesis process. Just include the generated .vhd file into your project.

Related

Raku: what is the syntax for shell calls with spaces?

Edit: I reported this as a bug to Raku:
qqx, shell not operating quotes properly
https://github.com/rakudo/rakudo/issues/3518
and one of the administrators referred me to
How should Proc::Async.new, run and shell call cmd.exe?
https://github.com/Raku/problem-solving/issues/20
which does sound exactly like what is occurring, especially the "It's not possible to escape spaces using ^." part.
If anyone comes up with a workaround, I would appreciate it.
Windows 7, and Windows 10-1909
Rakudo Star version 2019.03.1
How do I code this command in Raku?
fsutil usn readdata "C:/NtUtil/test 1"
The big bug-a-boo is that the file name has a space in it and Windows required double quotes around it. Single quotes crash.
I can not get either of these two to work with a file name with a space in it. fsutil either sees two parameters or one parameter where the name actually contains double quotes:
my #Result = qqx { C:/Windows/System32/fsutil.exe usn readdata "$FileName" }.lines;
for #Result -> $Line { say $Line; };
my $proc=run( "dir", "$FileName", :out );
my #RtnStr = $proc.out.slurp-rest.lines;
for #RtnStr -> $Line { say $Line; }
Many thanks,
-T
Edit: added Windows 10-1909 to the fray
Edit: no symptom change with "shell" command:
#Result = shell( "C:/Windows/System32/fsutil.exe usn readdata \"$FileName\"" ).lines;
for #Result -> $Line { say $Line; };
Usage : fsutil usn readData <filename>
Eg : fsutil usn readData C:\Temp\sample.txt
#Result = shell( "C:/Windows/System32/fsutil.exe usn readdata \"$FileName\"" );
for #Result -> $Line { say $Line; };
Exit with:
Proc.new(in => IO::Pipe, out => IO::Pipe, err => IO::Pipe, exitcode => 1, signal => 0, pid => 1728, command => ("C:/Windows/System32/fsutil.exe usn readdata \"C:/NtUtil/test 1\"",))
Note the "exitcode => 1" and the last parameter with the back slashes in it
Edit: using the single quote method:
#Result = shell( 'C:/Windows/System32/fsutil.exe usn readdata "$FileName"' );
results in the same error:
Usage : fsutil usn readData <filename>
Eg : fsutil usn readData C:\Temp\sample.txt
Error: The filename, directory name, or volume label syntax is incorrect.
Proc.new(in => IO::Pipe, out => IO::Pipe, err => IO::Pipe, exitcode => 1, signal => 0, pid => 1192, command => ("C:/Windows/System32/fsutil.exe usn readdata \"\$FileName\"",))
There's shell:
shell('echo "two words"'); # OUTPUT: «two words»
That's going to be the same here and there. It will also use existing common shell for any operating system. You can also use variables, provided you escape quotes destined for the shell:
my $words = "two words"
shell("echo \"$words\"")
or
shell "echo \""~ $words ~ "\""
Hello i've been testing Perl6 now Raku from windows 7 to windows 10.
i dont know if this solves the problem but for me it works :
in a file.rk or file.pl write :
shell "fsutil fsinfo drives & pause";
both fsutil and pause work.
Maybe this will help:
You can try escaping the space in the file path with ^
Example:
c:\Documents^ and^ Settings\a.bat
I have a workaround for anyone stopped because of this bug:
I am taking advantage of the Windows build in batch programming language:
my $PathIAm = $?FILE;
( my $IAm = $PathIAm ) ~~ s| .* "/" ||;
my Str $BatFile = $PathIAm ~ ".bat";
$BatFile ~~ s:global| '\\' |/|;
my Str $OS = $*KERNEL.name;
if not $OS eq "win32" {
say "Sorry, $IAm only work in Windows.";
exit; }
( $IAm = $PathIAm ) ~~ s| .* '\\' ||;
my Str $CmdStr =
Q[#echo off] ~ "\n" ~
Q[C:\Windows\System32\fsutil.exe usn readdata ] ~
Q["] ~ $FileName ~ Q["] ~ "\n";
# say $CmdStr;
spurt( $BatFile, $CmdStr );
say qqx { $BatFile };
Result:
C:\NtUtil>raku k:\Windows\NtUtil\FileAttributes.pl6 "Test 1"
Major Version : 0x3
Minor Version : 0x0
FileRef# : 0x00000000000000000058000000000340
Parent FileRef# : 0x00000000000000000013000000000eb9
Usn : 0x00000000711dab68
Time Stamp : 0x0000000000000000 12:00:00 AM 1/1/1601
Reason : 0x0
Source Info : 0x0
Security Id : 0x0
File Attributes : 0x20
File Name Length : 0xc
File Name Offset : 0x4c

Shell Script piping

#!/bin/sh
output=ANIL;
#
# Ask user for database inputs
#
echo -n "Enter Database Server Hostname: "
read dba_host
echo -n "Enter Database SID: "
read dba_sid
echo -n "Enter DBA User: "
read dba_usr
echo -n "Enter DBA password: "
read dba_pwd
echo -n "What daemon are we using: "
read daemon_str
#
# Loop to connect to database and exit if something is found
#
while :
do
output=`sqlplus $dba_usr/$dba_pwd#$dba_sid <<+ | grep '^-' | sed 's/-//'
set serveroutput on
DECLARE
command VARCHAR2(50);
return_name VARCHAR2(30);
value VARCHAR2(10000);
status INT;
system_time TIMESTAMP := SYSTIMESTAMP;
WHILE TRUE
BEGIN
status := DBMS_PIPE.RECEIVE_MESSAGE($daemon_str);
IF status = 0 THEN
DMS_PIPE.UNPACK_MESSAGE(command);
END IF;
IF command = "STOP" THEN
DBMS_OUTPUT.PUT_LINE('STOP was encountered') >> file.log;
DBMS_OUTPUT.PUT_LINE(system_time) >> file.log;
BREAK
ELSIF command = "SYSTEM" THEN
DBMS_PIPE.UNPACK_MESSAGE(return_name);
DBMS_PIPE.UNPACK_MESSAGE(value);
EXIT
$value
ELSIF command = "SQL"
DBMS_PIPE.UNPACK_MESSAGE(return_name);
DBMS_PIPE.UNPACK_MESSAGE(value);
EXECUTE IMMEDIATE value;
ELSE
nap(10)
EXCEPTION
WHEN OTHERS THEN
dbms_ouput.put_line('Unknown Input Error') >> file.log;
DBMS_OUTPUT.PUT_LINE(system_time) >> file.log;
DBMS_PIPE.PACK_MESSAGE('done');
DBMS_PIPE.PACK_MESSAGE(status);
status := DBMS_PIPE.SEND_MESSAGE(return_name,10);
END;
dbms_output.put_line(chr(10) || '-' || command);
END;
/
exit
+`
echo $output
done
I am trying to convert a c code block to what you see now a shell script block. I am just a beginner in this coding language and was wanting to know if anyone is seeing something I am not. To sum up what I am trying to accomplish is ask user for the oracle database they want to connect to then keep connection and receive things through pipe. Then the usual of unpacking, outputting errors and such. Then sending it back through same pipe. Any input on possible syntax or anything at all that could be causing this to constantly echo out nothing but blank lines from while loop.

Split very large files on record border

I have to split a very large file into N smaller files with the following constraints:
I have to split on record border
Record separator can be any character
the number of records in the resulting N files should be the same (+/- 1 record)
I can just use bash and standard coreutils (I have a working solution in Perl but we're not allowed to install Perl/Python/etc)
This is not a real constraint but - if possible - I'd like to scan the original (large) file just once.
Sort order of the resulting files is not important.
My working solution in Perl reads the original file and writes...
- the 1st record to the first file
- ...
- the Nth record to the Nth file
- the N+1 record back to the first file
- etc
So - at the end - with a single scan of the initial file I do get several smaller files with the same number of records (+/- 1).
For example, assume this is the input file:
1,1,1,1A2,2,2,2A3,
3,3,3A4,4,4,4A5,5,
5,5A6,6,6,6A7,7,7,
7,A8,8,8,8A9,9,9,9
A0,0,0,0
With record separator = 'A' and N = 3 I should get three files:
# First file:
1,1,1,1A2,2,2,2A3,
3,3,3
# Second file
4,4,4,4A5,5,
5,5A6,6,6,6
# Third file:
7,7,7,
7,A8,8,8,8A9,9,9,9
A0,0,0,0
UPDATE
Here you have the perl code. I tried to make it as simple and readable as I can:
#!/usr/bin/perl
use warnings;
use strict;
use locale;
use Getopt::Std;
#-----------------------------------------------------------------------------
# Declaring variables
#-----------------------------------------------------------------------------
my %op = (); # Command line parameters hash
my $line = 0; # Output file line number
my $fnum = 0; # Output file number
my #fout = (); # Output file names array
my #fhnd = (); # Output file handles array
my #ifiles = (); # Input file names
my $i = 0; # Loop variable
#-----------------------------------------------------------------------------
# Handling command line arguments
#-----------------------------------------------------------------------------
getopts("o:n:hvr:", \%op);
die "Usage: lfsplit [-h] -n number_of_files",
" [-o outfile_prefix] [-r rec_sep_decimal] [-v] input_file(s)\n"
if $op{h} ;
if ( #ARGV ) {
#ifiles = #ARGV ;
} else {
die "No input files...\n" ;
}
$/ = chr($op{r}) if $op{r} ;
#-----------------------------------------------------------------------------
# Setting Default values
#-----------------------------------------------------------------------------
$op{o} |= 'out_' ;
#-----------------------------------------------------------------------------
# Body - split in round-robin to $op{n} files
#-----------------------------------------------------------------------------
for ( $i = 0 ; $i < $op{n} ; $i++ ) {
local *OUT ; # Localize file glob
$fout[$i] = sprintf "%s_%04d.out", $op{o}, $i ;
open ( OUT, "> $fout[$i]" ) or
die "[lfsplit] Error writing to $fout[$i]: $!\n";
push ( #fhnd , *OUT ) ;
}
$i = 0 ;
foreach ( #ifiles ) {
print "Now reading $_ ..." if $op{v} ;
open ( IN, "< $_" ) or
die "[lfsplit] Error reading $op{i}: $!\n" ;
while ( <IN> ) {
print { $fhnd[$i] } $_ ;
$i = 0 if ++$i >= $op{n} ;
}
close IN ;
}
for ( $i = 0 ; $i < $op{n} ; $i++ ) {
close $fhnd[$i] ;
}
#-----------------------------------------------------------------------------
# Exit
#-----------------------------------------------------------------------------
exit 0 ;
Just for kicks, a pure bash solution, no external programs and no forking (I think):
#!/bin/bash
input=$1
separator=$2
outputs=$3
i=0
while read -r -d"$separator" record; do
out=$((i % outputs)).txt
if ((i < outputs)); then
: > $out
else
echo -n "$separator" >> $out
fi
echo -n "$record" >> $out
((i++))
done < $input
Sadly this will reopen every file for every output operation. I'm sure it's possible to fix this, using <> to open a file descriptor and keep it open, but using that with non-literal file descriptors is a bit of a pain.

IP calculator. Decimal to binary

I have ploblem with converting decimal numbers to binary. I want to have space between 8b, but i dont know how to do that in the code.
Function str2bin(strAddress)
'special decimal to binary function
'input 4 octet ip address
'output 32bit binary number
objAddress = Split(strAddress, ".")
For Each strOctet In objAddress
intOctet = CInt (strOctet)
strOctBin = ""
For x = 1 To 8
If intOctet Mod 2 > 0 Then
strOctBin = "1" & strOctBin
Else
strOctBin = "0" & strOctBin
End If
intOctet = Int(intOctet / 2)
Next
str2bin = str2bin & strOctBin
Next
End Function
'-----------------------------------------------------------
Quick and very dirty:
Append a space after each octet:
str2bin = str2bin & strOctBin & " "
and Trim() the return value in the calling code to get rid of the trailing space.
Evidence:
type 28139908.vbs & cscript 28139908.vbs
Option Explicit
Function str2bin(strAddress)
'special decimal to binary function
'input 4 octet ip address
'output 32bit binary number
Dim objAddress, strOctet, intOctet, strOctBin, x
objAddress = Split(strAddress, ".")
For Each strOctet In objAddress
intOctet = CInt (strOctet)
strOctBin = ""
For x = 1 To 8
If intOctet Mod 2 > 0 Then
strOctBin = "1" & strOctBin
Else
strOctBin = "0" & strOctBin
End If
intOctet = Int(intOctet / 2)
Next
str2bin = str2bin & strOctBin & " "
Next
End Function
Dim sIP : sIP = "127.15.32.255"
WScript.Echo sIP, ">" & str2bin(sIP) & "<", ">" & Trim(str2bin(sIP)) & "<"
127.15.32.255 >01111111 00001111 00100000 11111111 < >01111111 00001111 00100000 11111111<
'Subnet Calculator V1
'Script by Chavdarova
'usage cscript VBScriptSubnetCalcV2 > output.txt
'force script to run in cscript mode
Set objShell = CreateObject("WScript.Shell")
If Instr(1, WScript.FullName, "CScript", vbTextCompare) = 0 Then
objShell.Run "%comspec% /k cscript //nologo """ & WScript.ScriptFullName & """", 1, False
WScript.Quit
End If
'a bit of test code to feed a range of addresses into script for testing
' snm="255.255.192.0"
' for iCount=0 to 255
' ip="172.16.17."&iCount
' CalcSubnet ip, snm
' next
strIP=inputbox("Vnesite IP", "Chavdarova Subnet Calc", "172.16.98.53")
strSN=inputbox("Vnesite Subnet Mask", "Chavdarova Subnet Calc", "255.255.224.0")
CalcSubnet strIP, strSN
wscript.quit
----------
function CalcSubnet(strIP,strSNM)
binSNM=str2bin(strSNM)
binIP=str2bin(strIP)
'IP <AND> SN to find Network addresses
for c=32 to 1 step -1
temp=(cint(mid(binIP,c, 1)) and cint(mid(binSNM,c, 1))) & temp
next
netwAdd=temp : temp=""
'IP <OR> SN to find blocks of all "ones" - these addresss are broadcast addresses
for c=32 to 1 step -1
temp=(cint(mid(binIP,c, 1)) or cint(mid(binSNM,c, 1))) & temp
next
bcCheck=temp : temp=""
'Calc 1st. host address in range (Network Address + 1)
ist=binAdd(netwAdd,string(31, "0")&"1")
'Calc Last host address in range (111111...1 - bcCheck + IP - 0...000001)
lst=binSub(string(32,"1"),bcCheck)
lst=binadd(lst,binIP)
lst=binsub(lst,string(31, "0")&"1" )
wscript.echo "IP "&binIP&" "&bin2str(binIP)&vbcrlf&_
"Subnet Mask "&binSNM&" "&bin2str(binSNM)&vbcrlf&_
"Subnet Network "&netwAdd&" "&bin2str(netwAdd)&vbcrlf&_
"Host min "&ist &" "& bin2str(ist) &vbcrlf&_
"Host max "&lst &" "& bin2str(lst) &vbcrlf&_
"Hosts "&binsub(lst,ist) &" "& Bin2Dec(binsub(lst,ist)) &vbcrlf
end function
----------
Function Bin2Dec(strBin)
'Plain old binary to decimal function
result = 0
for intIndex = len(strBin) to 1 step -1
strDigit = mid(strBin, intIndex, 1)
if strDigit = "0" then
'do nothing
elseif strDigit = "1" then
result = result + (2 ^ (len(strBin)-intIndex))
else
Bin2Dec = 0
exit for
end if
next
Bin2Dec = result
End Function
----------
Function bin2str(strBinary)
'special binary to decimal function
'input 32bit binary number
'output 4 octet ip address
For iPosOct = 1 To 4
strOctBin = Right(Left(strBinary, iPosOct * 8), 8)
intOctet = 0
intValue = 1
For iPosBin = 1 To Len(strOctBin)
If Left(Right(strOctBin, iPosBin), 1) = "1" Then
intOctet = intOctet + intValue
end if
intValue = intValue * 2
Next
If bin2str = Empty Then
bin2str = CStr(intOctet)
Else
bin2str = bin2str & "." & CStr(intOctet)
end if
Next
End Function
----------
Function str2bin(strAddress)
'special decimal to binary function
'input 4 octet ip address
'output 32bit binary number
objAddress = Split(strAddress, ".")
For Each strOctet In objAddress
intOctet = CInt (strOctet)
strOctBin = ""
For x = 1 To 8
If intOctet Mod 2 > 0 Then
strOctBin = "1" & strOctBin
Else
strOctBin = "0" & strOctBin
End If
intOctet = Int(intOctet / 2)
Next
str2bin = str2bin & strOctBin & " "
Next
End Function
----------
function binSub(binA,binB)
'subtract one 32bit binary number from another
'binA must be biggest
c=0
for i=32 to 1 step-1
a=cint(mid(binA,i,1))
b=cint(mid(binB,i,1))
if a=0 and b=0 and c=0 then
subt=0 : c=0
elseif a=1 and b=0 and c=0 then
subt=1 : c=0
elseif a=0 and b=1 and c=0 then
subt=1 : c=1
elseif a=1 and b=1 and c=0 then
subt=0 : c=0
elseif a=1 and b=1 and c=1 then
subt=1 : c=1
elseif a=1 and b=0 and c=1 then
subt=0 : c=0
elseif a=0 and b=1 and c=1 then
subt=0 : c=0
elseif a=0 and b=0 and c=1 then
subt=1 : c=1
else
msgbox "This function is only for subtracting 2 32bit binary numbers"
binSub=0 : exit function
end if
total=subt&total
'wscript.echo "a-"&BinA&" "&a&vbcrlf&"b-"&BinB&" "&b&vbcrlf&"subtraction "&subt&vbcrlf&"carry "&
c&vbcrlf&"x-"&total&vbcrlf&cvcrlf
next
if c=1 then
msgbox "Error you are subtracting a larger number from a smaller number"&vbcrlf&binA&vbcrlf&binB
end if
binsub=total
end function
----------
function binAdd(binA,binB)
'add two 32bit binary numbers together
c=0
for i=32 to 1 step-1
a=cint(mid(binA,i,1))
b=cint(mid(binB,i,1))
if a=0 and b=0 and c=0 then
add=0 : c=0
elseif a=1 and b=0 and c=0 then
add=1 : c=0
elseif a=0 and b=1 and c=0 then
add=1 : c=0
elseif a=1 and b=1 and c=0 then
add=0 : c=1
elseif a=1 and b=1 and c=1 then
add=1 : c=1
elseif a=1 and b=0 and c=1 then
add=0 : c=1
elseif a=0 and b=1 and c=1 then
add=0 : c=1
elseif a=0 and b=0 and c=1 then
add=1 : c=0
else
msgbox "Error this function is only for adding 2 32bit binary numbers together"
binAdd=0 : exit function
end if
total=add&total
'wscript.echo "a-"&BinA&" "&a&vbcrlf&"b-"&BinB&" "&b&vbcrlf&"addition "&add&vbcrlf&"carry "& c&vbcrlf&"x-"&total
next
binAdd=total
end function

Perl: Weird Tie::File behaviour in Windows as opposed to Unix

I have this perl script that uses Tie::File.
In Linux(Ubuntu) when I invoke the script via Bash it works as expected but in Windows when I invoke the script via Powershell it behaves weirdly (check P.S. below).
Code:
#!/usr/bin/perl -T
use strict;
use warnings;
use Tie::File;
use CommonStringTasks;
if ( #ARGV != 4 ) {
print "ERROR:Inadequate/Redundant arguments.\n";
print "Usage: perl <pl_executable> <path/to/peer_main.java> <peer_main.java>\n";
print " <score_file_index> <port_step_index>\n";
print $ARGV[0], "\n";
print $ARGV[1], "\n";
print $ARGV[2], "\n";
print $ARGV[3], "\n";
exit 1;
}
my $PEER_DIR = $ARGV[0];
my $PEER_FILE = $ARGV[1];
my $PEER_PACKAGE = "src/planetlab/app";
my $PEER_PATH = "${PEER_DIR}/${PEER_PACKAGE}/${PEER_FILE}";
# Check if args are tainted ...
# Check $PEER_PATH file permissions ...
open(my $file, "+<", "$PEER_PATH")
or
die("File ", $PEER_FILE, " could not be opened for editing:$!");
# Edit the file and change variables for debugging/deployment setup.
# Number demanglers:
# -flock -> arg2 -> 2 stands for FILE_EX
# Options (critical!):
# -Memory: Inhibit caching as this will allow record changes on the fly.
tie my #fileLines,
'Tie::File',
$file,
memory => 0
or
die("File ", $PEER_FILE, " could not be tied with Tie::File:$!");
flock $file, 2;
my $i = 0;
my $scoreLine = "int FILE_INDEX = " . $SCORE . ";";
my $portLine = "int SERVER_PORT = " . $PORT . ";";
my $originalScoreLine = "int FILE_INDEX =";
my $originalPortLine = "int SERVER_PORT =";
(tied #fileLines)->defer;
while (my $line = <$file>) {
if ( ($line =~ m/($scoreLine)/) && ($SCORE+1 > 0) ) {
print "Original line (score): ", "\n", $scoreLine, "\n";
chomp $line;
$line = substr($line, 0, -($scoreDigits+1));
$line = $line . (++$SCORE) . ";";
print "Editing line (score): ", $i, "\n", trimLeadSpaces($fileLines[$i]), "\n";
$fileLines[$i] = $line;
print "Line replaced with:\n", trimLeadSpaces($line), "\n";
next;
}
if ( ($line =~ m/($portLine)/) && ($PORT > 0) ) {
print "Original line (port): ", "\n", $portLine, "\n";
chomp $line;
$line = substr($line, 0, -($portDigits+1));
$line = $line . (++$PORT) . ";";
print "Editing line (port): ", $i, "\n", trimLeadSpaces($fileLines[$i]), "\n";
$fileLines[$i] = $line;
print "Line replaced with:\n", trimLeadSpaces($line), "\n";
last;
}
# Restore original settings.
if ( ($line =~ m/($originalScoreLine)/) && ($SCORE < 0) ) {
print "Restoring line (score) - FROM: ", "\n", $fileLines[$i], "\n";
$fileLines[$i] = " private static final int FILE_INDEX = 0;";
print "Restoring line (score) - TO: ", "\n", $fileLines[$i], "\n";
next;
}
if ( ($line =~ m/($originalPortLine)/) && ($PORT < 0) ) {
print "Restoring line (port) - FROM: ", "\n", $fileLines[$i], "\n";
$PORT = abs($PORT);
$fileLines[$i] = " private static final int SERVER_PORT = " . $PORT . ";";
print "Restoring line (port) - TO: ", "\n", $fileLines[$i], "\n";
last;
}
} continue {
$i++;
}
(tied #fileLines)->flush;
untie #fileLines;
close $file;
The perl version in both OSes is 5+(in Windows Active-State Perl with CPAN modules).
Could it be the way I open the filehandle? Any ideas anyone?
P.S.: The first version had a while (<$file>) and instead of $line I used the $_ variable but when I did that I had a behaviour where specific lines would not be edited but instead the file would get appended with a hundred newlines or so followed by the (correctly) edited line and so on. I also had a warning about $fileLines[$i] being uninitialized!Clearly something's wrong with the Tie::File structure in Windows or something else that I am not aware of. Same erratic behaviour takes place with the changes and in Linux(Ubuntu) behaviour again is as expected.
The OPs question is vague, and lacks input and expected output. Therefore I will simply note some of my concerns:
First, using Tie::File and <$file> and flock on the same handle seems to be both overkill and dangerous. I would recommend simply using Tie::File to iterate and to edit, such as:
#!/usr/bin/env perl
use strict;
use warnings;
use Tie::File;
tie my #lines, 'Tie::File', 'filename';
foreach my $linenum ( 0..$#lines ) {
if ($lines[$linenum] =~ /something/) {
$lines[$linenum] = 'somethingelse';
}
}
Perhaps better than edit inline, as Tie::File allows, copy the file to a backup, iterate over the lines using <$file>, then write to a new file with the old name.
#!/usr/bin/env perl
use strict;
use warnings;
use File::Copy 'move';
my $infile = $ARGV[0];
move( $infile, "$infile.bak");
open my $inhandle, '<', "$infile.bak";
open my $outhandle, '>', $infile;
while( my $line = <$inhandle> ) {
if ($line =~ /something/) {
$line = 'somethingelse';
}
print $outhandle $line;
}
Second, the -MModule flag simply translates to a use Module; at the top of the script. Therefore -MCPAN is use CPAN;, however loading the CPAN module does nothing for the script. CPAN.pm gives a script the ability to install modules.
Third, we will be able to help better if you give and example input, an expected output, and a stripped down script that clearly shows how this operation is to perform while still failing in the same way that the actual script does.
I found out the source of my problems. The reason was the record separator!
Tie::File expected in Windows a /r/n record separator so it read the whole file in just one pass. My files are in UTF-8, with Unix line endings.
That is why when I was traversing the $fileLines and accessed any index beyond 0 I got from perl a warning that the string was not initialized. Fixed the problem and now I am ready to go on! :D
P.S.: Mr Joel Berger I am marking your answer as valid/appropriate because you really tried helping me and I followed your first advice about the file handle :).
Thank you everyone for assisting me xD xD xD

Resources