Lazarus

Free Pascal => General => Topic started by: Fred vS on October 23, 2022, 08:49:51 pm

Title: for achar := 'A' to 'Z' do
Post by: Fred vS on October 23, 2022, 08:49:51 pm
Hello.

I just tested this code:

Code: Pascal  [Select][+][-]
  1. procedure loop_of_char;
  2. var
  3. achar : char;
  4. begin
  5.   for achar := 'A' to 'Z' do writeln(achar);
  6. end;
  7.  

And (Wow) it gives me all the uppercase letters of the latin alphabet.

But it is safe to do that ?

Title: Re: for achar := 'A' to 'Z' do
Post by: Thaddy on October 23, 2022, 09:02:09 pm
This is a bit more safe:
Code: Pascal  [Select][+][-]
  1. var a: char;
  2. begin
  3.    for a in ['A'..'Z'] do writeln(a);
  4. end.
But your code is safe too.
Title: Re: for achar := 'A' to 'Z' do
Post by: MarkMLl on October 23, 2022, 09:02:42 pm
I think it should be, because of the strictures that apply to Pascal identifiers: I remember comment on this from Jonas et al. when somebody wanted to know if the compiler could be modified to run on an EBCDIC-based mainframe.

However it might still be safer to use AnsiChar.

MarkMLl
Title: Re: for achar := 'A' to 'Z' do
Post by: Thaddy on October 23, 2022, 09:38:10 pm
I agree that - given modern Pascal - dialects it is always better to write the intention.
But in this case it makes no difference either way.
So yes, explain your char or string type by proper declaration.
Title: Re: for achar := 'A' to 'Z' do
Post by: MarkMLl on October 23, 2022, 09:44:26 pm
One might laugh but... I've used a tool in the past which made no assumption about character set, i.e. collation order or what characters could appear in an identifier, but /did/ assume that digits were sequential and ordered 0...9.

And  damme, but if you look hard enough you can find character sets where even that doesn't apply.

MarkMLl
Title: Re: for achar := 'A' to 'Z' do
Post by: Fred vS on October 23, 2022, 10:01:34 pm
@Thaddy and @Mark : Thanks for the infos and happy to discover it.

It does not work with:
Code: Pascal  [Select][+][-]
  1. for achar := 'Ά' to 'Ω' do
but personnaly I dont need it (at the moment).
Title: Re: for achar := 'A' to 'Z' do
Post by: MarkMLl on October 23, 2022, 10:16:33 pm
Yeah, well they're outside the set of characters that can be legitimately used in Pascal identifiers, so all bets are off.

I've given a bit of thought to "simple" rules of thumb determining what can be in an identifier, what can be used as an operator and so on... but at the same time I think that the Unicode Consortium has put a serious amount of work into it some of which might actually be useful.

MarkMLl
Title: Re: for achar := 'A' to 'Z' do
Post by: Kays on October 23, 2022, 10:19:29 pm
[…] But it is safe to do that ?
To quote from the ISO standard 7185 (“Standard Pascal”):
Quote
6.4.2.2 Required simple-types
The following types shall exist
  • integer-type. […]
  • real-type. […]
  • Boolean-type. […]
  • char-type. […] The following relations shall hold.
    • The subset of character values representing the digits 0 to 9 shall be numerically ordered and contiguous.
    • The subset of character values representing the upper case letters A to Z, if available, shall be alphabetically ordered but not necessarily contiguous.
    • The subset of character values representing the lower case letters a to z, if available, shall be alphabetically ordered but not necessarily contiguous.
That’s all fine, but the compiler still needs to claim ISO-compliance. Bottom line, your algorithm is “safe”, i. e. produces the expected result, as long as ord('A') + 25 = ord('Z').
Title: Re: for achar := 'A' to 'Z' do
Post by: MarkMLl on October 23, 2022, 10:36:39 pm
Note that the ISO standard doesn't declare that there are 26 characters in the range A through Z.

MarkMLl
Title: Re: for achar := 'A' to 'Z' do
Post by: Bart on October 23, 2022, 10:40:43 pm
If you really want to be safe (in the sense that there are guaranteed to be no other characters in between, regardless of character set) you can do:
Code: Pascal  [Select][+][-]
  1. const
  2.   Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  3. begin
  4.   for aChar in Alphabet do writeln(AChar);
  5. end.

Yes, I know it's silly   ;)

Bart
Title: Re: for achar := 'A' to 'Z' do
Post by: Fred vS on October 23, 2022, 10:53:38 pm
Thanks all for the light.

By the way, the goal is to get all the devices on a Windows system with something like this:
 
Code: Pascal  [Select][+][-]
  1.    var
  2.     achar : char
  3.     ...
  4.      for achar := 'A' to 'Z' do
  5.         begin
  6.          if directoryexists(achar + ':\') then writeln(achar + ':\ exists'');
  7.  
     
