Vorbereitete Datenverzeichnise

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
diogenes
Beiträge: 200
Registriert: So 11. Jul 2010, 18:39
OS, Lazarus, FPC: Linux
CPU-Target: 64 Bit
Wohnort: Wien
Kontaktdaten:

Vorbereitete Datenverzeichnise

Beitrag von diogenes »

Es ist ja bei Betriebssystemen bzw. Oberflächen schon lange üblich, vorbereitete Verzeichnisse für gewisse Großgruppen von Daten einzurichten, wie z.B. Dokumente, Bilder und Videos. Hat Lazarus bzw. FPC Funktionen, die diese Verzeichnisse abfragen? Ich meine damit, dass, wenn ein Windoof-Kompilat diese Funktion benutzt, wird auf das passende Verzeichnis für Windoof verwiesen; das gleiche bei Mac, KDE, Gnome usw. usf.
Also so ähnich wie GetUserDir, nur halt etwas spezialiserter für diese Großǵruppen.

Gibt's sowas?
Ceterum censeo computatores per Pascal docendos esse.

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Vorbereitete Datenverzeichnise

Beitrag von Warf »

Unter windows kannst du Umgebungsvariablen lesen. Z.B. um an den AppData ordner zu kommen:

Code: Alles auswählen

GetEnvironmentVariable('APPDATA')

Unter Unix ist es ganz einfach, ~ ist der homeordner. Also ~/Documents entspricht /home/username/documents, bzw. wo auch immer das userverzeichnis liegt (das kann man ja beliebig wählen)

Eine Plattformübergreifende Funktion gibt es soweit ich weiß nicht. Vor allem aber weil bei Linux die Ordnervergebung von der Distribution abbhängt und es kein "allgemeingültes" standardschema gibt (ganz dumm, ein OpenSuse ohne grafisches UI hat weder Documents noch Downloads oder sonst irgendein standard user directory)

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Vorbereitete Datenverzeichnise

Beitrag von theo »

Ist mir nicht bekannt, dass es so etwas fixfertig gibt.
Vllt. hilft das:
http://wiki.lazarus.freepascal.org/Wind ... .2C_etc.29
https://www.freedesktop.org/wiki/Softwa ... user-dirs/

Bei mir auf OpenSUSE sieht /home/theo/.config/user-dirs.dirs z.B. so aus

Code: Alles auswählen

# This file is written by xdg-user-dirs-update
# If you want to change or add directories, just edit the line you're
# interested in. All local changes will be retained on the next run
# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an
# absolute path. No other format is supported.
#
XDG_DESKTOP_DIR="$HOME/Schreibtisch"
XDG_DOWNLOAD_DIR="$HOME/Downloads"
XDG_TEMPLATES_DIR="$HOME/Vorlagen"
XDG_PUBLICSHARE_DIR="$HOME/Öffentlich"
XDG_DOCUMENTS_DIR="$HOME/Dokumente"
XDG_MUSIC_DIR="$HOME/Musik"
XDG_PICTURES_DIR="$HOME/Bilder"
XDG_VIDEOS_DIR="$HOME/Videos"

diogenes
Beiträge: 200
Registriert: So 11. Jul 2010, 18:39
OS, Lazarus, FPC: Linux
CPU-Target: 64 Bit
Wohnort: Wien
Kontaktdaten:

Re: Vorbereitete Datenverzeichnise

Beitrag von diogenes »

Tja. Schade. Danke für die Auskunft in jedem Fall. Ununteressant ist das ja nicht. Man müsste es also selbst machen, mit einer Ḱaskade von Compilerschlatern, könnte man es hinkriegen. Und der Default ist halt das Userverzeichnis. Was solls. Danke nochmal.
Ceterum censeo computatores per Pascal docendos esse.

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Vorbereitete Datenverzeichnise

Beitrag von Warf »

