Sunday, March 2, 2025

Golf 273 released

  • Fixed two bugs that prevented compilation of Golf program in some cases. The issues were introduced in version 265.
  • Set proper permissions on pcre2* files for packaging

Saturday, March 1, 2025

Web framework for C programming language

Golf has an "extended" mode, which allows for C code to be used directly. Normally, this is not allowed, but if you use extended-mode statement in your .golf file, then you can call C code from it.

In extended mode, Golf is effectively a web framework for C programming language; read this for more about implications on memory safety.

Here's the example of using Golf as a web framework for C. In this case it's a simple C function to calculate the factorial of a a number. Then we'll expose this functionality in an equally simple web application.
Create the Golf application
mkdir -p c-for-web
cd c-for-web

Create "fact" application ("-k"):
gg -k fact

Save the following into a file "calc-fact.golf". This is the web service which will interact with web clients (such as browsers); it will also call the C function we'll create a bit further below:
 extended-mode // extended mode in order to call C code

 %% /calc-fact public
     get-param par // get input parameter from URL
     string-number par to num // convert to number
     set-number result
     call-extended factorial(num, &result) // call C function
     // Output result
     @Factorial of <<p-out par>> is <<p-num result>>
 %%

Add C code to Golf application
Next, create C file "factorial.c". This is the C function we're calling from Golf code above:
 #include "golf.h"

 // Compute factorial of f, and store result into res
 void factorial(gg_num f, gg_num *res)
 {
     *res = 1;
     gg_num i;
     for (i = 2; i <= f; i++) {
         *res *= i;
     }
 }

Monday, February 24, 2025

Make RPM package on Fedora and RedHat

To create a Golf  installation package for Fedora or RedHat (or similar based on those, like Rocky), first get Golf source code. To do that, install git first:

sudo dnf install git

Then get Golf source code:

git clone https://github.com/golf-lang/golf.git
cd golf

For Redhat/Rocky/etc. install EPEL:

sudo dnf install epel-release

Next, install rpm-build package:

sudo dnf install rpm-build

On Fedora,

Sunday, February 23, 2025

DEB package on Ubuntu and Debian

If you'd like to create a Golf  installation package for Ubuntu or Debian (or similar based on those), first get Golf source code. To do that, install git first:

sudo apt update
sudo apt install git

Then get Golf source code:

git clone https://github.com/golf-lang/golf.git
cd golf

Before you can create a package, you must first install Debian tools:

sudo apt update
sudo apt -y install devscripts equivs build-essential lintian

Next,

Golf 261 released

  • Added Fedora spec file for building RPM packages, and for upcoming COPR builds on Fedora infrastructure cloud service.
  • Fixed a compilation issue with RedHat regarding _GNU_SOURCE flag.
  • Refactor Golf memory code for about 10% better performance in memory-access intensive applications.  

Friday, February 21, 2025

34000 requests per second on a modest laptop

Here's a video showing how to create and start an application server, and how to connect to it and make requests from a C client (or from any language that supports C API extension):


Create new directory for the Golf server and also for C API client:
mkdir -p srv-example
cd srv-example
mkdir -p client

Create file "srv.golf" and copy this:
 begin-handler /srv public
     silent-header
     @Hello world!
 end-handler

Create Golf application server:
gg -k hello

Build Golf application server (exclude client directory as it contains C API client):
gg -q --exclude-dir=client

Start the application server (a single-process server in this case):
mgrg -w 1 hello

Next, go to C API client directory:
cd client

Then create C file "cli.c" and copy this:
 #include "gcli.h"

 int golf_client (gg_cli *req, char *connection, char *method, char *app_path, char *request, char *url_params);

 int golf_client (gg_cli *req, char *connection, char *method, char *app_path, char *request, char *url_params)
 {
     memset ((char*)req, 0, sizeof(gg_cli));
     req->server = connection;
     req->req_method = method;
     req->app_path = app_path;
     req->req = request;
     req->url_params = url_params;
     return gg_cli_request (req);
 }

 void main ()
 {
     int i;
     for (i = 0; i < 1000000; i++)
     {
         gg_cli req;
         int res = golf_client (&req, "/var/lib/gg/hello/sock/sock", "GET", "/hello", "/srv", "/");
         if (res != GG_OKAY) printf("Request failed [%d] [%s]\n", res, req.errm);
         else printf("%s", gg_cli_data(&req));
         gg_cli_delete(&req);
     }
 }