Maybe (surely) there are other ways but this code works as expected.  :-\
Title: Re: for achar := 'A' to 'Z' do
Post by: Kays on October 23, 2022, 10:59:28 pm
Note that the ISO standard doesn't declare that there are 26 characters in the range A through Z.
Well, if your comment is meant to say it could be less than 26 characters:
Quote
4 Definitional conventions
[…]
The characters required to form Pascal programs shall be those implicitly required to form the tokens and separators defined in 6.1.
[…]
6.1.1 General
[…] The representation of any letter (upper case or lower case, differences in font (https://xkcd.com/2309/), etc.) occurring anywhere outside of a character-string (see 6.1.7) shall be insignificant in that occurrence to the meaning of the program.
  • letter = ‘a’ | ‘b’ | ‘c’ | ‘d’ | […] ‘w’ | ‘x’ | ‘y’ | ‘z’ .
Because you can write, compose, say, identifiers as a sequence of letters A – Z, you can specify these letters in a character-string, too.

Furthermore, the ISO standards 7185 and 10206 incorporate clauses from ASCII (ISO standard 646:1983), but I’m not sure what exactly.

[…] By the way, the goal is to get all the devices on a Windows system with something like this: […]
Maybe it won’t catch unformatted devices, I don’t know.
Title: Re: for achar := 'A' to 'Z' do
Post by: Fred vS on October 23, 2022, 11:09:04 pm
[…] By the way, the goal is to get all the devices on a Windows system with something like this: […]
Maybe it won’t catch unformatted devices, I don’t know.

I hope so and also no mounted devices.

So all seems ok, I can go to sleep (after commit all that, of course).

Many thanks to all and have a good night and day (or day and night).

Fre;D
Title: Re: for achar := 'A' to 'Z' do
Post by: Fred vS on October 23, 2022, 11:21:30 pm
Allez, for the game, this one works too  ;) :

Code: Pascal  [Select][+][-]
  1. procedure inc_char;
  2. var
  3. achar : char = 'A';
  4. begin
  5.   while achar <= 'Z' do
  6.       begin
  7.       writeln(achar);
  8.       inc(achar);
  9.      end;
  10. end;
Title: Re: for achar := 'A' to 'Z' do
Post by: Bart on October 23, 2022, 11:50:33 pm
By the way, the goal is to get all the devices on a Windows system with something like this:
I haved a DriveComboBox for that...
You can specify what type of drive when populating (e.g. removables only).
Windows only of course.

Bart
Title: Re: for achar := 'A' to 'Z' do
Post by: Jorg3000 on October 24, 2022, 08:55:27 am
Hi!
And if you need information about the type of a drive, see ...

Code: Pascal  [Select][+][-]
  1. aType:=Windows.GetDriveType(PChar(aRootPath));

DRIVE_REMOVABLE=2; DRIVE_FIXED=3; DRIVE_REMOTE=4; DRIVE_CDROM=5; DRIVE_RAMDISK=6;

https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdrivetypea (https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdrivetypea)
Jörg
Title: Re: for achar := 'A' to 'Z' do
Post by: MarkMLl on October 24, 2022, 09:03:36 am
4 Definitional conventions
[…]
The characters required to form Pascal programs shall be those implicitly required to form the tokens and separators defined in 6.1.

But that is distinct from your earlier

Quote
6.4.2.2 Required simple-types

This was the point in the discussion a few years ago of a mainframe port: FPC could quite happily have EBCDIC-based string types (i.e. section 6), but changing the compiler itself to use anything other than an ASCII representation for the program (i.e. section 4) would have been decidedly non-trivial.

So a cross-compiler would have been viable, at least for newer variants of the IBM mainframe architecture, but a native compiler much less so.

MarkMLl
Title: Re: for achar := 'A' to 'Z' do
Post by: ASerge on October 24, 2022, 06:43:08 pm
By the way, the goal is to get all the devices on a Windows system with something like this:
Code: Pascal  [Select][+][-]
  1. {$MODE OBJFPC}
  2. {$APPTYPE CONSOLE}
  3. {$LONGSTRINGS ON}
  4.  
  5. uses SysUtils, Windows;
  6.  
  7. procedure PrintDrives;
  8. var
  9.   BufSize: DWORD;
  10.   P, Buffer: PUnicodeChar;
  11.   S: UnicodeString;
  12. begin
  13.   BufSize := GetLogicalDriveStringsW(0, nil);
  14.   if BufSize = 0 then
  15.     RaiseLastOSError;
  16.   GetMem(Buffer, BufSize * SizeOf(UnicodeChar));
  17.   try
  18.     if GetLogicalDriveStringsW(BufSize, Buffer) = 0 then
  19.       RaiseLastOSError;
  20.     P := Buffer;
  21.     while P[0] <> #0 do
  22.     begin
  23.       S := P;
  24.       Inc(P, Length(S) + 1);
  25.       Writeln(S);
  26.     end;
  27.   finally
  28.     FreeMem(Buffer);
  29.   end;
  30. end;
  31.  
  32. begin
  33.   PrintDrives;
  34.   Readln;
  35. end.
Title: Re: for achar := 'A' to 'Z' do
Post by: Fred vS on October 24, 2022, 07:52:37 pm
@Jorge3000 and @ASerge and @Bart: many thanks for that execellent options.

But I forgot to note that I prefer a cross-os code and not use window unit .
So I will stay with one of the options using a loop with if directoryexists((achar + ':\') in it.

Fre;D
Title: Re: for achar := 'A' to 'Z' do
Post by: wildfire on October 24, 2022, 08:12:36 pm
@Jorge3000 and @ASerge and @Bart: many thanks for that execellent options.

But I forgot to note that I prefer a cross-os code and not use window unit .
So I will stay with one of the options using a loop with if directoryexists((achar + ':\') in it.

Fre;D

Which in itself is not cross OS.
Title: Re: for achar := 'A' to 'Z' do
Post by: MarkMLl on October 24, 2022, 08:37:46 pm
Which in itself is not cross OS.

I have to agree, since I'm sure that Fred is interested in more than Windows and DOS. But allowing that the other OSes tend to be unix-based, it's difficult to decide on an appropriate alternative unless we try to do something like enumerating / plus any other filesystems that some system component can access without actually mounting it.

MarkMLl
Title: Re: for achar := 'A' to 'Z' do
Post by: Fred vS on October 24, 2022, 08:45:39 pm
@Jorge3000 and @ASerge and @Bart: many thanks for that execellent options.

But I forgot to note that I prefer a cross-os code and not use window unit .
So I will stay with one of the options using a loop with if directoryexists((achar + ':\') in it.

Fre;D

Which in itself is not cross OS.

It depend what you call cross OS, the previous code of course will have no result on Unix.
Here part of the code to populate a grid, like a filedialog.  (of course using {$ifdef windows} for the afphabet drivers and {$ifdef unix} for "/" in path will make code lighter but will not generate crash without it.)

Code: Pascal  [Select][+][-]
  1. // this will be for Windows only
  2. {$ifdef windows}  // optional
  3.   for achar := 'A' to 'Z' do
  4.     begin
  5.      if directoryexists(achar + ':\') then
  6.        begin
  7.         Inc(x);
  8.         fo.places.rowcount := x+1;
  9.          fo.places[1][x] := string(achar + ':\');
  10.        end;
  11.    end;
  12.    
  13.     if directoryexists('C:\users') then  // only Windows
  14.     begin
  15.       Inc(x);
  16.       fo.places.rowcount := x+1;
  17.       fo.places[1][x] := string('C:\users');
  18.     end;
  19. {$endif}  
  20.  
  21. {$ifdef unix} // optional
  22.     if directoryexists('/') then // only Unix
  23.     begin
  24.       Inc(x);
  25.       fo.places.rowcount := x+1;
  26.       fo.places[1][x] := string('/');
  27.     end;
  28.     if directoryexists('/usr') then // only unix
  29.     begin
  30.       Inc(x);
  31.       fo.places.rowcount := x+1;
  32.       fo.places[1][x] := string('/usr');
  33.     end;
  34.     {$endif}
  35.  
  36.     if directoryexists(tosysfilepath(sys_getuserhomedir)) then // Windows and Unix
  37.     begin
  38.       Inc(x);
  39.       fo.places.rowcount := x+1;
  40.       fo.places[1][x] := string(tosysfilepath(sys_getuserhomedir));
  41.     end;
  42.     if directoryexists(tosysfilepath(sys_getuserhomedir + directoryseparator + 'Desktop')) then // Windows and Unix
  43.     begin
  44.       Inc(x);
  45.       fo.places.rowcount := x+1;
  46.       fo.places[1][x] := string(tosysfilepath(sys_getuserhomedir + directoryseparator + 'Desktop'));
  47.     end;
  48. ....
  49.  
Title: Re: for achar := 'A' to 'Z' do
Post by: PascalDragon on October 25, 2022, 07:47:44 am
@Jorge3000 and @ASerge and @Bart: many thanks for that execellent options.

But I forgot to note that I prefer a cross-os code and not use window unit .
So I will stay with one of the options using a loop with if directoryexists((achar + ':\') in it.

Fre;D

Which in itself is not cross OS.

If you need to work with drive letters you already are not cross platform. And sometimes you need to provide a platform specific view (e.g. displaying the full root on *nix systems, but displaying the drive letters on Windows for the user to find themselves at home).
TinyPortal © 2005-2018