News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_TCMSLP

[cpctelera] stdio and strings?

Started by TCMSLP, 15:09, 27 January 16

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

TCMSLP

Hi,

I've written a very simple adventure (my first real attempt at C!) using gcc under Linux.  I tried compiling this to a Z80 target using sdcc but hit issues with lack of functions/libraries.

I figured CPCtelera may be a nice way to remove some of the pain, but I now see it still relies on the underlying SDCC libs.

The functions I'm missing:-

src/main.c:68: warning 112: function 'fgets' implicit declaration
src/main.c:91: warning 112: function 'atoi' implicit declaration
src/main.c:149: warning 112: function 'tolower' implicit declaration

Which I'm assuming are due to the SDCC stdio/strings libs lacking these functions.

Is there an easy way out of this?  I remember I used fgets and atoi to get around specific problems.  Re-engineering without these will likely be a painful exercise.

Edit: Painful exersise = Starting from scratch, using what I've learnt to ensure I don't make the same mistakes next time  ;)

Steve / TCMSLP

Alcoholics Anonymous

#1
Quote from: TCMSLP on 15:09, 27 January 16
I've written a very simple adventure (my first real attempt at C!) using gcc under Linux.  I tried compiling this to a Z80 target using sdcc but hit issues with lack of functions/libraries.

I figured CPCtelera may be a nice way to remove some of the pain, but I now see it still relies on the underlying SDCC libs.

The functions I'm missing:-

src/main.c:68: warning 112: function 'fgets' implicit declaration
src/main.c:91: warning 112: function 'atoi' implicit declaration
src/main.c:149: warning 112: function 'tolower' implicit declaration

Which I'm assuming are due to the SDCC stdio/strings libs lacking these functions.

Is there an easy way out of this?  I remember I used fgets and atoi to get around specific problems.  Re-engineering without these will likely be a painful exercise.

sdcc only has enough library functions to suit most needs of embedded targets.  All of it is written in C, except for about 6-7 important functions (for the z80 target), so they tend to be fairly large as well.  For example, it's missing the entire input side of stdio (no scanf, no fgets) and it has no concept of FILEs.  printf is done through a user-supplied putchar function so there can only be one output device.

There is a solution to this in z88dk which has a library aiming for c11 compliance written in assembly language.  Both sdcc and z88dk have been working together over the past year to become compatible and the first result is the latest release of z88dk (v1.99 although as always things continue to improve in cvs).  A patched version of sdcc is able to use z88dk's new c lib and what that means is sdcc provides the standards compliant C compiler and z88dk supplies the standards compliant C library written in assembly language.  You can see the extent of z88dk's new library here:  temp:front [z88dk] , which is only partially documented, and a function listing here:  libnew:listing [z88dk]

z88dk has gone a step further and improves on sdcc's output with a large peephole set that makes the C code 5-10% smaller, patches sdcc's relaxed register matching in its peepholer (something like this will be applied to sdcc after its next release - this is too scary a change just prior to a release :) ), attempts to fix a few code generation bugs, and takes full advantage of the new function linkages introduced by sdcc for z88dk compatibility (fastcall param passing via register and callee for multiple params).  At the moment, register preservation information is being added to header files as sdcc has introduced a "preserves_regs()" attribute for asm functions.

The result is that z88dk/sdcc is producing some quite good results.  You can see some benchmarks here:  temp:front [z88dk]

Unfortunately there isn't a cpc target yet.  The main impediment is that the z88dk libraries take full advantage of the z80's features, including use of the exx set which conflicts with the cpc's firmware.  A workaround for the cpc has to be found in the crt and, beyond that, low level functions to plot pixels and draw text would be needed too.

But the solution is almost there :)   If you need to, you can pluck out individual functions from z88dk to use in your project -- you'd need the function prototype from the header file and the asm implementation from the source tree.  atoi() and tolower() are fairly easy to pluck out but fgets() is another matter as it involves a large chunk of the underlying stdio implementation.  If you do pluck something out, please acknowledge where it came from :)

TCMSLP

#2

Thanks for the information! 

I've discovered it's only fgets that I'm lacking - so a work around may well be possible :)

Edit: ok, not so possible.  Every alternative I try lacks support (even gets complains of no getchar support).
         I just need to grab a string as input (which may include a space).   Any ideas?

Steve

FloppySoftware

Quote from: TCMSLP on 17:16, 27 January 16
Thanks for the information! 

I've discovered it's only fgets that I'm lacking - so a work around may well be possible :)


Steve

You can find the source code for fgets in a lot of places.
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

TCMSLP

It seems sdcc lacks any support for 'getchar' as embedded devices don't typically have input (or, their type of input may vary).

I just need to grab a string (including spaces) as input.    :doh:


Steve

TCMSLP


I'm guessing I could use cpct_scanKeyboard and cpct_isKeyPressed to scan for every possible key and build an array.  But, this seems crazy.  I'm hoping I'm just missing something obvious here!

Alcoholics Anonymous

#6
Quote from: FloppySoftware on 17:33, 27 January 16
You can find the source code for fgets in a lot of places.

It's not quite as simple as that as normal behaviour for fgets on stdin is to have the implementation supply line-oriented editing.  The implementations of fgets found on the internet hide many details behind the operating system, ie quite often the line editing is hidden behind getchar().

