Environment Variables and Temporary Files in Z88DK

Discuss game and other programming topics not specifically covered in another forum

Moderator: Programming Moderators

Alcoholics Anonymous
Posts: 463
Joined: Mon May 29, 2017 7:00 pm

Environment Variables and Temporary Files in Z88DK

Postby Alcoholics Anonymous » Wed Jun 27, 2018 2:23 am

ENVIRONMENT VARIABLES

On big machine systems, there is a concept of environment variables where "name = value" pairs are stored someplace and can be queried by running programs. You might use environment variables to store things like the user's home directory, path to locate programs entered on the command line and so on.

For the Next, Z88DK will store a set of global environment variables in a text file "/sys/env.cfg". You can edit this text file however you please to add new variables or remove old ones.

An example of "env.cfg" is this one that will be used in the example below:

/sys/env.cfg

Code: Select all

	HOME= /user/bob
  
  malformed
  = nothing

 = stuff

     thisthat =

message = change your passwords

PATH=/games/a;/games/b;/games/c   

ntp = 192.168.0.1

line = this long is much too long to be read into the default buffer; what will happen I wonder ???

This one is deliberately sloppy to test the Z88DK code. Normally it would be nice and neat with "name = value" pairs cleanly added to the file. In this file there is extra whitespace everywhere and examples of invalid "name = value" lines. Keep in mind that a "name = value" pair must exist completely in one line.

For the ZX Next the vision is to have path information here (the plan is to have a .run dot command that can search the path to locate a program you want to run; this would be the command line equivalent of the browser that already exists in NextOS). There may also be information like ntp server (internet address to set the time for the realtime clock), chat server (maybe an irc chat channel to meet other next users or arrange a multiplayer game), and so on.

The Z88DK api can also read "name = value" pairs from any file you supply. The intention for this is to allow a program to have an associated config file with "name = value" pairs so that the user can pass configuration information to the program. The program would read the information at startup and act accordingly. Because not everyone uses Z88DK, the Z88DK library is not available to them. Instead some useful functions from Z88DK, like these, will be made available as dot command toolkits that will allow programs to access these functions via dot command. The important thing about this is that these dot commands take 0 memory away from the program because they are run from divmmc memory. So even though Z88DK programs can get these functions into their programs easily, they too might still prefer to access them via toolkit dot command instead.

TEMPORARY FILES

Sometimes programs, especially utilities, need to create temporary files. This can be done via tmpam and mkstemp. tmpnam will create a unique filename guaranteed not to exist at the time of the call but it does not actually create the file. mkstemp does the same but does create the file and return a file handle to the program ready to use.

These temporary files are created in the /tmp directory by default. But both functions have an *_ex variant that takes as input a template string with "XXXX" at the end of the filename where these functions will randomize the "XXXX" to create a unique filename. The template string can indicate any directory, including none to create the temporary filename in the current working directory.

As one example of its usefulness, usually when a file is modified the modified version of the file is created first in a temporary file. Then the original file is deleted and the temporary file is renamed to the original filename. This way the original file is not lost in case the modified file cannot be finished for some reason.

EXAMPLE

game.c (test program)

Code: Select all

#pragma redirect CRT_OTERM_FONT_FZX = _ff_kk_McMillen

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arch/zxn.h>
#include <arch/zxn/esxdos.h>

const unsigned char cname[] = "foo_XXXX";    // constant template
      unsigned char  name[] = "foo_XXXX";    // changable copy of template

extern unsigned char _ENV_MKSNAM[];          // internal static memory for last mkstemp filename

unsigned char buf[128];

