Posts by Andreas

    Hallo zusammen,


    in letzter Zeit habe ich einiges programmiert, bei dem die typischen Stapelverarbeitungen First in - First out und First in - Last out / Last in - First out zum Einsatz kamen.


    Das geht in Icon natürlich auch beliebig einfach:


    Hierfür gibt es 5 Funktionen:

    • put(L, x) fügt der Liste L ein weiteres Element x mit neuem höchsten Index zu. Alle in der Liste enthaltenen Elemente behalten Ihren Index.
    • push(L, x) fügt der Liste L ein weiteres Element mit dem neuen Index 1 zu. Alle vorher vorhandenen Elemente x erhalten einen um 1 höheren Index.
    • x := pull(L) entfernt das Element x mit dem höchsten Index.
    • x := get(L) bzw. x := pop(L) entfernen das Element x mit dem Index 1.


    Somit ermöglichen dann folgende Funktionspaare die entsprechenden Stapelverabeitungen:


    StapelverarbeitungHinzufügenHerausnehmen
    FIFOput()get(), pop()
    push()pull()
    LIFOput()pull()
    push()get(), pop()


    Beste Grüße


    Andreas

    Hallo zusammen,

    Icon bietet wohl auch eine Möglichkeit dynamisch eine C-Funktion aus einer Bibliothek zu laden, aber da müssen die C-Funktionen bestimmten Anforderungen genügen, so dass man nicht einfach irgendwelche C-Funktionen aufrufen kann. Da müsste man sich also eine kleine C-Bibliothek mit der Funktionalität schreiben, die man dann einbinden kann.


    Mit bash ist da leider Essig :no_sad: Aber Icon kann das wohl ...


    Ja, ist in Icon relativ einfach. In den Tutorial-Teilen 30 wird die Verwendung von in C geschriebenen Libraries vorgestellt. In Teil 31 analog um in C++ geschriebene Libraries. Und im Teil 32 geht es um die Kommunikation von Icon (& Unicon) mit Code, der in D, Lazarus/FreePascal, Cobol, Prolog und ARM-Assembler.


    Allen gemeinsam ist, dass eine "fremdsprachige" Funktion seitens Icon dynamisch oder statisch geladen wird, Argumente ganz normal in die "fremdsprachige" Funktion übertragen werden. Da Icon keine richtigen Datentypen hat, muss dann in der "fremdsprachigen" Funktion angegeben werden, welchem Datentyp das in der "Fremdsprache" entspricht. Ńach Ablauf erfolgt dann eine Rückwandlung des Ergebnisses nach Icon, um das Ergebnis in Icon nutzen zu können.

    Werden keine Argumente übergeben, dann kann man sich da entsprechend Code sparen. Das Gleiche gilt dann auch für die Rückgabe von Ergebnissen.


    Beste Grüße


    Andreas

    Hallo framp,


    es gibt in Icon eine Datei "regexp.icn" (in ipl/gprocs) zum Einbinden in eigene Projekte, die laut Beschreibung


    Quote

    Procedure for regular-expression pattern matching

    enthält.

    Mit 831 Zeilen scheint das Ding auch recht mächtig zu sein.

    Ein Demo-Code befindet sich in /ipl/progs/igrep.icn.


    Das, was ich vorhin in Beitrag #75 gebracht habe, hat mit Regex so gar nichts zu tun. Das ist das "normale" String-Scanning von Icon.



    Beste Grüße


    Andreas

    Hallo zusammen,


    viele meiner Funktionen haben folgenden generellen Aufbau:



    Bei der Benennung der Argumente orientiere ich mich an den üblichen Icon-Vorgaben des Datentyps bzw. der Bedeutung als Argument der entsprechenden Funktion.


    Die obige Struktur hat den Vorteil, dass man sich auf das Wesentliche - das Programmieren der eigentlichen Aktion konzentrieren kann. Der Rest macht man irgendwie wie im Tran.

    Der Nachteil ist, dass man sich einen Wolf sucht, wenn man mal vergessen hat, z.B. den Zeichensatz für einen Alarm oder eine Systemmeldung zurückzusetzen, und alle weiteren Ausgaben auf der GUI in einem unpassenden Stil erfolgen.


    Viel einfacher geht das bei Verwendung eines Stapelspeichers STACK, der mit STACK := [] oder STACK := list() angelegt wurde.


    Eine Funktion sieht dann z.B. so aus:



    Code-Deutung:


    Die Zeile put(STACK, Font(), Fg(), Bg()) speichert den vorher verwendeten Zeichensatz, Vordergrundfarbe, Hintergrundfarbe auf diesen Stapelspeicher STACK.

    STACK[1] enthält den Zeichensatz, STACK[2] die Vordergrundfarbe etc.



    Die Zeile every i := 1 to *STACK do i(Bg, Fg, Font)(pull(STACK)) macht das dann wieder rückgängig. Hier habe ich die Funktion pull() verwendet, die - beginnend mit dem zuletzt mit put()auf den Stapel gebrachten Eintrag - den Stapel abräumt. Prinzipiell wären auch die anderen beiden Funktionen get() und pop() möglich gewesen. Dann müsste aber entweder in put() oder in der unteren Funktion die Reihenfolge der Parameter geändert werden, um FIFO, FILO / LIFO abzubilden.


    Was hier mit i(...)(...) sehr strange aussieht, nennt sich in Icon "mutual evaluation". Damit ist eine extreme Einsparung an Code verbunden.

    Ganz allgemein besteht dies aus einem Ausdruck, der ein ganzzahliges Ergebnis liefert, einer in Klammern stehenden Auflistung an "Angeboten", was getan werden könnte (also weitere Ausdrücke, Funktionen oder Variablen) und - sollten leere Funktionsnamen aufgeführt sein - dann folgen deren Parameter in einem weiteren Klammerpaar.

    Bei dem i ist das leicht durchschaubar, da dies die Schleifenvariable ist, die von 1 bis 3 laufen soll.

    Dieses ganzzahlige Ergebnis bildet nicht den Funktionsnamen sondern den Index, unter dem aus der nachfolgenden Aufzählung etwas ausgewählt werden soll. Bei i = 1 wird also der erste Eintrag herangezogen, also Bg. Hier könnte ein weiterer auswertbarer Ausdruck stehen, eine Variable, eine Funktion oder was auch immer. Hier steht also Bg, was eigentlich die Funktion für das Setzen der Hintergrundfarbe für kommende Zeichenfunktionen darstellt. Wenn es sich um eine Funktion handeln sollte, müssen danach auch Parameter in Klammern () angeboten werden. OK - Klammern folgen da auch noch. Die Argumente werden vom zuvor beschriebenen Stack geholt. Es handelt sich also tatsächlich um die Abwicklung der Icon-Funktion Bg().


    Bei i = 2 wird Analoges für den zweiten Index, also Fg und bei i = 3 für den drittem Index Font() durchgeführt.


    Am Ende ist der Stapel leer, egal, ob man ausreichend Funktionen bereitgestellt hat oder nicht und die betrachteten Einstellungen sind wieder so wie vorher.


    Ich mag "mutual evaluation", weil hier in einer Zeile stehen kann, was sonst in einer Fallunterscheidung geklärt werden muss.



    Beste Grüße


    Andreas

    Hallo __blackjack__,


    Icon's String-Scanning wäre in der Tat der nächste Ansatz gewesen - man braucht aber gar nicht so tief einzusteigen, da ein simples


    Code
    s := piper("ip -4 a s wlan0 | grep inet")
    suchvon := "inet "
    suchbis := "/"
    ergebnis := s[find(suchvon, s)+*suchvon:find(suchbis, s)]

    die reine IP-Adresse liefert.


    Aber da Du Icon's String-Scanning angesprochen hast - damit geht es natürlich auch:


    Code
    s := piper("ip -4 a s wlan0 | grep inet")
    suchvon := "inet "
    suchbis := "/"
    ergebnis := (s ? { tab(find(suchvon) + *suchvon) & tab(find(suchbis))})


    Oder kürzer, hübscher und mehr Icon-Style:

    Code
    write(s ? {tab(many(&letters ++ ' ')) & tab(many(&digits ++ "."))})

    Code-Deutung:

    In der Variablen s befindet sich das Ergebnis der Pipe


    Code
    ip -4 a s wlan0 | grep inet

    Die Funktion piper() liefert entweder

    • das Ergebnis &fail (wenn die Pipe kein Ergebnis geliefert hat; nachfolgende Funktionen, die ein solches Ergebnis verwenden, werden ohne weitere Prüfung nicht aufgerufen)
    • eine Zeichenkette (wenn die Pipe nur eine einzige Zeil geliefert hat)
    • eine Liste (wenn die Pipe mehrere Zeilen geliefert hat)


    Also etwas wie "inet 192.168.2.119/24 brd 192.168.2.255 scope global wlan0".


    Mit dem (binären) Operator Scanning-Operator ? wird das String-Scanning losgetreten. Links davon befindet sich die Zeichenkette, die in das String-Scanning eingekippt wird. Rechts davon befindet sich die sog. Matching Function. Die ersten Zeichen der Zeichenkette, die aus Elementen der Menge der Buchstaben (Schlüsselwort &letters) bestehen, vereinigt (mittels Operator ++) mit der Menge der Zeichen "Leerzeichen", werden übersprungen (Funktion many()) und an diese Stelle gesprungen (Funktion tab()).

    Ab dort sollen so viele Zeichen wie möglich (ausgedrückt durch die Funktion many() genommen werden, solange diese in der Menge der Ziffern (Schlüsselwort &digits) vereinigt mit der Menge der Zeichen "Punkt" enthalten sind. Ab der Stelle (ausgedrückt durch die Funktion tab()), an der das erste Zeichen außerhalb dieser Vereinigungsmenge enthalten ist, wird der Rest der Zeichenkette verworfen.

    Übrig bleibt somit eine Zeichenkette übrig, die mit der ersten Ziffer (oder Punkt) beginnt, und mit der letzten Ziffer (oder Punkt) endet, ohne dass Zeichen enthalten sind, die weder Ziffern noch Punkte sind.


    Beste Grüße


    Andreas

    Hallo hyle,


    hostname knallt Dir nur eine Liste von IP-Adressen im IP4v und IP6v-Format vor den Latz. Es bleibt vollkommen offen, was jetzt WLAN oder LAN oder WWAN oder ... ist.


    Beste Grüße


    Andreas

    Hallo Lutz,


    was sagt ip -Vbzw. apt-cache policy iproute2


    dieses:

    Code
    $ip -V
    ip utility, iproute2-ss131122


    und dieses:

    Code
    $apt-cache policy iproute2
    iproute2:
      Installiert:           3.12.0-2ubuntu1.2
      Installationskandidat: 3.12.0-2ubuntu1.2
      Versionstabelle:
     *** 3.12.0-2ubuntu1.2 0
            500 http://de.archive.ubuntu.com/ubuntu/ trusty-updates/main amd64 Packages
            100 /var/lib/dpkg/status
         3.12.0-2 0
            500 http://de.archive.ubuntu.com/ubuntu/ trusty/main amd64 Packages



    Beste Grüße


    Andreas

    Hallo Ihr Unermüdlichen,


    bei mir kommt bei bei Verwendung von ip -br ...  eine Fehlermeldung...

    Code
    Option "-br" is unknown, try "ip -help".


    Mir gefällt die Regex-Sache(*) von framp irgendwie ganz gut... und habe mal versucht das moderne "ip" mit dem Regex-Ansatz zu kreuzen:


    Code
    ip -4 a s wlan0 | grep inet | grep -o -E "([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}" | head -n 1

    liefert exakt die gewünschte IP-Adresse.

    Das hier auch

    Code
    ip a s dev wlan0 | grep inet | grep -o -E "([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}" | head -n 1

    Beste Grüße


    Andreas



    P.S.: Sollte ich mich auf meine alten Tage wirklich noch damit auseinandersetzen? Mein letzter Versuch mit Regex stammt aus dem Jahr 2013. Ich brauchte schlappe 2 Wochen, um die Fehlermeldung einer Programmiersprache auszuwerten, um daraus die Zeilennummer und Spalte zu erhalten, damit der Editor auf diese Textposition seinen Cursor setzen kann. Und dies nur, weil der Editor extra für diesen Zweck Regex-kompatibel war und weiterhin ist.

    Hallo framp,

    Seufz ... die Ausgaben sehen leider immer etwas anders aus je nachdem auf welcher Distro man sich bewegt. Bei Dir fehlt das :.

    Code
    ifconfig wlan0 | grep -o -E ":?([[:space:]])*([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}" | head -n 1 | tr -d :

    sollte jetzt sowohl fuer Andreas als auch Dich funktionieren.

    jau... funzt.


    Das macht die Sache aber problematisch, wenn man auf einem Distro-OS entwickelt & testet und optimiert, für ein anderes vorhandenes Distro-OS noch testen & anpassen kann ... und alle anderen Distro-OSse nur Bahnhof verstehen.


    Beste Grüße


    Andreas

    Hallo framp,


    liefert das richtige Ergebnis - nur ist der Ausschnitt

    Code
    ":([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}"


    (mir) nicht richtig eingängig... :conf::conf::conf:. Aber es funktioniert... :auslachen::conf::conf::conf:.


    Sieht für mich wie RegExp aus - das, wo ich immer einen großen Bogen herum gemacht habe.


    Beste Grüße


    Andreas

    Hallo Tell,



    Das cut bringe ich auch noch weg (:


    Wie sieht die Ausgabe von ifconfig auf diesem System aus?

    Code
    ifconfig

    liefert

    (ETH0 ist nicht angeschlossen)


    Beste Grüße


    Andreas

    Warum so kompliziert?


    Bei mir reicht:


    Code
    ifconfig eth0 | awk '/inet / {print $2}'


    bei mir nicht, denn da kommt als Rückmeldung Adresse:192.168.2.119. Und dieser sprachenabhängige Teil müsste dann auch noch entfernt werden. ... Der vor dem Doppelpunkt ... Ähm ... :conf: ... krieg' ich hin ... irgendwie schon ... :denker: ... so:

    Code
    ifconfig wlan0 | awk '/inet / {print $2}' | cut -d':' -f2

    liefert dann die pure IP-Adresse.


    :danke_ATDE:, Tell !



    Beste Grüße


    Andreas

    Hallo zusammen,


    für ein aktuelles Projekt brauche ich die IP-Adresse des ETH-Interfaces.


    Frickler-Pipe:

    Code
    ifconfig eth0 | grep inet | awk '{print $2}' | cut -d':' -f2 | head -n 1


    Und in Icon sieht das dann so aus:

    Code
    ip := piper("ifconfig eth0 | grep inet | awk '{print $2}' | cut -d':' -f2 | head -n 1")

    Gibt es eine IP-Adresse zum ETH0-Interface, dann steht das Ergebnis in der Variablen ip.

    Gibt es diese Schnittstelle nicht, oder ging sie verloren, dann wird ip der Nullwert &null zugewiesen.


    Die Funktion piper() kann über

    Code
    link icontoolbox

    eingebunden werden.



    Beste Grüße


    Andreas

    Hallo zusammen,


    für ein aktuelles Projekt brauche ich die IP-Adresse des WLAN-Interfaces.


    Frickler-Pipe:

    Code
    ifconfig wlan0 | grep inet | awk '{print $2}' | cut -d':' -f2 | head -n 1


    Und in Icon sieht das dann so aus:

    Code
    ip := piper("ifconfig wlan0 | grep inet | awk '{print $2}' | cut -d':' -f2 | head -n 1")

    Gibt es eine IP-Adresse zum WLAN-Interface, dann steht das Ergebnis in der Variablen ip.

    Gibt es diese Schnittstelle nicht, oder ging sie verloren, dann wird ip der Nullwert &null zugewiesen.


    Die Funktion piper() kann über

    Code
    link icontoolbox

    eingebunden werden.



    Beste Grüße


    Andreas

    Hallo zusammen,


    das passt am Besten zu diesem Teil des Icon-Tutorials.


    Wie toggelt (Umschalten zwischen zwei Zuständen) man am besten, wenn der Wert &null beteiligt ist?


    Wir erinnern uns:

    Beim Umschalten zwischen 0 und 1 nimmt man am Besten die Exklusiv-Oder-Verknüpfung:

    Code
    status := ixor(status, 1)

    schaltet von 0 auf 1, von 1 auf 0, immer wieder.



    Aber wie macht man das z.B. beim Umschalten des Status eines Bedienelementes, da ja in Icon nur 1 oder &null ist.


    Ein erster Ansatz ist z.B.:

    Code
    if status = 0 then status = &null else status := 1

    Abgesehen von Fehlermeldungen, wenn status den Wert Nullwert &null annimmt, geht das so nicht.


    Besser, weil funktional, ist:

    Code
    if /status then status := 1 else status := &null


    oder

    Code
    if \status then status := &null else status := 1


    Aber so richtig knackig ist das hier (mehr Icon-Style):

    Code
    (/status := 1) | (\status := &null)

    Hier braucht's kein if, then und else... Aber was passiert hier eigentlich?


    Ich hatte ja schon mal an anderer Stelle geschrieben, dass die beiden Operatoren / und \ sowas wie Icon's Exception-Handling darstellen und so manche Fallunterscheidung ersparen.


    Der Operator / prüft auf den Nullwert &null.

    Der Operator \ prüft auf den Wert ALLES ANDERE ALS &null.

    Der Operator | ist der Alternierungsoperator. Icon ist ja eine Programmiersprache, in der jeder Ausdruck und Code-Zeile möglichst erfolgreich (goal-directed) beendet werden soll. Das heißt, wenn ein Ausdruck erfolglos enden könnte, macht es Sinn, hinter dem Alternierungsoperator | noch einen Ausdruck anzubieten ... und ggf. noch einen ... und noch einen... .


    Von diesem Alternierungsoperator | mache ich oben Gebrauch.


    Links davon steht ein Ausdruck - rechts davon steht ein Ausdruck.


    Der linke Ausdruck prüft auf Übereinstimmung mit dem Nullwert &null. Wenn es übereinstimmt, wird der Variablen status der Wert 1 zugewiesen. Das Angebot mit / hinter dem Alternierungsoperator wird ignoriert.


    Wenn es nicht so war, wird der Ausdruck hinter dem Alternierungsoperator ausgewertet. Da wird auf Übereinstimmung mit allem anderen als dem Nullwert &null geprüft. Wenn es übereinstimmt (und es sollte, weil der Nullwert bereits im linken Ausdruck dabei war), dann wird der Variablen der Nullwert &null zugewiesen.


    Einer der beiden Ausdrücke wird also zutreffend sein und bewirkt ein Umschalten zwischen &null und 1.



    Beste Grüße


    Andreas

    Hallo zusammen,


    kann man eigentlich auch Graphiken auf den Bildschirm bringen und diese anklicken, um damit Ereignisse auszulösen, die von der Hauptereignisbehandlungsroutine (EventHandler) erkannt werden?


    Klar, das geht, wenn man sich an folgender Vorgehensweise orientiert.


    1. Mit VIB die Schaltfläche in das Bearbeitungsfenster der zu erstellenden GUI ziehen und durch Ziehen der 4 Ecken ungefähr auf die gewünschte Größe bringen.
    2. Feineinstellungen können vorgenommen werden, indem man die Region mit der rechten Maustaste anklickt und in dem sich öffnenden Dialogfenster die passenden Werte für x und y (als linke obere Ecke der Region) und Breite und Höhe pixelgenau festlegt. Als ID legt man den Namen fest, unter dem das Vidget innerhalb der Vidget-Liste (voreingestellt als local vidgets ==> besser also global VIDGETS umdefinieren!) angesprochen werden soll (in meinem Beispiel will ich ein Mikrophon-Piktogramm darstellen, also ist etwas wie r_micro naheliegend). Im Texteingabefeld callback wird der Name der Callback-Funktion festgelegt - also die Funktion, in der man definiert, was nach dem Anklicken eines Bedienelemeentes passieren soll. In meinem Fall (und faul wie ich bin, habe ich mir zur Gewohnheit gemacht, für ID und callback die Eingabe zu wiederholen) also auch r_micro.
    3. Tipp am Rande: Es hat sich als vorteilhaft erwiesen, Breite und Höhe um jeweils 4 größer zu wählen als die später aufzunehmende Graphikschaltfläche.
    4. Dann bearbeitet man mit z.B. ImageMagick eine Graphik durch Zurechtschneiden, Verkleinern etc. und speichert diese letztlich im Format "GIF".
    5. Diese Graphik kann mit dem Icon-Befehl ReadImage(s, x, y) in die Anwendung gebracht werden. ReadImage("/Pfad/zum/Bild.gif", x, u) mit Angabe des Pfades zum Bild sowie der linken oberen Ecke der Graphik.
    6. Wenn man die Graphik in die Region einpassen will, nutzt man die Angaben der Vidget-Struktur, z.B. ReadImage("/home/andreas/Bilder/Mikrophon32.gif", vidgets["r_micro.ux"].ux, vidgets["r_micro"].uy) oder innerhalb eines Callbacks als ReadImage("/home/andreas/Bilder/Mikrophon32.gif", vidget.ux, vidget.uy)
    7. Noch ein Tip: Der Unterschied der ebenfalls möglichen Vidget-Felder .ax und .ay besteht darin, dass die Paarung .ax und .ay sich auf die linke obere Ecke der Region bezieht und die Paarung .ux und .uy die tatsächlich nutzbare Zeichenfläche beschreiben. Deswegen auch der Tipp unter 3.
    8. Das Ergebnis sieht dann z.B. so aus:
    9. Der von VIB automatisch erzeugte Eintrag im UserInterface ist dann z.B. ["r_micro:Rect:raised::12,274,36,36:",r_micro],
    10. Als Callback kann man dann z.B. folgendes programmieren:

    Code
    procedure r_micro(vidget, e, x, y)
        if Event() === &lrelease then
        {
            Status_Micro := ixor(Status_Micro, 1)
            ReadImage("/home/andreas/Bilder/Mikrophon32.gif", vidget.ux, vidget.uy)
            if Status_Micro = 0 then cross(vidget)
        }
    end

    Code-Deutung:

    Nach Anklicken des Piktogramms Mikrophon soll beim Ereignis Linke Maustaste losgelassen etwas passieren, nämlich Toggeln des Status (Exklusiv-ODER-Verknüpfung von Status_Micro mit 1). Die GIF-Datei wird auf Position gebracht. Sollte der Status 0 sein, wird eine Funktion cross() mit dem Parameter dieses Vidgets aufgerufen. In der Funktion cross() wird ein rotes Kreuz über das Piktogramm gezeichnet.


    Beste Grüße


    Andreas




    Images

    • pasted-from-clipboard.png
    • pasted-from-clipboard.png

    Hallo commissario,



    Aufgrund meines Alters bin ich quasi Computeranwender der ersten Stunden und habe fast alle Computertypen durch, die es im Laufe der Jahre so gab. Beginnend mit programmierbaren Taschenrechnern (TI-55) und PC mit 1 Mhz (!) 6502 Prozessor.

    Da fällt mir VC-20 mit 3583 Bytes RAM und so ein... Ja ist lange her.


    Guten Einstieg!


    Beste Grüße


    Andreas