Quote
Every alternative I try lacks support (even gets complains of no getchar support).

You will have to implement getchar as that's target-dependent.  If you don't care about editing (ie backspace) you can probably bang up something using cpct_scanKeyboard and cpct_isKeyPressed if you take care about key repeat or deny key repeat by only allowing one key press to register.

The classic side of z88dk has an fgets() with simple line edit -- let me see if I can dig it out for you and find out if it is applicable.

Alcoholics Anonymous

#7
The classic-side z88dk implementation of fgets is fairly independent from the rest of the lib so maybe you can use it.  It's called fgets_cons instead of fgets below.

fgets()

/*
*    Spectrum C library
*
*    23/1/2000 djm
*    24/1/2003 minor fixes by chriscowley
*
*    This is as usual my slightly non standard gets()
*    which takes a length argument..
*
* --------
* $Id: fgets_cons.c,v 1.9 2015/12/12 03:13:11 aralbrec Exp $
*/

#include <stdio.h>
#include <ctype.h>

extern unsigned char _cons_state;

int fgets_cons(unsigned char *str, int max)
{   
   unsigned char c;
   int ptr;
   ptr=0;

   while (1) {
      c = fgetc_cons();

      if (ptr == max-1) return str;
     
      if (c == 6)
      {
         _cons_state = ! _cons_state;   // toggle CAPS LOCK
      }
      else if (c == 12 || c == 8 )
      {
    if ( ptr > 0 )
    {
           str[--ptr] = 0;
       fputc_cons(;
       fputc_cons(32);
       fputc_cons(;
        }
      }
      else
      {
         if (_cons_state)
            c = toupper(c);
           
         str[ptr++] = c;
         str[ptr] = 0;
     fputc_cons(c);
         if (c == '\n' || c == '\r') return str;
      }
   }
}


There is a global variable "_cons_state" to keep track of caps lock which you can do away with if you want.  As you can see in the code, fgetc_cons is called to get a single char from the keyboard (example source below).  Code 6 is taken as caps lock.  Code 8 or 12 is taken as backspace.  fputc_cons is called to print a single char (example source below).  It's expected that fputc_cons understands code 8 means back up one char space.  If you don't want simple editing you can make this much simpler as mentioned in the previous post.

fgetc_cons

        PUBLIC    fgetc_cons

.fgetc_cons
    xor    a
    ld    (23560),a
.getkey1
    ld    a,(23560)
    and    a
    jr    z,getkey1
    ld    l,a
    ld    h,0
    ret


This is the spectrum's fgetc_cons.  All it does is busy-wait for a keypress and returns it.  You can do something similar with the cpctelera functions but keep in mind code 6 is interpretted as caps lock and code 8/12 as backspace by fgets.

fputc_cons
is target dependent.  You need to print the char passed, treat code 8 as meaning move back one character position.  You can probably do something with cpctelera here too.  To move back a char position you may have to keep track of current cursor coordinate and you may have to worry about scrolling if the screen fills.


Maybe the cpc firmware or cpctelera has an input string routine.  That would simplify matters quite a bit :)

FloppySoftware

Quote from: Alcoholics Anonymous on 18:10, 27 January 16
It's not quite as simple as that as normal behaviour for fgets on stdin is to have the implementation supply line-oriented editing.  The implementations of fgets found on the internet hide many details behind the operating system, ie quite often the line editing is hidden behind getchar().

For a simple-but-working version, only getchar() is needed. And that would not be a big problem having access to the firmware.
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

ronaldo

@TCMSLP: As some previous posts have told you, these functions are not implemented in SDCC C standard libraries because they usually depend on system-specific implementations. SDCC is an embeded compiler for multiple devices and systems, and their decision is to keep libraries general. Therefore, is left to developers to implement system-specific functions, like character printing and reading.

CPCtelera has 2 main parts: 1) a project creation/management/building system to ease project creation and help developers concentrate on programming and not on "administrative" tasks, and 2) a low-level game-programming library. The low-level library is designed for game programming, and that's why it does not implement fgets/atoi/tolower functions. That functions are from standard library and generally used for applications, not for games. So, technically speaking, CPCtelera does not rely at all on C's stdlib. You may use C's stdlib on a CPCtelera project or not, at will. C's stdlib functions are not CPCtelera's target. However, as others have already told you, there are implementations of these functions available, and you can easily include them in your project. You will need a getchar() implementation first, as all those functions rely on getchar().

The other approach is implementing your own input/output system. For a game, I will always prefer this approach. General input/output systems are for many aplications (they are general), but your game usually has specific requirements. Implementing an specific input/output system will make it probably smaller and faster, which is always desirable for a game. @ervin did that to let uses input name for rankings on RUN CPC, for instance. You may see implemeting these functions as a painful exercise: I personally see it as an interesting experience and a greater possibility of adaptation to your needs. In fact, it is important to notice that stdlib functions hace to do these low-level operations for you (i.e. reading keyboard status and transforming keys into characters one by one).

So, summing up, 2 approaches:
Hope this helps you select an appropriate strategy for developing your project.

TCMSLP


Thanks again for all the comments - I now have a lot of things to look into.

You guys are awesome :D

Steve

Powered by SMFPacks Menu Editor Mod