diogenes hat geschrieben:Tja. Schade. Danke für die Auskunft in jedem Fall. Ununteressant ist das ja nicht. Man müsste es also selbst machen, mit einer Ḱaskade von Compilerschlatern, könnte man es hinkriegen. Und der Default ist halt das Userverzeichnis. Was solls. Danke nochmal.


Es geht eigentlich, du brauchst eigentlich nur einmal Compilerswitches:

Code: Alles auswählen

type
  TUserDirectories = record
    Home,
    Documents,
    ... : String;
  end;
 
var UserDirectories: TUserDirectories ;
...
 
{$IF Defined(Windows)}
function DefaultDirectories: TUserDirectories;
begin
  Result.Home = ... // keine ahnung auswendig
end;
{$ELSEIF Defined(Linux)}
function DefaultDirectories: TUserDirectories;
begin
  Result.Home = '~';
  // Lese xdg file
end;
{$ELSEIF Defined(Darwin)}
function DefaultDirectories: TUserDirectories;
begin
  Result.Home = '~';
  // Rest hardcoden
end;
{$ENDIF}
 
initialization
    UserDirectories := DefaultDirectories;
end;


Musst dann halt sicher gehen unter Linux das xdg installiert ist, das kannst du ja aber einfach als abbhängigkeit vorraussetzen.
Du kannst den Windows Linux und Mac Part auch in separate .inc files schreiben und die dann über {$I} (glaube ich) includen. Dann ist alles schön getrennt was das editieren einfacher macht, und in deiner Hauptdatei ist nur Betriebsystemabhängiger Code

diogenes
Beiträge: 200
Registriert: So 11. Jul 2010, 18:39
OS, Lazarus, FPC: Linux
CPU-Target: 64 Bit
Wohnort: Wien
Kontaktdaten:

Re: Vorbereitete Datenverzeichnise

Beitrag von diogenes »

Ja, so ähnlich hab ich mir das vorgestellt. Die Idee mit dem Record ist gut, ich hätte nicht daran gedacht :idea:
Ceterum censeo computatores per Pascal docendos esse.

diogenes
Beiträge: 200
Registriert: So 11. Jul 2010, 18:39
OS, Lazarus, FPC: Linux
CPU-Target: 64 Bit
Wohnort: Wien
Kontaktdaten:

Re: Vorbereitete Datenverzeichnise

Beitrag von diogenes »

Noch eine Frage zu den xdg-Dateien: wie liest man die? muss man die selbst parsen?

Ich hätte die Idee, die Datei in eine Stringliste zu lesen, dann alle Zeilen, die mit '#" oder leer sind, beginnen, zu entfernen, und dann mit '=' als Separator zwweischen Key und Value auszulesen. Geht das einfacher?
Ceterum censeo computatores per Pascal docendos esse.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Vorbereitete Datenverzeichnise

Beitrag von Socke »

diogenes hat geschrieben:Ich hätte die Idee, die Datei in eine Stringliste zu lesen, dann alle Zeilen, die mit '#" oder leer sind, beginnen, zu entfernen, und dann mit '=' als Separator zwweischen Key und Value auszulesen. Geht das einfacher?

Nein; du musst zusätzlich alle Umgebungsvariablen (z.B. $HOME) ersetzen.

Alternativ rufst du das Programm xdg-user-dirs auf:

Code: Alles auswählen

simon@debian:~/.config$ xdg-user-dir DESKTOP
/home/simon/Schreibtisch 

In Free Pascal:

Code: Alles auswählen

uses Process;
var
  DirectoryName: String;
begin
  RunCommand('xdg-user-dir', ['DESKTOP'], DirectoryName);
  WriteLn(DirecotryName);
end;

Folgende Parameter sind auf meinem System laut manpage möglich:

Code: Alles auswählen

DESKTOP
DOWNLOAD
TEMPLATES
PUBLICSHARE
DOCUMENTS
MUSIC
PICTURES
VIDEOS


Edit: uses Process hinzugefügt
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

