int AMXEXPORT AMXAPI amx_TimeInit(AMX *amx) { #if !defined AMXTIME_NOIDLE /* see whether there is a @timer() function */ if (amx_FindPublic(amx,"@timer",&idxTimer) == AMX_ERR_NONE) { if (amx_GetUserData(amx, AMX_USERTAG('I','d','l','e'), (void**)&PrevIdle) != AMX_ERR_NONE) PrevIdle = NULL; amx_SetUserData(amx, AMX_USERTAG('I','d','l','e'), (void*)amx_TimeIdle); } /* if */ #endif return amx_Register(amx, time_Natives, -1); }
int AMXEXPORT AMXAPI amx_DGramInit(AMX *amx) { dgramBound = 0; if (udp_Open()==-1) return AMX_ERR_GENERAL; /* see whether there is an @receivestring() function */ if (amx_FindPublic(amx,"@receivestring",&idxReceiveString)==AMX_ERR_NONE || amx_FindPublic(amx,"@receivepacket",&idxReceivePacket)==AMX_ERR_NONE) { if (amx_GetUserData(amx,AMX_USERTAG('I','d','l','e'),(void**)&PrevIdle)!=AMX_ERR_NONE) PrevIdle=NULL; amx_SetUserData(amx,AMX_USERTAG('I','d','l','e'),amx_DGramIdle); } /* if */ return amx_Register(amx,dgram_Natives,-1); }
int main(int argc,char *argv[]) { AMX amx; cell ret = 0; int err, i; clock_t start,end; STACKINFO stackinfo = { 0 }; AMX_IDLE idlefunc; if (argc < 2) PrintUsage(argv[0]); /* function "usage" aborts the program */ #if !defined AMX_NODYNALOAD && defined ENABLE_BINRELOC && (defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__) /* see www.autopackage.org for the BinReloc module */ if (br_init(NULL)) { char *libroot=br_find_exe_dir(""); setenv("AMXLIB",libroot,0); free(libroot); } /* if */ #endif /* Load the program and initialize the abstract machine. */ err = aux_LoadProgram(&amx, argv[1]); if (err != AMX_ERR_NONE) { /* try adding an extension */ char filename[_MAX_PATH]; strcpy(filename, argv[1]); strcat(filename, ".amx"); err = aux_LoadProgram(&amx, filename); if (err != AMX_ERR_NONE) PrintUsage(argv[0]); } /* if */ /* To install the debug hook "just-in-time", the signal function needs * a pointer to the abstract machine(s) to abort. There are various ways * to implement this; here I have done so with a simple global variable. */ global_amx = &amx; signal(SIGINT, sigabort); /* Initialize two core extension modules (more extension modules may be * loaded & initialized automatically as DLLs or shared libraries. */ amx_ConsoleInit(&amx); err = amx_CoreInit(&amx); ExitOnError(&amx, err); /* save the idle function, if set by any of the extension modules */ if (amx_GetUserData(&amx, AMX_USERTAG('I','d','l','e'), (void**)&idlefunc) != AMX_ERR_NONE) idlefunc = NULL; for (i = 2; i < argc; i++) { if (strcmp(argv[i],"-stack") == 0) { uint16_t flags; amx_Flags(&amx, &flags); if ((flags & AMX_FLAG_NOCHECKS) != 0) printf("This script was compiled with debug information removed.\n" "Stack monitoring is disfunctional\n\n"); /* Set "user data" with which the debug monitor can monitor stack usage * per abstract machine (in this example, though, there is only one abstract * machine, so a global variable would have sufficed). */ memset(&stackinfo, 0, sizeof stackinfo); err = amx_SetUserData(&amx, AMX_USERTAG('S','t','c','k'), &stackinfo); ExitOnError(&amx, err); /* Install the debug hook, so that we can start monitoring the stack/heap * usage right from the beginning of the script. */ amx_SetDebugHook(&amx, prun_Monitor); } /* if */ } /* for */ start=clock(); /* Run the compiled script and time it. The "sleep" instruction causes the * abstract machine to return in a "restartable" state (it restarts from * the point that it stopped. This allows for a kind of light-weight * cooperative multi-tasking. As native functions (or the debug hook) can * also force an abstract machine to "sleep", you can also use it to create * "latent functions": functions that allow the host application to continue * processing, and/or other abstract machines to run, while they wait for * some resource. */ err = amx_Exec(&amx, &ret, AMX_EXEC_MAIN); while (err == AMX_ERR_SLEEP) { if (idlefunc != NULL) { /* If the abstract machine was put to sleep, we can handle events during * that time. To save the "restart point", we must make a copy of the AMX * (keeping the stack, frame, instruction pointer and other vital * registers), but without cloning the entire abstract machine. * There should be some criterion on when the abstract machine must be * "woken up". In this example run-time, the parameter of the sleep * instruction is taken to be a delay in milliseconds. In your own host * application, you can choose to wait on a resource/semaphore or other. */ AMX nested_amx = amx; clock_t stamp = clock(); while (((clock() - stamp)*1000)/CLOCKS_PER_SEC < amx.pri && (err = idlefunc(&nested_amx,amx_Exec)) == AMX_ERR_NONE) /* nothing */; ExitOnError(&nested_amx, err); } /* if */ err = amx_Exec(&amx, &ret, AMX_EXEC_CONT); } /* while */ if (idlefunc == NULL || err != AMX_ERR_INDEX) ExitOnError(&amx, err); /* event-driven programs may not have main() */ /* For event-driven programs, we also need to loop over the idle/monitor * function that some extension module installed (this could be the console * module, for example). We did this if the main program was put to "sleep", * but we do that here too. */ if (idlefunc != NULL) { while ((err = idlefunc(&amx,amx_Exec)) == AMX_ERR_NONE) /* nothing */; ExitOnError(&amx, err); } /* if */ end=clock(); /* Free the compiled script and resources. This also unloads and DLLs or * shared libraries that were registered automatically by amx_Init(). */ aux_FreeProgram(&amx); /* Print the return code of the compiled script (often not very useful), * its run time, and its stack usage. */ if (ret!=0) printf("\nReturn value: %ld\n", (long)ret); printf("\nRun time: %.2f seconds\n",(double)(end-start)/CLOCKS_PER_SEC); if (stackinfo.maxstack != 0 || stackinfo.maxheap != 0) { printf("Stack usage: %ld cells (%ld bytes)\n", stackinfo.maxstack / sizeof(cell), stackinfo.maxstack); printf("Heap usage: %ld cells (%ld bytes)\n", stackinfo.maxheap / sizeof(cell), stackinfo.maxheap); } /* if */ #if defined AMX_TERMINAL /* This is likely a graphical terminal, which should not be closed * automatically */ { extern int amx_termctl(int,int); while (amx_termctl(4,0)) /* nothing */; } #endif return 0; }