void main(void)
{
   unsigned int n;
   
   zx_cls(INK_BLACK | PAPER_WHITE);
   
   // temp files in /tmp

   printf("How many tmp files in /tmp ? ");
   
   fflush(stdin);
   scanf("%u", &n);
   
   while (n--)
   {
      unsigned char handle;
      
      // mkstemp_ex(0) uses internal static memory to generate a filename into
      
      if ((handle = mkstemp_ex(0)) == 0xff)
         printf("fail\n");
      else
      {
         printf("success \"%s\"\n", _ENV_MKSNAM);
         esx_f_close(handle);
      }
   }
   
   // temp files in current directory

   printf("\nHow many tmp files in current dir ? ");
   
   fflush(stdin);
   scanf("%u", &n);
   
   while (n--)
   {
      unsigned char handle;
      
      // mkstemp_ex(foo) uses the string foo as tempate to generate a filename into
      
      if ((handle = mkstemp_ex(strcpy(name, cname))) == 0xff)
         printf("fail \"%s\"\n", name);
      else
      {
         printf("success \"%s\"\n", name);
         esx_f_close(handle);
      }
   }
   
   // create tmp filename only for /tmp (no actual file is created)
   
   printf("\nGenerating 10 unique filenames for /tmp:\n");
   
   for (n = 0; n != 10; ++n)
   {
      unsigned char *s;
      
      // tmpnam(0) uses internal static memory to generate a filename into

      if (s = tmpnam(0))
         printf("success: \"%s\"\n", s);
      else
         printf("fail\n");
   }
   
   // create tmp filename only for current dir (no actual file is created)
   
   printf("\nGenerating 10 unique filenames for the current dir:\n");
   
   for (n = 0; n != 10; ++n)
   {
      unsigned char *s;
      
      // tmpnam_ex(foo) uses the string foo as template to generate a filename into
      
      if (s = tmpnam_ex(strcpy(name, cname)))
         printf("success: \"%s\"\n", s);
      else
         printf("fail: \"%s\"\n", s);
   }
   
   // query environment
   
   printf("\nQuery environment variables.\n");
   
   while (1)
   {
      unsigned char *s;
      
      printf("\nEnter name: ");
      
      fflush(stdin);
      scanf("%s", buf);
      
      s = strrstrip(strstrip(buf));   // unnecessary as %s will prune surrounding whitespace
      
      // if the name is not found in the environment file, 0 is returned by getenv*
      // z88dk printf prints <null> for 0 but normally you should not print a NULL string
      
      printf("\nGlobal environment:\n");
      printf("%s = %s\n", s, getenv(s));
      
      printf("\nLocal environment:\n");
      printf("%s = %s\n", s, getenv_ex("game.cfg", s));
   }
}
Compile with:
zcc +zxn -v -startup=8 -clib=sdcc_iy -SO3 --max-allocs-per-node200000 game.c -o game -subtype=sna -Cz"--clean --fullsize --pages" -create-app

As always although the example is in c, all functions are implemented in assembly language and can be called from asm as well.

Save the compiled "game.sna" to a directory on the sd card and along with it save this local environment variables file:

game.cfg

Code: Select all

; shared player data

player_name = pogo

; internet

hi_score_ip = 192.168.0.1
chat_ip     = 200.152.9.10

; multiplayer

timeout = 123456
server  = 50.50.50.50

THIS FILE MUST BE SAVED WITH UNIX LINE ENDINGS (IE \N ONLY). Your text editor should be able to do that. It might be ok with windows \r\n endings but this is untested. Certainly it will not work with \r only endings.

You will also need to create a "/tmp" directory on your sd card and a populated global environment variables file in /sys:

/sys/env.cfg

Code: Select all

	HOME= /user/bob
  
  malformed
  = nothing

 = stuff

     thisthat =

message = change your passwords

PATH=/games/a;/games/b;/games/c   

ntp = 192.168.0.1

line = this long is much too long to be read into the default buffer; what will happen I wonder ???

Again the file should be saved with unix line endings.


With that all set up, give it a run and answer the prompts. The program source has some comments that should make it clear what is going on.

BUG IN NEXTOS 1.98M AND BEFORE

A bug was found concerning 0-byte files that this program will generate. NextOS improperly marks the 0-byte filesize in the directory entry. What this means is windows will not be able to delete these 0-byte files. However NextOS can.

Who is online

Users browsing this forum: No registered users and 3 guests