diogenes
Beiträge: 200
Registriert: So 11. Jul 2010, 18:39
OS, Lazarus, FPC: Linux
CPU-Target: 64 Bit
Wohnort: Wien
Kontaktdaten:

Re: Vorbereitete Datenverzeichnise

Beitrag von diogenes »

Aha. Kann ich annehmen, dass das programm zur Verfügung ist, wenn die Datei exisitert?
Ceterum censeo computatores per Pascal docendos esse.

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Vorbereitete Datenverzeichnise

Beitrag von Warf »

diogenes hat geschrieben:Aha. Kann ich annehmen, dass das programm zur Verfügung ist, wenn die Datei exisitert?


Ja, die datei ist ja von xdg erzeugt daher wäre es recht unwahrscheinlich das die datei ohne XDG exsistert. Bzw. wenn die datei ohne XDG existieren würde kannst du auch nicht sicher sein ob sie korrekt ist.

diogenes
Beiträge: 200
Registriert: So 11. Jul 2010, 18:39
OS, Lazarus, FPC: Linux
CPU-Target: 64 Bit
Wohnort: Wien
Kontaktdaten:

Re: Vorbereitete Datenverzeichnise

Beitrag von diogenes »

Danke. Ich werde mien vorläufige Ergebnis hier posten :)
Ceterum censeo computatores per Pascal docendos esse.

diogenes
Beiträge: 200
Registriert: So 11. Jul 2010, 18:39
OS, Lazarus, FPC: Linux
CPU-Target: 64 Bit
Wohnort: Wien
Kontaktdaten:

Re: Vorbereitete Datenverzeichnise

Beitrag von diogenes »

Soweit mein bisheriges Ergebnis. ich hab' das absichtich auf Erweiterbarkeit gebaut :)