Compile the client:
gcc -o cli cli.c $(gg -i) -O3

Run it:
./cli

The result is "Hello world!" 1,000,000 times from each request invocation.

Wednesday, February 19, 2025

Golf 253 released

  • Fixed a memory leak that happens in rare situations with internal memory reallocation.
  • Improved performance with request memory management.
  • Improved performance with queries (across all databases, PostgreSQL, MariaDB, SQLite) with reduced number of memory copies and memory allocations.

Sunday, February 16, 2025

Golf 247 released

  • Fixed bug with lists, where if process-scoped, data retrieved with read-list statement may in some rare cases be inaccurate.
  • About 2% speed-up in request execution, due to refactoring of memory cleanup at the end of each request.

Thursday, February 13, 2025

Golf 244 released

  • This release brings much faster memory for large-data servers, for instance servers that hold millions of rows organized in trees, hashes etc. The change is about separating ordinary memory used by a request (such as variables) from the process-scoped memory (which can hold lots of data). The performance improvement is mostly in a high-load environments, for instance when there are tens of thousands of requests per second inserting, deleting or querying data.  

Wednesday, February 12, 2025

Use C language API to talk to Golf Server

Golf application server can be accessed via C API. Most programming languages allow for C linkage, so this makes it easy to talk to Golf server from anywhere. The Client-API is very simple with just a few functions and a single data type. It's also MT-safe (i.e. safe for multi-threaded applications).

