This is the open source Pawn interpreter ported to mbed. See here: http://www.compuphase.com/pawn/pawn.htm and here: http://code.google.com/p/pawnscript/

Dependents:   Pawn4Test

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers amxcons.c Source File

amxcons.c

00001 /* Console output module (terminal I/O) for the Pawn AMX
00002  *
00003  *  Since some of these routines go further than those of standard C, they
00004  *  cannot always be implemented with portable C functions. In other words,
00005  *  these routines must be ported to other environments.
00006  *
00007  *  Copyright (c) ITB CompuPhase, 1997-2011
00008  *
00009  *  Licensed under the Apache License, Version 2.0 (the "License"); you may not
00010  *  use this file except in compliance with the License. You may obtain a copy
00011  *  of the License at
00012  *
00013  *      http://www.apache.org/licenses/LICENSE-2.0
00014  *
00015  *  Unless required by applicable law or agreed to in writing, software
00016  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00017  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
00018  *  License for the specific language governing permissions and limitations
00019  *  under the License.
00020  *
00021  *  Version: $Id: amxcons.c 4523 2011-06-21 15:03:47Z thiadmer $
00022  */
00023 
00024 #if defined _UNICODE || defined __UNICODE__ || defined UNICODE
00025 # if !defined UNICODE   /* for Windows */
00026 #   define UNICODE
00027 # endif
00028 # if !defined _UNICODE  /* for C library */
00029 #   define _UNICODE
00030 # endif
00031 #endif
00032 
00033 #include <limits.h>
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <assert.h>
00038 #if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
00039   #define HAVE_CONIO
00040   #include <conio.h>
00041   #include <malloc.h>
00042 #endif
00043 #if defined USE_CURSES || defined HAVE_CURSES_H
00044   #include <curses.h>
00045   #if !defined CURSES
00046     #define CURSES  1
00047   #endif
00048 #endif
00049 #include "osdefs.h"
00050 #if defined __ECOS__
00051   /* eCos puts include files in cyg/package_name */
00052   #include <cyg/hal/hal_if.h>
00053   #include <cyg/infra/diag.h>
00054   #include <cyg/hal/hal_diag.h>
00055   #include <cyg/pawn/amx.h>
00056 #else
00057   #include "amx.h"
00058 #endif
00059 #if defined __WIN32__ || defined _WIN32 || defined WIN32
00060   #include <windows.h>
00061 #endif
00062 
00063 #if defined _UNICODE
00064 # include <tchar.h>
00065 #elif !defined __T
00066   typedef char          TCHAR;
00067 # define __T(string)    string
00068 # define _fgetts        fgets
00069 # define _puttchar      putchar
00070 # define _stprintf      sprintf
00071 # define _tcschr        strchr
00072 # define _tcscpy        strcpy
00073 # define _tcsdup        strdup
00074 # define _tcslen        strlen
00075 # define _tprintf       printf
00076 #endif
00077 #include "amxcons.h"
00078 
00079 #if defined AMX_TERMINAL
00080   #define EOL_CHAR       '\r'
00081 #endif
00082 #if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
00083   #define EOL_CHAR       '\r'
00084 #endif
00085 #if !defined EOL_CHAR
00086   /* if not a "known" operating system, assume Linux/Unix */
00087   #define EOL_CHAR     '\n'
00088 #endif
00089 
00090 #if !defined AMX_STRING_LIB
00091 
00092 #if defined AMX_TERMINAL
00093   /* required functions are implemented elsewhere */
00094   int amx_putstr(const TCHAR *);
00095   int amx_putchar(int);
00096   int amx_fflush(void);
00097   int amx_getch(void);
00098   TCHAR *amx_gets(TCHAR *,int);
00099   int amx_termctl(int,int);
00100   void amx_clrscr(void);
00101   void amx_clreol(void);
00102   int amx_gotoxy(int x,int y);
00103   void amx_wherexy(int *x,int *y);
00104   unsigned int amx_setattr(int foregr,int backgr,int highlight);
00105   void amx_console(int columns, int lines, int flags);
00106   void amx_viewsize(int *width,int *height);
00107   int amx_kbhit(void);
00108 #elif defined CURSES && CURSES != 0
00109   /* Use the "curses" library to implement the console */
00110   static WINDOW *curseswin;
00111   #define amx_putstr(s)       printw("%s",(s))
00112   #define amx_putchar(c)      addch(c)
00113   #define amx_fflush()        refresh()
00114   #define amx_getch()         getch()
00115   #define amx_gets(s,n)       getnstr((s),(n))
00116   #define amx_clrscr()        clear()
00117   #define amx_clreol()        clrtoeol()
00118   #define amx_gotoxy(x,y)     move((y)-1,(x)-1)
00119   #define amx_console(c,l,f)  ((void)(c),(void)(l),(void)(f))
00120   unsigned int amx_setattr(int foregr,int backgr,int highlight)
00121   {
00122     int attribs=A_NORMAL;
00123     if (highlight>0)
00124       attribs=(attribs & ~A_NORMAL) | A_STANDOUT;
00125     attrset(attribs);
00126     //??? in future, also handle colours
00127   }
00128   void CreateConsole(void);
00129   int amx_kbhit(void)
00130   {
00131     int result;
00132     CreateConsole();
00133     nodelay(curseswin,TRUE);    /* enter non-blocking state */
00134     result=getch();             /* read key (if any) */
00135     nodelay(curseswin,FALSE);   /* leave non-blocking state */
00136     if (result!=ERR)
00137       ungetch(result);          /* a key is waiting, push it back */
00138     return (result==ERR) ? 0 : 1;
00139   }
00140   int amx_termctl(int code,int value)
00141   {
00142     switch (code) {
00143     case 0:           /* query terminal support */
00144       return 1;
00145     /* case 1: */     /* switch auto-wrap on/off (not supported in curses!) */
00146     /* case 2: */     /* create/switch to another console */
00147     case 3:           /* set emphasized font */
00148       if (value)
00149         attron(A_BOLD);
00150       else
00151         attroff(A_BOLD);
00152       return 1;
00153     /* case 4: */     /* query whether a terminal is "open" */
00154     default:
00155       return 0;
00156     } /* switch */
00157   }
00158   void amx_wherexy(int *x,int *y)
00159   {
00160     int row,col;
00161     getyx(curseswin,row,col);
00162     if (x!=NULL)
00163       *x=col+1;
00164     if (y!=NULL)
00165       *y=row+1;
00166   }
00167   void amx_viewsize(int *width,int *height)
00168   {
00169     int row,col;
00170     getmaxyx(curseswin,row,col);
00171     if (width!=NULL)
00172       *width=col;
00173     if (height!=NULL)
00174       *height=row;
00175   }
00176 #elif defined VT100 || defined __LINUX__ || defined ANSITERM || defined __ECOS__
00177   /* ANSI/VT100 terminal, or shell emulating "xterm" */
00178   #if defined __ECOS__
00179     #define AMXCONSOLE_NOIDLE
00180   #endif
00181 
00182   #if CYGPKG_PAWN_AMXCONSOLE_DIAG==1
00183     /* eCos has basically two ways to make simple exchanges with a terminal:
00184      * - with the diag_*() functions (no input provided!)
00185      * - with f*() functions (fprintf(),fputs(), etc).
00186      */
00187     #define amx_fflush()
00188 
00189     static int amx_putstr(TCHAR *s)
00190     {
00191       diag_write_string(s);
00192       return 1;
00193     }
00194     static int amx_putchar(TCHAR c)
00195     {
00196       diag_write_char(c);
00197       return c;
00198     }
00199     static char amx_getch(void)
00200     {
00201       char c=-1;
00202       HAL_DIAG_READ_CHAR(c);
00203       return c;
00204     }
00205   #else
00206 
00207     #define amx_putstr(s)     fputs((s),stdout)
00208     #define amx_putchar(c)    putchar(c)
00209     #define amx_fflush()      fflush(stdout)
00210     #define amx_getch()       getch()
00211     #define amx_gets(s,n)     fgets(s,n,stdin)
00212     #define amx_kbhit()       kbhit()
00213   #endif
00214 
00215   int amx_termctl(int code,int value)
00216   {
00217     switch (code) {
00218     case 0:             /* query terminal support */
00219       return 1;
00220 
00221     case 1:             /* switch "auto-wrap" on or off */
00222       if (value)
00223         amx_putstr("\033[?7h"); /* enable "auto-wrap" */
00224       else
00225         amx_putstr("\033[?7l"); /* disable "auto-wrap" */
00226       return 1;
00227 
00228     #if 0
00229       /* next to swapping buffers, more information should be saved and swapped,
00230        * such as the cursor position and the current terminal attributes
00231        */
00232     case 2:             /* swap console buffers */
00233       amx_fflush();
00234       if (value==1) {
00235         amx_putstr("\033[?47h");
00236       } else {
00237         amx_putstr("\033[?47l");
00238       } /* if */
00239       amx_fflush();
00240       return 1;
00241     #endif
00242 
00243     case 3:             /* set bold/highlighted font */
00244       return 0;
00245 
00246     default:
00247       return 0;
00248     } /* switch */
00249   }
00250   void amx_clrscr(void)
00251   {
00252     amx_putstr("\033[2J");
00253     amx_fflush();        /* pump through the terminal codes */
00254   }
00255   void amx_clreol(void)
00256   {
00257     amx_putstr("\033[K");
00258     amx_fflush();        /* pump through the terminal codes */
00259   }
00260   int amx_gotoxy(int x,int y)
00261   {
00262     char str[30];
00263     _stprintf(str,"\033[%d;%dH",y,x);
00264     amx_putstr(str);
00265     amx_fflush();        /* pump through the terminal codes */
00266     return 1;
00267   }
00268   void amx_wherexy(int *x,int *y)
00269   {
00270     int val,i;
00271     char str[10];
00272 
00273     assert(x!=NULL && y!=NULL);
00274     amx_putstr("\033[6n");
00275     amx_fflush();
00276     while (amx_getch()!='\033')
00277       /* nothing */;
00278     val=amx_getch();
00279     assert(val=='[');
00280     for (i=0; i<8 && (val=amx_getch())!=';'; i++)
00281       str[i]=(char)val;
00282     str[i]='\0';
00283     if (y!=NULL)
00284       *y=atoi(str);
00285     for (i=0; i<8 && (val=amx_getch())!='R'; i++)
00286       str[i]=(char)val;
00287     str[i]='\0';
00288     if (x!=NULL)
00289       *x=atoi(str);
00290     #if defined ANSITERM
00291       val=amx_getch();
00292       assert(val=='\r');    /* ANSI driver adds CR to the end of the command */
00293     #endif
00294   }
00295   unsigned int amx_setattr(int foregr,int backgr,int highlight)
00296   {
00297     static short current=(0 << 8) | 7;
00298     short prev = current;
00299     char str[30];
00300 
00301     if (foregr>=0) {
00302       _stprintf(str,"\x1b[%dm",foregr+30);
00303       amx_putstr(str);
00304       current=(current & 0xff00) | (foregr & 0x0f);
00305     } /* if */
00306     if (backgr>=0) {
00307       _stprintf(str,"\x1b[%dm",backgr+40);
00308       amx_putstr(str);
00309       current=(current & 0x00ff) | ((backgr & 0x0f) << 8);
00310     } /* if */
00311     if (highlight>=0) {
00312       _stprintf(str,"\x1b[%dm",highlight);
00313       amx_putstr(str);
00314       current=(current & 0x7fff) | ((highlight & 0x01) << 15);
00315     } /* if */
00316     return prev;
00317   }
00318   void amx_console(int columns, int lines, int flags)
00319   {
00320     char str[30];
00321 
00322     (void)flags;
00323     /* There is no ANSI code (or VT100/VT220) to set the size of the console
00324      * (indeed, the terminal was that of the alphanumeric display). In xterm (a
00325      * terminal emulator) we can set the terminal size though, and most
00326      * terminals that in use today are in fact emulators.
00327      * Putty understands this code too, by many others do not.
00328      */
00329     sprintf(str,"\033[8;%d;%dt",lines,columns);
00330     amx_putstr(str);
00331     amx_fflush();
00332   }
00333   void amx_viewsize(int *width,int *height)
00334   {
00335     /* a trick to get the size of the terminal is to position the cursor far
00336      * away and then read it back
00337      */
00338     amx_gotoxy(999,999);
00339     amx_wherexy(width,height);
00340   }
00341 #elif defined __WIN32__ || defined _WIN32 || defined WIN32
00342   /* Win32 console */
00343   #define amx_putstr(s)       _tprintf("%s",(s))
00344   #define amx_putchar(c)      _puttchar(c)
00345   #define amx_fflush()        fflush(stdout)
00346   #define amx_getch()         getch()
00347   #define amx_gets(s,n)       _fgetts(s,n,stdin)
00348   #define amx_kbhit()         kbhit()
00349 
00350   int amx_termctl(int code,int value)
00351   {
00352     switch (code) {
00353     case 0:             /* query terminal support */
00354       return 1;
00355 
00356     case 1: {           /* switch auto-wrap on/off */
00357       /* only works in Windows 2000/XP */
00358       HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
00359       DWORD Flags=ENABLE_PROCESSED_OUTPUT;
00360       if (value)
00361         Flags |= ENABLE_WRAP_AT_EOL_OUTPUT;
00362       SetConsoleMode(hConsole,Flags);
00363       return 1;
00364     } /* case */
00365 
00366     /* case 2: */     /* create/switch to another console */
00367     /* case 3: */     /* set emphasized font */
00368     /* case 4: */     /* query whether a terminal is "open" */
00369     default:
00370       return 0;
00371     } /* switch */
00372   }
00373   void amx_clrscr(void)
00374   {
00375     COORD coordScreen={0,0};
00376     DWORD cCharsWritten;
00377     CONSOLE_SCREEN_BUFFER_INFO csbi;
00378     DWORD dwConSize;
00379     HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
00380 
00381     amx_fflush();       /* make sure the I/O buffer is empty */
00382     GetConsoleScreenBufferInfo(hConsole,&csbi);
00383     dwConSize=csbi.dwSize.X*csbi.dwSize.Y;
00384     FillConsoleOutputCharacter(hConsole,' ',dwConSize,coordScreen,&cCharsWritten);
00385     FillConsoleOutputAttribute(hConsole,csbi.wAttributes,dwConSize,coordScreen, &cCharsWritten);
00386     SetConsoleCursorPosition(hConsole,coordScreen);
00387   }
00388   void amx_clreol(void)
00389   {
00390     DWORD cCharsWritten;
00391     CONSOLE_SCREEN_BUFFER_INFO csbi;
00392     DWORD dwConSize;
00393     HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
00394 
00395     amx_fflush();       /* make sure all output is written */
00396     GetConsoleScreenBufferInfo(hConsole,&csbi);
00397     dwConSize=csbi.dwSize.X - csbi.dwCursorPosition.X;
00398     FillConsoleOutputCharacter(hConsole,' ',dwConSize,csbi.dwCursorPosition,&cCharsWritten);
00399     FillConsoleOutputAttribute(hConsole,csbi.wAttributes,dwConSize,csbi.dwCursorPosition,&cCharsWritten);
00400   }
00401   int amx_gotoxy(int x,int y)
00402   {
00403     COORD point;
00404     CONSOLE_SCREEN_BUFFER_INFO csbi;
00405     HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
00406 
00407     GetConsoleScreenBufferInfo(hConsole, &csbi);
00408     if (x<=0 || x>csbi.dwSize.X || y<=0 || y>csbi.dwSize.Y)
00409       return 0;
00410     amx_fflush();       /* make sure all output is written */
00411     point.X=(short)(x-1);
00412     point.Y=(short)(y-1);
00413     SetConsoleCursorPosition(hConsole,point);
00414     return 1;
00415   }
00416   void amx_wherexy(int *x,int *y)
00417   {
00418     CONSOLE_SCREEN_BUFFER_INFO csbi;
00419     amx_fflush();       /* make sure all output is written */
00420     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
00421     if (x!=NULL)
00422       *x=csbi.dwCursorPosition.X+1;
00423     if (y!=NULL)
00424       *y=csbi.dwCursorPosition.Y+1;
00425   }
00426   unsigned int amx_setattr(int foregr,int backgr,int highlight)
00427   {
00428     static int ansi_colours[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
00429     CONSOLE_SCREEN_BUFFER_INFO csbi;
00430     int f,b,h,prev;
00431     HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
00432 
00433     amx_fflush();       /* make sure all output is written */
00434     GetConsoleScreenBufferInfo(hConsole,&csbi);
00435     f=csbi.wAttributes & 0x07;
00436     b=(csbi.wAttributes >> 4) & 0x0f;
00437     h=(csbi.wAttributes & 0x08) ? 1 : 0;
00438     prev=(b << 8) | f | (h << 15);
00439     if (foregr>=0 && foregr<8)
00440       f=ansi_colours[foregr];
00441     if (backgr>=0 && backgr<8)
00442       b=ansi_colours[backgr];
00443     if (highlight>=0)
00444       h=highlight!=0;
00445     SetConsoleTextAttribute(hConsole, (WORD)((b << 4) | f | (h << 3)));
00446     return prev;
00447   }
00448   void amx_console(int columns, int lines, int flags)
00449   {
00450     SMALL_RECT rect;
00451     COORD dwSize;
00452     (void)flags;
00453     dwSize.X=(short)columns;
00454     dwSize.Y=(short)lines;
00455     SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),dwSize);
00456     rect.Left=0;
00457     rect.Top=0;
00458     rect.Right=(short)(columns-1);
00459     rect.Bottom=(short)(lines-1);
00460     SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE),TRUE,&rect);
00461   }
00462   void amx_viewsize(int *width,int *height)
00463   {
00464     CONSOLE_SCREEN_BUFFER_INFO csbi;
00465     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&csbi);
00466     if (width!=NULL)
00467       *width=(int)csbi.dwSize.X;
00468     if (height!=NULL)
00469       *height=(int)(csbi.srWindow.Bottom-csbi.srWindow.Top+1);
00470   }
00471 #else
00472   /* assume a streaming terminal; limited features (no colour, no cursor
00473    * control)
00474    */
00475   #define amx_putstr(s)       printf("%s",(s))
00476   #define amx_putchar(c)      putchar(c)
00477   #define amx_fflush()        fflush(stdout)
00478   #define amx_gets(s,n)       fgets(s,n,stdin)
00479   #define amx_clrscr()        (void)(0)
00480   #define amx_clreol()        (void)(0)
00481   #define amx_gotoxy(x,y)     ((void)(x),(void)(y),(0))
00482   #define amx_wherexy(x,y)    (*(x)=*(y)=0)
00483   #define amx_setattr(c,b,h)  ((void)(c),(void)(b),(void)(h),(0))
00484   #define amx_termctl(c,v)    ((void)(c),(void)(v),(0))
00485   #define amx_console(c,l,f)  ((void)(c),(void)(l),(void)(f))
00486   #define amx_viewsize        (*(x)=80,*(y)=25)
00487   #if defined HAVE_CONIO
00488     #define amx_getch()       getch()
00489     #define amx_kbhit()       kbhit()
00490   #else
00491     #define amx_getch()       getchar()
00492     #define amx_kbhit()       (0)
00493   #endif
00494 #endif
00495 
00496 #if !defined AMX_TERMINAL && (defined __WIN32__ || defined _WIN32 || defined WIN32)
00497   void CreateConsole(void)
00498   { static int createdconsole=0;
00499     if (!createdconsole) {
00500       AllocConsole();
00501       createdconsole=1;
00502     } /* if */
00503   }
00504 #elif defined CURSES && CURSES != 0
00505   // The Mac OS X build variant uses curses.
00506   void CreateConsole(void)
00507   { static int createdconsole=0;
00508     if (!createdconsole) {
00509       curseswin=initscr();
00510       cbreak();
00511       noecho();
00512       nonl();
00513       scrollok(curseswin,TRUE);
00514       intrflush(curseswin,FALSE);
00515       keypad(curseswin,TRUE);
00516       createdconsole=1;
00517     } /* if */
00518   }
00519 #else
00520   #define CreateConsole()
00521 #endif
00522 
00523 static int cons_putstr(void *dest,const TCHAR *str)
00524 {
00525   (void)dest;
00526   return amx_putstr(str);
00527 }
00528 
00529 static int cons_putchar(void *dest,TCHAR ch)
00530 {
00531   (void)dest;
00532   return amx_putchar(ch);
00533 }
00534 
00535 #endif /* AMX_STRING_LIB */
00536 
00537 enum {
00538   SV_DECIMAL,
00539   SV_HEX
00540 };
00541 
00542 static TCHAR *reverse(TCHAR *string,int stop)
00543 {
00544     int start=0;
00545     TCHAR temp;
00546 
00547     /* swap the string */
00548     stop--;             /* avoid swapping the '\0' byte to the first position */
00549     while (stop - start > 0) {
00550         temp = string[start];
00551         string[start] = string[stop];
00552         string[stop] = temp;
00553         start++;
00554         stop--;
00555     } /* while */
00556     return string;
00557 }
00558 
00559 /* Converts an integral value to a string, with optional padding with spaces or
00560  * zeros.
00561  * The "format" must be decimal or hexadecimal
00562  * The number is right-aligned in the field with the size of the absolute value
00563  * of the "width" parameter.
00564  * If the width value is positive, the string is padded with spaces; if it is
00565  * negative, it is padded with zeros.
00566  */
00567 static TCHAR *amx_strval(TCHAR buffer[], long value, int format, int width)
00568 {
00569     int start, stop;
00570     TCHAR temp;
00571 
00572     start = stop = 0;
00573     if (format == SV_DECIMAL) {
00574         if (value < 0) {
00575             buffer[0] = __T('-');
00576             start = stop = 1;
00577             value = -value;
00578         } /* if */
00579         do {
00580             buffer[stop++] = (TCHAR)((value % 10) + __T('0'));
00581             value /= 10;
00582         } while (value > 0);
00583     } else {
00584         /* hexadecimal */
00585         unsigned long v = (unsigned long)value; /* copy to unsigned value for shifting */
00586         do {
00587             buffer[stop] = (TCHAR)((v & 0x0f) + __T('0'));
00588             if (buffer[stop] > __T('9'))
00589                 buffer[stop] += (TCHAR)(__T('A') - __T('0') - 10);
00590             v >>= 4;
00591             stop++;
00592         } while (v != 0);
00593     } /* if */
00594 
00595     /* pad to given width */
00596     if (width < 0) {
00597         temp = __T('0');
00598         width = -width;
00599     } else {
00600         temp = __T(' ');
00601     } /* if */
00602     while (stop < width)
00603         buffer[stop++] = temp;
00604 
00605     buffer[stop] = __T('\0');
00606 
00607     /* swap the string, and we are done */
00608     reverse(buffer+start,stop-start);
00609     return buffer;
00610 }
00611 
00612 #if defined FIXEDPOINT
00613   #define FIXEDMULT     1000
00614   #define FIXEDDIGITS   3
00615 
00616 static TCHAR *formatfixed(TCHAR *string,cell value,TCHAR align,int width,TCHAR decpoint,int digits,TCHAR filler)
00617 {
00618   int i, len;
00619   cell ipart,v;
00620   TCHAR vsign=__T('\0');
00621 
00622   /* make the value positive (but keep the sign) */
00623   if (value<0) {
00624     value=-value;
00625     vsign=__T('-');
00626   } /* if */
00627 
00628   /* "prepare" the value so that when it is truncated to the requested
00629    * number of digits, the result is rounded towards the dropped digits
00630    */
00631   assert(digits<INT_MAX);
00632   v=FIXEDMULT/2;
00633   for (i=0; i<digits; i++)
00634     v/=10;
00635   value+=v;
00636 
00637   /* get the integer part and remove it from the value */
00638   ipart=value/FIXEDMULT;
00639   value-=FIXEDMULT*ipart;
00640   assert(ipart>=0);
00641   assert(value>=0);
00642 
00643   /* truncate the fractional part to the requested number of digits */
00644   for (i=FIXEDDIGITS; i>digits; i--)
00645     value/=10;
00646 
00647   string[0]=__T('\0');
00648 
00649   /* add sign */
00650   i=_tcslen(string);
00651   string[i]=vsign;
00652   string[i+1]=__T('\0');
00653 
00654   /* add integer part */
00655   amx_strval(string+_tcslen(string),(long)ipart,SV_DECIMAL,0);
00656 
00657   /* add fractional part */
00658   if (digits>0) {
00659     i=_tcslen(string);
00660     string[i]=decpoint;
00661     amx_strval(string+i+1,(long)value,SV_DECIMAL,-digits);
00662   } /* if */
00663 
00664   len=_tcslen(string);
00665   if (len<width) {
00666     /* pad to the requested width */
00667     for (i=len; i<width; i++)
00668       string[i]=filler;
00669     string[i]=__T('\0');
00670     /* optionally move the padding to the beginning of the string, using the handwaving algorithm */
00671     if (align!=__T('-')) {
00672       assert(i==(int)_tcslen(string));
00673       assert(i>=len);
00674       reverse(string,len);
00675       reverse(string+len,i-len);
00676       reverse(string,i);
00677     } /* if */
00678   } /* if */
00679 
00680   return string;
00681 }
00682 #endif
00683 
00684 
00685 static int dochar(AMX *amx,TCHAR ch,cell param,TCHAR sign,TCHAR decpoint,int width,int digits,TCHAR filler,
00686                   int (*f_putstr)(void*,const TCHAR *),int (*f_putchar)(void*,TCHAR),void *user)
00687 {
00688   cell *cptr;
00689   TCHAR buffer[40];
00690   #if defined FLOATPOINT
00691     TCHAR formatstring[40];
00692   #endif
00693 
00694   #if !defined FIXEDPOINT && !defined FLOATPOINT
00695     (void)decpoint;
00696   #endif
00697   assert(f_putstr!=NULL);
00698   assert(f_putchar!=NULL);
00699 
00700   switch (ch) {
00701   case __T('c'):
00702     cptr=amx_Address(amx,param);
00703     width--;            /* single character itself has a with of 1 */
00704     if (sign!=__T('-'))
00705       while (width-->0)
00706         f_putchar(user,filler);
00707     f_putchar(user,(TCHAR)*cptr);
00708     while (width-->0)
00709       f_putchar(user,filler);
00710     return 1;
00711 
00712   case __T('d'): {
00713     cell value;
00714     int length=1;
00715     cptr=amx_Address(amx,param);
00716     value=*cptr;
00717     if (value<0 || sign==__T('+'))
00718       length++;
00719     if (value<0)
00720       value=-value;
00721     while (value>=10) {
00722       length++;
00723       value/=10;
00724     } /* while */
00725     width-=length;
00726     if (sign!=__T('-'))
00727       while (width-->0)
00728         f_putchar(user,filler);
00729     amx_strval(buffer,*cptr,SV_DECIMAL,0);
00730     if (sign==__T('+') && *cptr>=0)
00731       f_putchar(user,sign);
00732     f_putstr(user,buffer);
00733     while (width-->0)
00734       f_putchar(user,filler);
00735     return 1;
00736   } /* case */
00737 
00738 #if defined FLOATPOINT
00739   case __T('f'): /* 32-bit floating point number */
00740   case __T('r'): /* if floating point is enabled, %r == %f */
00741     /* build a format string */
00742     if (digits==INT_MAX)
00743       digits=5;
00744     else if (digits>25)
00745       digits=25;
00746     _tcscpy(formatstring,__T("%"));
00747     if (sign!=__T('\0'))
00748       _stprintf(formatstring+_tcslen(formatstring),__T("%c"),sign);
00749     if (width>0)
00750       _stprintf(formatstring+_tcslen(formatstring),__T("%d"),width);
00751     _stprintf(formatstring+_tcslen(formatstring),__T(".%df"),digits);
00752     cptr=amx_Address(amx,param);
00753     #if PAWN_CELL_SIZE == 64
00754       _stprintf(buffer,formatstring,*(double*)cptr);
00755     #else
00756       _stprintf(buffer,formatstring,*(float*)cptr);
00757     #endif
00758     if (decpoint==__T(',')) {
00759       TCHAR *ptr=_tcschr(buffer,__T('.'));
00760       if (ptr!=NULL)
00761         *ptr=__T(',');
00762     } /* if */
00763     f_putstr(user,buffer);
00764     return 1;
00765 #endif
00766 
00767 #if defined FIXEDPOINT
00768   #define FIXEDMULT 1000
00769   case __T('q'): /* 32-bit fixed point number */
00770 #if !defined FLOATPOINT
00771   case __T('r'): /* if fixed point is enabled, and floating point is not, %r == %q */
00772 #endif
00773     cptr=amx_Address(amx,param);
00774     /* format the number */
00775     if (digits==INT_MAX)
00776       digits=3;
00777     else if (digits>25)
00778       digits=25;
00779     formatfixed(buffer,*cptr,sign,width,decpoint,digits,filler);
00780     assert(_tcslen(buffer)<sizeof buffer);
00781     f_putstr(user,buffer);
00782     return 1;
00783 #endif
00784 
00785 #if !defined FLOATPOINT && !defined FIXEDPOINT
00786   case __T('f'):
00787   case __T('q'):
00788   case __T('r'):
00789     f_putstr(user,__T("(no rational number support)"));
00790     return 0; /* flag this as an error */
00791 #endif
00792 
00793   case __T('s'): {
00794     AMX_FMTINFO info;
00795     memset(&info,0,sizeof info);
00796     info.length=digits;
00797     info.f_putstr=f_putstr;
00798     info.f_putchar=f_putchar;
00799     info.user=user;
00800     cptr=amx_Address(amx,param);
00801     amx_printstring(amx,cptr,&info);
00802     return 1;
00803   } /* case */
00804 
00805   case __T('x'): {
00806     ucell value;
00807     int length=1;
00808     cptr=amx_Address(amx,param);
00809     value=*(ucell*)cptr;
00810     while (value>=0x10) {
00811       length++;
00812       value>>=4;
00813     } /* while */
00814     width-=length;
00815     if (sign!=__T('-'))
00816       while (width-->0)
00817         f_putchar(user,filler);
00818     amx_strval(buffer,(long)*cptr,SV_HEX,0);
00819     f_putstr(user,buffer);
00820     while (width-->0)
00821       f_putchar(user,filler);
00822     return 1;
00823   } /* case */
00824 
00825   } /* switch */
00826   /* error in the string format, try to repair */
00827   f_putchar(user,ch);
00828   return 0;
00829 }
00830 
00831 enum {
00832   FMT_NONE,   /* not in format state; accept '%' */
00833   FMT_START,  /* found '%', accept '+', '-' (START), '0' (filler; START), digit (WIDTH), '.' (DECIM), or '%' or format letter (done) */
00834   FMT_WIDTH,  /* found digit after '%' or sign, accept digit (WIDTH), '.' (DECIM) or format letter (done) */
00835   FMT_DECIM,  /* found digit after '.', accept accept digit (DECIM) or format letter (done) */
00836 };
00837 
00838 static int formatstate(TCHAR c,int *state,TCHAR *sign,TCHAR *decpoint,int *width,int *digits,TCHAR *filler)
00839 {
00840   assert(state!=NULL && sign!=NULL && decpoint!=NULL && width!=NULL && digits!=NULL && filler!=NULL);
00841   switch (*state) {
00842   case FMT_NONE:
00843     if (c==__T('%')) {
00844       *state=FMT_START;
00845       *sign=__T('\0');
00846       *decpoint=__T('.');
00847       *width=0;
00848       *digits=INT_MAX;
00849       *filler=__T(' ');
00850     } else {
00851       return -1;  /* print a single character */
00852     } /* if */
00853     break;
00854   case FMT_START:
00855     if (c==__T('+') || c==__T('-')) {
00856       *sign=c;
00857     } else if (c==__T('0')) {
00858       *filler=c;
00859     } else if (c>=__T('1') && c<=__T('9')) {
00860       *width=(int)(c-__T('0'));
00861       *state=FMT_WIDTH;
00862     } else if (c==__T('.') || c==__T(',')) {
00863       *decpoint=c;
00864       *digits=0;
00865       *state=FMT_DECIM;
00866     } else if (c==__T('%')) {
00867       *state=FMT_NONE;
00868       return -1;  /* print literal '%' */
00869     } else {
00870       return 1;   /* print formatted character */
00871     } /* if */
00872     break;
00873   case FMT_WIDTH:
00874     if (c>=__T('0') && c<=__T('9')) {
00875       *width=*width*10+(int)(c-__T('0'));
00876     } else if (c==__T('.') || c==__T(',')) {
00877       *decpoint=c;
00878       *digits=0;
00879       *state=FMT_DECIM;
00880     } else {
00881       return 1;   /* print formatted character */
00882     } /* if */
00883     break;
00884   case FMT_DECIM:
00885     if (c>=__T('0') && c<=__T('9')) {
00886       *digits=*digits*10+(int)(c-__T('0'));
00887     } else {
00888       return 1;   /* print formatted character */
00889     } /* if */
00890     break;
00891   } /* switch */
00892 
00893   return 0;
00894 }
00895 
00896 int amx_printstring(AMX *amx,cell *cstr,AMX_FMTINFO *info)
00897 {
00898   int i,paramidx=0;
00899   int fmtstate=FMT_NONE,width,digits;
00900   TCHAR sign,decpoint,filler;
00901   int (*f_putstr)(void*,const TCHAR *);
00902   int (*f_putchar)(void*,TCHAR);
00903   void *user;
00904   int skip,length;
00905 
00906   if (info!=NULL) {
00907     f_putstr=info->f_putstr;
00908     f_putchar=info->f_putchar;
00909     user=info->user;
00910     skip=info->skip;
00911     length=info->length;
00912   } else {
00913     f_putstr=NULL;
00914     f_putchar=NULL;
00915     user=NULL;
00916     skip=0;
00917     length=INT_MAX;
00918   } /* if */
00919   #if !defined AMX_STRING_LIB
00920     if (f_putstr==NULL)
00921       f_putstr=cons_putstr;
00922     if (f_putchar==NULL)
00923       f_putchar=cons_putchar;
00924   #else
00925     assert(f_putstr!=NULL && f_putchar!=NULL);
00926   #endif
00927 
00928   /* if no placeholders appear, we can use a quicker routine */
00929   if (info==NULL || info->params==NULL) {
00930 
00931     TCHAR cache[100];
00932     int idx=0;
00933 
00934     if ((ucell)*cstr>UNPACKEDMAX) {
00935       int j=sizeof(cell)-sizeof(char);
00936       char c;
00937       /* the string is packed */
00938       i=0;
00939       for ( ; ; ) {
00940         c=(char)((ucell)cstr[i] >> 8*j);
00941         if (c==0)
00942           break;
00943         if (skip>0) {
00944           skip--;               /* skip a number of characters */
00945         } else {
00946           if (length--<=0)
00947             break;              /* print up to a certain length */
00948           assert(idx<sizeof cache);
00949           cache[idx++]=c;
00950           if (idx==sizeof cache - 1) {
00951             cache[idx]=__T('\0');
00952             f_putstr(user,cache);
00953             idx=0;
00954           } /* if */
00955         } /* if */
00956         if (j==0)
00957           i++;
00958         j=(j+sizeof(cell)-sizeof(char)) % sizeof(cell);
00959       } /* for */
00960     } else {
00961       /* unpacked string */
00962       for (i=0; cstr[i]!=0; i++) {
00963         if (skip-->0)
00964           continue;
00965         assert(idx<sizeof cache);
00966         cache[idx++]=(TCHAR)cstr[i];
00967         if (idx==sizeof cache - 1) {
00968           cache[idx]=__T('\0');
00969           f_putstr(user,cache);
00970           idx=0;
00971         } /* if */
00972       } /* for */
00973     } /* if */
00974     if (idx>0) {
00975       cache[idx]=__T('\0');
00976       f_putstr(user,cache);
00977     } /* if */
00978 
00979   } else {
00980 
00981     /* check whether this is a packed string */
00982     if ((ucell)*cstr>UNPACKEDMAX) {
00983       int j=sizeof(cell)-sizeof(char);
00984       char c;
00985       /* the string is packed */
00986       i=0;
00987       for ( ; ; ) {
00988         c=(char)((ucell)cstr[i] >> 8*j);
00989         if (c==0)
00990           break;
00991         switch (formatstate(c,&fmtstate,&sign,&decpoint,&width,&digits,&filler)) {
00992         case -1:
00993           f_putchar(user,c);
00994           break;
00995         case 0:
00996           break;
00997         case 1:
00998           assert(info!=NULL && info->params!=NULL);
00999           if (paramidx>=info->numparams)  /* insufficient parameters passed */
01000             amx_RaiseError(amx, AMX_ERR_NATIVE);
01001           else
01002             paramidx+=dochar(amx,c,info->params[paramidx],sign,decpoint,width,digits,filler,
01003                              f_putstr,f_putchar,user);
01004           fmtstate=FMT_NONE;
01005           break;
01006         default:
01007           assert(0);
01008         } /* switch */
01009         if (j==0)
01010           i++;
01011         j=(j+sizeof(cell)-sizeof(char)) % sizeof(cell);
01012       } /* for */
01013     } else {
01014       /* the string is unpacked */
01015       for (i=0; cstr[i]!=0; i++) {
01016         switch (formatstate((TCHAR)cstr[i],&fmtstate,&sign,&decpoint,&width,&digits,&filler)) {
01017         case -1:
01018           f_putchar(user,(TCHAR)cstr[i]);
01019           break;
01020         case 0:
01021           break;
01022         case 1:
01023           assert(info!=NULL && info->params!=NULL);
01024           if (paramidx>=info->numparams)  /* insufficient parameters passed */
01025             amx_RaiseError(amx, AMX_ERR_NATIVE);
01026           else
01027             paramidx+=dochar(amx,(TCHAR)cstr[i],info->params[paramidx],sign,decpoint,width,digits,filler,
01028                              f_putstr,f_putchar,user);
01029           fmtstate=FMT_NONE;
01030           break;
01031         default:
01032           assert(0);
01033         } /* switch */
01034       } /* for */
01035     } /* if */
01036 
01037   } /* if (info==NULL || info->params==NULL) */
01038 
01039   return paramidx;
01040 }
01041 
01042 #if !defined AMX_STRING_LIB
01043 
01044 #if defined AMX_ALTPRINT
01045 /* print(const string[], start=0, end=cellmax) */
01046 static cell AMX_NATIVE_CALL n_print(AMX *amx,const cell *params)
01047 {
01048   cell *cstr;
01049   AMX_FMTINFO info;
01050 
01051   memset(&info,0,sizeof info);
01052   info.skip= ((size_t)params[0]>=2*sizeof(cell)) ? (int)params[2] : 0;
01053   info.length= ((size_t)params[0]>=3*sizeof(cell)) ? (int)(params[3]-info.skip) : INT_MAX;
01054 
01055   CreateConsole();
01056   cstr=amx_Address(amx,params[1]);
01057   amx_printstring(amx,cstr,&info);
01058   amx_fflush();
01059   return 0;
01060 }
01061 #else
01062 /* print(const string[], foreground=-1, background=-1, highlight=-1) */
01063 static cell AMX_NATIVE_CALL n_print(AMX *amx,const cell *params)
01064 {
01065   cell *cstr;
01066   int oldcolours;
01067 
01068   CreateConsole();
01069 
01070   /* set the new colours */
01071   oldcolours=amx_setattr((int)params[2],(int)params[3],(int)params[4]);
01072 
01073   cstr=amx_Address(amx,params[1]);
01074   amx_printstring(amx,cstr,NULL);
01075 
01076   /* reset the colours */
01077   (void)amx_setattr(oldcolours & 0xff,(oldcolours >> 8) & 0x7f,(oldcolours >> 15) & 0x01);
01078   amx_fflush();
01079   return 0;
01080 }
01081 #endif
01082 
01083 static cell AMX_NATIVE_CALL n_printf(AMX *amx,const cell *params)
01084 {
01085   cell *cstr;
01086   AMX_FMTINFO info;
01087 
01088   memset(&info,0,sizeof info);
01089   info.params=params+2;
01090   info.numparams=(int)(params[0]/sizeof(cell))-1;
01091   info.skip=0;
01092   info.length=INT_MAX;
01093 
01094   CreateConsole();
01095   cstr=amx_Address(amx,params[1]);
01096   amx_printstring(amx,cstr,&info);
01097   amx_fflush();
01098   return 0;
01099 }
01100 
01101 /* getchar(bool:echo=true) */
01102 static cell AMX_NATIVE_CALL n_getchar(AMX *amx,const cell *params)
01103 {
01104   int c;
01105 
01106   (void)amx;
01107   CreateConsole();
01108   c=amx_getch();
01109   if (params[1]) {
01110     #if defined(SUPPRESS_ECHO)
01111       /* For Mac OS X, non-Curses, don't echo the character */
01112     #else
01113       amx_putchar((TCHAR)c);
01114       amx_fflush();
01115     #endif
01116   } /* if */
01117   return c;
01118 }
01119 
01120 /* getstring(string[], size=sizeof string, bool:pack=false) */
01121 static cell AMX_NATIVE_CALL n_getstring(AMX *amx,const cell *params)
01122 {
01123   int c,chars,max;
01124   cell *cptr;
01125 
01126   (void)amx;
01127   CreateConsole();
01128   chars=0;
01129   max=(int)params[2];
01130   if (max>0) {
01131     #if __STDC_VERSION__ >= 199901L
01132       TCHAR str[max];   /* use C99 feature if available */
01133     #else
01134       TCHAR *str=(TCHAR *)alloca(max*sizeof(TCHAR));
01135       if (str==NULL)
01136         return chars;
01137     #endif
01138 
01139     c=amx_getch();
01140     while (c!=EOF && c!=EOL_CHAR && chars<max-1) {
01141       str[chars++]=(TCHAR)c;
01142       #if defined(SUPPRESS_ECHO)
01143         /* For Mac OS X, non-Curses, don't echo the character */
01144       #else
01145         amx_putchar((TCHAR)c);
01146         amx_fflush();
01147       #endif
01148       if (chars<max-1)
01149         c=amx_getch();
01150     } /* while */
01151 
01152     if (c==EOL_CHAR)
01153       amx_putchar('\n');
01154     assert(chars<max);
01155     str[chars]='\0';
01156 
01157     cptr=amx_Address(amx,params[1]);
01158     amx_SetString(cptr,(char*)str,(int)params[3],sizeof(TCHAR)>1,max);
01159 
01160   } /* if */
01161   return chars;
01162 }
01163 
01164 static void acceptchar(int c,int *num)
01165 {
01166   switch (c) {
01167   case '\b':
01168     amx_putchar('\b');
01169     *num-=1;
01170     #if defined amx_putchar && (defined __BORLANDC__ || defined __WATCOMC__)
01171       /* the backspace key does not erase the
01172        * character, so do this explicitly */
01173       amx_putchar(' ');     /* erase */
01174       amx_putchar('\b');    /* go back */
01175     #endif
01176     break;
01177   case EOL_CHAR:
01178     amx_putchar('\n');
01179     *num+=1;
01180     break;
01181   default:
01182     #if defined(SUPPRESS_ECHO)
01183       /* For Mac OS X, non-Curses, don't echo the character */
01184     #else
01185       amx_putchar((TCHAR)c);
01186     #endif
01187     *num+=1;
01188   } /* switch */
01189   amx_fflush();
01190 }
01191 
01192 static int inlist(AMX *amx,int c,const cell *params,int num)
01193 {
01194   int i, key;
01195 
01196   (void)amx;
01197   for (i=0; i<num; i++) {
01198     if (i==0) {
01199       /* first key is passed by value, others are passed by reference */
01200       key = (int)params[i];
01201     } else {
01202       cell *cptr;
01203       cptr=amx_Address(amx,params[i]);
01204       key=(int)*cptr;
01205     } /* if */
01206     if (c==key || c==-key)
01207       return key;
01208   } /* for */
01209   return 0;
01210 }
01211 
01212 static cell AMX_NATIVE_CALL n_getvalue(AMX *amx,const cell *params)
01213 {
01214   cell value;
01215   int base,sign,c,d;
01216   int chars,n;
01217 
01218   CreateConsole();
01219   base=(int)params[1];
01220   if (base<2 || base>36)
01221     return 0;
01222 
01223   chars=0;
01224   value=0;
01225   sign=1;       /* to avoid a compiler warning (Microsoft Visual C/C++ 6.0) */
01226 
01227   c=amx_getch();
01228   while (c!=EOF) {
01229     /* check for sign (if any) */
01230     if (chars==0) {
01231       if (c=='-') {
01232         sign=-1;
01233         acceptchar(c,&chars);
01234         c=amx_getch();
01235       } else {
01236         sign=1;
01237       } /* if */
01238     } /* if */
01239 
01240     /* check end of input */
01241     #if EOL_CHAR!='\r'
01242       if (c==EOL_CHAR && inlist(amx,'\r',params+2,(int)params[0]/sizeof(cell)-1)!=0)
01243         c='\r';
01244     #endif
01245     if ((chars>1 || chars>0 && sign>0)
01246         && (n=inlist(amx,c,params+2,(int)params[0]/sizeof(cell)-1))!=0)
01247     {
01248       if (n>0)
01249         acceptchar(c,&chars);
01250       break;
01251     } /* if */
01252     #if EOL_CHAR!='\r'
01253       if (c=='\r')
01254         c=EOL_CHAR;
01255     #endif
01256 
01257     /* get value */
01258     d=base;     /* by default, do not accept the character */
01259     if (c>='0' && c<='9') {
01260       d=c-'0';
01261     } else if (c>='a' && c<='z') {
01262       d=c-'a'+10;
01263     } else if (c>='A' && c<='Z') {
01264       d=c-'A'+10;
01265     } else if (c=='\b') {
01266       if (chars>0) {
01267         value/=base;
01268         acceptchar(c,&chars);
01269       } /* if */
01270     } /* if */
01271     if (d<base) {
01272       acceptchar(c,&chars);
01273       value=value*base + d;
01274     } /* if */
01275     c=amx_getch();
01276   } /* while */
01277   return sign*value;
01278 }
01279 
01280 static cell AMX_NATIVE_CALL n_clrscr(AMX *amx,const cell *params)
01281 {
01282   (void)amx;
01283   (void)params;
01284   CreateConsole();
01285   amx_clrscr();
01286   return 0;
01287 }
01288 
01289 static cell AMX_NATIVE_CALL n_clreol(AMX *amx,const cell *params)
01290 {
01291   (void)amx;
01292   (void)params;
01293   CreateConsole();
01294   amx_clreol();
01295   return 0;
01296 }
01297 
01298 static cell AMX_NATIVE_CALL n_gotoxy(AMX *amx,const cell *params)
01299 {
01300   (void)amx;
01301   CreateConsole();
01302   return amx_gotoxy((int)params[1],(int)params[2]);
01303 }
01304 
01305 static cell AMX_NATIVE_CALL n_wherexy(AMX *amx,const cell *params)
01306 {
01307   cell *px,*py;
01308   int x,y;
01309 
01310   (void)amx;
01311   CreateConsole();
01312   amx_wherexy(&x,&y);
01313   px=amx_Address(amx,params[1]);
01314   py=amx_Address(amx,params[2]);
01315   *px=x;
01316   *py=y;
01317   return 0;
01318 }
01319 
01320 static cell AMX_NATIVE_CALL n_setattr(AMX *amx,const cell *params)
01321 {
01322   (void)amx;
01323   CreateConsole();
01324   (void)amx_setattr((int)params[1],(int)params[2],(int)params[3]);
01325   return 0;
01326 }
01327 
01328 static cell AMX_NATIVE_CALL n_consctrl(AMX *amx,const cell *params)
01329 {
01330   (void)amx;
01331   CreateConsole();
01332   (void)amx_termctl((int)params[1],(int)params[2]);
01333   return 0;
01334 }
01335 
01336 static cell AMX_NATIVE_CALL n_console(AMX *amx,const cell *params)
01337 {
01338   (void)amx;
01339   CreateConsole();
01340   amx_console((int)params[1],(int)params[2],(int)params[3]);
01341   return 0;
01342 }
01343 
01344 
01345 #if !defined AMXCONSOLE_NOIDLE
01346 static AMX_IDLE PrevIdle = NULL;
01347 static int idxKeyPressed = -1;
01348 
01349 static int AMXAPI amx_ConsoleIdle(AMX *amx, int AMXAPI Exec(AMX *, cell *, int))
01350 {
01351   int err=0, key;
01352 
01353   assert(idxKeyPressed >= 0);
01354 
01355   if (PrevIdle != NULL)
01356     PrevIdle(amx, Exec);
01357 
01358   if (amx_kbhit()) {
01359     key = amx_getch();
01360     amx_Push(amx, key);
01361     err = Exec(amx, NULL, idxKeyPressed);
01362     while (err == AMX_ERR_SLEEP)
01363       err = Exec(amx, NULL, AMX_EXEC_CONT);
01364   } /* if */
01365 
01366   return err;
01367 }
01368 #endif
01369 
01370 #if defined __cplusplus
01371   extern "C"
01372 #endif
01373 const AMX_NATIVE_INFO console_Natives[] = {
01374 //  { "getchar",   n_getchar },
01375 //  { "getstring", n_getstring },
01376 //  { "getvalue",  n_getvalue },
01377   { "print",     n_print },
01378   { "printf",    n_printf },
01379 //  { "clrscr",    n_clrscr },
01380 //  { "clreol",    n_clreol },
01381 //  { "gotoxy",    n_gotoxy },
01382 //  { "wherexy",   n_wherexy },
01383 //  { "setattr",   n_setattr },
01384 //  { "console",   n_console },
01385 //  { "consctrl",  n_consctrl },
01386   { NULL, NULL }        /* terminator */
01387 };
01388 
01389 int AMXEXPORT AMXAPI amx_ConsoleInit(AMX *amx)
01390 {
01391   #if !defined AMXCONSOLE_NOIDLE
01392     /* see whether there is an @keypressed() function */
01393     if (amx_FindPublic(amx, "@keypressed", &idxKeyPressed) == AMX_ERR_NONE) {
01394       if (amx_GetUserData(amx, AMX_USERTAG('I','d','l','e'), (void**)&PrevIdle) != AMX_ERR_NONE)
01395         PrevIdle = NULL;
01396       amx_SetUserData(amx, AMX_USERTAG('I','d','l','e'), (void*)amx_ConsoleIdle);
01397     } /* if */
01398   #endif
01399 
01400   return amx_Register(amx, console_Natives, -1);
01401 }
01402 
01403 int AMXEXPORT AMXAPI amx_ConsoleCleanup(AMX *amx)
01404 {
01405   (void)amx;
01406   #if !defined AMXCONSOLE_NOIDLE
01407     PrevIdle = NULL;
01408   #endif
01409   return AMX_ERR_NONE;
01410 }
01411 
01412 #endif /* AMX_STRING_LIB */