Code: Alles auswählen

 
unit Zystem;
{************************************
 * extension of System and SysUtils *
 ************************************
 
 Copyright (C) 2018  By Robert H. Mangl
 
 This program is free software: you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License along with
 this program.  If not, see <http://www.gnu.org/licenses/>.}
 
 {$mode objfpc}{$H+}
 
 interface
 
   uses SysUtils;
 
  {**********************
   * exception handling *
   **********************}
   type
    EZett = class( Exception);
    EZettClass = class of EZett;
  {******************************
   * preperaed user directories *
   ******************************}
   type
    TDefaultDires = record
      Home: string;
      Desktop: string;
      Download: string;
      Templates: string;
      PublicShare: string;
      Documents: string;
      Pictures: string;
      Music: string;
      Videos: string;
     end;
    var
     DefaultDires: TDefaultDires;
  {*****************
   * miscellaneous *
   *****************}
   function Voided( Ptr: Pointer): Boolean; inline;
                  {returns True if the Ptr points to NIL -- it's ust a "not
                   Assigned( Ptr)"}
   procedure NoOperation; inline;
                        {does nothiong.  can clarify if-then-else structures
                         greatly}
   function AssertDire( const Dire: string; DoForce: Boolean= True): string;
                      {assuming the passed Path is a directory path, this
                       function corrects separators and adds one if it is
                       missing at the end. this makes sure that you simply can
                       add a file name to create a complete locator. by default,
                       it will also force the directory's existence. you can
                       switch off this}
 
implementation
 
  uses Classes, Process, StrUtils;
 
  procedure SetupDefaultDires( var Dires: TDefaultDires); forward;
                          {set up Dires sith the GUI's default directories.
                           tries to be platform independent.  where the
                           platform-specific directories cannot retrieved, the
                           usr's home direcotry is returned}
  function GetHomeDefault: TDefaultDires; forward;
                         {return a user directories record that has the user's
                          home directoy in every field}
 
  function AssertDire( const Dire: string; DoForce: Boolean): string;
   begin
     Result := Dire;
     DoDirSeparators( Result);
     if not AnsiEndsStr( DirectorySeparator, Result)
      then Result := Result + DirectorySeparator;
     while Result[ Length( Result) - 1] = DirectorySeparator do
      Delete( Result, Length( Result) - 1, 1);
     if DoForce
      then ForceDirectories( Result)
    end;
 
   function GetHomeDefault: TDefaultDires;
    begin
      with Result do begin
        Home := AssertDire( GetUserDir, False);
        Desktop := Home;
        Download := Home;
        Templates := Home;
        PublicShare := Home;
        Documents := Home;
        Pictures := Home;
        Music := Home;
        Videos := Home;
       end
     end;
 
   {$IF DEFINED(LINUX)}
      procedure SetupDefaultDires( var Dires: TDefaultDires);
       var
        HomeDire: string;
       procedure ReadFromUserDirsDirs;
        function ValueOf( Key: string): string;
         begin
           RunCommand( 'xdg-user-dir', [Key], Result);
           if Result = ''
            then Result := HomeDire
            else if AnsiEndsStr( LineEnding, Result)
                  then Result := LeftStr( Result,
                                          Length( Result) - Length( LineEnding))
          end;
        begin
          with Dires do begin
            Home := HomeDire;
            Desktop := ValueOf( 'DESKTOP');
            Download := ValueOf( 'DOWNLOAD');
            Templates := ValueOf( 'TEMPLATES');
            PublicShare := ValueOf( 'PUBLICSHARE');
            Documents := ValueOf( 'DOCUMENTS');
            Pictures := ValueOf( 'PICTURES');
            Music := ValueOf( 'MUSIC');
            Videos := ValueOf( 'VIDEOS')
           end
         end;
       begin
         HomeDire := AssertDire( GetUserDir, False);
         if FileExists( HomeDire + '.config/user-dirs.dirs')
          then ReadFromUserDirsDirs
        end;
     {$ELSEIF DEFINED(WINDOWS)}
      procedure SetupDefaultDires( var Dires: TDefaultDires);
       begin
        end;
     {$ELSE}
      procedure SetupDefaultDires( var Dires: TDefaultDires);
       begin
        end;
    {$ENDIF}
 
  procedure NoOperation; begin end;
 
   function Voided(Ptr: Pointer): Boolean;
    begin
      Result := not Assigned( Ptr)
     end;
 
  initialization
    SetupDefaultDires( DefaultDires)
   end.
 
Ceterum censeo computatores per Pascal docendos esse.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Vorbereitete Datenverzeichnise

Beitrag von Socke »

Hallo diogenes,

vielen Dank, dass du deine Unit hier veröffentlichst. Würde es dir etwas ausmachen, diese Unit unter der LGPL mit Linking Exception wie die LCL zu veröffentlichen? Dann könnte man das umbauen und in Free Pascal oder Lazarus ausliefern. Andernfalls wird jede Software, die deine Unit verwendet automatisch zu GPL-Software. Falls du das so bedacht und gewollt hast, ist das natürlich auch in Ordnung.

Zur Vollständigkeit: Für MS Office kann man die Vorlagenverzeichnisse (User und Public) aus der Registry auslesen: Verwalten von Vorlagen in Office 2007-Programmen Man müsste es wohl aber für alle Versionen abfragen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Vorbereitete Datenverzeichnise

Beitrag von wp_xyz »

Hmmm... Also wenn ich zu entscheiden hätte, die Unit in Lazarus oder FPC aufzunehmen, würde ich sie ablehen. Ich will nicht sagen, dass sie schlecht ist, aber ich fände für diese konkrete Implementierung keine Anwendung. Der Hauptkritikpunkt ist: Warum packst du die einzelnen Verzeichnisse in einen Record? Denn das bedeutet, dass ich, wenn ich z.B. nur das Documents-Directory brauche, auch das Music-, Pictures-, Videos- etc. Directory in meinem Programm mitschleppen muss.

Ich hätte eine Aufzählung TSpecialDirectory = (sdHome, sdDocuments, sdMusic, ... usw) deklariert und dann eine Funktion "GetSpecialDirectory" geschrieben, die den Aufzählungswert für das gewünschte Verzeichnis als Parameter erhält, also "GetSpecialDirectory(sdMusic)" --> ValueOf('MUSIC") usw.

Für Windows gibt es eine Unit WinDirs (in fpc/source/rtl/win) mit Konstanten CSIDL_PROGRAMS, CSIDL_PERSONAL usw, und den Funktionen GetWindowsSpecialDir(),GetWindowsSpecialDirUnicode(), die damit aufgerufen werden können und das entsprechende Spezial-Verzeichnis zurückgeben.

Was kann Voided() mehr als das standardmäßig vorhandene Assigned()?

Bei den Bezeichnern würde ich mich fragen: was meint er damit? "dire" lt. https://de.langenscheidt.com/englisch-deutsch/dire: "gräßlich", "entsetzlich", Warum nicht einfach "Dir", so wie es jeder in "mkdir" oder "rmdir" kennt? Und bei den Typen "EZett" und "EZettClass", sowie bei dem Unitnamen "Zystem" frage ich ich: Welche Gags habe ich nun wieder nicht verstanden?

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Vorbereitete Datenverzeichnise

Beitrag von Warf »

wp_xyz hat geschrieben:Hmmm... Also wenn ich zu entscheiden hätte, die Unit in Lazarus oder FPC aufzunehmen, würde ich sie ablehen. Ich will nicht sagen, dass sie schlecht ist, aber ich fände für diese konkrete Implementierung keine Anwendung. Der Hauptkritikpunkt ist: Warum packst du die einzelnen Verzeichnisse in einen Record? Denn das bedeutet, dass ich, wenn ich z.B. nur das Documents-Directory brauche, auch das Music-, Pictures-, Videos- etc. Directory in meinem Programm mitschleppen muss.

Ich hätte eine Aufzählung TSpecialDirectory = (sdHome, sdDocuments, sdMusic, ... usw) deklariert und dann eine Funktion "GetSpecialDirectory" geschrieben, die den Aufzählungswert für das gewünschte Verzeichnis als Parameter erhält, also "GetSpecialDirectory(sdMusic)" --> ValueOf('MUSIC") usw.

Für Windows gibt es eine Unit WinDirs (in fpc/source/rtl/win) mit Konstanten CSIDL_PROGRAMS, CSIDL_PERSONAL usw, und den Funktionen GetWindowsSpecialDir(),GetWindowsSpecialDirUnicode(), die damit aufgerufen werden können und das entsprechende Spezial-Verzeichnis zurückgeben.

Was kann Voided() mehr als das standardmäßig vorhandene Assigned()?

Bei den Bezeichnern würde ich mich fragen: was meint er damit? "dire" lt. https://de.langenscheidt.com/englisch-deutsch/dire: "gräßlich", "entsetzlich", Warum nicht einfach "Dir", so wie es jeder in "mkdir" oder "rmdir" kennt? Und bei den Typen "EZett" und "EZettClass", sowie bei dem Unitnamen "Zystem" frage ich ich: Welche Gags habe ich nun wieder nicht verstanden?


Die Verzeichnisse machen nicht mal 1KB aus, weniger als 1/20tel der minimalen größe unter OSX, mit LCL sind die Dateien im MB Bereich. Man muss schon auf sehr eingeschränkten Systemen arbeiten damit 1KB wichtig ist, und auf denen kann man die unit auch einfach nicht verwenden.
Vor allem wird damit die ganze Ladephase an den Programmstart versetzt und jeder sukzessive zugriff ist (zumindest für linux) kostenlos, denn Runcommand dauert viel länger als der zugriff auf einen record (ich würde so einen Faktor 100 oder so schätzen).

Mit der Namensgebung geb ich dir recht, irgendwie ergeben die für mich nicht so sinn

Antworten