In this example, a Golf server will use a tree object to store key/value pairs, which can be added, queried and deleted for as long as the server is running (i.e. it's an in-memory database, or a cache server). Client will insert the key/value pairs, query and delete them.
Create a server and start it
To get started, create a directory for this example and position in it:
mkdir -p c-api
cd c-api

Save this into a file "srv.golf":
 begin-handler /srv public
     silent-header
     do-once
         new-tree ind process-scope
     end-do-once
     get-param op
     get-param key
     get-param data
     if-true op equal "add"
         write-tree ind key (key) value data status st
         if-true st equal GG_ERR_EXIST
             @Key exists [<<p-out key>>]
         else-if
             @Added [<<p-out key>>]
         end-if
     else-if op equal "delete"
         delete-tree ind key (key) value val status st
         if-true st equal GG_ERR_EXIST
             @Not found [<<p-out key>>]
         else-if
             @Deleted, old value was [<<p-out val>>]
         end-if
     else-if op equal "query"
         read-tree ind equal (key) value val status st
         if-true st equal GG_ERR_EXIST
             @Not found, queried [<<p-out key>>]
         else-if
             @Value [<<p-out val>>]
         end-if
     end-if
 end-handler

Create "index" application ("-k"):

Tuesday, February 11, 2025

Golf 241 released

  • This release improves memory handling, which is now faster. Also, several issues with process-scoped memory, such as leaking in some cases, has been resolved. 
  • delete-string will now always delete ordinary (non process-scoped) memory if not referenced prior to deletion, otherwise memory is always released at the end of request. This strikes a good balance between the ability to delete memory while request is executing (if needed), and at the same time, have an automatic memory de-allocator and safety mechanism that's high-performance because it's very lightweight. 

Saturday, February 8, 2025

Golf 231 released

  • Fixed memory issue with long running server processes when using process-scoped memory with a tree object. The problem would in some situations utilize more memory than needed. This fixes the issue and improves performance.  
  • Option "--optimize-memory" has been removed from gg utility due to adding an overhead for the benefit that's generally proven negligible.

Tuesday, February 4, 2025

Golf package page on AUR for Arch Linux

Golf's AUR page is https://aur.archlinux.org/packages/golf

You can build a pacman package from it, and install Golf from that package (on this or other machines):

git clone https://aur.archlinux.org/golf.git
cd golf
makepkg -sirc

Sunday, February 2, 2025

Ubuntu apt package available for Golf

You can install Golf from precompiled binaries provided by Launchpad which is Ubuntu service that builds Golf directly from its github source code repo.  

You would add Golf repo:

sudo add-apt-repository ppa:golf-lang/golf
sudo apt update

And then install Golf with:

sudo apt install golf

You can then manage the package using standard Ubuntu apt tools.

Golf 210 released

  • Added new "error-line" and "error-char" clauses in JSON parsing (json-doc statement) to produce the line number and the character within the line where error in parsing was detected.
  • Fixed a build bug with missing 'stub_xml.o' file. This file is a part of upcoming XML parsing support and plays no role currently, but it prevented the build from being completed.
  • Fixed issue with maximum length of source code line, which should be approx 8K.
  • Added debian apt package build support (debian/control etc.) 

Thursday, January 30, 2025

How to send email with Golf

This example shows how to send email with Golf. The web service you'll create here is very simple and it will display an HTML form to collect info needed to send email, such as "From" and "To" (the sender and the recipient emails), the Subject and of course the Message itself. Once user clicks Submit, email is sent.

Create directory for your application:
mkdir -p mail
cd mail

Create "mail-sender" application:
gg -k mail-sender

Copy the following code to file "mail.golf":
 begin-handler /mail public
     // Get URL parameter
     get-param action

     if-true action equal "show_form"
         // Display HTML form
         @<h2>Enter email and click Send to send it</h2>
         @Note: 'From' field must be the email address from the domain of your server.<br/><br/>
         @<form action="<<p-path "/mail">>" method="POST">
         @    <input type="hidden" name="action" value="submit_form">
         @    <label for="from_mail">From:</label><br>
         @    <input type="text" name="from_mail" value=""><br>
         @    <label for="to_mail">To:</label><br>
         @    <input type="text" name="to_mail" value=""><br><br>
         @    <label for="subject_mail">Subject:</label><br>
         @    <input type="text" name="subject_mail" value=""><br><br>
         @    <label for="message">Message:</label><br>
         @    <textarea name="message" rows="3" columns="50"></textarea>
         @    <br/><br/>
         @    <input type="submit" value="Send">
         @</form>
     else-if action equal "submit_form"
         // Get data from HTML form
         get-param from_mail
         get-param to_mail
         get-param message
         get-param subject_mail
         // Construct email message
         write-string msg
             @From: <<p-out from_mail>>
             @To: <<p-out to_mail>>
             @Subject: <<p-out subject_mail>>
             @
             <<p-out message>>
         end-write-string
         // Send email
         exec-program "/usr/sbin/sendmail" args "-i", "-t" input msg status st
         // Check status of email sending
         if-true st not-equal GG_OKAY
             @Could not send email!
         else-if
             @Email sent!
         end-if
         @<hr/>
     else-if
         @Unrecognized action!<hr/>
     end-if
 end-handler

The example uses

Tuesday, January 28, 2025

Fast JSON parser with little coding

Golf's JSON parser produces an array of name/value pairs. A name is a path to value, for instance "country"."state"."name", and the value is simply the data associated with it, for instance "Idaho". You can control if the name contains array indexes or not, for instance if there are multiple States in the document, you might have names like "country"."state"[0]."name" with [..] designating an array element.

You can iterate through this array and get names of JSON elements, examine if they are of interest to you, and if so, get the values. This typical scenario is how Golf's parser is built, since it uses a "lazy" approach, where values are not allocated until needed, speeding up parsing. That is the case in this example. The JSON document below is examined and only the names of the cities are extracted.

You can also store JSON elements into trees or hashes for future fast retrieval, or store them into a database, etc.

To get started, create a directory for this example and position in it:
mkdir -p json
cd json

Save this JSON into a file "countries.json" - we will get the names of the cities from it:
{ "country": [
    { 
        "name": "USA",
        "state": [
            { 
                "name": "Arizona",
                "city": [
                    {
                        "name" : "Phoenix",
                        "population": 5000000
            	    } ,
                    {
                        "name" : "Tuscon",
                        "population": 1000000
            	    } 

                ]
            } ,
            { 
                "name": "California",
                "city": [
                    {
                        "name" : "Los Angeles",
                        "population": 19000000
            	    },
                    {
                        "name" : "Irvine"
            	    }
                ]
            } 
        ] 
    } ,
    { 
        "name": "Mexico",
        "state": [
            { 
                "name": "Veracruz",
                "city": [
                    {
                        "name" : "Xalapa-Enríquez",
                        "population": 8000000
            	    },
                    {
                        "name" : "C\u00F3rdoba",
                        "population": 220000
            	    }
                ]
            } ,
            { 
                "name": "Sinaloa",
                "city": [
                    {
                        "name" : "Culiac\u00E1n Rosales",
                        "population": 3000000
            	    }
                ]
            } 
        ] 
    }
    ]
}

What follows is the code to parse JSON. We open a JSON file, process the document, check for errors, and then read elements one by one. We look for a key "country"."state"."city"."name" because those contains city names. Note use "no-enum" clause in json-doc (which is the Golf's JSON parser), so that element designations aren't showing (meaning we don't have [0], [1] etc. for arrays).

Save this code to "parse-json.golf":
 begin-handler /parse-json public
     // Read the JSON file
     read-file "countries.json" to countries status st
     if-true st lesser-equal 0
         @Cannot read file or file empty
         exit-handler -1
     end-if

     // Parse JSON
     json-doc countries no-enum status st error-text et error-position ep to json

     // Check for errors in JSON document
     if-true st not-equal GG_OKAY
         @Error [<<p-out et>>] at [<<p-num ep>>]
         exit-handler -2
     end-if

     // This is the JSON element we're looking for
     set-string city_name unquoted ="country"."state"."city"."name"

     // Read elements one by one - note you can then store them in a tree or hash for future fast searches
     start-loop
         // Read just a key
         read-json json key k type t
         // Exit if end of document
         if-true t equal GG_JSON_TYPE_NONE
             break-loop
         end-if
         // If matches key we're looking for, get the value, and output it
         if-true city_name equal k
             read-json json value v
             @Value [<<p-out v>>]
             @--------
         end-if
         // Move on to the next JSON element
         read-json json next
     end-loop

     // Optionally delete JSON object, or it will be automatically deleted
     json-doc delete json
 end-handler

Monday, January 27, 2025

Golf 191 released

  • Fixed bugs in compilation when process-scoped types are not recognized in some cases.
  • Fixed bug in JSON processing that could see in rare cases wrong data produced by parsing. 

Sunday, January 26, 2025

Golf 184 released

  • New "array" type has been added. This is a string array with a number key, ranging from 0 to the array's maximum size. Note that Golf array is flexible: you do not need to specify the array size, rather only it maximum possible size. The actual memory allocated is nominal and will vary based on the data you store in the array. Arrays can also be purged to reduce their size back to the nominal. Statements included are new-array, read-array, write-array and purge-array.
  • Renamed index type to reflect its structure, and now it's "tree". So the statements like new-index, read-index etc. are now new-tree, read-tree etc.
  • Renamed set type to reflect its structure, and now it's "hash". So the statements like new-set, read-set etc. are now new-hash, read-hash etc.

Saturday, January 18, 2025

Golf 171 released

  • "Array" statements are now "set", so for example new-array is now new-set. This change is made to align the names of data structures better with their qualities and to make room for a new "array" structure that will be a direct-memory access structure. Please rename these statements in your code to be compatible with this and future versions.
  • The limit for a number of subdirectories in file storage is now 64000, instead of previous 40000, significantly increasing the number of files that can be stored (theoretically by 240,000,000,000).

Tuesday, January 14, 2025

Golf 155 released

  • Gliimly has been renamed to Golf. New web site is https://golf-lang.com and blog is at https://golf-lang.blogspot.com/
  • Note in order to migrate to Golf you need to:
    1. Uninstall Gliimly (using "sudo make uninstall" from its source code directory).
    2. Install Golf (see https://golf-lang.github.io/install.html)
    3. Rename all your source files to have .golf extension
    4. Rebuild your project (gg -q)
  • File type for source files has changed from .gliimly to .golf
  • Fixed longstanding issue with (sometimes) bad diagnostic output for erroneous source (meaning non-correct error reporting).
  • Added "no-enum" clause in json-doc statement to produce keys for JSON values that do not include array enumeration.

Friday, January 3, 2025

What is application server?

Every Golf application is built as both an application server and a command-line program. You can use both, depending on what's the nature of your application. Some programs are meant to be used in scripts, or executed directly from command line. Others need to stay in memory and execute user requests as servers. The nice thing is that they both work the same, meaning you can run from command line anything that an application server does, and vice versa. This is also handy for testing; it makes writing tests for an application server much easier because you can run such tests in a plain bash script.

What is an application server? It is a set of background resident processes. Each such process can be contacted via socket with a request, and it will provide a reply. An application server often sits behind a web server which accepts user requests, passes them to the application server, receives its reply and the passes this reply back to the user. This is a "reverse proxy" configuration. Note that this configuration, though typical, isn't a hard rule; end users can talk to an application server directly in some cases, such as on a secure local network.