PROGRAM archivosejercic1o;
TYPE
num = file of integer;
VAR
arch_num: num;
name: string[20];
x: integer;
BEGIN
writeln('Type the name of the file without extension:');
readln(name);
name:=name+'.txt';
Assign (arch_num,name);
Rewrite(arch_num);
writeln('Type in a number to add to the file:');
readln(x);
WHILE (x <> 0) DO BEGIN
write(arch_num,x);
writeln('Type in another number to add to the file:');
readln(x);
END;
close(arch_num);
END.
I have this code which creates a file with a series of numbers that the user provides, after compiling and executing the file appears in the Pascal directory but when I open it, I get something like this:
I'm just starting to interact with archives so I'm brand new at this, if you can help me I'd be thankful.
Binary vs. text
You are opening a file of Integer. This means that you write integers to the file, i.e. the file is in a binary format.
But you name it name + '.txt', which suggests to me you want to write text, not binary values, to the file.
Now if you display it as text, but it isn't text, you don't get what you want.
Binary means that you, for instance, write a 4 byte integer like 12345 (or hex $3039) as those 4 bytes, i.e. the bytes $39, $30, $00 and $00, in that order (or in reverse order, depending on the endianness of your computer).
Binary is compact, but seldom human readable. If you display such a binary file as text, you may get weird output, or perhaps even none at all (just try to open an .exe file in a text editor and see what you get). You probably want to write the numbers as text. Or you use something like a hex editor to view them (if you can read hex).
So open your files as type text:
PROGRAM archivosejercic1o;
TYPE
num = text;
VAR
arch_num: num;
name: string[20];
x: integer;
BEGIN
...
writeln(arch_num, x);
...
END.
More info on binary vs text: https://fileinfo.com/help/binary_vs_text_files. Note that that doesn't explain the different versions of Unicode text yet.
Related
I am currently doing the Ada tutorial from learn.adacore.com, and I am now at the second example: reading and outputting an integer. Since copy-pasting is for people who don't want to learn the syntax, I manually typed out most of the code (Some of it was generated by gnat-gps, but I'm now using vim).
I compiled and ran the program, and surprisingly, the second line of output is indented by roughly one tab. Why?
Here's the code:
With Ada.Text_IO;
Use Ada.Text_IO;
With Ada.Integer_Text_IO;
use Ada.Integer_Text_IO;
procedure Main is
N : Integer;
begin
-- Insert code here.
Put("Enter an integer value: ");
Get(N);
if N>0 then
Put (N);
Put_Line(" is a positive number");
end if;
end Main;
(how do I get syntax highlighting?)
Here is a sample of the output (the first 1 being input):
Enter an integer value: 1
1 is a positive number
The Put procedure from Ada.Integer_Text_IO uses a default field width padded with spaces.
The specification for that procedure is defined in the Ada Language Reference Manual as:
procedure Put(Item : in Num;
Width : in Field := Default_Width;
Base : in Number_Base := Default_Base);
The Width and Base parameters are given default values. Your call to Put only supplied a value for the formal parameter Item. To eliminate the left padding simply specify a desired width. I suggest you use Ada named notation for the call as in
Put(Item => N, Width => 1);
I'm looking for an easy/quick way to identify and extract hashtags from a string, and temporarily store them separately - e.g.:
If I have the following string:
2017-08-31 This is a useless sentence being used as an example. #Example #Date:2017-09-01 #NothingWow (and then some more text for good measure).
Then I want to be able to get this:
#Example
#Date:2017-09-01
#NothingWow
I figured storing it in a TStringList should be sufficient until I'm done. I just need to store them outside of the original string for easier cross referencing, then if the original string changes, add them back at the end.
(but that's easy - its the extracting part I'm having trouble with)
It should start at the # and end/break when it encounters a [space].
The way I initially planned it was to use Boolean flags (defaulted to False), then check for the different hashtags, set them to true if found, and extract anything after a [:] separately.
(but I'm sure there is a better way of doing it)
Any advice will be greatly appreciated.
The following shows a simple console application which you could use as the basis
for a solution. It works because assigning your input string to the DelimitedText property of a StringList causes the StringList to parse the input into a series of space-limited lines. It is then a simple matter to look for the ones which start with a #.
The code is written as a Delphi console application but should be trivial to convert to Lazarus/FPC.
Code:
program HashTags;
{$APPTYPE CONSOLE}
uses
Classes, SysUtils;
procedure TestHashTags;
var
TL : TStringList;
S : String;
i : Integer;
begin
TL := TStringList.Create;
try
S := '2017-08-31 This is a useless sentence being used as an example. #Example #Date:2017-09-01 #NothingWow (and then some more text for good measure)';
TL.DelimitedText := S;
for i := 0 to TL.Count - 1 do begin
if Pos('#', TL[i]) = 1 then
writeln(i, ' ', TL[i]);
end;
finally
TL.Free;
end;
readln;
end;
begin
TestHashTags;
end.
In the example below, I am wondering, why line 17 does not work, but line 18? Can I not convert a System.Address directly to an Integer (see line 17)?
main.adb
with Ada.Text_IO;
with Ada.Unchecked_Conversion;
with System.Storage_Elements;
procedure Main is
package SSE renames System.Storage_Elements;
type Integer_Access is access Integer;
I1_Access : Integer_Access := new Integer'(42);
I1_Address : System.Address := I1_Access.all'Address;
function Convert1 is new Ada.Unchecked_Conversion (System.Address, Integer);
function Convert2 is new Ada.Unchecked_Conversion (System.Address, Integer_Access);
begin
Ada.Text_IO.Put_Line (SSE.To_Integer (I1_Access'Address)'Img);
Ada.Text_IO.Put_Line (SSE.To_Integer (I1_Access.all'Address)'Img);
Ada.Text_IO.Put_Line (I1_Access.all'Img);
Ada.Text_IO.Put_Line (Convert1 (I1_Address)'Img); -- why does this NOT work?
Ada.Text_IO.Put_Line (Convert2 (I1_Address).all'Img); -- why does this work?
end Main;
Result
140734773254664
140243203260416
42
-363855872
42
If I compile your code on this Mac with -gnatwa (most warnings) and -gnatl (generate a listing) I get (excerpted)
12. function Convert1 is new Ada.Unchecked_Conversion (System.Address, Integer);
|
>>> warning: types for unchecked conversion have different sizes
because Integer is 32-bits while System.Address (and most access types) are 64-bits. Your machine is evidently similar.
So the reason you get a weird 5th output line (I got -490720512, by the way) is that it’s only looking at the bottom 32 bits of the actual address.
You might look at System.Address_To_Access_Conversions (ARM 13.7.2) for the supported way to do this.
It does work. Apparently it's doing something other than what you expected.
You can convert a System.Address to an Integer using Unchecked_Conversion, but the result isn't necessarily going to be meaningful. You'll get an integer representing the (probably virtual) address held in the System.Address value -- not the value of whatever object it points to. And if System.Address and Integer aren't the same size, the result will be even less meaningful.
Ada.Text_IO.Put_Line (Convert1 (I1_Address)'Img);
This prints an Integer representation of a memory address. It's not particularly meaningful. (Typically you'd want to see such an address in hexadecimal.)
Ada.Text_IO.Put_Line (Convert2 (I1_Address).all'Img);
This prints the Integer value, 42, of the object at the memory location indicated by the value of I1_Address. It's just a roundabout way of printing I1_Access.all.
If you only want to print the value of an image, as in your example, consider using the function System.Address_Image. This is not good for pointer arithmetic, but leads to better output (hexadecimal, for instance)
I have more of a 'problem solving' question than a syntax related problem.
Briefly, I'm creating a program that will read a text file full of words (that may feasibly be a list of passwords), one word per line - I'll be using ReadLn for that bit in a loop. For every word it finds, I want it to add "an amount" of obfuscation in line with how users these days will use '3' instead of 'E' in their passwords, or '1' instead of 'I'. I work in the IT security field and password breaking is often part of it and that's what the program is for.
I have managed to create the program so far that it generates a LEET table full of many different values for each letter of the alphabet and stacks them in a StringGrid that I can access as part of the process (and it is also outputted visually to a table).
type
TLetters = 'A'..'Z';
TLeet = array[TLetters] of TStringList;
var
SourceFileName, str : string;
StartIndexFile : TextFile;
i : TLetters;
leet : TLeet;
s : string;
n, o, ColumnSize : integer;
begin
for i in TLetters do
leet[ i ] := TStringList.Create;
// The next sequence of loops populates the string grid by counting the number of characters for each letter of the alphabet and then inserting them down, column by column and row by row...
//Letter A:
s := '4 # /-\ /\ ^ aye ∂ ci λ Z';
ColumnSize := wordcount(s,[' ']);
o := 0;
for n := 0 to ColumnSize do
leet['A'].Add(ExtractWord(n,s,[' ']));
for o := 0 to ColumnSize do
StringGrid1.Cells[1,o] := Leet['A'][o];
// And so on for B - Z
// ... then an OpenDialog that opens the source text file to read. Got that sorted
// A load of file opening stuff and then the obsfucation
repeat
Readln(StartIndexFile, Str);
LblProgress.Caption := ('Parsing Index File...please wait');
OBSFUCATE THE WORDS HERE TO SOME EXTENT
// but now I have hit a barrier....
until(EOF(StartIndexFile));
My problem is this : given the word 'Edward', for example, how do I decide to what level I should obfuscate it? Just the first letter 'E' to be replaced with a '3', and nothing more perhaps? Or the first two letters 'E' and 'd' to be replaced with ALL the values in the LEET table for both of the letters E and d (meaning dozens of new words would be generated from 'Edward', and so on), or all the values for 'E' but nothing else...the list goes on. Potentially, for every word, I could create thousands of additional one's! A 100Gb source file would soon become terabytes!
In other words, I need to set "a level" for which the program will function, that the user can decide. But I'm not sure how to structure that level?
So I'm not sure how to make it work? I didn't really think it through enough before I started. My initial thoughts were "It would be cool to have a program that would take an index of words from a computer, and then generate variations of every word to account for people who obfuscate characters." but having come to code it, I've realised it's a bigger job than I thought and I am now stuck at the section for actually 'LEETing my input file'!
You could use a level (0-10) as input.
0: replace nothing
10: replace all letters with LEET letters.
Depending on the length of the word, you calculate how many letters to replace and just replace random letters in the word, so that you not always replace the first letter for level 1 etc.
I am trying to learn Free Pascal using Lazarus and one of my pet projects involves reading the 64 byte headers of a particular set of untyped files that cannot be read and displayed using text or ASCII related procedures (so cannot be outputted directly to Memo boxes etc).
So far, I have devised the following code which does, I think, read in the 64 bytes of the header and I am using TStreams and a "Select Directory" dialog box to do this, based on advice received via the Lazarus IRC. My question though is how to actually USE the data that is read into the buffer from the header? For example, in the headers, there are sequences of 8 bytes, then 16 bytes, then 2 bytes and so on that I want to "work on" to generate other output that will eventually be converted to a string to go into my string grid.
Some of what I have so far is based on what I found here written by Mason Wheeler near the end (http://stackoverflow.com/questions/455790/fast-read-write-from-file-in-delphi) but it only shows how to read it in, not how to use it. I also read this (http://stackoverflow.com/questions/4309739/best-way-to-read-parse-a-untyped-binary-file-in-delphi) but again, it shows you how to READ the data too, but not subsequently USE the data. Any guidance wamrly received! So far, the code below just outputs single value integer numbers to the edit box, as opposed to, say, a range of 8 hexadecimal values.
PS - I am new to programming so please be gentle! Nothing too complex.
procedure TForm1.ProbeFile(FileIterator: TFileIterator);
type
TMyHeader = Array[1..64] of packed record
First8Bytes,
Next16Bytes,
Next2Bytes: byte;
end;
var
FI : TFileIterator; //File Iterator class
SG : TStringGrid;
NumRead : SmallInt;
FileToProbe: TStream;
header: TMyHeader;
begin
FI := TFileIterator.Create;
SG := TStringGrid.Create(self);
// Open the file and read the header
FileToProbe := TFileStream.Create(FileIterator.FileName, fmOpenRead);
try
FileToProbe.seek(0, soFromBeginning);
FileToProbe.ReadBuffer(header, SizeOf(header));
edit1.text := IntToStr(header[0].First8Bytes); // Just outputs '0' to the field? If I try '10' it ooutputs '29' and so on
finally
FileToProbe.Free;
end;
Please forgive me if I misunderstood your question.
As I understand it there is a header of 64 bytes. The first 8 bytes belong together, then the next 16 bytes and finally another 2 bytes.
To me it seems the declaration for this header should be:
TMyHeader = packed record
First8Bytes: array[0..7] of byte;
Next16Bytes: array [0..15] of byte;
Next2Bytes: array [0..1] of byte;
// add more if you like
end;
This recordtype has a size of 8+16+2 = 26 bytes.
Your code that reads the header looks ok to me, So I won't repeat that.
The next16bytes in your header can be retrieved, for example, like this:
edit1.text:= '';
// needs a declaration of a variable "i" as integer
for i:= 0 to 15 do
edit1.text:= edit1.text + IntToStr(header.next16bytes[i]) + '-';
Change the value of the first byte in the next2bytes part of your header as follows (again as an example):
header.next2bytes[0]:= 123;
Finally, you could write your changes back to the header of the file with help of the filetoprobe.writebuffer method.