Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ea7d7ba19f | |||
| dc9f84ba4c | |||
| 5cd901e5a9 | |||
| fe39cd6c60 | |||
| 5bd290c95d | |||
| d117cd3b8b | |||
| b51ef4ba64 | |||
| d1e8425b09 | |||
| 770971142f | |||
| 90f057fc5e | |||
| 948870215d | |||
| a125e799ad | |||
| e6d4833e8b | |||
| 9c4c94093c | |||
| 52d2fcf0d3 | |||
| 884df104bd | |||
| c0d1b1fecf | |||
| 380295aed0 | |||
| 0142d79d91 | |||
| 14a7fda8b7 | |||
| 6cfddadf43 | |||
| bc006b8f72 | |||
| 569221d047 | |||
| 4a1627835f | |||
| f4eac55989 | |||
| 5c0b046ad8 | |||
| 7739b563f3 | |||
| 6e5f9fb1a8 | |||
| 6f5bdd274a | |||
| 6a24086556 | |||
| b78fbe4378 | |||
| 9f8533f62b | |||
| 8a4110e821 | |||
| 0547378331 |
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
mini.exe
|
/mini.exe
|
||||||
mini
|
/mini
|
||||||
mini_debug.exe
|
mini_debug.exe
|
||||||
mini_debug
|
mini_debug
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
+4
-2
@@ -9,10 +9,12 @@ IF "%1"=="" (
|
|||||||
set PARAM=%1
|
set PARAM=%1
|
||||||
|
|
||||||
echo Compilando windows...
|
echo Compilando windows...
|
||||||
make windows || exit /b 1
|
rmdir /S /Q build || exit /b 1
|
||||||
|
lagueirto windows || exit /b 1
|
||||||
|
|
||||||
echo Compilando windows_debug...
|
echo Compilando windows_debug...
|
||||||
make windows_debug || exit /b 1
|
rmdir /S /Q build || exit /b 1
|
||||||
|
lagueirto windows_debug || exit /b 1
|
||||||
|
|
||||||
echo Creando paquetes...
|
echo Creando paquetes...
|
||||||
|
|
||||||
|
|||||||
+10
-8
@@ -7,20 +7,22 @@ set -e
|
|||||||
#fi
|
#fi
|
||||||
|
|
||||||
# Leer versión desde version.h
|
# Leer versión desde version.h
|
||||||
VERSION=$(grep '#define MINI_VERSION' version.h | sed 's/.*"\(.*\)".*/\1/')
|
VERSION=$(grep '#define MINI_VERSION' source/mini/version.h | sed 's/.*"\(.*\)".*/\1/')
|
||||||
echo "Versión detectada: $VERSION"
|
echo "Versión detectada: $VERSION"
|
||||||
|
|
||||||
#PARAM=$1
|
#PARAM=$1
|
||||||
|
|
||||||
# Datos Windows
|
# Datos Windows
|
||||||
WIN_USER="raimon"
|
WIN_USER="raimon"
|
||||||
WIN_HOST="tonlab19"
|
WIN_HOST="192.168.1.53"
|
||||||
WIN_PATH_SSH="C:\Users\raimon\dev\mini"
|
WIN_PATH_SSH="C:\Users\raimon\dev\mini"
|
||||||
WIN_PATH_SCP="C:/Users/Raimon/dev/mini"
|
WIN_PATH_SCP="C:/Users/Raimon/dev/mini"
|
||||||
|
|
||||||
echo "=== Compilando Linux ==="
|
echo "=== Compilando Linux ==="
|
||||||
make linux
|
rm -rf build
|
||||||
make linux_debug
|
lagueirto linux
|
||||||
|
rm -rf build
|
||||||
|
lagueirto linux_debug
|
||||||
|
|
||||||
echo "=== Empaquetando Linux ==="
|
echo "=== Empaquetando Linux ==="
|
||||||
tar -czf mini_v${VERSION}_linux_release.tar.gz mini
|
tar -czf mini_v${VERSION}_linux_release.tar.gz mini
|
||||||
@@ -30,12 +32,12 @@ echo "=== Ejecutando build remoto Windows ==="
|
|||||||
ssh ${WIN_USER}@${WIN_HOST} "cd ${WIN_PATH_SSH} && do_release.bat v${VERSION}"
|
ssh ${WIN_USER}@${WIN_HOST} "cd ${WIN_PATH_SSH} && do_release.bat v${VERSION}"
|
||||||
|
|
||||||
echo "=== Copiando ZIPs desde Windows ==="
|
echo "=== Copiando ZIPs desde Windows ==="
|
||||||
scp ${WIN_USER}@${WIN_HOST}:"${WIN_PATH_SCP}/mini_v${VERSION}_windows_release.zip" .
|
scp ${WIN_USER}@${WIN_HOST}:"${WIN_PATH_SCP}/mini_v${VERSION}_win32-x64_release.zip" .
|
||||||
scp ${WIN_USER}@${WIN_HOST}:"${WIN_PATH_SCP}/mini_v${VERSION}_windows_debug.zip" .
|
scp ${WIN_USER}@${WIN_HOST}:"${WIN_PATH_SCP}/mini_v${VERSION}_win32-x64_debug.zip" .
|
||||||
|
|
||||||
echo "=== Build completado correctamente ==="
|
echo "=== Build completado correctamente ==="
|
||||||
echo "Generados:"
|
echo "Generados:"
|
||||||
echo " mini_v${VERSION}_linux_release.tar.gz"
|
echo " mini_v${VERSION}_linux_release.tar.gz"
|
||||||
echo " mini_v${VERSION}_linux_debug.tar.gz"
|
echo " mini_v${VERSION}_linux_debug.tar.gz"
|
||||||
echo " mini_v${VERSION}_windows_release.zip"
|
echo " mini_v${VERSION}_win32-x64_release.zip"
|
||||||
echo " mini_v${VERSION}_windows_debug.zip"
|
echo " mini_v${VERSION}_win32-x64_debug.zip"
|
||||||
|
|||||||
-507
@@ -1,507 +0,0 @@
|
|||||||
#ifndef JA_USESDLMIXER
|
|
||||||
#include "jail_audio.h"
|
|
||||||
#include "stb_vorbis.h"
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
#define JA_MAX_SIMULTANEOUS_CHANNELS 5
|
|
||||||
|
|
||||||
struct JA_Sound_t
|
|
||||||
{
|
|
||||||
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
|
|
||||||
Uint32 length { 0 };
|
|
||||||
Uint8 *buffer { NULL };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct JA_Channel_t
|
|
||||||
{
|
|
||||||
JA_Sound_t *sound { nullptr };
|
|
||||||
int pos { 0 };
|
|
||||||
int times { 0 };
|
|
||||||
SDL_AudioStream *stream { nullptr };
|
|
||||||
JA_Channel_state state { JA_CHANNEL_FREE };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct JA_Music_t
|
|
||||||
{
|
|
||||||
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
|
|
||||||
Uint32 length { 0 };
|
|
||||||
Uint8 *buffer { nullptr };
|
|
||||||
|
|
||||||
int pos { 0 };
|
|
||||||
int times { 0 };
|
|
||||||
SDL_AudioStream *stream { nullptr };
|
|
||||||
JA_Music_state state { JA_MUSIC_INVALID };
|
|
||||||
};
|
|
||||||
|
|
||||||
JA_Music_t *current_music { nullptr };
|
|
||||||
JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS];
|
|
||||||
|
|
||||||
SDL_AudioSpec JA_audioSpec { SDL_AUDIO_S16, 2, 48000 };
|
|
||||||
float JA_musicVolume { 1.0f };
|
|
||||||
float JA_soundVolume { 0.5f };
|
|
||||||
bool JA_musicEnabled { true };
|
|
||||||
bool JA_soundEnabled { true };
|
|
||||||
SDL_AudioDeviceID sdlAudioDevice { 0 };
|
|
||||||
SDL_TimerID JA_timerID { 0 };
|
|
||||||
|
|
||||||
bool fading = false;
|
|
||||||
int fade_start_time;
|
|
||||||
int fade_duration;
|
|
||||||
int fade_initial_volume;
|
|
||||||
|
|
||||||
/*
|
|
||||||
void audioCallback(void * userdata, uint8_t * stream, int len) {
|
|
||||||
SDL_memset(stream, 0, len);
|
|
||||||
if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) {
|
|
||||||
const int size = SDL_min(len, current_music->samples*2-current_music->pos);
|
|
||||||
SDL_MixAudioFormat(stream, (Uint8*)(current_music->output+current_music->pos), AUDIO_S16, size, JA_musicVolume);
|
|
||||||
current_music->pos += size/2;
|
|
||||||
if (size < len) {
|
|
||||||
if (current_music->times != 0) {
|
|
||||||
SDL_MixAudioFormat(stream+size, (Uint8*)current_music->output, AUDIO_S16, len-size, JA_musicVolume);
|
|
||||||
current_music->pos = (len-size)/2;
|
|
||||||
if (current_music->times > 0) current_music->times--;
|
|
||||||
} else {
|
|
||||||
current_music->pos = 0;
|
|
||||||
current_music->state = JA_MUSIC_STOPPED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Mixar els channels mi amol
|
|
||||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
|
|
||||||
if (channels[i].state == JA_CHANNEL_PLAYING) {
|
|
||||||
const int size = SDL_min(len, channels[i].sound->length - channels[i].pos);
|
|
||||||
SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume);
|
|
||||||
channels[i].pos += size;
|
|
||||||
if (size < len) {
|
|
||||||
if (channels[i].times != 0) {
|
|
||||||
SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len-size, JA_soundVolume);
|
|
||||||
channels[i].pos = len-size;
|
|
||||||
if (channels[i].times > 0) channels[i].times--;
|
|
||||||
} else {
|
|
||||||
JA_StopChannel(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
Uint32 JA_UpdateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval)
|
|
||||||
{
|
|
||||||
if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING)
|
|
||||||
{
|
|
||||||
if (fading) {
|
|
||||||
int time = SDL_GetTicks();
|
|
||||||
if (time > (fade_start_time+fade_duration)) {
|
|
||||||
fading = false;
|
|
||||||
JA_StopMusic();
|
|
||||||
return 30;
|
|
||||||
} else {
|
|
||||||
const int time_passed = time - fade_start_time;
|
|
||||||
const float percent = (float)time_passed / (float)fade_duration;
|
|
||||||
SDL_SetAudioStreamGain(current_music->stream, 1.0 - percent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current_music->times != 0)
|
|
||||||
{
|
|
||||||
if (SDL_GetAudioStreamAvailable(current_music->stream) < int(current_music->length/2)) {
|
|
||||||
SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length);
|
|
||||||
}
|
|
||||||
if (current_music->times>0) current_music->times--;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (SDL_GetAudioStreamAvailable(current_music->stream) == 0) JA_StopMusic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (JA_soundEnabled)
|
|
||||||
{
|
|
||||||
for (int i=0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i)
|
|
||||||
if (channels[i].state == JA_CHANNEL_PLAYING)
|
|
||||||
{
|
|
||||||
if (channels[i].times != 0)
|
|
||||||
{
|
|
||||||
if (SDL_GetAudioStreamAvailable(channels[i].stream) < int(channels[i].sound->length/2))
|
|
||||||
SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer, channels[i].sound->length);
|
|
||||||
if (channels[i].times>0) channels[i].times--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) JA_StopChannel(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JA_audioSpec = {format, channels, freq };
|
|
||||||
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
|
|
||||||
sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec);
|
|
||||||
if (!sdlAudioDevice) {
|
|
||||||
log_msg(LOG_FAIL, "Failed to initialize SDL audio: %s\n", SDL_GetError());
|
|
||||||
} else {
|
|
||||||
log_msg(LOG_OK, "Audio subsytem initialized\n");
|
|
||||||
}
|
|
||||||
//SDL_PauseAudioDevice(sdlAudioDevice);
|
|
||||||
JA_timerID = SDL_AddTimer(30, JA_UpdateCallback, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_Quit()
|
|
||||||
{
|
|
||||||
if (JA_timerID) SDL_RemoveTimer(JA_timerID);
|
|
||||||
|
|
||||||
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
|
|
||||||
sdlAudioDevice = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length)
|
|
||||||
{
|
|
||||||
JA_Music_t *music = new JA_Music_t();
|
|
||||||
|
|
||||||
int chan, samplerate;
|
|
||||||
short *output;
|
|
||||||
music->length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2;
|
|
||||||
|
|
||||||
music->spec.channels = chan;
|
|
||||||
music->spec.freq = samplerate;
|
|
||||||
music->spec.format = SDL_AUDIO_S16;
|
|
||||||
music->buffer = (Uint8*)SDL_malloc(music->length);
|
|
||||||
SDL_memcpy(music->buffer, output, music->length);
|
|
||||||
free(output);
|
|
||||||
music->pos = 0;
|
|
||||||
music->state = JA_MUSIC_STOPPED;
|
|
||||||
|
|
||||||
return music;
|
|
||||||
}
|
|
||||||
|
|
||||||
JA_Music_t *JA_LoadMusic(const char* filename)
|
|
||||||
{
|
|
||||||
// [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid.
|
|
||||||
FILE *f = fopen(filename, "rb");
|
|
||||||
fseek(f, 0, SEEK_END);
|
|
||||||
long fsize = ftell(f);
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
Uint8 *buffer = (Uint8*)malloc(fsize + 1);
|
|
||||||
if (fread(buffer, fsize, 1, f)!=1) return NULL;
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
JA_Music_t *music = JA_LoadMusic(buffer, fsize);
|
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
|
|
||||||
return music;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_PlayMusic(JA_Music_t *music, const int loop)
|
|
||||||
{
|
|
||||||
if (!JA_musicEnabled) return;
|
|
||||||
|
|
||||||
JA_StopMusic();
|
|
||||||
|
|
||||||
current_music = music;
|
|
||||||
current_music->pos = 0;
|
|
||||||
current_music->state = JA_MUSIC_PLAYING;
|
|
||||||
current_music->times = loop;
|
|
||||||
|
|
||||||
current_music->stream = SDL_CreateAudioStream(¤t_music->spec, &JA_audioSpec);
|
|
||||||
if (!SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length)) log_msg(LOG_FAIL, "SDL_PutAudioStreamData failed!\n");
|
|
||||||
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
|
|
||||||
if (!SDL_BindAudioStream(sdlAudioDevice, current_music->stream)) log_msg(LOG_FAIL, "SDL_BindAudioStream failed!\n");
|
|
||||||
//SDL_ResumeAudioStreamDevice(current_music->stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_PauseMusic()
|
|
||||||
{
|
|
||||||
if (!JA_musicEnabled) return;
|
|
||||||
if (!current_music || current_music->state == JA_MUSIC_INVALID) return;
|
|
||||||
|
|
||||||
current_music->state = JA_MUSIC_PAUSED;
|
|
||||||
//SDL_PauseAudioStreamDevice(current_music->stream);
|
|
||||||
SDL_UnbindAudioStream(current_music->stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_ResumeMusic()
|
|
||||||
{
|
|
||||||
if (!JA_musicEnabled) return;
|
|
||||||
if (!current_music || current_music->state == JA_MUSIC_INVALID) return;
|
|
||||||
|
|
||||||
current_music->state = JA_MUSIC_PLAYING;
|
|
||||||
//SDL_ResumeAudioStreamDevice(current_music->stream);
|
|
||||||
SDL_BindAudioStream(sdlAudioDevice, current_music->stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_StopMusic()
|
|
||||||
{
|
|
||||||
if (!JA_musicEnabled) return;
|
|
||||||
if (!current_music || current_music->state == JA_MUSIC_INVALID) return;
|
|
||||||
|
|
||||||
current_music->pos = 0;
|
|
||||||
current_music->state = JA_MUSIC_STOPPED;
|
|
||||||
//SDL_PauseAudioStreamDevice(current_music->stream);
|
|
||||||
SDL_DestroyAudioStream(current_music->stream);
|
|
||||||
current_music->stream = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_FadeOutMusic(const int milliseconds)
|
|
||||||
{
|
|
||||||
if (!JA_musicEnabled) return;
|
|
||||||
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
|
|
||||||
|
|
||||||
fading = true;
|
|
||||||
fade_start_time = SDL_GetTicks();
|
|
||||||
fade_duration = milliseconds;
|
|
||||||
fade_initial_volume = JA_musicVolume;
|
|
||||||
}
|
|
||||||
|
|
||||||
JA_Music_state JA_GetMusicState()
|
|
||||||
{
|
|
||||||
if (!JA_musicEnabled) return JA_MUSIC_DISABLED;
|
|
||||||
if (!current_music) return JA_MUSIC_INVALID;
|
|
||||||
|
|
||||||
return current_music->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_DeleteMusic(JA_Music_t *music)
|
|
||||||
{
|
|
||||||
if (current_music == music) current_music = nullptr;
|
|
||||||
SDL_free(music->buffer);
|
|
||||||
if (music->stream) SDL_DestroyAudioStream(music->stream);
|
|
||||||
delete music;
|
|
||||||
}
|
|
||||||
|
|
||||||
float JA_SetMusicVolume(float volume)
|
|
||||||
{
|
|
||||||
JA_musicVolume = SDL_clamp( volume, 0.0f, 1.0f );
|
|
||||||
if (current_music) SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
|
|
||||||
return JA_musicVolume;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_SetMusicPosition(float value)
|
|
||||||
{
|
|
||||||
if (!current_music) return;
|
|
||||||
current_music->pos = value * current_music->spec.freq;
|
|
||||||
}
|
|
||||||
|
|
||||||
float JA_GetMusicPosition()
|
|
||||||
{
|
|
||||||
if (!current_music) return 0;
|
|
||||||
return float(current_music->pos)/float(current_music->spec.freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_EnableMusic(const bool value)
|
|
||||||
{
|
|
||||||
if ( !value && current_music && (current_music->state==JA_MUSIC_PLAYING) ) JA_StopMusic();
|
|
||||||
|
|
||||||
JA_musicEnabled = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool JA_IsMusicEnabled()
|
|
||||||
{
|
|
||||||
return JA_musicEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length)
|
|
||||||
{
|
|
||||||
JA_Sound_t *sound = new JA_Sound_t();
|
|
||||||
sound->buffer = buffer;
|
|
||||||
sound->length = length;
|
|
||||||
return sound;
|
|
||||||
}
|
|
||||||
|
|
||||||
JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size)
|
|
||||||
{
|
|
||||||
JA_Sound_t *sound = new JA_Sound_t();
|
|
||||||
SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size),1, &sound->spec, &sound->buffer, &sound->length);
|
|
||||||
|
|
||||||
return sound;
|
|
||||||
}
|
|
||||||
|
|
||||||
JA_Sound_t *JA_LoadSound(const char* filename)
|
|
||||||
{
|
|
||||||
JA_Sound_t *sound = new JA_Sound_t();
|
|
||||||
SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length);
|
|
||||||
|
|
||||||
return sound;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JA_PlaySound(JA_Sound_t *sound, const int loop)
|
|
||||||
{
|
|
||||||
if (!JA_soundEnabled) return -1;
|
|
||||||
|
|
||||||
int channel = 0;
|
|
||||||
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; }
|
|
||||||
if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channel = 0;
|
|
||||||
JA_StopChannel(channel);
|
|
||||||
|
|
||||||
channels[channel].sound = sound;
|
|
||||||
channels[channel].times = loop;
|
|
||||||
channels[channel].pos = 0;
|
|
||||||
channels[channel].state = JA_CHANNEL_PLAYING;
|
|
||||||
channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec);
|
|
||||||
SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer, channels[channel].sound->length);
|
|
||||||
SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume);
|
|
||||||
SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream);
|
|
||||||
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop)
|
|
||||||
{
|
|
||||||
if (!JA_soundEnabled) return -1;
|
|
||||||
|
|
||||||
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1;
|
|
||||||
JA_StopChannel(channel);
|
|
||||||
|
|
||||||
channels[channel].sound = sound;
|
|
||||||
channels[channel].times = loop;
|
|
||||||
channels[channel].pos = 0;
|
|
||||||
channels[channel].state = JA_CHANNEL_PLAYING;
|
|
||||||
channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec);
|
|
||||||
SDL_PutAudioStreamData(channels[channel].stream, channels[channel].sound->buffer, channels[channel].sound->length);
|
|
||||||
SDL_SetAudioStreamGain(channels[channel].stream, JA_soundVolume);
|
|
||||||
SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream);
|
|
||||||
|
|
||||||
return channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_DeleteSound(JA_Sound_t *sound)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
|
|
||||||
if (channels[i].sound == sound) JA_StopChannel(i);
|
|
||||||
}
|
|
||||||
SDL_free(sound->buffer);
|
|
||||||
delete sound;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_PauseChannel(const int channel)
|
|
||||||
{
|
|
||||||
if (!JA_soundEnabled) return;
|
|
||||||
|
|
||||||
if (channel == -1)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
|
||||||
if (channels[i].state == JA_CHANNEL_PLAYING)
|
|
||||||
{
|
|
||||||
channels[i].state = JA_CHANNEL_PAUSED;
|
|
||||||
//SDL_PauseAudioStreamDevice(channels[i].stream);
|
|
||||||
SDL_UnbindAudioStream(channels[i].stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
|
|
||||||
{
|
|
||||||
if (channels[channel].state == JA_CHANNEL_PLAYING)
|
|
||||||
{
|
|
||||||
channels[channel].state = JA_CHANNEL_PAUSED;
|
|
||||||
//SDL_PauseAudioStreamDevice(channels[channel].stream);
|
|
||||||
SDL_UnbindAudioStream(channels[channel].stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_ResumeChannel(const int channel)
|
|
||||||
{
|
|
||||||
if (!JA_soundEnabled) return;
|
|
||||||
|
|
||||||
if (channel == -1)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
|
||||||
if (channels[i].state == JA_CHANNEL_PAUSED)
|
|
||||||
{
|
|
||||||
channels[i].state = JA_CHANNEL_PLAYING;
|
|
||||||
//SDL_ResumeAudioStreamDevice(channels[i].stream);
|
|
||||||
SDL_BindAudioStream(sdlAudioDevice, channels[i].stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
|
|
||||||
{
|
|
||||||
if (channels[channel].state == JA_CHANNEL_PAUSED)
|
|
||||||
{
|
|
||||||
channels[channel].state = JA_CHANNEL_PLAYING;
|
|
||||||
//SDL_ResumeAudioStreamDevice(channels[channel].stream);
|
|
||||||
SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_StopChannel(const int channel)
|
|
||||||
{
|
|
||||||
if (!JA_soundEnabled) return;
|
|
||||||
|
|
||||||
if (channel == -1)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
|
|
||||||
if (channels[i].state != JA_CHANNEL_FREE) SDL_DestroyAudioStream(channels[i].stream);
|
|
||||||
channels[i].stream = nullptr;
|
|
||||||
channels[i].state = JA_CHANNEL_FREE;
|
|
||||||
channels[i].pos = 0;
|
|
||||||
channels[i].sound = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
|
|
||||||
{
|
|
||||||
if (channels[channel].state != JA_CHANNEL_FREE) SDL_DestroyAudioStream(channels[channel].stream);
|
|
||||||
channels[channel].stream = nullptr;
|
|
||||||
channels[channel].state = JA_CHANNEL_FREE;
|
|
||||||
channels[channel].pos = 0;
|
|
||||||
channels[channel].sound = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JA_Channel_state JA_GetChannelState(const int channel)
|
|
||||||
{
|
|
||||||
if (!JA_soundEnabled) return JA_SOUND_DISABLED;
|
|
||||||
|
|
||||||
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID;
|
|
||||||
|
|
||||||
return channels[channel].state;
|
|
||||||
}
|
|
||||||
|
|
||||||
float JA_SetSoundVolume(float volume)
|
|
||||||
{
|
|
||||||
JA_soundVolume = SDL_clamp( volume, 0.0f, 1.0f );
|
|
||||||
|
|
||||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
|
||||||
if ( (channels[i].state == JA_CHANNEL_PLAYING) || (channels[i].state == JA_CHANNEL_PAUSED) )
|
|
||||||
SDL_SetAudioStreamGain(channels[i].stream, JA_soundVolume);
|
|
||||||
|
|
||||||
return JA_soundVolume;
|
|
||||||
}
|
|
||||||
|
|
||||||
void JA_EnableSound(const bool value)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
|
||||||
{
|
|
||||||
if (channels[i].state == JA_CHANNEL_PLAYING) JA_StopChannel(i);
|
|
||||||
}
|
|
||||||
JA_soundEnabled = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool JA_IsSoundEnabled()
|
|
||||||
{
|
|
||||||
return JA_soundEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
float JA_SetVolume(float volume)
|
|
||||||
{
|
|
||||||
JA_SetSoundVolume(JA_SetMusicVolume(volume) / 2.0f);
|
|
||||||
|
|
||||||
return JA_musicVolume;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
|
|
||||||
enum JA_Channel_state { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED };
|
|
||||||
enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED };
|
|
||||||
|
|
||||||
struct JA_Sound_t;
|
|
||||||
struct JA_Music_t;
|
|
||||||
|
|
||||||
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels);
|
|
||||||
void JA_Quit();
|
|
||||||
|
|
||||||
JA_Music_t *JA_LoadMusic(const char* filename);
|
|
||||||
JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length);
|
|
||||||
void JA_PlayMusic(JA_Music_t *music, const int loop = -1);
|
|
||||||
void JA_PauseMusic();
|
|
||||||
void JA_ResumeMusic();
|
|
||||||
void JA_StopMusic();
|
|
||||||
void JA_FadeOutMusic(const int milliseconds);
|
|
||||||
JA_Music_state JA_GetMusicState();
|
|
||||||
void JA_DeleteMusic(JA_Music_t *music);
|
|
||||||
float JA_SetMusicVolume(float volume);
|
|
||||||
void JA_SetMusicPosition(float value);
|
|
||||||
float JA_GetMusicPosition();
|
|
||||||
void JA_EnableMusic(const bool value);
|
|
||||||
const bool JA_IsMusicEnabled();
|
|
||||||
|
|
||||||
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length);
|
|
||||||
JA_Sound_t *JA_LoadSound(Uint8* buffer, Uint32 length);
|
|
||||||
JA_Sound_t *JA_LoadSound(const char* filename);
|
|
||||||
int JA_PlaySound(JA_Sound_t *sound, const int loop = 0);
|
|
||||||
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop = 0);
|
|
||||||
void JA_PauseChannel(const int channel);
|
|
||||||
void JA_ResumeChannel(const int channel);
|
|
||||||
void JA_StopChannel(const int channel);
|
|
||||||
JA_Channel_state JA_GetChannelState(const int channel);
|
|
||||||
void JA_DeleteSound(JA_Sound_t *sound);
|
|
||||||
float JA_SetSoundVolume(float volume);
|
|
||||||
void JA_EnableSound(const bool value);
|
|
||||||
const bool JA_IsSoundEnabled();
|
|
||||||
|
|
||||||
float JA_SetVolume(float volume);
|
|
||||||
@@ -1,384 +0,0 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "jfile.h"
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <dirent.h> // Para opendir/readdir en SOURCE_FOLDER
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <pwd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEFAULT_FILENAME "data.jf2"
|
|
||||||
#define DEFAULT_FOLDER "data/"
|
|
||||||
#define CONFIG_FILENAME "config.txt"
|
|
||||||
|
|
||||||
struct file_t
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
uint32_t size;
|
|
||||||
uint32_t offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<file_t> toc;
|
|
||||||
|
|
||||||
/* El std::map me fa coses rares, vaig a usar un good old std::vector amb una estructura key,value propia i au, que sempre funciona */
|
|
||||||
struct keyvalue_t {
|
|
||||||
std::string key, value;
|
|
||||||
};
|
|
||||||
|
|
||||||
char *resource_filename = NULL;
|
|
||||||
char *resource_folder = NULL;
|
|
||||||
int file_source = SOURCE_FILE;
|
|
||||||
char scratch[255];
|
|
||||||
static std::string config_folder;
|
|
||||||
std::vector<keyvalue_t> config;
|
|
||||||
|
|
||||||
void file_setresourcefilename(const char *str) {
|
|
||||||
if (resource_filename != NULL) free(resource_filename);
|
|
||||||
resource_filename = (char*)malloc(strlen(str)+1);
|
|
||||||
strcpy(resource_filename, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_setresourcefolder(const char *str) {
|
|
||||||
if (resource_folder != NULL) free(resource_folder);
|
|
||||||
resource_folder = (char*)malloc(strlen(str)+1);
|
|
||||||
strcpy(resource_folder, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_setsource(const int src) {
|
|
||||||
file_source = src%2; // mod 2 so it always is a valid value, 0 (file) or 1 (folder)
|
|
||||||
if (src==SOURCE_FOLDER && resource_folder==NULL) file_setresourcefolder(DEFAULT_FOLDER);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_getdictionary() {
|
|
||||||
if (resource_filename == NULL) file_setresourcefilename(DEFAULT_FILENAME);
|
|
||||||
|
|
||||||
std::ifstream fi (resource_filename, std::ios::binary);
|
|
||||||
if (!fi.is_open()) return false;
|
|
||||||
char header[4];
|
|
||||||
fi.read(header, 4);
|
|
||||||
uint32_t num_files, toc_offset;
|
|
||||||
fi.read((char*)&num_files, 4);
|
|
||||||
fi.read((char*)&toc_offset, 4);
|
|
||||||
fi.seekg(toc_offset);
|
|
||||||
|
|
||||||
for (uint32_t i=0; i<num_files; ++i)
|
|
||||||
{
|
|
||||||
uint32_t file_offset, file_size;
|
|
||||||
fi.read( (char*)&file_offset, 4 );
|
|
||||||
fi.read( (char*)&file_size, 4 );
|
|
||||||
uint8_t path_size;
|
|
||||||
fi.read( (char*)&path_size, 1 );
|
|
||||||
char *file_name = (char*)malloc(path_size+1);
|
|
||||||
fi.read( file_name, path_size );
|
|
||||||
file_name[path_size] = 0;
|
|
||||||
std::string filename = file_name;
|
|
||||||
free(file_name);
|
|
||||||
toc.push_back({filename, file_size, file_offset});
|
|
||||||
}
|
|
||||||
fi.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *file_getfilenamewithfolder(const char* filename) {
|
|
||||||
strcpy(scratch, resource_folder);
|
|
||||||
strcat(scratch, filename);
|
|
||||||
return scratch;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool binary) {
|
|
||||||
|
|
||||||
if (file_source==SOURCE_FILE and toc.size()==0) {
|
|
||||||
if (not file_getdictionary()) file_setsource(SOURCE_FOLDER);
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *f;
|
|
||||||
|
|
||||||
if (file_source==SOURCE_FILE) {
|
|
||||||
bool found = false;
|
|
||||||
uint32_t count = 0;
|
|
||||||
while( !found && count < toc.size() ) {
|
|
||||||
found = ( std::string(resourcename) == toc[count].path );
|
|
||||||
if( !found ) count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !found ) {
|
|
||||||
perror("El recurs no s'ha trobat en l'arxiu de recursos");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
filesize = toc[count].size;
|
|
||||||
|
|
||||||
f = fopen(resource_filename, binary?"rb":"r");
|
|
||||||
if (not f) {
|
|
||||||
perror("No s'ha pogut obrir l'arxiu de recursos");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
fseek(f, toc[count].offset, SEEK_SET);
|
|
||||||
} else {
|
|
||||||
f = fopen(file_getfilenamewithfolder(resourcename), binary?"rb":"r");
|
|
||||||
fseek(f, 0, SEEK_END);
|
|
||||||
filesize = ftell(f);
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
}
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *file_getfilebuffer(const char *resourcename, int& filesize, const bool zero_terminate) {
|
|
||||||
FILE *f = file_getfilepointer(resourcename, filesize, true);
|
|
||||||
char* buffer = (char*)malloc(zero_terminate?filesize:filesize+1);
|
|
||||||
fread(buffer, filesize, 1, f);
|
|
||||||
if (zero_terminate) buffer[filesize]=0;
|
|
||||||
fclose(f);
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *file_getfilepointerex(const char *filename, int& filesize, const bool binary) {
|
|
||||||
|
|
||||||
FILE *f;
|
|
||||||
f = fopen(filename, binary?"rb":"r");
|
|
||||||
fseek(f, 0, SEEK_END);
|
|
||||||
filesize = ftell(f);
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *file_getfilebufferex(const char *filename, int& filesize, const bool zero_terminate) {
|
|
||||||
FILE *f = file_getfilepointerex(filename, filesize, true);
|
|
||||||
char* buffer = (char*)malloc(zero_terminate?filesize:filesize+1);
|
|
||||||
fread(buffer, filesize, 1, f);
|
|
||||||
if (zero_terminate) buffer[filesize]=0;
|
|
||||||
fclose(f);
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crea la carpeta del sistema donde guardar datos
|
|
||||||
void file_setconfigfolder(const char *foldername)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
config_folder = std::string(getenv("APPDATA")) + "/" + foldername;
|
|
||||||
#elif __APPLE__
|
|
||||||
struct passwd *pw = getpwuid(getuid());
|
|
||||||
const char *homedir = pw->pw_dir;
|
|
||||||
config_folder = std::string(homedir) + "/Library/Application Support/" + foldername;
|
|
||||||
#elif __linux__
|
|
||||||
struct passwd *pw = getpwuid(getuid());
|
|
||||||
const char *homedir = pw->pw_dir;
|
|
||||||
config_folder = std::string(homedir) + "/." + foldername;
|
|
||||||
config_folder = std::string(homedir) + "/.config/jailgames/" + foldername;
|
|
||||||
|
|
||||||
{
|
|
||||||
// Intenta crear ".config", per si no existeix
|
|
||||||
std::string config_base_folder = std::string(homedir) + "/.config";
|
|
||||||
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
|
|
||||||
if (ret == -1 && errno != EEXIST)
|
|
||||||
{
|
|
||||||
printf("ERROR CREATING CONFIG BASE FOLDER.");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Intenta crear ".config/jailgames", per si no existeix
|
|
||||||
std::string config_base_folder = std::string(homedir) + "/.config/jailgames";
|
|
||||||
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
|
|
||||||
if (ret == -1 && errno != EEXIST)
|
|
||||||
{
|
|
||||||
printf("ERROR CREATING CONFIG BASE FOLDER.");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct stat st = {0};
|
|
||||||
if (stat(config_folder.c_str(), &st) == -1)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
int ret = mkdir(config_folder.c_str());
|
|
||||||
#else
|
|
||||||
int ret = mkdir(config_folder.c_str(), S_IRWXU);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ret == -1)
|
|
||||||
{
|
|
||||||
printf("ERROR CREATING CONFIG FOLDER.");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *file_getconfigfolder() {
|
|
||||||
static std::string folder = config_folder + "/";
|
|
||||||
return folder.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_loadconfigvalues() {
|
|
||||||
config.clear();
|
|
||||||
std::string config_file = config_folder + "/config.txt";
|
|
||||||
FILE *f = fopen(config_file.c_str(), "r");
|
|
||||||
if (!f) return;
|
|
||||||
|
|
||||||
char line[1024];
|
|
||||||
while (fgets(line, sizeof(line), f)) {
|
|
||||||
char *value = strchr(line, '=');
|
|
||||||
if (value) {
|
|
||||||
*value='\0'; value++;
|
|
||||||
value[strlen(value)-1] = '\0';
|
|
||||||
config.push_back({line, value});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_saveconfigvalues() {
|
|
||||||
std::string config_file = config_folder + "/config.txt";
|
|
||||||
FILE *f = fopen(config_file.c_str(), "w");
|
|
||||||
if (f) {
|
|
||||||
for (auto pair : config) {
|
|
||||||
fprintf(f, "%s=%s\n", pair.key.c_str(), pair.value.c_str());
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* file_getconfigvalue(const char *key) {
|
|
||||||
if (config.empty()) file_loadconfigvalues();
|
|
||||||
for (auto pair : config) {
|
|
||||||
if (pair.key == std::string(key)) {
|
|
||||||
strcpy(scratch, pair.value.c_str());
|
|
||||||
return scratch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_setconfigvalue(const char* key, const char* value) {
|
|
||||||
if (config.empty()) file_loadconfigvalues();
|
|
||||||
for (auto &pair : config) {
|
|
||||||
if (pair.key == std::string(key)) {
|
|
||||||
pair.value = value;
|
|
||||||
file_saveconfigvalues();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
config.push_back({key, value});
|
|
||||||
file_saveconfigvalues();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_createFolder(const char* name) {
|
|
||||||
char tmp[256];
|
|
||||||
strcpy(tmp, "./");
|
|
||||||
strcat(tmp, name);
|
|
||||||
#ifdef _WIN32
|
|
||||||
return mkdir(tmp)==0;
|
|
||||||
#else
|
|
||||||
return mkdir(tmp, 0755)==0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool has_extension(const std::string &name, const char *ext)
|
|
||||||
{
|
|
||||||
if (!ext) return true; // sin filtro
|
|
||||||
|
|
||||||
std::string e = ext;
|
|
||||||
std::string suffix = "." + e;
|
|
||||||
|
|
||||||
if (name.size() < suffix.size())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return (name.compare(name.size() - suffix.size(), suffix.size(), suffix) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> file_listdir(const char *folder, const char *extension)
|
|
||||||
{
|
|
||||||
std::vector<std::string> result;
|
|
||||||
std::string base(folder);
|
|
||||||
|
|
||||||
// Normalizar: quitar "/" final si existe
|
|
||||||
if (!base.empty() && base.back() == '/')
|
|
||||||
base.pop_back();
|
|
||||||
|
|
||||||
// -------------------------------
|
|
||||||
// 1. MODO: ARCHIVOS SUELTOS
|
|
||||||
// -------------------------------
|
|
||||||
if (file_source == SOURCE_FOLDER)
|
|
||||||
{
|
|
||||||
std::string fullpath = std::string(resource_folder) + base;
|
|
||||||
|
|
||||||
DIR *dir = opendir(fullpath.c_str());
|
|
||||||
if (!dir)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
struct dirent *entry;
|
|
||||||
while ((entry = readdir(dir)) != nullptr)
|
|
||||||
{
|
|
||||||
std::string name = entry->d_name;
|
|
||||||
|
|
||||||
// Ignorar "." y ".."
|
|
||||||
if (name == "." || name == "..")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Ignorar subdirectorios
|
|
||||||
std::string full = fullpath + "/" + name;
|
|
||||||
DIR *test = opendir(full.c_str());
|
|
||||||
if (test)
|
|
||||||
{
|
|
||||||
closedir(test);
|
|
||||||
continue; // es un directorio
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filtrar por extensión
|
|
||||||
if (!has_extension(name, extension))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
result.push_back(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------
|
|
||||||
// 2. MODO: ARCHIVO CONTENEDOR
|
|
||||||
// -------------------------------
|
|
||||||
if (file_source == SOURCE_FILE)
|
|
||||||
{
|
|
||||||
std::string prefix = base + "/";
|
|
||||||
|
|
||||||
for (auto &f : toc)
|
|
||||||
{
|
|
||||||
const std::string &path = f.path;
|
|
||||||
|
|
||||||
// Debe empezar por "folder/"
|
|
||||||
if (path.compare(0, prefix.size(), prefix) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Extraer la parte después de "folder/"
|
|
||||||
std::string rest = path.substr(prefix.size());
|
|
||||||
|
|
||||||
// Ignorar subdirectorios
|
|
||||||
if (rest.find('/') != std::string::npos)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Filtrar por extensión
|
|
||||||
if (!has_extension(rest, extension))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
result.push_back(rest);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#define SOURCE_FILE 0
|
|
||||||
#define SOURCE_FOLDER 1
|
|
||||||
|
|
||||||
void file_setconfigfolder(const char *foldername);
|
|
||||||
const char *file_getconfigfolder();
|
|
||||||
|
|
||||||
void file_setresourcefilename(const char *str);
|
|
||||||
void file_setresourcefolder(const char *str);
|
|
||||||
void file_setsource(const int src);
|
|
||||||
|
|
||||||
FILE *file_getfilepointer(const char *resourcename, int& filesize, const bool binary=false);
|
|
||||||
char *file_getfilebuffer(const char *resourcename, int& filesize, const bool zero_terminate=false);
|
|
||||||
|
|
||||||
FILE *file_getfilepointerex(const char *filename, int& filesize, const bool binary=false);
|
|
||||||
char *file_getfilebufferex(const char *filename, int& filesize, const bool zero_terminate=false);
|
|
||||||
|
|
||||||
const char* file_getconfigvalue(const char *key);
|
|
||||||
void file_setconfigvalue(const char* key, const char* value);
|
|
||||||
|
|
||||||
bool file_createFolder(const char* name);
|
|
||||||
std::vector<std::string> file_listdir(const char *folder, const char *extension=NULL);
|
|
||||||
-253
@@ -1,253 +0,0 @@
|
|||||||
#include "jshader.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include "CoreFoundation/CoreFoundation.h"
|
|
||||||
#include <OpenGL/OpenGL.h>
|
|
||||||
|
|
||||||
#if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
|
||||||
#include <OpenGL/gl3.h>
|
|
||||||
#else
|
|
||||||
#include <OpenGL/gl.h>
|
|
||||||
#endif //!ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
|
||||||
#else
|
|
||||||
#include <SDL3/SDL_opengl.h>
|
|
||||||
#include <SDL3/SDL_opengl_glext.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace shader
|
|
||||||
{
|
|
||||||
SDL_Window *win = nullptr;
|
|
||||||
SDL_Renderer *renderer = nullptr;
|
|
||||||
GLuint programId = 0;
|
|
||||||
SDL_Texture* backBuffer = nullptr;
|
|
||||||
SDL_Point win_size = {640, 480};
|
|
||||||
SDL_FPoint tex_size = {320, 240};
|
|
||||||
bool can_use_opengl = false;
|
|
||||||
bool using_opengl = false;
|
|
||||||
GLuint texture_number;
|
|
||||||
GLuint nose;
|
|
||||||
|
|
||||||
#ifndef __APPLE__
|
|
||||||
|
|
||||||
// I'm avoiding the use of GLEW or some extensions handler, but that
|
|
||||||
// doesn't mean you should...
|
|
||||||
PFNGLCREATESHADERPROC glCreateShader;
|
|
||||||
PFNGLSHADERSOURCEPROC glShaderSource;
|
|
||||||
PFNGLCOMPILESHADERPROC glCompileShader;
|
|
||||||
PFNGLGETSHADERIVPROC glGetShaderiv;
|
|
||||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
|
||||||
PFNGLDELETESHADERPROC glDeleteShader;
|
|
||||||
PFNGLATTACHSHADERPROC glAttachShader;
|
|
||||||
PFNGLCREATEPROGRAMPROC glCreateProgram;
|
|
||||||
PFNGLDELETEPROGRAMPROC glDeleteProgram;
|
|
||||||
PFNGLLINKPROGRAMPROC glLinkProgram;
|
|
||||||
PFNGLVALIDATEPROGRAMPROC glValidateProgram;
|
|
||||||
PFNGLGETPROGRAMIVPROC glGetProgramiv;
|
|
||||||
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
|
|
||||||
PFNGLUSEPROGRAMPROC glUseProgram;
|
|
||||||
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
|
|
||||||
PFNGLACTIVETEXTUREPROC glActiveTexture;
|
|
||||||
|
|
||||||
|
|
||||||
bool initGLExtensions() {
|
|
||||||
glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader");
|
|
||||||
glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource");
|
|
||||||
glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader");
|
|
||||||
glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv");
|
|
||||||
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog");
|
|
||||||
glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader");
|
|
||||||
glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader");
|
|
||||||
glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram");
|
|
||||||
glDeleteProgram = (PFNGLDELETEPROGRAMPROC)SDL_GL_GetProcAddress("glDeleteProgram");
|
|
||||||
glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram");
|
|
||||||
glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram");
|
|
||||||
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv");
|
|
||||||
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog");
|
|
||||||
glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram");
|
|
||||||
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)SDL_GL_GetProcAddress("glGetUniformLocation");
|
|
||||||
glActiveTexture = (PFNGLACTIVETEXTUREPROC)SDL_GL_GetProcAddress("glActiveTexture");
|
|
||||||
|
|
||||||
return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv &&
|
|
||||||
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
|
|
||||||
glDeleteProgram && glLinkProgram && glValidateProgram && glGetProgramiv &&
|
|
||||||
glGetProgramInfoLog && glUseProgram && glGetUniformLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GLuint compileShader(const char* source, GLuint shaderType) {
|
|
||||||
// Create ID for shader
|
|
||||||
GLuint result = glCreateShader(shaderType);
|
|
||||||
// Add define depending on shader type
|
|
||||||
const char *sources[2] = { shaderType==GL_VERTEX_SHADER?"#define VERTEX\n":"#define FRAGMENT\n", source };
|
|
||||||
// Define shader text
|
|
||||||
glShaderSource(result, 2, sources, NULL);
|
|
||||||
// Compile shader
|
|
||||||
glCompileShader(result);
|
|
||||||
|
|
||||||
//Check vertex shader for errors
|
|
||||||
GLint shaderCompiled = GL_FALSE;
|
|
||||||
glGetShaderiv( result, GL_COMPILE_STATUS, &shaderCompiled );
|
|
||||||
if (shaderCompiled != GL_TRUE)
|
|
||||||
{
|
|
||||||
std::cout << "Error en la compilación: " << result << "!" << std::endl;
|
|
||||||
GLint logLength;
|
|
||||||
glGetShaderiv(result, GL_INFO_LOG_LENGTH, &logLength);
|
|
||||||
if (logLength > 0)
|
|
||||||
{
|
|
||||||
GLchar *log = (GLchar*)malloc(logLength);
|
|
||||||
glGetShaderInfoLog(result, logLength, &logLength, log);
|
|
||||||
std::cout << "Shader compile log:" << log << std::endl;
|
|
||||||
//std::cout << source << std::endl;
|
|
||||||
free(log);
|
|
||||||
}
|
|
||||||
glDeleteShader(result);
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLuint compileProgram(const char* vertexShaderSource, const char* fragmentShaderSource)
|
|
||||||
{
|
|
||||||
GLuint programId = 0;
|
|
||||||
GLuint vtxShaderId, fragShaderId;
|
|
||||||
|
|
||||||
if (programId != 0) glDeleteProgram(programId);
|
|
||||||
programId = glCreateProgram();
|
|
||||||
|
|
||||||
|
|
||||||
vtxShaderId = compileShader(vertexShaderSource, GL_VERTEX_SHADER);
|
|
||||||
fragShaderId = compileShader(fragmentShaderSource?fragmentShaderSource:vertexShaderSource, GL_FRAGMENT_SHADER);
|
|
||||||
|
|
||||||
if(vtxShaderId && fragShaderId)
|
|
||||||
{
|
|
||||||
// Associate shader with program
|
|
||||||
glAttachShader(programId, vtxShaderId);
|
|
||||||
glAttachShader(programId, fragShaderId);
|
|
||||||
glLinkProgram(programId);
|
|
||||||
glValidateProgram(programId);
|
|
||||||
|
|
||||||
// Check the status of the compile/link
|
|
||||||
GLint logLen;
|
|
||||||
glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &logLen);
|
|
||||||
if (logLen > 0)
|
|
||||||
{
|
|
||||||
char* log = (char*) malloc(logLen * sizeof(char));
|
|
||||||
// Show any errors as appropriate
|
|
||||||
glGetProgramInfoLog(programId, logLen, &logLen, log);
|
|
||||||
std::cout << "Prog Info Log: " << std::endl << log << std::endl;
|
|
||||||
free(log);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (vtxShaderId) glDeleteShader(vtxShaderId);
|
|
||||||
if (fragShaderId) glDeleteShader(fragShaderId);
|
|
||||||
return programId;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool init(SDL_Window* win, SDL_Texture* backBuffer, const char* vertexShader, const char* fragmentShader)
|
|
||||||
{
|
|
||||||
shader::win = win;
|
|
||||||
shader::renderer = SDL_GetRenderer(win);
|
|
||||||
shader::backBuffer = backBuffer;
|
|
||||||
SDL_GetWindowSize(win, &win_size.x, &win_size.y);
|
|
||||||
SDL_GetTextureSize(backBuffer, &tex_size.x, &tex_size.y);
|
|
||||||
//printf("tex size: %fx%f\n", tex_size.x, tex_size.y);
|
|
||||||
SDL_PropertiesID props = SDL_GetTextureProperties(backBuffer);
|
|
||||||
texture_number = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_NUMBER, -1);
|
|
||||||
//printf("texture number: %i\n", texture_number);
|
|
||||||
int access = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_ACCESS_NUMBER, -1);
|
|
||||||
nose = SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_TARGET_NUMBER, -1);
|
|
||||||
//printf("texture target number: %i\n", nose);
|
|
||||||
|
|
||||||
if (access != SDL_TEXTUREACCESS_TARGET)
|
|
||||||
{
|
|
||||||
std::cout << "ERROR FATAL: La textura per al render ha de tindre SDL_TEXTUREACCESS_TARGET definit." << std::endl;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * renderer_name = SDL_GetRendererName(renderer);
|
|
||||||
//printf("rendererInfo.name: %s\n", renderer_name);
|
|
||||||
|
|
||||||
if(!strncmp(renderer_name, "opengl", 6)) {
|
|
||||||
#ifndef __APPLE__
|
|
||||||
static bool gl_extensions_initialized = false;
|
|
||||||
if (!gl_extensions_initialized) {
|
|
||||||
if (!initGLExtensions()) {
|
|
||||||
std::cout << "WARNING: No s'han pogut inicialitzar les extensions d'OpenGL!" << std::endl;
|
|
||||||
can_use_opengl = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
gl_extensions_initialized = true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// Compilar el shader y dejarlo listo para usar.
|
|
||||||
if (!vertexShader) {
|
|
||||||
can_use_opengl = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
programId = compileProgram(vertexShader, fragmentShader);
|
|
||||||
} else {
|
|
||||||
std::cout << "WARNING: El driver del renderer no es OpenGL." << std::endl;
|
|
||||||
can_use_opengl = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
can_use_opengl = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char pixels[512*240*4];
|
|
||||||
|
|
||||||
void enable() { if (can_use_opengl) using_opengl = true; }
|
|
||||||
void disable() { using_opengl = false; }
|
|
||||||
|
|
||||||
void render()
|
|
||||||
{
|
|
||||||
SDL_FlushRenderer(renderer);
|
|
||||||
SDL_SetRenderTarget(renderer, NULL);
|
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
|
||||||
SDL_RenderClear(renderer);
|
|
||||||
SDL_FlushRenderer(renderer);
|
|
||||||
|
|
||||||
if (using_opengl)
|
|
||||||
{
|
|
||||||
GLint oldProgramId;
|
|
||||||
if (programId != 0)
|
|
||||||
{
|
|
||||||
glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId);
|
|
||||||
glUseProgram(programId);
|
|
||||||
}
|
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 1);
|
|
||||||
//glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, pixels);
|
|
||||||
//if (glGetError()) { printf("GLGETERROR!\n"); exit(1);}
|
|
||||||
//GLint param;
|
|
||||||
//glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, ¶m);
|
|
||||||
//printf("tex width: %i\n", param);
|
|
||||||
glViewport(0, 0, win_size.x, win_size.y);
|
|
||||||
|
|
||||||
glBegin(GL_TRIANGLE_STRIP);
|
|
||||||
glTexCoord2f(0.0f, 0.0f);
|
|
||||||
glVertex2f(-1.0f, -1.0f);
|
|
||||||
glTexCoord2f(tex_size.x, 0.0f);
|
|
||||||
glVertex2f(1.0f, -1.0f);
|
|
||||||
glTexCoord2f(0.0f, tex_size.y);
|
|
||||||
glVertex2f(-1.0f, 1.0f);
|
|
||||||
glTexCoord2f(tex_size.x, tex_size.y);
|
|
||||||
glVertex2f(1.0f, 1.0f);
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
SDL_GL_SwapWindow(win);
|
|
||||||
|
|
||||||
if (programId != 0) glUseProgram(oldProgramId);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
SDL_RenderTexture(renderer, backBuffer, NULL, NULL);
|
|
||||||
SDL_RenderPresent(renderer);
|
|
||||||
}
|
|
||||||
if (glGetError()) { printf("GLERROR!\n"); exit(1); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
|
|
||||||
// TIPS:
|
|
||||||
// =======================================================================
|
|
||||||
// Abans de crear el renderer, cridar a la següent funció:
|
|
||||||
//
|
|
||||||
// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
|
|
||||||
//
|
|
||||||
// Aixó li diu que volem un renderer que use especificament opengl. A més,
|
|
||||||
// al crear el renderer li tenim que dir que el volem que use acceeració
|
|
||||||
// per hardware, i que soporte render a textura. Per exemple:
|
|
||||||
//
|
|
||||||
// SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED |
|
|
||||||
// SDL_RENDERER_TARGETTEXTURE);
|
|
||||||
//
|
|
||||||
// Per altra part, al crear la textura tenim que definir que puga ser target
|
|
||||||
// de renderitzat (SDL_TEXTUREACCESS_TARGET), per exemple:
|
|
||||||
//
|
|
||||||
// SDL_Texture *tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
|
|
||||||
// SDL_TEXTUREACCESS_TARGET, 320, 240);
|
|
||||||
//
|
|
||||||
// Els shaders li'ls passem com una cadena, som nosaltres els que s'encarreguem
|
|
||||||
// de carregarlos de disc, amb fopen, ifstream, jfile o el que vullgues.
|
|
||||||
// Si els tens en un std::string, passa-li-la com "cadena.c_str()".
|
|
||||||
//
|
|
||||||
// Poden ser els dos el mateix arxiu, com fa libRetro, jo desde dins ja fique
|
|
||||||
// els defines necessaris. Si es el mateix arxiu, pots no ficar el quart paràmetre.
|
|
||||||
//
|
|
||||||
// Els shaders de libRetro no funcionen directament, hi ha que fer algunes modificacions.
|
|
||||||
//
|
|
||||||
// El pintat final de la teua escena l'has de fer com si "backBuffer" fora la pantalla.
|
|
||||||
//
|
|
||||||
// Ah! una cosa mes: al compilar, en Linux afegir "-lGL", en Windows afegir "-lopengl32".
|
|
||||||
// En Mac ni idea
|
|
||||||
|
|
||||||
namespace shader
|
|
||||||
{
|
|
||||||
const bool init(SDL_Window* win, SDL_Texture* backBuffer,
|
|
||||||
const char* vertexShader, const char* fragmentShader=nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
void enable();
|
|
||||||
void disable();
|
|
||||||
|
|
||||||
void render();
|
|
||||||
}
|
|
||||||
+26
-4
@@ -1,5 +1,27 @@
|
|||||||
libs = -lSDL3 -lGL
|
[linux]
|
||||||
cppflags = -D LUA_USE_LINUX -D DEBUG -g -Wall
|
cppflags = -D LUA_USE_LINUX -Wall -Os -ffunction-sections -fdata-sections -std=c++20 -Isource
|
||||||
executable = mini_debug
|
libs = -Wl,--gc-sections -lSDL3 -lGL
|
||||||
sourcepath = . lua
|
executable = mini
|
||||||
|
sourcepath = source+
|
||||||
|
buildpath = build
|
||||||
|
|
||||||
|
[linux_debug] default
|
||||||
|
cppflags = -D LUA_USE_LINUX -D DEBUG -g -Wall -std=c++20 -Isource
|
||||||
|
libs = -lSDL3 -lGL
|
||||||
|
executable = mini_debug
|
||||||
|
sourcepath = source+
|
||||||
|
buildpath = build
|
||||||
|
|
||||||
|
[windows]
|
||||||
|
cppflags = -Wall -Os -ffunction-sections -fdata-sections -std=c++20 -Isource
|
||||||
|
libs = icon.res -Wl,--gc-sections -lmingw32 -lSDL3 -lopengl32 -static-libstdc++ -static-libgcc -lpthread -mwindows
|
||||||
|
executable = mini.exe
|
||||||
|
sourcepath = source+
|
||||||
|
buildpath = build
|
||||||
|
|
||||||
|
[windows_debug]
|
||||||
|
cppflags = -D DEBUG -g -Wall -std=c++20 -Isource
|
||||||
|
libs = -lmingw32 -lSDL3 -lopengl32
|
||||||
|
executable = mini_debug.exe
|
||||||
|
sourcepath = source+
|
||||||
buildpath = build
|
buildpath = build
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
bool lua_is_playing();
|
|
||||||
void lua_init(const char* main_lua_file = "main.lua");
|
|
||||||
void lua_call_init();
|
|
||||||
void lua_call_update();
|
|
||||||
void lua_quit();
|
|
||||||
-49
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
** $Id: lapi.h $
|
|
||||||
** Auxiliary functions from Lua API
|
|
||||||
** See Copyright Notice in lua.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef lapi_h
|
|
||||||
#define lapi_h
|
|
||||||
|
|
||||||
|
|
||||||
#include "llimits.h"
|
|
||||||
#include "lstate.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* Increments 'L->top', checking for stack overflows */
|
|
||||||
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
|
|
||||||
"stack overflow");}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** If a call returns too many multiple returns, the callee may not have
|
|
||||||
** stack space to accommodate all results. In this case, this macro
|
|
||||||
** increases its stack space ('L->ci->top').
|
|
||||||
*/
|
|
||||||
#define adjustresults(L,nres) \
|
|
||||||
{ if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
|
|
||||||
|
|
||||||
|
|
||||||
/* Ensure the stack has at least 'n' elements */
|
|
||||||
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
|
|
||||||
"not enough elements in the stack")
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** To reduce the overhead of returning from C functions, the presence of
|
|
||||||
** to-be-closed variables in these functions is coded in the CallInfo's
|
|
||||||
** field 'nresults', in a way that functions with no to-be-closed variables
|
|
||||||
** with zero, one, or "all" wanted results have no overhead. Functions
|
|
||||||
** with other number of wanted results, as well as functions with
|
|
||||||
** variables to be closed, have an extra check.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define hastocloseCfunc(n) ((n) < LUA_MULTRET)
|
|
||||||
|
|
||||||
/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */
|
|
||||||
#define codeNresults(n) (-(n) - 3)
|
|
||||||
#define decodeNresults(n) (-(n) - 3)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
-226
@@ -1,226 +0,0 @@
|
|||||||
/*
|
|
||||||
** $Id: ldump.c $
|
|
||||||
** save precompiled Lua chunks
|
|
||||||
** See Copyright Notice in lua.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define ldump_c
|
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
|
|
||||||
#include "lobject.h"
|
|
||||||
#include "lstate.h"
|
|
||||||
#include "lundump.h"
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
lua_State *L;
|
|
||||||
lua_Writer writer;
|
|
||||||
void *data;
|
|
||||||
int strip;
|
|
||||||
int status;
|
|
||||||
} DumpState;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** All high-level dumps go through dumpVector; you can change it to
|
|
||||||
** change the endianness of the result
|
|
||||||
*/
|
|
||||||
#define dumpVector(D,v,n) dumpBlock(D,v,(n)*sizeof((v)[0]))
|
|
||||||
|
|
||||||
#define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char))
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpBlock (DumpState *D, const void *b, size_t size) {
|
|
||||||
if (D->status == 0 && size > 0) {
|
|
||||||
lua_unlock(D->L);
|
|
||||||
D->status = (*D->writer)(D->L, b, size, D->data);
|
|
||||||
lua_lock(D->L);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define dumpVar(D,x) dumpVector(D,&x,1)
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpByte (DumpState *D, int y) {
|
|
||||||
lu_byte x = (lu_byte)y;
|
|
||||||
dumpVar(D, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* dumpInt Buff Size */
|
|
||||||
#define DIBS ((sizeof(size_t) * 8 / 7) + 1)
|
|
||||||
|
|
||||||
static void dumpSize (DumpState *D, size_t x) {
|
|
||||||
lu_byte buff[DIBS];
|
|
||||||
int n = 0;
|
|
||||||
do {
|
|
||||||
buff[DIBS - (++n)] = x & 0x7f; /* fill buffer in reverse order */
|
|
||||||
x >>= 7;
|
|
||||||
} while (x != 0);
|
|
||||||
buff[DIBS - 1] |= 0x80; /* mark last byte */
|
|
||||||
dumpVector(D, buff + DIBS - n, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpInt (DumpState *D, int x) {
|
|
||||||
dumpSize(D, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpNumber (DumpState *D, lua_Number x) {
|
|
||||||
dumpVar(D, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpInteger (DumpState *D, lua_Integer x) {
|
|
||||||
dumpVar(D, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpString (DumpState *D, const TString *s) {
|
|
||||||
if (s == NULL)
|
|
||||||
dumpSize(D, 0);
|
|
||||||
else {
|
|
||||||
size_t size = tsslen(s);
|
|
||||||
const char *str = getstr(s);
|
|
||||||
dumpSize(D, size + 1);
|
|
||||||
dumpVector(D, str, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpCode (DumpState *D, const Proto *f) {
|
|
||||||
dumpInt(D, f->sizecode);
|
|
||||||
dumpVector(D, f->code, f->sizecode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpFunction(DumpState *D, const Proto *f, TString *psource);
|
|
||||||
|
|
||||||
static void dumpConstants (DumpState *D, const Proto *f) {
|
|
||||||
int i;
|
|
||||||
int n = f->sizek;
|
|
||||||
dumpInt(D, n);
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
const TValue *o = &f->k[i];
|
|
||||||
int tt = ttypetag(o);
|
|
||||||
dumpByte(D, tt);
|
|
||||||
switch (tt) {
|
|
||||||
case LUA_VNUMFLT:
|
|
||||||
dumpNumber(D, fltvalue(o));
|
|
||||||
break;
|
|
||||||
case LUA_VNUMINT:
|
|
||||||
dumpInteger(D, ivalue(o));
|
|
||||||
break;
|
|
||||||
case LUA_VSHRSTR:
|
|
||||||
case LUA_VLNGSTR:
|
|
||||||
dumpString(D, tsvalue(o));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
lua_assert(tt == LUA_VNIL || tt == LUA_VFALSE || tt == LUA_VTRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpProtos (DumpState *D, const Proto *f) {
|
|
||||||
int i;
|
|
||||||
int n = f->sizep;
|
|
||||||
dumpInt(D, n);
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
dumpFunction(D, f->p[i], f->source);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpUpvalues (DumpState *D, const Proto *f) {
|
|
||||||
int i, n = f->sizeupvalues;
|
|
||||||
dumpInt(D, n);
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
dumpByte(D, f->upvalues[i].instack);
|
|
||||||
dumpByte(D, f->upvalues[i].idx);
|
|
||||||
dumpByte(D, f->upvalues[i].kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpDebug (DumpState *D, const Proto *f) {
|
|
||||||
int i, n;
|
|
||||||
n = (D->strip) ? 0 : f->sizelineinfo;
|
|
||||||
dumpInt(D, n);
|
|
||||||
dumpVector(D, f->lineinfo, n);
|
|
||||||
n = (D->strip) ? 0 : f->sizeabslineinfo;
|
|
||||||
dumpInt(D, n);
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
dumpInt(D, f->abslineinfo[i].pc);
|
|
||||||
dumpInt(D, f->abslineinfo[i].line);
|
|
||||||
}
|
|
||||||
n = (D->strip) ? 0 : f->sizelocvars;
|
|
||||||
dumpInt(D, n);
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
dumpString(D, f->locvars[i].varname);
|
|
||||||
dumpInt(D, f->locvars[i].startpc);
|
|
||||||
dumpInt(D, f->locvars[i].endpc);
|
|
||||||
}
|
|
||||||
n = (D->strip) ? 0 : f->sizeupvalues;
|
|
||||||
dumpInt(D, n);
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
dumpString(D, f->upvalues[i].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpFunction (DumpState *D, const Proto *f, TString *psource) {
|
|
||||||
if (D->strip || f->source == psource)
|
|
||||||
dumpString(D, NULL); /* no debug info or same source as its parent */
|
|
||||||
else
|
|
||||||
dumpString(D, f->source);
|
|
||||||
dumpInt(D, f->linedefined);
|
|
||||||
dumpInt(D, f->lastlinedefined);
|
|
||||||
dumpByte(D, f->numparams);
|
|
||||||
dumpByte(D, f->is_vararg);
|
|
||||||
dumpByte(D, f->maxstacksize);
|
|
||||||
dumpCode(D, f);
|
|
||||||
dumpConstants(D, f);
|
|
||||||
dumpUpvalues(D, f);
|
|
||||||
dumpProtos(D, f);
|
|
||||||
dumpDebug(D, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dumpHeader (DumpState *D) {
|
|
||||||
dumpLiteral(D, LUA_SIGNATURE);
|
|
||||||
dumpByte(D, LUAC_VERSION);
|
|
||||||
dumpByte(D, LUAC_FORMAT);
|
|
||||||
dumpLiteral(D, LUAC_DATA);
|
|
||||||
dumpByte(D, sizeof(Instruction));
|
|
||||||
dumpByte(D, sizeof(lua_Integer));
|
|
||||||
dumpByte(D, sizeof(lua_Number));
|
|
||||||
dumpInteger(D, LUAC_INT);
|
|
||||||
dumpNumber(D, LUAC_NUM);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** dump Lua function as precompiled chunk
|
|
||||||
*/
|
|
||||||
int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
|
|
||||||
int strip) {
|
|
||||||
DumpState D;
|
|
||||||
D.L = L;
|
|
||||||
D.writer = w;
|
|
||||||
D.data = data;
|
|
||||||
D.strip = strip;
|
|
||||||
D.status = 0;
|
|
||||||
dumpHeader(&D);
|
|
||||||
dumpByte(&D, f->sizeupvalues);
|
|
||||||
dumpFunction(&D, f, NULL);
|
|
||||||
return D.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
/*
|
|
||||||
** $Id: lgc.h $
|
|
||||||
** Garbage Collector
|
|
||||||
** See Copyright Notice in lua.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef lgc_h
|
|
||||||
#define lgc_h
|
|
||||||
|
|
||||||
|
|
||||||
#include "lobject.h"
|
|
||||||
#include "lstate.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Collectable objects may have one of three colors: white, which means
|
|
||||||
** the object is not marked; gray, which means the object is marked, but
|
|
||||||
** its references may be not marked; and black, which means that the
|
|
||||||
** object and all its references are marked. The main invariant of the
|
|
||||||
** garbage collector, while marking objects, is that a black object can
|
|
||||||
** never point to a white one. Moreover, any gray object must be in a
|
|
||||||
** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it
|
|
||||||
** can be visited again before finishing the collection cycle. (Open
|
|
||||||
** upvalues are an exception to this rule.) These lists have no meaning
|
|
||||||
** when the invariant is not being enforced (e.g., sweep phase).
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Possible states of the Garbage Collector
|
|
||||||
*/
|
|
||||||
#define GCSpropagate 0
|
|
||||||
#define GCSenteratomic 1
|
|
||||||
#define GCSatomic 2
|
|
||||||
#define GCSswpallgc 3
|
|
||||||
#define GCSswpfinobj 4
|
|
||||||
#define GCSswptobefnz 5
|
|
||||||
#define GCSswpend 6
|
|
||||||
#define GCScallfin 7
|
|
||||||
#define GCSpause 8
|
|
||||||
|
|
||||||
|
|
||||||
#define issweepphase(g) \
|
|
||||||
(GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** macro to tell when main invariant (white objects cannot point to black
|
|
||||||
** ones) must be kept. During a collection, the sweep
|
|
||||||
** phase may break the invariant, as objects turned white may point to
|
|
||||||
** still-black objects. The invariant is restored when sweep ends and
|
|
||||||
** all objects are white again.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define keepinvariant(g) ((g)->gcstate <= GCSatomic)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** some useful bit tricks
|
|
||||||
*/
|
|
||||||
#define resetbits(x,m) ((x) &= cast_byte(~(m)))
|
|
||||||
#define setbits(x,m) ((x) |= (m))
|
|
||||||
#define testbits(x,m) ((x) & (m))
|
|
||||||
#define bitmask(b) (1<<(b))
|
|
||||||
#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2))
|
|
||||||
#define l_setbit(x,b) setbits(x, bitmask(b))
|
|
||||||
#define resetbit(x,b) resetbits(x, bitmask(b))
|
|
||||||
#define testbit(x,b) testbits(x, bitmask(b))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Layout for bit use in 'marked' field. First three bits are
|
|
||||||
** used for object "age" in generational mode. Last bit is used
|
|
||||||
** by tests.
|
|
||||||
*/
|
|
||||||
#define WHITE0BIT 3 /* object is white (type 0) */
|
|
||||||
#define WHITE1BIT 4 /* object is white (type 1) */
|
|
||||||
#define BLACKBIT 5 /* object is black */
|
|
||||||
#define FINALIZEDBIT 6 /* object has been marked for finalization */
|
|
||||||
|
|
||||||
#define TESTBIT 7
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
|
|
||||||
|
|
||||||
|
|
||||||
#define iswhite(x) testbits((x)->marked, WHITEBITS)
|
|
||||||
#define isblack(x) testbit((x)->marked, BLACKBIT)
|
|
||||||
#define isgray(x) /* neither white nor black */ \
|
|
||||||
(!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT)))
|
|
||||||
|
|
||||||
#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT)
|
|
||||||
|
|
||||||
#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS)
|
|
||||||
#define isdeadm(ow,m) ((m) & (ow))
|
|
||||||
#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
|
|
||||||
|
|
||||||
#define changewhite(x) ((x)->marked ^= WHITEBITS)
|
|
||||||
#define nw2black(x) \
|
|
||||||
check_exp(!iswhite(x), l_setbit((x)->marked, BLACKBIT))
|
|
||||||
|
|
||||||
#define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS)
|
|
||||||
|
|
||||||
|
|
||||||
/* object age in generational mode */
|
|
||||||
#define G_NEW 0 /* created in current cycle */
|
|
||||||
#define G_SURVIVAL 1 /* created in previous cycle */
|
|
||||||
#define G_OLD0 2 /* marked old by frw. barrier in this cycle */
|
|
||||||
#define G_OLD1 3 /* first full cycle as old */
|
|
||||||
#define G_OLD 4 /* really old object (not to be visited) */
|
|
||||||
#define G_TOUCHED1 5 /* old object touched this cycle */
|
|
||||||
#define G_TOUCHED2 6 /* old object touched in previous cycle */
|
|
||||||
|
|
||||||
#define AGEBITS 7 /* all age bits (111) */
|
|
||||||
|
|
||||||
#define getage(o) ((o)->marked & AGEBITS)
|
|
||||||
#define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a))
|
|
||||||
#define isold(o) (getage(o) > G_SURVIVAL)
|
|
||||||
|
|
||||||
#define changeage(o,f,t) \
|
|
||||||
check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t)))
|
|
||||||
|
|
||||||
|
|
||||||
/* Default Values for GC parameters */
|
|
||||||
#define LUAI_GENMAJORMUL 100
|
|
||||||
#define LUAI_GENMINORMUL 20
|
|
||||||
|
|
||||||
/* wait memory to double before starting new cycle */
|
|
||||||
#define LUAI_GCPAUSE 200
|
|
||||||
|
|
||||||
/*
|
|
||||||
** some gc parameters are stored divided by 4 to allow a maximum value
|
|
||||||
** up to 1023 in a 'lu_byte'.
|
|
||||||
*/
|
|
||||||
#define getgcparam(p) ((p) * 4)
|
|
||||||
#define setgcparam(p,v) ((p) = (v) / 4)
|
|
||||||
|
|
||||||
#define LUAI_GCMUL 100
|
|
||||||
|
|
||||||
/* how much to allocate before next GC step (log2) */
|
|
||||||
#define LUAI_GCSTEPSIZE 13 /* 8 KB */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Check whether the declared GC mode is generational. While in
|
|
||||||
** generational mode, the collector can go temporarily to incremental
|
|
||||||
** mode to improve performance. This is signaled by 'g->lastatomic != 0'.
|
|
||||||
*/
|
|
||||||
#define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0)
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Does one step of collection when debt becomes positive. 'pre'/'pos'
|
|
||||||
** allows some adjustments to be done only when needed. macro
|
|
||||||
** 'condchangemem' is used only for heavy tests (forcing a full
|
|
||||||
** GC cycle on every opportunity)
|
|
||||||
*/
|
|
||||||
#define luaC_condGC(L,pre,pos) \
|
|
||||||
{ if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \
|
|
||||||
condchangemem(L,pre,pos); }
|
|
||||||
|
|
||||||
/* more often than not, 'pre'/'pos' are empty */
|
|
||||||
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
|
|
||||||
|
|
||||||
|
|
||||||
#define luaC_barrier(L,p,v) ( \
|
|
||||||
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
|
|
||||||
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
|
|
||||||
|
|
||||||
#define luaC_barrierback(L,p,v) ( \
|
|
||||||
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
|
|
||||||
luaC_barrierback_(L,p) : cast_void(0))
|
|
||||||
|
|
||||||
#define luaC_objbarrier(L,p,o) ( \
|
|
||||||
(isblack(p) && iswhite(o)) ? \
|
|
||||||
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
|
|
||||||
|
|
||||||
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
|
|
||||||
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
|
|
||||||
LUAI_FUNC void luaC_step (lua_State *L);
|
|
||||||
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
|
|
||||||
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
|
|
||||||
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
|
|
||||||
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
|
|
||||||
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
|
|
||||||
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
|
|
||||||
LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
-65
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
** $Id: linit.c $
|
|
||||||
** Initialization of libraries for lua.c and other clients
|
|
||||||
** See Copyright Notice in lua.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#define linit_c
|
|
||||||
#define LUA_LIB
|
|
||||||
|
|
||||||
/*
|
|
||||||
** If you embed Lua in your program and need to open the standard
|
|
||||||
** libraries, call luaL_openlibs in your program. If you need a
|
|
||||||
** different set of libraries, copy this file to your project and edit
|
|
||||||
** it to suit your needs.
|
|
||||||
**
|
|
||||||
** You can also *preload* libraries, so that a later 'require' can
|
|
||||||
** open the library, which is already linked to the application.
|
|
||||||
** For that, do the following code:
|
|
||||||
**
|
|
||||||
** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
|
|
||||||
** lua_pushcfunction(L, luaopen_modname);
|
|
||||||
** lua_setfield(L, -2, modname);
|
|
||||||
** lua_pop(L, 1); // remove PRELOAD table
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
|
|
||||||
#include "lualib.h"
|
|
||||||
#include "lauxlib.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** these libs are loaded by lua.c and are readily available to any Lua
|
|
||||||
** program
|
|
||||||
*/
|
|
||||||
static const luaL_Reg loadedlibs[] = {
|
|
||||||
{LUA_GNAME, luaopen_base},
|
|
||||||
{LUA_LOADLIBNAME, luaopen_package},
|
|
||||||
{LUA_COLIBNAME, luaopen_coroutine},
|
|
||||||
{LUA_TABLIBNAME, luaopen_table},
|
|
||||||
{LUA_IOLIBNAME, luaopen_io},
|
|
||||||
{LUA_OSLIBNAME, luaopen_os},
|
|
||||||
{LUA_STRLIBNAME, luaopen_string},
|
|
||||||
{LUA_MATHLIBNAME, luaopen_math},
|
|
||||||
{LUA_UTF8LIBNAME, luaopen_utf8},
|
|
||||||
{LUA_DBLIBNAME, luaopen_debug},
|
|
||||||
{NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API void luaL_openlibs (lua_State *L) {
|
|
||||||
const luaL_Reg *lib;
|
|
||||||
/* "require" functions from 'loadedlibs' and set results to global table */
|
|
||||||
for (lib = loadedlibs; lib->func; lib++) {
|
|
||||||
luaL_requiref(L, lib->name, lib->func, 1);
|
|
||||||
lua_pop(L, 1); /* remove lib */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-353
@@ -1,353 +0,0 @@
|
|||||||
/*
|
|
||||||
** $Id: llimits.h $
|
|
||||||
** Limits, basic types, and some other 'installation-dependent' definitions
|
|
||||||
** See Copyright Notice in lua.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef llimits_h
|
|
||||||
#define llimits_h
|
|
||||||
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count
|
|
||||||
** the total memory used by Lua (in bytes). Usually, 'size_t' and
|
|
||||||
** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines.
|
|
||||||
*/
|
|
||||||
#if defined(LUAI_MEM) /* { external definitions? */
|
|
||||||
typedef LUAI_UMEM lu_mem;
|
|
||||||
typedef LUAI_MEM l_mem;
|
|
||||||
#elif LUAI_IS32INT /* }{ */
|
|
||||||
typedef size_t lu_mem;
|
|
||||||
typedef ptrdiff_t l_mem;
|
|
||||||
#else /* 16-bit ints */ /* }{ */
|
|
||||||
typedef unsigned long lu_mem;
|
|
||||||
typedef long l_mem;
|
|
||||||
#endif /* } */
|
|
||||||
|
|
||||||
|
|
||||||
/* chars used as small naturals (so that 'char' is reserved for characters) */
|
|
||||||
typedef unsigned char lu_byte;
|
|
||||||
typedef signed char ls_byte;
|
|
||||||
|
|
||||||
|
|
||||||
/* maximum value for size_t */
|
|
||||||
#define MAX_SIZET ((size_t)(~(size_t)0))
|
|
||||||
|
|
||||||
/* maximum size visible for Lua (must be representable in a lua_Integer) */
|
|
||||||
#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \
|
|
||||||
: (size_t)(LUA_MAXINTEGER))
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_LUMEM ((lu_mem)(~(lu_mem)0))
|
|
||||||
|
|
||||||
#define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1))
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_INT INT_MAX /* maximum value of an int */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** floor of the log2 of the maximum signed value for integral type 't'.
|
|
||||||
** (That is, maximum 'n' such that '2^n' fits in the given signed type.)
|
|
||||||
*/
|
|
||||||
#define log2maxs(t) (sizeof(t) * 8 - 2)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** test whether an unsigned value is a power of 2 (or zero)
|
|
||||||
*/
|
|
||||||
#define ispow2(x) (((x) & ((x) - 1)) == 0)
|
|
||||||
|
|
||||||
|
|
||||||
/* number of chars of a literal string without the ending \0 */
|
|
||||||
#define LL(x) (sizeof(x)/sizeof(char) - 1)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** conversion of pointer to unsigned integer:
|
|
||||||
** this is for hashing only; there is no problem if the integer
|
|
||||||
** cannot hold the whole pointer value
|
|
||||||
*/
|
|
||||||
#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* types of 'usual argument conversions' for lua_Number and lua_Integer */
|
|
||||||
typedef LUAI_UACNUMBER l_uacNumber;
|
|
||||||
typedef LUAI_UACINT l_uacInt;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Internal assertions for in-house debugging
|
|
||||||
*/
|
|
||||||
#if defined LUAI_ASSERT
|
|
||||||
#undef NDEBUG
|
|
||||||
#include <assert.h>
|
|
||||||
#define lua_assert(c) assert(c)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(lua_assert)
|
|
||||||
#define check_exp(c,e) (lua_assert(c), (e))
|
|
||||||
/* to avoid problems with conditions too long */
|
|
||||||
#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0))
|
|
||||||
#else
|
|
||||||
#define lua_assert(c) ((void)0)
|
|
||||||
#define check_exp(c,e) (e)
|
|
||||||
#define lua_longassert(c) ((void)0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
** assertion for checking API calls
|
|
||||||
*/
|
|
||||||
#if !defined(luai_apicheck)
|
|
||||||
#define luai_apicheck(l,e) ((void)l, lua_assert(e))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define api_check(l,e,msg) luai_apicheck(l,(e) && msg)
|
|
||||||
|
|
||||||
|
|
||||||
/* macro to avoid warnings about unused variables */
|
|
||||||
#if !defined(UNUSED)
|
|
||||||
#define UNUSED(x) ((void)(x))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* type casts (a macro highlights casts in the code) */
|
|
||||||
#define cast(t, exp) ((t)(exp))
|
|
||||||
|
|
||||||
#define cast_void(i) cast(void, (i))
|
|
||||||
#define cast_voidp(i) cast(void *, (i))
|
|
||||||
#define cast_num(i) cast(lua_Number, (i))
|
|
||||||
#define cast_int(i) cast(int, (i))
|
|
||||||
#define cast_uint(i) cast(unsigned int, (i))
|
|
||||||
#define cast_byte(i) cast(lu_byte, (i))
|
|
||||||
#define cast_uchar(i) cast(unsigned char, (i))
|
|
||||||
#define cast_char(i) cast(char, (i))
|
|
||||||
#define cast_charp(i) cast(char *, (i))
|
|
||||||
#define cast_sizet(i) cast(size_t, (i))
|
|
||||||
|
|
||||||
|
|
||||||
/* cast a signed lua_Integer to lua_Unsigned */
|
|
||||||
#if !defined(l_castS2U)
|
|
||||||
#define l_castS2U(i) ((lua_Unsigned)(i))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
** cast a lua_Unsigned to a signed lua_Integer; this cast is
|
|
||||||
** not strict ISO C, but two-complement architectures should
|
|
||||||
** work fine.
|
|
||||||
*/
|
|
||||||
#if !defined(l_castU2S)
|
|
||||||
#define l_castU2S(i) ((lua_Integer)(i))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** non-return type
|
|
||||||
*/
|
|
||||||
#if !defined(l_noret)
|
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
|
||||||
#define l_noret void __attribute__((noreturn))
|
|
||||||
#elif defined(_MSC_VER) && _MSC_VER >= 1200
|
|
||||||
#define l_noret void __declspec(noreturn)
|
|
||||||
#else
|
|
||||||
#define l_noret void
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** type for virtual-machine instructions;
|
|
||||||
** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
|
|
||||||
*/
|
|
||||||
#if LUAI_IS32INT
|
|
||||||
typedef unsigned int l_uint32;
|
|
||||||
#else
|
|
||||||
typedef unsigned long l_uint32;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef l_uint32 Instruction;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Maximum length for short strings, that is, strings that are
|
|
||||||
** internalized. (Cannot be smaller than reserved words or tags for
|
|
||||||
** metamethods, as these strings must be internalized;
|
|
||||||
** #("function") = 8, #("__newindex") = 10.)
|
|
||||||
*/
|
|
||||||
#if !defined(LUAI_MAXSHORTLEN)
|
|
||||||
#define LUAI_MAXSHORTLEN 40
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Initial size for the string table (must be power of 2).
|
|
||||||
** The Lua core alone registers ~50 strings (reserved words +
|
|
||||||
** metaevent keys + a few others). Libraries would typically add
|
|
||||||
** a few dozens more.
|
|
||||||
*/
|
|
||||||
#if !defined(MINSTRTABSIZE)
|
|
||||||
#define MINSTRTABSIZE 128
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Size of cache for strings in the API. 'N' is the number of
|
|
||||||
** sets (better be a prime) and "M" is the size of each set (M == 1
|
|
||||||
** makes a direct cache.)
|
|
||||||
*/
|
|
||||||
#if !defined(STRCACHE_N)
|
|
||||||
#define STRCACHE_N 53
|
|
||||||
#define STRCACHE_M 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* minimum size for string buffer */
|
|
||||||
#if !defined(LUA_MINBUFFER)
|
|
||||||
#define LUA_MINBUFFER 32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Maximum depth for nested C calls, syntactical nested non-terminals,
|
|
||||||
** and other features implemented through recursion in C. (Value must
|
|
||||||
** fit in a 16-bit unsigned integer. It must also be compatible with
|
|
||||||
** the size of the C stack.)
|
|
||||||
*/
|
|
||||||
#if !defined(LUAI_MAXCCALLS)
|
|
||||||
#define LUAI_MAXCCALLS 200
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** macros that are executed whenever program enters the Lua core
|
|
||||||
** ('lua_lock') and leaves the core ('lua_unlock')
|
|
||||||
*/
|
|
||||||
#if !defined(lua_lock)
|
|
||||||
#define lua_lock(L) ((void) 0)
|
|
||||||
#define lua_unlock(L) ((void) 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
** macro executed during Lua functions at points where the
|
|
||||||
** function can yield.
|
|
||||||
*/
|
|
||||||
#if !defined(luai_threadyield)
|
|
||||||
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** these macros allow user-specific actions when a thread is
|
|
||||||
** created/deleted/resumed/yielded.
|
|
||||||
*/
|
|
||||||
#if !defined(luai_userstateopen)
|
|
||||||
#define luai_userstateopen(L) ((void)L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(luai_userstateclose)
|
|
||||||
#define luai_userstateclose(L) ((void)L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(luai_userstatethread)
|
|
||||||
#define luai_userstatethread(L,L1) ((void)L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(luai_userstatefree)
|
|
||||||
#define luai_userstatefree(L,L1) ((void)L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(luai_userstateresume)
|
|
||||||
#define luai_userstateresume(L,n) ((void)L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(luai_userstateyield)
|
|
||||||
#define luai_userstateyield(L,n) ((void)L)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** The luai_num* macros define the primitive operations over numbers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* floor division (defined as 'floor(a/b)') */
|
|
||||||
#if !defined(luai_numidiv)
|
|
||||||
#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* float division */
|
|
||||||
#if !defined(luai_numdiv)
|
|
||||||
#define luai_numdiv(L,a,b) ((a)/(b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
** modulo: defined as 'a - floor(a/b)*b'; the direct computation
|
|
||||||
** using this definition has several problems with rounding errors,
|
|
||||||
** so it is better to use 'fmod'. 'fmod' gives the result of
|
|
||||||
** 'a - trunc(a/b)*b', and therefore must be corrected when
|
|
||||||
** 'trunc(a/b) ~= floor(a/b)'. That happens when the division has a
|
|
||||||
** non-integer negative result: non-integer result is equivalent to
|
|
||||||
** a non-zero remainder 'm'; negative result is equivalent to 'a' and
|
|
||||||
** 'b' with different signs, or 'm' and 'b' with different signs
|
|
||||||
** (as the result 'm' of 'fmod' has the same sign of 'a').
|
|
||||||
*/
|
|
||||||
#if !defined(luai_nummod)
|
|
||||||
#define luai_nummod(L,a,b,m) \
|
|
||||||
{ (void)L; (m) = l_mathop(fmod)(a,b); \
|
|
||||||
if (((m) > 0) ? (b) < 0 : ((m) < 0 && (b) > 0)) (m) += (b); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* exponentiation */
|
|
||||||
#if !defined(luai_numpow)
|
|
||||||
#define luai_numpow(L,a,b) \
|
|
||||||
((void)L, (b == 2) ? (a)*(a) : l_mathop(pow)(a,b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* the others are quite standard operations */
|
|
||||||
#if !defined(luai_numadd)
|
|
||||||
#define luai_numadd(L,a,b) ((a)+(b))
|
|
||||||
#define luai_numsub(L,a,b) ((a)-(b))
|
|
||||||
#define luai_nummul(L,a,b) ((a)*(b))
|
|
||||||
#define luai_numunm(L,a) (-(a))
|
|
||||||
#define luai_numeq(a,b) ((a)==(b))
|
|
||||||
#define luai_numlt(a,b) ((a)<(b))
|
|
||||||
#define luai_numle(a,b) ((a)<=(b))
|
|
||||||
#define luai_numgt(a,b) ((a)>(b))
|
|
||||||
#define luai_numge(a,b) ((a)>=(b))
|
|
||||||
#define luai_numisnan(a) (!luai_numeq((a), (a)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** macro to control inclusion of some hard tests on stack reallocation
|
|
||||||
*/
|
|
||||||
#if !defined(HARDSTACKTESTS)
|
|
||||||
#define condmovestack(L,pre,pos) ((void)0)
|
|
||||||
#else
|
|
||||||
/* realloc stack keeping its size */
|
|
||||||
#define condmovestack(L,pre,pos) \
|
|
||||||
{ int sz_ = stacksize(L); pre; luaD_reallocstack((L), sz_, 0); pos; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(HARDMEMTESTS)
|
|
||||||
#define condchangemem(L,pre,pos) ((void)0)
|
|
||||||
#else
|
|
||||||
#define condchangemem(L,pre,pos) \
|
|
||||||
{ if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
-971
@@ -1,971 +0,0 @@
|
|||||||
/*
|
|
||||||
** $Id: ltable.c $
|
|
||||||
** Lua tables (hash)
|
|
||||||
** See Copyright Notice in lua.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define ltable_c
|
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Implementation of tables (aka arrays, objects, or hash tables).
|
|
||||||
** Tables keep its elements in two parts: an array part and a hash part.
|
|
||||||
** Non-negative integer keys are all candidates to be kept in the array
|
|
||||||
** part. The actual size of the array is the largest 'n' such that
|
|
||||||
** more than half the slots between 1 and n are in use.
|
|
||||||
** Hash uses a mix of chained scatter table with Brent's variation.
|
|
||||||
** A main invariant of these tables is that, if an element is not
|
|
||||||
** in its main position (i.e. the 'original' position that its hash gives
|
|
||||||
** to it), then the colliding element is in its own main position.
|
|
||||||
** Hence even when the load factor reaches 100%, performance remains good.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
|
|
||||||
#include "ldebug.h"
|
|
||||||
#include "ldo.h"
|
|
||||||
#include "lgc.h"
|
|
||||||
#include "lmem.h"
|
|
||||||
#include "lobject.h"
|
|
||||||
#include "lstate.h"
|
|
||||||
#include "lstring.h"
|
|
||||||
#include "ltable.h"
|
|
||||||
#include "lvm.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** MAXABITS is the largest integer such that MAXASIZE fits in an
|
|
||||||
** unsigned int.
|
|
||||||
*/
|
|
||||||
#define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** MAXASIZE is the maximum size of the array part. It is the minimum
|
|
||||||
** between 2^MAXABITS and the maximum size that, measured in bytes,
|
|
||||||
** fits in a 'size_t'.
|
|
||||||
*/
|
|
||||||
#define MAXASIZE luaM_limitN(1u << MAXABITS, TValue)
|
|
||||||
|
|
||||||
/*
|
|
||||||
** MAXHBITS is the largest integer such that 2^MAXHBITS fits in a
|
|
||||||
** signed int.
|
|
||||||
*/
|
|
||||||
#define MAXHBITS (MAXABITS - 1)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** MAXHSIZE is the maximum size of the hash part. It is the minimum
|
|
||||||
** between 2^MAXHBITS and the maximum size such that, measured in bytes,
|
|
||||||
** it fits in a 'size_t'.
|
|
||||||
*/
|
|
||||||
#define MAXHSIZE luaM_limitN(1u << MAXHBITS, Node)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** When the original hash value is good, hashing by a power of 2
|
|
||||||
** avoids the cost of '%'.
|
|
||||||
*/
|
|
||||||
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
|
|
||||||
|
|
||||||
/*
|
|
||||||
** for other types, it is better to avoid modulo by power of 2, as
|
|
||||||
** they can have many 2 factors.
|
|
||||||
*/
|
|
||||||
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
|
|
||||||
|
|
||||||
|
|
||||||
#define hashstr(t,str) hashpow2(t, (str)->hash)
|
|
||||||
#define hashboolean(t,p) hashpow2(t, p)
|
|
||||||
|
|
||||||
#define hashint(t,i) hashpow2(t, i)
|
|
||||||
|
|
||||||
|
|
||||||
#define hashpointer(t,p) hashmod(t, point2uint(p))
|
|
||||||
|
|
||||||
|
|
||||||
#define dummynode (&dummynode_)
|
|
||||||
|
|
||||||
static const Node dummynode_ = {
|
|
||||||
{{NULL}, LUA_VEMPTY, /* value's value and type */
|
|
||||||
LUA_VNIL, 0, {NULL}} /* key type, next, and key value */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static const TValue absentkey = {ABSTKEYCONSTANT};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Hash for floating-point numbers.
|
|
||||||
** The main computation should be just
|
|
||||||
** n = frexp(n, &i); return (n * INT_MAX) + i
|
|
||||||
** but there are some numerical subtleties.
|
|
||||||
** In a two-complement representation, INT_MAX does not has an exact
|
|
||||||
** representation as a float, but INT_MIN does; because the absolute
|
|
||||||
** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the
|
|
||||||
** absolute value of the product 'frexp * -INT_MIN' is smaller or equal
|
|
||||||
** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when
|
|
||||||
** adding 'i'; the use of '~u' (instead of '-u') avoids problems with
|
|
||||||
** INT_MIN.
|
|
||||||
*/
|
|
||||||
#if !defined(l_hashfloat)
|
|
||||||
static int l_hashfloat (lua_Number n) {
|
|
||||||
int i;
|
|
||||||
lua_Integer ni;
|
|
||||||
n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN);
|
|
||||||
if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */
|
|
||||||
lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else { /* normal case */
|
|
||||||
unsigned int u = cast_uint(i) + cast_uint(ni);
|
|
||||||
return cast_int(u <= cast_uint(INT_MAX) ? u : ~u);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** returns the 'main' position of an element in a table (that is,
|
|
||||||
** the index of its hash value). The key comes broken (tag in 'ktt'
|
|
||||||
** and value in 'vkl') so that we can call it on keys inserted into
|
|
||||||
** nodes.
|
|
||||||
*/
|
|
||||||
static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
|
|
||||||
switch (withvariant(ktt)) {
|
|
||||||
case LUA_VNUMINT: {
|
|
||||||
lua_Integer key = ivalueraw(*kvl);
|
|
||||||
return hashint(t, key);
|
|
||||||
}
|
|
||||||
case LUA_VNUMFLT: {
|
|
||||||
lua_Number n = fltvalueraw(*kvl);
|
|
||||||
return hashmod(t, l_hashfloat(n));
|
|
||||||
}
|
|
||||||
case LUA_VSHRSTR: {
|
|
||||||
TString *ts = tsvalueraw(*kvl);
|
|
||||||
return hashstr(t, ts);
|
|
||||||
}
|
|
||||||
case LUA_VLNGSTR: {
|
|
||||||
TString *ts = tsvalueraw(*kvl);
|
|
||||||
return hashpow2(t, luaS_hashlongstr(ts));
|
|
||||||
}
|
|
||||||
case LUA_VFALSE:
|
|
||||||
return hashboolean(t, 0);
|
|
||||||
case LUA_VTRUE:
|
|
||||||
return hashboolean(t, 1);
|
|
||||||
case LUA_VLIGHTUSERDATA: {
|
|
||||||
void *p = pvalueraw(*kvl);
|
|
||||||
return hashpointer(t, p);
|
|
||||||
}
|
|
||||||
case LUA_VLCF: {
|
|
||||||
lua_CFunction f = fvalueraw(*kvl);
|
|
||||||
return hashpointer(t, f);
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
GCObject *o = gcvalueraw(*kvl);
|
|
||||||
return hashpointer(t, o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Returns the main position of an element given as a 'TValue'
|
|
||||||
*/
|
|
||||||
static Node *mainpositionTV (const Table *t, const TValue *key) {
|
|
||||||
return mainposition(t, rawtt(key), valraw(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Check whether key 'k1' is equal to the key in node 'n2'. This
|
|
||||||
** equality is raw, so there are no metamethods. Floats with integer
|
|
||||||
** values have been normalized, so integers cannot be equal to
|
|
||||||
** floats. It is assumed that 'eqshrstr' is simply pointer equality, so
|
|
||||||
** that short strings are handled in the default case.
|
|
||||||
** A true 'deadok' means to accept dead keys as equal to their original
|
|
||||||
** values. All dead keys are compared in the default case, by pointer
|
|
||||||
** identity. (Only collectable objects can produce dead keys.) Note that
|
|
||||||
** dead long strings are also compared by identity.
|
|
||||||
** Once a key is dead, its corresponding value may be collected, and
|
|
||||||
** then another value can be created with the same address. If this
|
|
||||||
** other value is given to 'next', 'equalkey' will signal a false
|
|
||||||
** positive. In a regular traversal, this situation should never happen,
|
|
||||||
** as all keys given to 'next' came from the table itself, and therefore
|
|
||||||
** could not have been collected. Outside a regular traversal, we
|
|
||||||
** have garbage in, garbage out. What is relevant is that this false
|
|
||||||
** positive does not break anything. (In particular, 'next' will return
|
|
||||||
** some other valid item on the table or nil.)
|
|
||||||
*/
|
|
||||||
static int equalkey (const TValue *k1, const Node *n2, int deadok) {
|
|
||||||
if ((rawtt(k1) != keytt(n2)) && /* not the same variants? */
|
|
||||||
!(deadok && keyisdead(n2) && iscollectable(k1)))
|
|
||||||
return 0; /* cannot be same key */
|
|
||||||
switch (keytt(n2)) {
|
|
||||||
case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE:
|
|
||||||
return 1;
|
|
||||||
case LUA_VNUMINT:
|
|
||||||
return (ivalue(k1) == keyival(n2));
|
|
||||||
case LUA_VNUMFLT:
|
|
||||||
return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2)));
|
|
||||||
case LUA_VLIGHTUSERDATA:
|
|
||||||
return pvalue(k1) == pvalueraw(keyval(n2));
|
|
||||||
case LUA_VLCF:
|
|
||||||
return fvalue(k1) == fvalueraw(keyval(n2));
|
|
||||||
case ctb(LUA_VLNGSTR):
|
|
||||||
return luaS_eqlngstr(tsvalue(k1), keystrval(n2));
|
|
||||||
default:
|
|
||||||
return gcvalue(k1) == gcvalueraw(keyval(n2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** True if value of 'alimit' is equal to the real size of the array
|
|
||||||
** part of table 't'. (Otherwise, the array part must be larger than
|
|
||||||
** 'alimit'.)
|
|
||||||
*/
|
|
||||||
#define limitequalsasize(t) (isrealasize(t) || ispow2((t)->alimit))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Returns the real size of the 'array' array
|
|
||||||
*/
|
|
||||||
LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
|
|
||||||
if (limitequalsasize(t))
|
|
||||||
return t->alimit; /* this is the size */
|
|
||||||
else {
|
|
||||||
unsigned int size = t->alimit;
|
|
||||||
/* compute the smallest power of 2 not smaller than 'n' */
|
|
||||||
size |= (size >> 1);
|
|
||||||
size |= (size >> 2);
|
|
||||||
size |= (size >> 4);
|
|
||||||
size |= (size >> 8);
|
|
||||||
size |= (size >> 16);
|
|
||||||
#if (UINT_MAX >> 30) > 3
|
|
||||||
size |= (size >> 32); /* unsigned int has more than 32 bits */
|
|
||||||
#endif
|
|
||||||
size++;
|
|
||||||
lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Check whether real size of the array is a power of 2.
|
|
||||||
** (If it is not, 'alimit' cannot be changed to any other value
|
|
||||||
** without changing the real size.)
|
|
||||||
*/
|
|
||||||
static int ispow2realasize (const Table *t) {
|
|
||||||
return (!isrealasize(t) || ispow2(t->alimit));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned int setlimittosize (Table *t) {
|
|
||||||
t->alimit = luaH_realasize(t);
|
|
||||||
setrealasize(t);
|
|
||||||
return t->alimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define limitasasize(t) check_exp(isrealasize(t), t->alimit)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** "Generic" get version. (Not that generic: not valid for integers,
|
|
||||||
** which may be in array part, nor for floats with integral values.)
|
|
||||||
** See explanation about 'deadok' in function 'equalkey'.
|
|
||||||
*/
|
|
||||||
static const TValue *getgeneric (Table *t, const TValue *key, int deadok) {
|
|
||||||
Node *n = mainpositionTV(t, key);
|
|
||||||
for (;;) { /* check whether 'key' is somewhere in the chain */
|
|
||||||
if (equalkey(key, n, deadok))
|
|
||||||
return gval(n); /* that's it */
|
|
||||||
else {
|
|
||||||
int nx = gnext(n);
|
|
||||||
if (nx == 0)
|
|
||||||
return &absentkey; /* not found */
|
|
||||||
n += nx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** returns the index for 'k' if 'k' is an appropriate key to live in
|
|
||||||
** the array part of a table, 0 otherwise.
|
|
||||||
*/
|
|
||||||
static unsigned int arrayindex (lua_Integer k) {
|
|
||||||
if (l_castS2U(k) - 1u < MAXASIZE) /* 'k' in [1, MAXASIZE]? */
|
|
||||||
return cast_uint(k); /* 'key' is an appropriate array index */
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** returns the index of a 'key' for table traversals. First goes all
|
|
||||||
** elements in the array part, then elements in the hash part. The
|
|
||||||
** beginning of a traversal is signaled by 0.
|
|
||||||
*/
|
|
||||||
static unsigned int findindex (lua_State *L, Table *t, TValue *key,
|
|
||||||
unsigned int asize) {
|
|
||||||
unsigned int i;
|
|
||||||
if (ttisnil(key)) return 0; /* first iteration */
|
|
||||||
i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0;
|
|
||||||
if (i - 1u < asize) /* is 'key' inside array part? */
|
|
||||||
return i; /* yes; that's the index */
|
|
||||||
else {
|
|
||||||
const TValue *n = getgeneric(t, key, 1);
|
|
||||||
if (l_unlikely(isabstkey(n)))
|
|
||||||
luaG_runerror(L, "invalid key to 'next'"); /* key not found */
|
|
||||||
i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */
|
|
||||||
/* hash elements are numbered after array ones */
|
|
||||||
return (i + 1) + asize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int luaH_next (lua_State *L, Table *t, StkId key) {
|
|
||||||
unsigned int asize = luaH_realasize(t);
|
|
||||||
unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */
|
|
||||||
for (; i < asize; i++) { /* try first array part */
|
|
||||||
if (!isempty(&t->array[i])) { /* a non-empty entry? */
|
|
||||||
setivalue(s2v(key), i + 1);
|
|
||||||
setobj2s(L, key + 1, &t->array[i]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i -= asize; cast_int(i) < sizenode(t); i++) { /* hash part */
|
|
||||||
if (!isempty(gval(gnode(t, i)))) { /* a non-empty entry? */
|
|
||||||
Node *n = gnode(t, i);
|
|
||||||
getnodekey(L, s2v(key), n);
|
|
||||||
setobj2s(L, key + 1, gval(n));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0; /* no more elements */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void freehash (lua_State *L, Table *t) {
|
|
||||||
if (!isdummy(t))
|
|
||||||
luaM_freearray(L, t->node, cast_sizet(sizenode(t)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** {=============================================================
|
|
||||||
** Rehash
|
|
||||||
** ==============================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Compute the optimal size for the array part of table 't'. 'nums' is a
|
|
||||||
** "count array" where 'nums[i]' is the number of integers in the table
|
|
||||||
** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of
|
|
||||||
** integer keys in the table and leaves with the number of keys that
|
|
||||||
** will go to the array part; return the optimal size. (The condition
|
|
||||||
** 'twotoi > 0' in the for loop stops the loop if 'twotoi' overflows.)
|
|
||||||
*/
|
|
||||||
static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
|
|
||||||
int i;
|
|
||||||
unsigned int twotoi; /* 2^i (candidate for optimal size) */
|
|
||||||
unsigned int a = 0; /* number of elements smaller than 2^i */
|
|
||||||
unsigned int na = 0; /* number of elements to go to array part */
|
|
||||||
unsigned int optimal = 0; /* optimal size for array part */
|
|
||||||
/* loop while keys can fill more than half of total size */
|
|
||||||
for (i = 0, twotoi = 1;
|
|
||||||
twotoi > 0 && *pna > twotoi / 2;
|
|
||||||
i++, twotoi *= 2) {
|
|
||||||
a += nums[i];
|
|
||||||
if (a > twotoi/2) { /* more than half elements present? */
|
|
||||||
optimal = twotoi; /* optimal size (till now) */
|
|
||||||
na = a; /* all elements up to 'optimal' will go to array part */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal);
|
|
||||||
*pna = na;
|
|
||||||
return optimal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int countint (lua_Integer key, unsigned int *nums) {
|
|
||||||
unsigned int k = arrayindex(key);
|
|
||||||
if (k != 0) { /* is 'key' an appropriate array index? */
|
|
||||||
nums[luaO_ceillog2(k)]++; /* count as such */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Count keys in array part of table 't': Fill 'nums[i]' with
|
|
||||||
** number of keys that will go into corresponding slice and return
|
|
||||||
** total number of non-nil keys.
|
|
||||||
*/
|
|
||||||
static unsigned int numusearray (const Table *t, unsigned int *nums) {
|
|
||||||
int lg;
|
|
||||||
unsigned int ttlg; /* 2^lg */
|
|
||||||
unsigned int ause = 0; /* summation of 'nums' */
|
|
||||||
unsigned int i = 1; /* count to traverse all array keys */
|
|
||||||
unsigned int asize = limitasasize(t); /* real array size */
|
|
||||||
/* traverse each slice */
|
|
||||||
for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) {
|
|
||||||
unsigned int lc = 0; /* counter */
|
|
||||||
unsigned int lim = ttlg;
|
|
||||||
if (lim > asize) {
|
|
||||||
lim = asize; /* adjust upper limit */
|
|
||||||
if (i > lim)
|
|
||||||
break; /* no more elements to count */
|
|
||||||
}
|
|
||||||
/* count elements in range (2^(lg - 1), 2^lg] */
|
|
||||||
for (; i <= lim; i++) {
|
|
||||||
if (!isempty(&t->array[i-1]))
|
|
||||||
lc++;
|
|
||||||
}
|
|
||||||
nums[lg] += lc;
|
|
||||||
ause += lc;
|
|
||||||
}
|
|
||||||
return ause;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
|
|
||||||
int totaluse = 0; /* total number of elements */
|
|
||||||
int ause = 0; /* elements added to 'nums' (can go to array part) */
|
|
||||||
int i = sizenode(t);
|
|
||||||
while (i--) {
|
|
||||||
Node *n = &t->node[i];
|
|
||||||
if (!isempty(gval(n))) {
|
|
||||||
if (keyisinteger(n))
|
|
||||||
ause += countint(keyival(n), nums);
|
|
||||||
totaluse++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*pna += ause;
|
|
||||||
return totaluse;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Creates an array for the hash part of a table with the given
|
|
||||||
** size, or reuses the dummy node if size is zero.
|
|
||||||
** The computation for size overflow is in two steps: the first
|
|
||||||
** comparison ensures that the shift in the second one does not
|
|
||||||
** overflow.
|
|
||||||
*/
|
|
||||||
static void setnodevector (lua_State *L, Table *t, unsigned int size) {
|
|
||||||
if (size == 0) { /* no elements to hash part? */
|
|
||||||
t->node = cast(Node *, dummynode); /* use common 'dummynode' */
|
|
||||||
t->lsizenode = 0;
|
|
||||||
t->lastfree = NULL; /* signal that it is using dummy node */
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int i;
|
|
||||||
int lsize = luaO_ceillog2(size);
|
|
||||||
if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE)
|
|
||||||
luaG_runerror(L, "table overflow");
|
|
||||||
size = twoto(lsize);
|
|
||||||
t->node = luaM_newvector(L, size, Node);
|
|
||||||
for (i = 0; i < (int)size; i++) {
|
|
||||||
Node *n = gnode(t, i);
|
|
||||||
gnext(n) = 0;
|
|
||||||
setnilkey(n);
|
|
||||||
setempty(gval(n));
|
|
||||||
}
|
|
||||||
t->lsizenode = cast_byte(lsize);
|
|
||||||
t->lastfree = gnode(t, size); /* all positions are free */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** (Re)insert all elements from the hash part of 'ot' into table 't'.
|
|
||||||
*/
|
|
||||||
static void reinsert (lua_State *L, Table *ot, Table *t) {
|
|
||||||
int j;
|
|
||||||
int size = sizenode(ot);
|
|
||||||
for (j = 0; j < size; j++) {
|
|
||||||
Node *old = gnode(ot, j);
|
|
||||||
if (!isempty(gval(old))) {
|
|
||||||
/* doesn't need barrier/invalidate cache, as entry was
|
|
||||||
already present in the table */
|
|
||||||
TValue k;
|
|
||||||
getnodekey(L, &k, old);
|
|
||||||
luaH_set(L, t, &k, gval(old));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Exchange the hash part of 't1' and 't2'.
|
|
||||||
*/
|
|
||||||
static void exchangehashpart (Table *t1, Table *t2) {
|
|
||||||
lu_byte lsizenode = t1->lsizenode;
|
|
||||||
Node *node = t1->node;
|
|
||||||
Node *lastfree = t1->lastfree;
|
|
||||||
t1->lsizenode = t2->lsizenode;
|
|
||||||
t1->node = t2->node;
|
|
||||||
t1->lastfree = t2->lastfree;
|
|
||||||
t2->lsizenode = lsizenode;
|
|
||||||
t2->node = node;
|
|
||||||
t2->lastfree = lastfree;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Resize table 't' for the new given sizes. Both allocations (for
|
|
||||||
** the hash part and for the array part) can fail, which creates some
|
|
||||||
** subtleties. If the first allocation, for the hash part, fails, an
|
|
||||||
** error is raised and that is it. Otherwise, it copies the elements from
|
|
||||||
** the shrinking part of the array (if it is shrinking) into the new
|
|
||||||
** hash. Then it reallocates the array part. If that fails, the table
|
|
||||||
** is in its original state; the function frees the new hash part and then
|
|
||||||
** raises the allocation error. Otherwise, it sets the new hash part
|
|
||||||
** into the table, initializes the new part of the array (if any) with
|
|
||||||
** nils and reinserts the elements of the old hash back into the new
|
|
||||||
** parts of the table.
|
|
||||||
*/
|
|
||||||
void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
|
|
||||||
unsigned int nhsize) {
|
|
||||||
unsigned int i;
|
|
||||||
Table newt; /* to keep the new hash part */
|
|
||||||
unsigned int oldasize = setlimittosize(t);
|
|
||||||
TValue *newarray;
|
|
||||||
/* create new hash part with appropriate size into 'newt' */
|
|
||||||
setnodevector(L, &newt, nhsize);
|
|
||||||
if (newasize < oldasize) { /* will array shrink? */
|
|
||||||
t->alimit = newasize; /* pretend array has new size... */
|
|
||||||
exchangehashpart(t, &newt); /* and new hash */
|
|
||||||
/* re-insert into the new hash the elements from vanishing slice */
|
|
||||||
for (i = newasize; i < oldasize; i++) {
|
|
||||||
if (!isempty(&t->array[i]))
|
|
||||||
luaH_setint(L, t, i + 1, &t->array[i]);
|
|
||||||
}
|
|
||||||
t->alimit = oldasize; /* restore current size... */
|
|
||||||
exchangehashpart(t, &newt); /* and hash (in case of errors) */
|
|
||||||
}
|
|
||||||
/* allocate new array */
|
|
||||||
newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue);
|
|
||||||
if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */
|
|
||||||
freehash(L, &newt); /* release new hash part */
|
|
||||||
luaM_error(L); /* raise error (with array unchanged) */
|
|
||||||
}
|
|
||||||
/* allocation ok; initialize new part of the array */
|
|
||||||
exchangehashpart(t, &newt); /* 't' has the new hash ('newt' has the old) */
|
|
||||||
t->array = newarray; /* set new array part */
|
|
||||||
t->alimit = newasize;
|
|
||||||
for (i = oldasize; i < newasize; i++) /* clear new slice of the array */
|
|
||||||
setempty(&t->array[i]);
|
|
||||||
/* re-insert elements from old hash part into new parts */
|
|
||||||
reinsert(L, &newt, t); /* 'newt' now has the old hash */
|
|
||||||
freehash(L, &newt); /* free old hash part */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
|
|
||||||
int nsize = allocsizenode(t);
|
|
||||||
luaH_resize(L, t, nasize, nsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i
|
|
||||||
*/
|
|
||||||
static void rehash (lua_State *L, Table *t, const TValue *ek) {
|
|
||||||
unsigned int asize; /* optimal size for array part */
|
|
||||||
unsigned int na; /* number of keys in the array part */
|
|
||||||
unsigned int nums[MAXABITS + 1];
|
|
||||||
int i;
|
|
||||||
int totaluse;
|
|
||||||
for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */
|
|
||||||
setlimittosize(t);
|
|
||||||
na = numusearray(t, nums); /* count keys in array part */
|
|
||||||
totaluse = na; /* all those keys are integer keys */
|
|
||||||
totaluse += numusehash(t, nums, &na); /* count keys in hash part */
|
|
||||||
/* count extra key */
|
|
||||||
if (ttisinteger(ek))
|
|
||||||
na += countint(ivalue(ek), nums);
|
|
||||||
totaluse++;
|
|
||||||
/* compute new size for array part */
|
|
||||||
asize = computesizes(nums, &na);
|
|
||||||
/* resize the table to new computed sizes */
|
|
||||||
luaH_resize(L, t, asize, totaluse - na);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** }=============================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Table *luaH_new (lua_State *L) {
|
|
||||||
GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table));
|
|
||||||
Table *t = gco2t(o);
|
|
||||||
t->metatable = NULL;
|
|
||||||
t->flags = cast_byte(maskflags); /* table has no metamethod fields */
|
|
||||||
t->array = NULL;
|
|
||||||
t->alimit = 0;
|
|
||||||
setnodevector(L, t, 0);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaH_free (lua_State *L, Table *t) {
|
|
||||||
freehash(L, t);
|
|
||||||
luaM_freearray(L, t->array, luaH_realasize(t));
|
|
||||||
luaM_free(L, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Node *getfreepos (Table *t) {
|
|
||||||
if (!isdummy(t)) {
|
|
||||||
while (t->lastfree > t->node) {
|
|
||||||
t->lastfree--;
|
|
||||||
if (keyisnil(t->lastfree))
|
|
||||||
return t->lastfree;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL; /* could not find a free place */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** inserts a new key into a hash table; first, check whether key's main
|
|
||||||
** position is free. If not, check whether colliding node is in its main
|
|
||||||
** position or not: if it is not, move colliding node to an empty place and
|
|
||||||
** put new key in its main position; otherwise (colliding node is in its main
|
|
||||||
** position), new key goes to an empty position.
|
|
||||||
*/
|
|
||||||
void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
|
|
||||||
Node *mp;
|
|
||||||
TValue aux;
|
|
||||||
if (l_unlikely(ttisnil(key)))
|
|
||||||
luaG_runerror(L, "table index is nil");
|
|
||||||
else if (ttisfloat(key)) {
|
|
||||||
lua_Number f = fltvalue(key);
|
|
||||||
lua_Integer k;
|
|
||||||
if (luaV_flttointeger(f, &k, F2Ieq)) { /* does key fit in an integer? */
|
|
||||||
setivalue(&aux, k);
|
|
||||||
key = &aux; /* insert it as an integer */
|
|
||||||
}
|
|
||||||
else if (l_unlikely(luai_numisnan(f)))
|
|
||||||
luaG_runerror(L, "table index is NaN");
|
|
||||||
}
|
|
||||||
if (ttisnil(value))
|
|
||||||
return; /* do not insert nil values */
|
|
||||||
mp = mainpositionTV(t, key);
|
|
||||||
if (!isempty(gval(mp)) || isdummy(t)) { /* main position is taken? */
|
|
||||||
Node *othern;
|
|
||||||
Node *f = getfreepos(t); /* get a free place */
|
|
||||||
if (f == NULL) { /* cannot find a free place? */
|
|
||||||
rehash(L, t, key); /* grow table */
|
|
||||||
/* whatever called 'newkey' takes care of TM cache */
|
|
||||||
luaH_set(L, t, key, value); /* insert key into grown table */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lua_assert(!isdummy(t));
|
|
||||||
othern = mainposition(t, keytt(mp), &keyval(mp));
|
|
||||||
if (othern != mp) { /* is colliding node out of its main position? */
|
|
||||||
/* yes; move colliding node into free position */
|
|
||||||
while (othern + gnext(othern) != mp) /* find previous */
|
|
||||||
othern += gnext(othern);
|
|
||||||
gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */
|
|
||||||
*f = *mp; /* copy colliding node into free pos. (mp->next also goes) */
|
|
||||||
if (gnext(mp) != 0) {
|
|
||||||
gnext(f) += cast_int(mp - f); /* correct 'next' */
|
|
||||||
gnext(mp) = 0; /* now 'mp' is free */
|
|
||||||
}
|
|
||||||
setempty(gval(mp));
|
|
||||||
}
|
|
||||||
else { /* colliding node is in its own main position */
|
|
||||||
/* new node will go into free position */
|
|
||||||
if (gnext(mp) != 0)
|
|
||||||
gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */
|
|
||||||
else lua_assert(gnext(f) == 0);
|
|
||||||
gnext(mp) = cast_int(f - mp);
|
|
||||||
mp = f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setnodekey(L, mp, key);
|
|
||||||
luaC_barrierback(L, obj2gco(t), key);
|
|
||||||
lua_assert(isempty(gval(mp)));
|
|
||||||
setobj2t(L, gval(mp), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Search function for integers. If integer is inside 'alimit', get it
|
|
||||||
** directly from the array part. Otherwise, if 'alimit' is not equal to
|
|
||||||
** the real size of the array, key still can be in the array part. In
|
|
||||||
** this case, try to avoid a call to 'luaH_realasize' when key is just
|
|
||||||
** one more than the limit (so that it can be incremented without
|
|
||||||
** changing the real size of the array).
|
|
||||||
*/
|
|
||||||
const TValue *luaH_getint (Table *t, lua_Integer key) {
|
|
||||||
if (l_castS2U(key) - 1u < t->alimit) /* 'key' in [1, t->alimit]? */
|
|
||||||
return &t->array[key - 1];
|
|
||||||
else if (!limitequalsasize(t) && /* key still may be in the array part? */
|
|
||||||
(l_castS2U(key) == t->alimit + 1 ||
|
|
||||||
l_castS2U(key) - 1u < luaH_realasize(t))) {
|
|
||||||
t->alimit = cast_uint(key); /* probably '#t' is here now */
|
|
||||||
return &t->array[key - 1];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Node *n = hashint(t, key);
|
|
||||||
for (;;) { /* check whether 'key' is somewhere in the chain */
|
|
||||||
if (keyisinteger(n) && keyival(n) == key)
|
|
||||||
return gval(n); /* that's it */
|
|
||||||
else {
|
|
||||||
int nx = gnext(n);
|
|
||||||
if (nx == 0) break;
|
|
||||||
n += nx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &absentkey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** search function for short strings
|
|
||||||
*/
|
|
||||||
const TValue *luaH_getshortstr (Table *t, TString *key) {
|
|
||||||
Node *n = hashstr(t, key);
|
|
||||||
lua_assert(key->tt == LUA_VSHRSTR);
|
|
||||||
for (;;) { /* check whether 'key' is somewhere in the chain */
|
|
||||||
if (keyisshrstr(n) && eqshrstr(keystrval(n), key))
|
|
||||||
return gval(n); /* that's it */
|
|
||||||
else {
|
|
||||||
int nx = gnext(n);
|
|
||||||
if (nx == 0)
|
|
||||||
return &absentkey; /* not found */
|
|
||||||
n += nx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const TValue *luaH_getstr (Table *t, TString *key) {
|
|
||||||
if (key->tt == LUA_VSHRSTR)
|
|
||||||
return luaH_getshortstr(t, key);
|
|
||||||
else { /* for long strings, use generic case */
|
|
||||||
TValue ko;
|
|
||||||
setsvalue(cast(lua_State *, NULL), &ko, key);
|
|
||||||
return getgeneric(t, &ko, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** main search function
|
|
||||||
*/
|
|
||||||
const TValue *luaH_get (Table *t, const TValue *key) {
|
|
||||||
switch (ttypetag(key)) {
|
|
||||||
case LUA_VSHRSTR: return luaH_getshortstr(t, tsvalue(key));
|
|
||||||
case LUA_VNUMINT: return luaH_getint(t, ivalue(key));
|
|
||||||
case LUA_VNIL: return &absentkey;
|
|
||||||
case LUA_VNUMFLT: {
|
|
||||||
lua_Integer k;
|
|
||||||
if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* integral index? */
|
|
||||||
return luaH_getint(t, k); /* use specialized version */
|
|
||||||
/* else... */
|
|
||||||
} /* FALLTHROUGH */
|
|
||||||
default:
|
|
||||||
return getgeneric(t, key, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Finish a raw "set table" operation, where 'slot' is where the value
|
|
||||||
** should have been (the result of a previous "get table").
|
|
||||||
** Beware: when using this function you probably need to check a GC
|
|
||||||
** barrier and invalidate the TM cache.
|
|
||||||
*/
|
|
||||||
void luaH_finishset (lua_State *L, Table *t, const TValue *key,
|
|
||||||
const TValue *slot, TValue *value) {
|
|
||||||
if (isabstkey(slot))
|
|
||||||
luaH_newkey(L, t, key, value);
|
|
||||||
else
|
|
||||||
setobj2t(L, cast(TValue *, slot), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** beware: when using this function you probably need to check a GC
|
|
||||||
** barrier and invalidate the TM cache.
|
|
||||||
*/
|
|
||||||
void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) {
|
|
||||||
const TValue *slot = luaH_get(t, key);
|
|
||||||
luaH_finishset(L, t, key, slot, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
|
|
||||||
const TValue *p = luaH_getint(t, key);
|
|
||||||
if (isabstkey(p)) {
|
|
||||||
TValue k;
|
|
||||||
setivalue(&k, key);
|
|
||||||
luaH_newkey(L, t, &k, value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
setobj2t(L, cast(TValue *, p), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Try to find a boundary in the hash part of table 't'. From the
|
|
||||||
** caller, we know that 'j' is zero or present and that 'j + 1' is
|
|
||||||
** present. We want to find a larger key that is absent from the
|
|
||||||
** table, so that we can do a binary search between the two keys to
|
|
||||||
** find a boundary. We keep doubling 'j' until we get an absent index.
|
|
||||||
** If the doubling would overflow, we try LUA_MAXINTEGER. If it is
|
|
||||||
** absent, we are ready for the binary search. ('j', being max integer,
|
|
||||||
** is larger or equal to 'i', but it cannot be equal because it is
|
|
||||||
** absent while 'i' is present; so 'j > i'.) Otherwise, 'j' is a
|
|
||||||
** boundary. ('j + 1' cannot be a present integer key because it is
|
|
||||||
** not a valid integer in Lua.)
|
|
||||||
*/
|
|
||||||
static lua_Unsigned hash_search (Table *t, lua_Unsigned j) {
|
|
||||||
lua_Unsigned i;
|
|
||||||
if (j == 0) j++; /* the caller ensures 'j + 1' is present */
|
|
||||||
do {
|
|
||||||
i = j; /* 'i' is a present index */
|
|
||||||
if (j <= l_castS2U(LUA_MAXINTEGER) / 2)
|
|
||||||
j *= 2;
|
|
||||||
else {
|
|
||||||
j = LUA_MAXINTEGER;
|
|
||||||
if (isempty(luaH_getint(t, j))) /* t[j] not present? */
|
|
||||||
break; /* 'j' now is an absent index */
|
|
||||||
else /* weird case */
|
|
||||||
return j; /* well, max integer is a boundary... */
|
|
||||||
}
|
|
||||||
} while (!isempty(luaH_getint(t, j))); /* repeat until an absent t[j] */
|
|
||||||
/* i < j && t[i] present && t[j] absent */
|
|
||||||
while (j - i > 1u) { /* do a binary search between them */
|
|
||||||
lua_Unsigned m = (i + j) / 2;
|
|
||||||
if (isempty(luaH_getint(t, m))) j = m;
|
|
||||||
else i = m;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned int binsearch (const TValue *array, unsigned int i,
|
|
||||||
unsigned int j) {
|
|
||||||
while (j - i > 1u) { /* binary search */
|
|
||||||
unsigned int m = (i + j) / 2;
|
|
||||||
if (isempty(&array[m - 1])) j = m;
|
|
||||||
else i = m;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Try to find a boundary in table 't'. (A 'boundary' is an integer index
|
|
||||||
** such that t[i] is present and t[i+1] is absent, or 0 if t[1] is absent
|
|
||||||
** and 'maxinteger' if t[maxinteger] is present.)
|
|
||||||
** (In the next explanation, we use Lua indices, that is, with base 1.
|
|
||||||
** The code itself uses base 0 when indexing the array part of the table.)
|
|
||||||
** The code starts with 'limit = t->alimit', a position in the array
|
|
||||||
** part that may be a boundary.
|
|
||||||
**
|
|
||||||
** (1) If 't[limit]' is empty, there must be a boundary before it.
|
|
||||||
** As a common case (e.g., after 't[#t]=nil'), check whether 'limit-1'
|
|
||||||
** is present. If so, it is a boundary. Otherwise, do a binary search
|
|
||||||
** between 0 and limit to find a boundary. In both cases, try to
|
|
||||||
** use this boundary as the new 'alimit', as a hint for the next call.
|
|
||||||
**
|
|
||||||
** (2) If 't[limit]' is not empty and the array has more elements
|
|
||||||
** after 'limit', try to find a boundary there. Again, try first
|
|
||||||
** the special case (which should be quite frequent) where 'limit+1'
|
|
||||||
** is empty, so that 'limit' is a boundary. Otherwise, check the
|
|
||||||
** last element of the array part. If it is empty, there must be a
|
|
||||||
** boundary between the old limit (present) and the last element
|
|
||||||
** (absent), which is found with a binary search. (This boundary always
|
|
||||||
** can be a new limit.)
|
|
||||||
**
|
|
||||||
** (3) The last case is when there are no elements in the array part
|
|
||||||
** (limit == 0) or its last element (the new limit) is present.
|
|
||||||
** In this case, must check the hash part. If there is no hash part
|
|
||||||
** or 'limit+1' is absent, 'limit' is a boundary. Otherwise, call
|
|
||||||
** 'hash_search' to find a boundary in the hash part of the table.
|
|
||||||
** (In those cases, the boundary is not inside the array part, and
|
|
||||||
** therefore cannot be used as a new limit.)
|
|
||||||
*/
|
|
||||||
lua_Unsigned luaH_getn (Table *t) {
|
|
||||||
unsigned int limit = t->alimit;
|
|
||||||
if (limit > 0 && isempty(&t->array[limit - 1])) { /* (1)? */
|
|
||||||
/* there must be a boundary before 'limit' */
|
|
||||||
if (limit >= 2 && !isempty(&t->array[limit - 2])) {
|
|
||||||
/* 'limit - 1' is a boundary; can it be a new limit? */
|
|
||||||
if (ispow2realasize(t) && !ispow2(limit - 1)) {
|
|
||||||
t->alimit = limit - 1;
|
|
||||||
setnorealasize(t); /* now 'alimit' is not the real size */
|
|
||||||
}
|
|
||||||
return limit - 1;
|
|
||||||
}
|
|
||||||
else { /* must search for a boundary in [0, limit] */
|
|
||||||
unsigned int boundary = binsearch(t->array, 0, limit);
|
|
||||||
/* can this boundary represent the real size of the array? */
|
|
||||||
if (ispow2realasize(t) && boundary > luaH_realasize(t) / 2) {
|
|
||||||
t->alimit = boundary; /* use it as the new limit */
|
|
||||||
setnorealasize(t);
|
|
||||||
}
|
|
||||||
return boundary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* 'limit' is zero or present in table */
|
|
||||||
if (!limitequalsasize(t)) { /* (2)? */
|
|
||||||
/* 'limit' > 0 and array has more elements after 'limit' */
|
|
||||||
if (isempty(&t->array[limit])) /* 'limit + 1' is empty? */
|
|
||||||
return limit; /* this is the boundary */
|
|
||||||
/* else, try last element in the array */
|
|
||||||
limit = luaH_realasize(t);
|
|
||||||
if (isempty(&t->array[limit - 1])) { /* empty? */
|
|
||||||
/* there must be a boundary in the array after old limit,
|
|
||||||
and it must be a valid new limit */
|
|
||||||
unsigned int boundary = binsearch(t->array, t->alimit, limit);
|
|
||||||
t->alimit = boundary;
|
|
||||||
return boundary;
|
|
||||||
}
|
|
||||||
/* else, new limit is present in the table; check the hash part */
|
|
||||||
}
|
|
||||||
/* (3) 'limit' is the last element and either is zero or present in table */
|
|
||||||
lua_assert(limit == luaH_realasize(t) &&
|
|
||||||
(limit == 0 || !isempty(&t->array[limit - 1])));
|
|
||||||
if (isdummy(t) || isempty(luaH_getint(t, cast(lua_Integer, limit + 1))))
|
|
||||||
return limit; /* 'limit + 1' is absent */
|
|
||||||
else /* 'limit + 1' is also present */
|
|
||||||
return hash_search(t, limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_DEBUG)
|
|
||||||
|
|
||||||
/* export these functions for the test library */
|
|
||||||
|
|
||||||
Node *luaH_mainposition (const Table *t, const TValue *key) {
|
|
||||||
return mainpositionTV(t, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
int luaH_isdummy (const Table *t) { return isdummy(t); }
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
** $Id: ltable.h $
|
|
||||||
** Lua tables (hash)
|
|
||||||
** See Copyright Notice in lua.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ltable_h
|
|
||||||
#define ltable_h
|
|
||||||
|
|
||||||
#include "lobject.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define gnode(t,i) (&(t)->node[i])
|
|
||||||
#define gval(n) (&(n)->i_val)
|
|
||||||
#define gnext(n) ((n)->u.next)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Clear all bits of fast-access metamethods, which means that the table
|
|
||||||
** may have any of these metamethods. (First access that fails after the
|
|
||||||
** clearing will set the bit again.)
|
|
||||||
*/
|
|
||||||
#define invalidateTMcache(t) ((t)->flags &= ~maskflags)
|
|
||||||
|
|
||||||
|
|
||||||
/* true when 't' is using 'dummynode' as its hash part */
|
|
||||||
#define isdummy(t) ((t)->lastfree == NULL)
|
|
||||||
|
|
||||||
|
|
||||||
/* allocated size for hash nodes */
|
|
||||||
#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t))
|
|
||||||
|
|
||||||
|
|
||||||
/* returns the Node, given the value of a table entry */
|
|
||||||
#define nodefromval(v) cast(Node *, (v))
|
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
|
|
||||||
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
|
|
||||||
TValue *value);
|
|
||||||
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
|
|
||||||
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
|
|
||||||
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
|
|
||||||
LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key,
|
|
||||||
TValue *value);
|
|
||||||
LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
|
|
||||||
TValue *value);
|
|
||||||
LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
|
|
||||||
const TValue *slot, TValue *value);
|
|
||||||
LUAI_FUNC Table *luaH_new (lua_State *L);
|
|
||||||
LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
|
|
||||||
unsigned int nhsize);
|
|
||||||
LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize);
|
|
||||||
LUAI_FUNC void luaH_free (lua_State *L, Table *t);
|
|
||||||
LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
|
|
||||||
LUAI_FUNC lua_Unsigned luaH_getn (Table *t);
|
|
||||||
LUAI_FUNC unsigned int luaH_realasize (const Table *t);
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_DEBUG)
|
|
||||||
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
|
|
||||||
LUAI_FUNC int luaH_isdummy (const Table *t);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,271 +0,0 @@
|
|||||||
/*
|
|
||||||
** $Id: ltm.c $
|
|
||||||
** Tag methods
|
|
||||||
** See Copyright Notice in lua.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define ltm_c
|
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
|
|
||||||
#include "ldebug.h"
|
|
||||||
#include "ldo.h"
|
|
||||||
#include "lgc.h"
|
|
||||||
#include "lobject.h"
|
|
||||||
#include "lstate.h"
|
|
||||||
#include "lstring.h"
|
|
||||||
#include "ltable.h"
|
|
||||||
#include "ltm.h"
|
|
||||||
#include "lvm.h"
|
|
||||||
|
|
||||||
|
|
||||||
static const char udatatypename[] = "userdata";
|
|
||||||
|
|
||||||
LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTYPES] = {
|
|
||||||
"no value",
|
|
||||||
"nil", "boolean", udatatypename, "number",
|
|
||||||
"string", "table", "function", udatatypename, "thread",
|
|
||||||
"upvalue", "proto" /* these last cases are used for tests only */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void luaT_init (lua_State *L) {
|
|
||||||
static const char *const luaT_eventname[] = { /* ORDER TM */
|
|
||||||
"__index", "__newindex",
|
|
||||||
"__gc", "__mode", "__len", "__eq",
|
|
||||||
"__add", "__sub", "__mul", "__mod", "__pow",
|
|
||||||
"__div", "__idiv",
|
|
||||||
"__band", "__bor", "__bxor", "__shl", "__shr",
|
|
||||||
"__unm", "__bnot", "__lt", "__le",
|
|
||||||
"__concat", "__call", "__close"
|
|
||||||
};
|
|
||||||
int i;
|
|
||||||
for (i=0; i<TM_N; i++) {
|
|
||||||
G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);
|
|
||||||
luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** function to be used with macro "fasttm": optimized for absence of
|
|
||||||
** tag methods
|
|
||||||
*/
|
|
||||||
const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
|
|
||||||
const TValue *tm = luaH_getshortstr(events, ename);
|
|
||||||
lua_assert(event <= TM_EQ);
|
|
||||||
if (notm(tm)) { /* no tag method? */
|
|
||||||
events->flags |= cast_byte(1u<<event); /* cache this fact */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else return tm;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
|
|
||||||
Table *mt;
|
|
||||||
switch (ttype(o)) {
|
|
||||||
case LUA_TTABLE:
|
|
||||||
mt = hvalue(o)->metatable;
|
|
||||||
break;
|
|
||||||
case LUA_TUSERDATA:
|
|
||||||
mt = uvalue(o)->metatable;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mt = G(L)->mt[ttype(o)];
|
|
||||||
}
|
|
||||||
return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : &G(L)->nilvalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Return the name of the type of an object. For tables and userdata
|
|
||||||
** with metatable, use their '__name' metafield, if present.
|
|
||||||
*/
|
|
||||||
const char *luaT_objtypename (lua_State *L, const TValue *o) {
|
|
||||||
Table *mt;
|
|
||||||
if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
|
|
||||||
(ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
|
|
||||||
const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name"));
|
|
||||||
if (ttisstring(name)) /* is '__name' a string? */
|
|
||||||
return getstr(tsvalue(name)); /* use it as type name */
|
|
||||||
}
|
|
||||||
return ttypename(ttype(o)); /* else use standard type name */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
|
|
||||||
const TValue *p2, const TValue *p3) {
|
|
||||||
StkId func = L->top;
|
|
||||||
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
|
|
||||||
setobj2s(L, func + 1, p1); /* 1st argument */
|
|
||||||
setobj2s(L, func + 2, p2); /* 2nd argument */
|
|
||||||
setobj2s(L, func + 3, p3); /* 3rd argument */
|
|
||||||
L->top = func + 4;
|
|
||||||
/* metamethod may yield only when called from Lua code */
|
|
||||||
if (isLuacode(L->ci))
|
|
||||||
luaD_call(L, func, 0);
|
|
||||||
else
|
|
||||||
luaD_callnoyield(L, func, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
|
|
||||||
const TValue *p2, StkId res) {
|
|
||||||
ptrdiff_t result = savestack(L, res);
|
|
||||||
StkId func = L->top;
|
|
||||||
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
|
|
||||||
setobj2s(L, func + 1, p1); /* 1st argument */
|
|
||||||
setobj2s(L, func + 2, p2); /* 2nd argument */
|
|
||||||
L->top += 3;
|
|
||||||
/* metamethod may yield only when called from Lua code */
|
|
||||||
if (isLuacode(L->ci))
|
|
||||||
luaD_call(L, func, 1);
|
|
||||||
else
|
|
||||||
luaD_callnoyield(L, func, 1);
|
|
||||||
res = restorestack(L, result);
|
|
||||||
setobjs2s(L, res, --L->top); /* move result to its place */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
|
||||||
StkId res, TMS event) {
|
|
||||||
const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */
|
|
||||||
if (notm(tm))
|
|
||||||
tm = luaT_gettmbyobj(L, p2, event); /* try second operand */
|
|
||||||
if (notm(tm)) return 0;
|
|
||||||
luaT_callTMres(L, tm, p1, p2, res);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
|
||||||
StkId res, TMS event) {
|
|
||||||
if (l_unlikely(!callbinTM(L, p1, p2, res, event))) {
|
|
||||||
switch (event) {
|
|
||||||
case TM_BAND: case TM_BOR: case TM_BXOR:
|
|
||||||
case TM_SHL: case TM_SHR: case TM_BNOT: {
|
|
||||||
if (ttisnumber(p1) && ttisnumber(p2))
|
|
||||||
luaG_tointerror(L, p1, p2);
|
|
||||||
else
|
|
||||||
luaG_opinterror(L, p1, p2, "perform bitwise operation on");
|
|
||||||
}
|
|
||||||
/* calls never return, but to avoid warnings: *//* FALLTHROUGH */
|
|
||||||
default:
|
|
||||||
luaG_opinterror(L, p1, p2, "perform arithmetic on");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaT_tryconcatTM (lua_State *L) {
|
|
||||||
StkId top = L->top;
|
|
||||||
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
|
|
||||||
TM_CONCAT)))
|
|
||||||
luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaT_trybinassocTM (lua_State *L, const TValue *p1, const TValue *p2,
|
|
||||||
int flip, StkId res, TMS event) {
|
|
||||||
if (flip)
|
|
||||||
luaT_trybinTM(L, p2, p1, res, event);
|
|
||||||
else
|
|
||||||
luaT_trybinTM(L, p1, p2, res, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
|
|
||||||
int flip, StkId res, TMS event) {
|
|
||||||
TValue aux;
|
|
||||||
setivalue(&aux, i2);
|
|
||||||
luaT_trybinassocTM(L, p1, &aux, flip, res, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Calls an order tag method.
|
|
||||||
** For lessequal, LUA_COMPAT_LT_LE keeps compatibility with old
|
|
||||||
** behavior: if there is no '__le', try '__lt', based on l <= r iff
|
|
||||||
** !(r < l) (assuming a total order). If the metamethod yields during
|
|
||||||
** this substitution, the continuation has to know about it (to negate
|
|
||||||
** the result of r<l); bit CIST_LEQ in the call status keeps that
|
|
||||||
** information.
|
|
||||||
*/
|
|
||||||
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
|
|
||||||
TMS event) {
|
|
||||||
if (callbinTM(L, p1, p2, L->top, event)) /* try original event */
|
|
||||||
return !l_isfalse(s2v(L->top));
|
|
||||||
#if defined(LUA_COMPAT_LT_LE)
|
|
||||||
else if (event == TM_LE) {
|
|
||||||
/* try '!(p2 < p1)' for '(p1 <= p2)' */
|
|
||||||
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
|
|
||||||
if (callbinTM(L, p2, p1, L->top, TM_LT)) {
|
|
||||||
L->ci->callstatus ^= CIST_LEQ; /* clear mark */
|
|
||||||
return l_isfalse(s2v(L->top));
|
|
||||||
}
|
|
||||||
/* else error will remove this 'ci'; no need to clear mark */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
luaG_ordererror(L, p1, p2); /* no metamethod found */
|
|
||||||
return 0; /* to avoid warnings */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
|
||||||
int flip, int isfloat, TMS event) {
|
|
||||||
TValue aux; const TValue *p2;
|
|
||||||
if (isfloat) {
|
|
||||||
setfltvalue(&aux, cast_num(v2));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
setivalue(&aux, v2);
|
|
||||||
if (flip) { /* arguments were exchanged? */
|
|
||||||
p2 = p1; p1 = &aux; /* correct them */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
p2 = &aux;
|
|
||||||
return luaT_callorderTM(L, p1, p2, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
|
|
||||||
const Proto *p) {
|
|
||||||
int i;
|
|
||||||
int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */
|
|
||||||
int nextra = actual - nfixparams; /* number of extra arguments */
|
|
||||||
ci->u.l.nextraargs = nextra;
|
|
||||||
luaD_checkstack(L, p->maxstacksize + 1);
|
|
||||||
/* copy function to the top of the stack */
|
|
||||||
setobjs2s(L, L->top++, ci->func);
|
|
||||||
/* move fixed parameters to the top of the stack */
|
|
||||||
for (i = 1; i <= nfixparams; i++) {
|
|
||||||
setobjs2s(L, L->top++, ci->func + i);
|
|
||||||
setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */
|
|
||||||
}
|
|
||||||
ci->func += actual + 1;
|
|
||||||
ci->top += actual + 1;
|
|
||||||
lua_assert(L->top <= ci->top && ci->top <= L->stack_last);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
|
|
||||||
int i;
|
|
||||||
int nextra = ci->u.l.nextraargs;
|
|
||||||
if (wanted < 0) {
|
|
||||||
wanted = nextra; /* get all extra arguments available */
|
|
||||||
checkstackGCp(L, nextra, where); /* ensure stack space */
|
|
||||||
L->top = where + nextra; /* next instruction will need top */
|
|
||||||
}
|
|
||||||
for (i = 0; i < wanted && i < nextra; i++)
|
|
||||||
setobjs2s(L, where + i, ci->func - nextra + i);
|
|
||||||
for (; i < wanted; i++) /* complete required results with nil */
|
|
||||||
setnilvalue(s2v(where + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
-333
@@ -1,333 +0,0 @@
|
|||||||
/*
|
|
||||||
** $Id: lundump.c $
|
|
||||||
** load precompiled Lua chunks
|
|
||||||
** See Copyright Notice in lua.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define lundump_c
|
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
|
|
||||||
#include "ldebug.h"
|
|
||||||
#include "ldo.h"
|
|
||||||
#include "lfunc.h"
|
|
||||||
#include "lmem.h"
|
|
||||||
#include "lobject.h"
|
|
||||||
#include "lstring.h"
|
|
||||||
#include "lundump.h"
|
|
||||||
#include "lzio.h"
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(luai_verifycode)
|
|
||||||
#define luai_verifycode(L,f) /* empty */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
lua_State *L;
|
|
||||||
ZIO *Z;
|
|
||||||
const char *name;
|
|
||||||
} LoadState;
|
|
||||||
|
|
||||||
|
|
||||||
static l_noret error (LoadState *S, const char *why) {
|
|
||||||
luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why);
|
|
||||||
luaD_throw(S->L, LUA_ERRSYNTAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** All high-level loads go through loadVector; you can change it to
|
|
||||||
** adapt to the endianness of the input
|
|
||||||
*/
|
|
||||||
#define loadVector(S,b,n) loadBlock(S,b,(n)*sizeof((b)[0]))
|
|
||||||
|
|
||||||
static void loadBlock (LoadState *S, void *b, size_t size) {
|
|
||||||
if (luaZ_read(S->Z, b, size) != 0)
|
|
||||||
error(S, "truncated chunk");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define loadVar(S,x) loadVector(S,&x,1)
|
|
||||||
|
|
||||||
|
|
||||||
static lu_byte loadByte (LoadState *S) {
|
|
||||||
int b = zgetc(S->Z);
|
|
||||||
if (b == EOZ)
|
|
||||||
error(S, "truncated chunk");
|
|
||||||
return cast_byte(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static size_t loadUnsigned (LoadState *S, size_t limit) {
|
|
||||||
size_t x = 0;
|
|
||||||
int b;
|
|
||||||
limit >>= 7;
|
|
||||||
do {
|
|
||||||
b = loadByte(S);
|
|
||||||
if (x >= limit)
|
|
||||||
error(S, "integer overflow");
|
|
||||||
x = (x << 7) | (b & 0x7f);
|
|
||||||
} while ((b & 0x80) == 0);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static size_t loadSize (LoadState *S) {
|
|
||||||
return loadUnsigned(S, ~(size_t)0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int loadInt (LoadState *S) {
|
|
||||||
return cast_int(loadUnsigned(S, INT_MAX));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static lua_Number loadNumber (LoadState *S) {
|
|
||||||
lua_Number x;
|
|
||||||
loadVar(S, x);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static lua_Integer loadInteger (LoadState *S) {
|
|
||||||
lua_Integer x;
|
|
||||||
loadVar(S, x);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Load a nullable string into prototype 'p'.
|
|
||||||
*/
|
|
||||||
static TString *loadStringN (LoadState *S, Proto *p) {
|
|
||||||
lua_State *L = S->L;
|
|
||||||
TString *ts;
|
|
||||||
size_t size = loadSize(S);
|
|
||||||
if (size == 0) /* no string? */
|
|
||||||
return NULL;
|
|
||||||
else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
|
|
||||||
char buff[LUAI_MAXSHORTLEN];
|
|
||||||
loadVector(S, buff, size); /* load string into buffer */
|
|
||||||
ts = luaS_newlstr(L, buff, size); /* create string */
|
|
||||||
}
|
|
||||||
else { /* long string */
|
|
||||||
ts = luaS_createlngstrobj(L, size); /* create string */
|
|
||||||
setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */
|
|
||||||
luaD_inctop(L);
|
|
||||||
loadVector(S, getstr(ts), size); /* load directly in final place */
|
|
||||||
L->top--; /* pop string */
|
|
||||||
}
|
|
||||||
luaC_objbarrier(L, p, ts);
|
|
||||||
return ts;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Load a non-nullable string into prototype 'p'.
|
|
||||||
*/
|
|
||||||
static TString *loadString (LoadState *S, Proto *p) {
|
|
||||||
TString *st = loadStringN(S, p);
|
|
||||||
if (st == NULL)
|
|
||||||
error(S, "bad format for constant string");
|
|
||||||
return st;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void loadCode (LoadState *S, Proto *f) {
|
|
||||||
int n = loadInt(S);
|
|
||||||
f->code = luaM_newvectorchecked(S->L, n, Instruction);
|
|
||||||
f->sizecode = n;
|
|
||||||
loadVector(S, f->code, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void loadFunction(LoadState *S, Proto *f, TString *psource);
|
|
||||||
|
|
||||||
|
|
||||||
static void loadConstants (LoadState *S, Proto *f) {
|
|
||||||
int i;
|
|
||||||
int n = loadInt(S);
|
|
||||||
f->k = luaM_newvectorchecked(S->L, n, TValue);
|
|
||||||
f->sizek = n;
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
setnilvalue(&f->k[i]);
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
TValue *o = &f->k[i];
|
|
||||||
int t = loadByte(S);
|
|
||||||
switch (t) {
|
|
||||||
case LUA_VNIL:
|
|
||||||
setnilvalue(o);
|
|
||||||
break;
|
|
||||||
case LUA_VFALSE:
|
|
||||||
setbfvalue(o);
|
|
||||||
break;
|
|
||||||
case LUA_VTRUE:
|
|
||||||
setbtvalue(o);
|
|
||||||
break;
|
|
||||||
case LUA_VNUMFLT:
|
|
||||||
setfltvalue(o, loadNumber(S));
|
|
||||||
break;
|
|
||||||
case LUA_VNUMINT:
|
|
||||||
setivalue(o, loadInteger(S));
|
|
||||||
break;
|
|
||||||
case LUA_VSHRSTR:
|
|
||||||
case LUA_VLNGSTR:
|
|
||||||
setsvalue2n(S->L, o, loadString(S, f));
|
|
||||||
break;
|
|
||||||
default: lua_assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void loadProtos (LoadState *S, Proto *f) {
|
|
||||||
int i;
|
|
||||||
int n = loadInt(S);
|
|
||||||
f->p = luaM_newvectorchecked(S->L, n, Proto *);
|
|
||||||
f->sizep = n;
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
f->p[i] = NULL;
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
f->p[i] = luaF_newproto(S->L);
|
|
||||||
luaC_objbarrier(S->L, f, f->p[i]);
|
|
||||||
loadFunction(S, f->p[i], f->source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Load the upvalues for a function. The names must be filled first,
|
|
||||||
** because the filling of the other fields can raise read errors and
|
|
||||||
** the creation of the error message can call an emergency collection;
|
|
||||||
** in that case all prototypes must be consistent for the GC.
|
|
||||||
*/
|
|
||||||
static void loadUpvalues (LoadState *S, Proto *f) {
|
|
||||||
int i, n;
|
|
||||||
n = loadInt(S);
|
|
||||||
f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
|
|
||||||
f->sizeupvalues = n;
|
|
||||||
for (i = 0; i < n; i++) /* make array valid for GC */
|
|
||||||
f->upvalues[i].name = NULL;
|
|
||||||
for (i = 0; i < n; i++) { /* following calls can raise errors */
|
|
||||||
f->upvalues[i].instack = loadByte(S);
|
|
||||||
f->upvalues[i].idx = loadByte(S);
|
|
||||||
f->upvalues[i].kind = loadByte(S);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void loadDebug (LoadState *S, Proto *f) {
|
|
||||||
int i, n;
|
|
||||||
n = loadInt(S);
|
|
||||||
f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
|
|
||||||
f->sizelineinfo = n;
|
|
||||||
loadVector(S, f->lineinfo, n);
|
|
||||||
n = loadInt(S);
|
|
||||||
f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
|
|
||||||
f->sizeabslineinfo = n;
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
f->abslineinfo[i].pc = loadInt(S);
|
|
||||||
f->abslineinfo[i].line = loadInt(S);
|
|
||||||
}
|
|
||||||
n = loadInt(S);
|
|
||||||
f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
|
|
||||||
f->sizelocvars = n;
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
f->locvars[i].varname = NULL;
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
f->locvars[i].varname = loadStringN(S, f);
|
|
||||||
f->locvars[i].startpc = loadInt(S);
|
|
||||||
f->locvars[i].endpc = loadInt(S);
|
|
||||||
}
|
|
||||||
n = loadInt(S);
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
f->upvalues[i].name = loadStringN(S, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void loadFunction (LoadState *S, Proto *f, TString *psource) {
|
|
||||||
f->source = loadStringN(S, f);
|
|
||||||
if (f->source == NULL) /* no source in dump? */
|
|
||||||
f->source = psource; /* reuse parent's source */
|
|
||||||
f->linedefined = loadInt(S);
|
|
||||||
f->lastlinedefined = loadInt(S);
|
|
||||||
f->numparams = loadByte(S);
|
|
||||||
f->is_vararg = loadByte(S);
|
|
||||||
f->maxstacksize = loadByte(S);
|
|
||||||
loadCode(S, f);
|
|
||||||
loadConstants(S, f);
|
|
||||||
loadUpvalues(S, f);
|
|
||||||
loadProtos(S, f);
|
|
||||||
loadDebug(S, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void checkliteral (LoadState *S, const char *s, const char *msg) {
|
|
||||||
char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
|
|
||||||
size_t len = strlen(s);
|
|
||||||
loadVector(S, buff, len);
|
|
||||||
if (memcmp(s, buff, len) != 0)
|
|
||||||
error(S, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void fchecksize (LoadState *S, size_t size, const char *tname) {
|
|
||||||
if (loadByte(S) != size)
|
|
||||||
error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define checksize(S,t) fchecksize(S,sizeof(t),#t)
|
|
||||||
|
|
||||||
static void checkHeader (LoadState *S) {
|
|
||||||
/* skip 1st char (already read and checked) */
|
|
||||||
checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
|
|
||||||
if (loadByte(S) != LUAC_VERSION)
|
|
||||||
error(S, "version mismatch");
|
|
||||||
if (loadByte(S) != LUAC_FORMAT)
|
|
||||||
error(S, "format mismatch");
|
|
||||||
checkliteral(S, LUAC_DATA, "corrupted chunk");
|
|
||||||
checksize(S, Instruction);
|
|
||||||
checksize(S, lua_Integer);
|
|
||||||
checksize(S, lua_Number);
|
|
||||||
if (loadInteger(S) != LUAC_INT)
|
|
||||||
error(S, "integer format mismatch");
|
|
||||||
if (loadNumber(S) != LUAC_NUM)
|
|
||||||
error(S, "float format mismatch");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Load precompiled chunk.
|
|
||||||
*/
|
|
||||||
LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
|
|
||||||
LoadState S;
|
|
||||||
LClosure *cl;
|
|
||||||
if (*name == '@' || *name == '=')
|
|
||||||
S.name = name + 1;
|
|
||||||
else if (*name == LUA_SIGNATURE[0])
|
|
||||||
S.name = "binary string";
|
|
||||||
else
|
|
||||||
S.name = name;
|
|
||||||
S.L = L;
|
|
||||||
S.Z = Z;
|
|
||||||
checkHeader(&S);
|
|
||||||
cl = luaF_newLclosure(L, loadByte(&S));
|
|
||||||
setclLvalue2s(L, L->top, cl);
|
|
||||||
luaD_inctop(L);
|
|
||||||
cl->p = luaF_newproto(L);
|
|
||||||
luaC_objbarrier(L, cl, cl->p);
|
|
||||||
loadFunction(&S, cl->p, NULL);
|
|
||||||
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
|
|
||||||
luai_verifycode(L, cl->p);
|
|
||||||
return cl;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#include "mini.h"
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
settrans(255);
|
|
||||||
setcolor(0,0xff0000);
|
|
||||||
const int w=scrw();
|
|
||||||
const int h=scrh();
|
|
||||||
rect(0,0,w-1,h-1,0);
|
|
||||||
}
|
|
||||||
@@ -1,294 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
|
|
||||||
#include "version.h"
|
|
||||||
|
|
||||||
#define KEY_UNKNOWN 0
|
|
||||||
#define KEY_A 4
|
|
||||||
#define KEY_B 5
|
|
||||||
#define KEY_C 6
|
|
||||||
#define KEY_D 7
|
|
||||||
#define KEY_E 8
|
|
||||||
#define KEY_F 9
|
|
||||||
#define KEY_G 10
|
|
||||||
#define KEY_H 11
|
|
||||||
#define KEY_I 12
|
|
||||||
#define KEY_J 13
|
|
||||||
#define KEY_K 14
|
|
||||||
#define KEY_L 15
|
|
||||||
#define KEY_M 16
|
|
||||||
#define KEY_N 17
|
|
||||||
#define KEY_O 18
|
|
||||||
#define KEY_P 19
|
|
||||||
#define KEY_Q 20
|
|
||||||
#define KEY_R 21
|
|
||||||
#define KEY_S 22
|
|
||||||
#define KEY_T 23
|
|
||||||
#define KEY_U 24
|
|
||||||
#define KEY_V 25
|
|
||||||
#define KEY_W 26
|
|
||||||
#define KEY_X 27
|
|
||||||
#define KEY_Y 28
|
|
||||||
#define KEY_Z 29
|
|
||||||
#define KEY_1 30
|
|
||||||
#define KEY_2 31
|
|
||||||
#define KEY_3 32
|
|
||||||
#define KEY_4 33
|
|
||||||
#define KEY_5 34
|
|
||||||
#define KEY_6 35
|
|
||||||
#define KEY_7 36
|
|
||||||
#define KEY_8 37
|
|
||||||
#define KEY_9 38
|
|
||||||
#define KEY_0 39
|
|
||||||
#define KEY_RETURN 40
|
|
||||||
#define KEY_ESCAPE 41
|
|
||||||
#define KEY_BACKSPACE 42
|
|
||||||
#define KEY_TAB 43
|
|
||||||
#define KEY_SPACE 44
|
|
||||||
#define KEY_MINUS 45
|
|
||||||
#define KEY_EQUALS 46
|
|
||||||
#define KEY_LEFTBRACKET 47
|
|
||||||
#define KEY_RIGHTBRACKET 48
|
|
||||||
#define KEY_BACKSLASH 49
|
|
||||||
#define KEY_NONUSHASH 50
|
|
||||||
#define KEY_SEMICOLON 51
|
|
||||||
#define KEY_APOSTROPHE 52
|
|
||||||
#define KEY_GRAVE 53
|
|
||||||
#define KEY_COMMA 54
|
|
||||||
#define KEY_PERIOD 55
|
|
||||||
#define KEY_SLASH 56
|
|
||||||
#define KEY_CAPSLOCK 57
|
|
||||||
#define KEY_F1 58
|
|
||||||
#define KEY_F2 59
|
|
||||||
#define KEY_F3 60
|
|
||||||
#define KEY_F4 61
|
|
||||||
#define KEY_F5 62
|
|
||||||
#define KEY_F6 63
|
|
||||||
#define KEY_F7 64
|
|
||||||
#define KEY_F8 65
|
|
||||||
#define KEY_F9 66
|
|
||||||
#define KEY_F10 67
|
|
||||||
#define KEY_F11 68
|
|
||||||
#define KEY_F12 69
|
|
||||||
#define KEY_PRINTSCREEN 70
|
|
||||||
#define KEY_SCROLLLOCK 71
|
|
||||||
#define KEY_PAUSE 72
|
|
||||||
#define KEY_INSERT 73
|
|
||||||
#define KEY_HOME 74
|
|
||||||
#define KEY_PAGEUP 75
|
|
||||||
#define KEY_DELETE 76
|
|
||||||
#define KEY_END 77
|
|
||||||
#define KEY_PAGEDOWN 78
|
|
||||||
#define KEY_RIGHT 79
|
|
||||||
#define KEY_LEFT 80
|
|
||||||
#define KEY_DOWN 81
|
|
||||||
#define KEY_UP 82
|
|
||||||
#define KEY_NUMLOCKCLEAR 83
|
|
||||||
#define KEY_KP_DIVIDE 84
|
|
||||||
#define KEY_KP_MULTIPLY 85
|
|
||||||
#define KEY_KP_MINUS 86
|
|
||||||
#define KEY_KP_PLUS 87
|
|
||||||
#define KEY_KP_ENTER 88
|
|
||||||
#define KEY_KP_1 89
|
|
||||||
#define KEY_KP_2 90
|
|
||||||
#define KEY_KP_3 91
|
|
||||||
#define KEY_KP_4 92
|
|
||||||
#define KEY_KP_5 93
|
|
||||||
#define KEY_KP_6 94
|
|
||||||
#define KEY_KP_7 95
|
|
||||||
#define KEY_KP_8 96
|
|
||||||
#define KEY_KP_9 97
|
|
||||||
#define KEY_KP_0 98
|
|
||||||
#define KEY_KP_PERIOD 99
|
|
||||||
#define KEY_NONUSBACKSLASH 100
|
|
||||||
#define KEY_APPLICATION 101
|
|
||||||
#define KEY_LCTRL 224
|
|
||||||
#define KEY_LSHIFT 225
|
|
||||||
#define KEY_LALT 226
|
|
||||||
#define KEY_LGUI 227
|
|
||||||
#define KEY_RCTRL 228
|
|
||||||
#define KEY_RSHIFT 229
|
|
||||||
#define KEY_RALT 230
|
|
||||||
#define KEY_RGUI 231
|
|
||||||
|
|
||||||
#define DRAWMODE_NORMAL 0
|
|
||||||
#define DRAWMODE_PATTERN 1
|
|
||||||
#define DRAWMODE_AND 2
|
|
||||||
#define DRAWMODE_OR 3
|
|
||||||
#define DRAWMODE_XOR 4
|
|
||||||
#define DRAWMODE_NOT 5
|
|
||||||
|
|
||||||
void loop();
|
|
||||||
|
|
||||||
int scrw();
|
|
||||||
int scrh();
|
|
||||||
|
|
||||||
uint8_t newsurf(int w, int h);
|
|
||||||
uint8_t loadsurf(const char* filename, const bool external = false);
|
|
||||||
void savesurf(uint8_t surface, const char* filename, uint8_t *pal, uint8_t colors=0);
|
|
||||||
void freesurf(uint8_t surface);
|
|
||||||
int surfw(uint8_t surface);
|
|
||||||
int surfh(uint8_t surface);
|
|
||||||
|
|
||||||
void setdest(uint8_t surface);
|
|
||||||
void setsource(uint8_t surface);
|
|
||||||
void setmap(uint8_t surface);
|
|
||||||
uint8_t getdest();
|
|
||||||
uint8_t getsource();
|
|
||||||
uint8_t getmap();
|
|
||||||
|
|
||||||
void shader_init(const char* vshader, const char* fshader);
|
|
||||||
void shader_enable();
|
|
||||||
void shader_disable();
|
|
||||||
|
|
||||||
uint8_t loadfont(const char *filename);
|
|
||||||
uint8_t getfont();
|
|
||||||
void setfont(uint8_t font);
|
|
||||||
uint8_t getfontspacing();
|
|
||||||
void setfontspacing(uint8_t spacing);
|
|
||||||
|
|
||||||
void cls(uint8_t color=0);
|
|
||||||
void color(uint8_t color=6);
|
|
||||||
void bcolor(uint8_t color=0);
|
|
||||||
|
|
||||||
uint32_t *loadpal(const char* filename, uint16_t *palsize=NULL);
|
|
||||||
void setpal(uint32_t *pal);
|
|
||||||
void setcolor(uint8_t index, uint32_t color);
|
|
||||||
uint32_t getcolor(uint8_t index);
|
|
||||||
void settrans(uint8_t index);
|
|
||||||
uint8_t gettrans();
|
|
||||||
uint8_t subpal(uint8_t index, uint8_t color);
|
|
||||||
void reset_subpal();
|
|
||||||
|
|
||||||
void set_draw_mode(uint8_t mode);
|
|
||||||
void pset(int x, int y);
|
|
||||||
void pset(int x, int y, uint8_t color);
|
|
||||||
|
|
||||||
uint8_t pget(int x, int y);
|
|
||||||
|
|
||||||
void line(int x0, int y0, int x1, int y1);
|
|
||||||
void line(int x0, int y0, int x1, int y1, uint8_t color);
|
|
||||||
|
|
||||||
void hline(int x0, int y, int x1);
|
|
||||||
void hline(int x0, int y, int x1, uint8_t color);
|
|
||||||
|
|
||||||
void vline(int x, int y0, int y1);
|
|
||||||
void vline(int x, int y0, int y1, uint8_t color);
|
|
||||||
|
|
||||||
void rect(int x, int y, int w, int h);
|
|
||||||
void rect(int x, int y, int w, int h, uint8_t color);
|
|
||||||
|
|
||||||
void rectfill(int x, int y, int w, int h);
|
|
||||||
void rectfill(int x, int y, int w, int h, uint8_t color);
|
|
||||||
|
|
||||||
void fillp(uint16_t pat, bool transparent = false);
|
|
||||||
|
|
||||||
void print(const char *str, int x, int y);
|
|
||||||
void print(const char *str, int x, int y, uint8_t color);
|
|
||||||
|
|
||||||
void clip(int x, int y, int w, int h);
|
|
||||||
void clip();
|
|
||||||
void origin(int x, int y);
|
|
||||||
int camx();
|
|
||||||
int camy();
|
|
||||||
|
|
||||||
void circ(int x, int y, uint8_t r = 4);
|
|
||||||
void circ(int x, int y, uint8_t r, uint8_t color);
|
|
||||||
|
|
||||||
void circfill(int x, int y, uint8_t r = 4);
|
|
||||||
void circfill(int x, int y, uint8_t r, uint8_t color);
|
|
||||||
|
|
||||||
void roundrect(int x, int y, int w, int h, uint8_t r);
|
|
||||||
void roundrect(int x, int y, int w, int h, uint8_t r, uint8_t color);
|
|
||||||
|
|
||||||
void roundrectfill(int x, int y, int w, int h, uint8_t r);
|
|
||||||
void roundrectfill(int x, int y, int w, int h, uint8_t r, uint8_t color);
|
|
||||||
|
|
||||||
void oval(int x0, int y0, int x1, int y1);
|
|
||||||
void oval(int x0, int y0, int x1, int y1, uint8_t color);
|
|
||||||
|
|
||||||
void ovalfill(int x0, int y0, int x1, int y1);
|
|
||||||
void ovalfill(int x0, int y0, int x1, int y1, uint8_t color);
|
|
||||||
|
|
||||||
uint8_t sget(int x, int y);
|
|
||||||
void sset(int x, int y);
|
|
||||||
void sset(int x, int y, uint8_t color);
|
|
||||||
|
|
||||||
void spr(uint8_t n, int x, int y, float w = 1.0f, float h = 1.0f, bool flip_x = false, bool flip_y = false);
|
|
||||||
void blit(int sx, int sy, int sw, int sh, int dx, int dy, int dw=0, int dh=0, bool flip_x = false, bool flip_y = false, bool invert = false);
|
|
||||||
//void blit_r(int sx, int sy, int sw, int sh, int x, int y, float a);
|
|
||||||
void blit_r(int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, bool flip_x, bool flip_y, float angle_deg);
|
|
||||||
|
|
||||||
void tline(int x0, int y0, int x1, int y1, float mx, float my, float mdx=0.125f, float mdy=0.0f);
|
|
||||||
void thline(int x0, int y, int x1, float mx, float my, float mdx=0.125f, float mdy=0.0f);
|
|
||||||
void tvline(int x, int y0, int y1, float mx, float my, float mdx=0.0f, float mdy=0.125f);
|
|
||||||
|
|
||||||
uint8_t mget(int celx, int cely);
|
|
||||||
void mset(int celx, int cely, uint8_t snum);
|
|
||||||
uint8_t gettilew();
|
|
||||||
uint8_t gettileh();
|
|
||||||
void settilesize(int w, int h);
|
|
||||||
void map(); //int celx, int cely, int sx, int sy, uint8_t celw, uint8_t celh, uint8_t layer=0);
|
|
||||||
|
|
||||||
bool btn(uint8_t i);
|
|
||||||
int wbtnp();
|
|
||||||
bool btnp(uint8_t i);
|
|
||||||
bool anykey();
|
|
||||||
void textenable(const bool enable);
|
|
||||||
const char *textinput();
|
|
||||||
|
|
||||||
bool pad(int8_t i);
|
|
||||||
bool padp(int8_t i);
|
|
||||||
int wpad();
|
|
||||||
|
|
||||||
int mousex();
|
|
||||||
int mousey();
|
|
||||||
int mwheel();
|
|
||||||
bool mbtn(uint8_t i);
|
|
||||||
bool mbtnp(uint8_t i);
|
|
||||||
bool doubleclick();
|
|
||||||
void mdiscard();
|
|
||||||
bool minside(int x, int y, int w, int h);
|
|
||||||
|
|
||||||
float time();
|
|
||||||
bool beat(int16_t i);
|
|
||||||
|
|
||||||
int rnd(int x);
|
|
||||||
int getfps();
|
|
||||||
|
|
||||||
void playmusic(const char *filename, const int loop=-1);
|
|
||||||
void pausemusic();
|
|
||||||
void resumemusic();
|
|
||||||
void stopmusic(const int t=1000);
|
|
||||||
void musicpos(float value);
|
|
||||||
float musicpos();
|
|
||||||
void enablemusic(const bool value);
|
|
||||||
const bool ismusicenabled();
|
|
||||||
|
|
||||||
int loadsound(const char *filename);
|
|
||||||
void freesound(int soundfile);
|
|
||||||
int playsound(int soundfile, const int volume=-1);
|
|
||||||
void stopsound(int soundchannel);
|
|
||||||
void enablesound(const bool value);
|
|
||||||
const bool issoundenabled();
|
|
||||||
|
|
||||||
int getzoom();
|
|
||||||
void setzoom(const int value);
|
|
||||||
void setres(const int w, const int h);
|
|
||||||
bool getfullscreen();
|
|
||||||
void setfullscreen(const bool value);
|
|
||||||
bool getcursor();
|
|
||||||
void setcursor(const bool value);
|
|
||||||
|
|
||||||
const char *getconfig(const char* key);
|
|
||||||
void setconfig(const char* key, const char* value);
|
|
||||||
const char *configfolder();
|
|
||||||
|
|
||||||
#define UPDATE_ALWAYS 0
|
|
||||||
#define UPDATE_WAIT 1
|
|
||||||
#define UPDATE_TIMEOUT 2
|
|
||||||
void setupdatemode(const int value, const int t=0);
|
|
||||||
int getupdatemode();
|
|
||||||
|
|
||||||
void exit();
|
|
||||||
+2
-2
@@ -6,7 +6,7 @@ set -e
|
|||||||
# exit 1
|
# exit 1
|
||||||
#fi
|
#fi
|
||||||
|
|
||||||
GITEA_TOKEN="eb44d9c0142f5038c61c5afd17f5a41177bfaedc"
|
#GITEA_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
|
||||||
if [ -z "$GITEA_TOKEN" ]; then
|
if [ -z "$GITEA_TOKEN" ]; then
|
||||||
echo "ERROR: Debes exportar GITEA_TOKEN"
|
echo "ERROR: Debes exportar GITEA_TOKEN"
|
||||||
@@ -14,7 +14,7 @@ if [ -z "$GITEA_TOKEN" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Leer versión desde version.h
|
# Leer versión desde version.h
|
||||||
VERSION=$(grep '#define MINI_VERSION' version.h | sed 's/.*"\(.*\)".*/\1/')
|
VERSION=$(grep '#define MINI_VERSION' source/mini/version.h | sed 's/.*"\(.*\)".*/\1/')
|
||||||
echo "Versión detectada: $VERSION"
|
echo "Versión detectada: $VERSION"
|
||||||
|
|
||||||
#PARAM=$1
|
#PARAM=$1
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
#if BACKEND == SDL3
|
||||||
|
|
||||||
|
#include "backends/backend.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "mini/win/win.h"
|
||||||
|
#include "mini/surf/surf.h"
|
||||||
|
|
||||||
|
namespace backend
|
||||||
|
{
|
||||||
|
state_t current_state = running;
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD);
|
||||||
|
//video::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void quit() {
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void poll_events() {
|
||||||
|
//[TODO]
|
||||||
|
//if (update_mode==UPDATE_WAIT)
|
||||||
|
// SDL_WaitEvent(NULL);
|
||||||
|
//else if (update_mode==UPDATE_TIMEOUT)
|
||||||
|
// SDL_WaitEventTimeout(NULL, timeout);
|
||||||
|
|
||||||
|
SDL_Event e;
|
||||||
|
while(SDL_PollEvent(&e)) {
|
||||||
|
if (e.type == SDL_EVENT_QUIT) {
|
||||||
|
current_state=quitting;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (e.type == SDL_EVENT_TEXT_INPUT) {
|
||||||
|
SDL_strlcpy(input::key::text_input_buffer, e.text.text, sizeof(input::key::text_input_buffer));
|
||||||
|
input::key::has_text_input = true;
|
||||||
|
}
|
||||||
|
else if (e.type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (e.key.scancode == SDL_SCANCODE_F12) {
|
||||||
|
mini::surf::reloadsurfs();
|
||||||
|
//} else if (e.key.scancode == SDL_SCANCODE_F11) {
|
||||||
|
// mini::lua::debug::toggle();
|
||||||
|
} else if (e.key.scancode == SDL_SCANCODE_F5) {
|
||||||
|
current_state=exiting;
|
||||||
|
} else {
|
||||||
|
input::key::just_pressed = e.key.scancode;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
input::key::just_pressed = e.key.scancode;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (e.type == SDL_EVENT_MOUSE_BUTTON_UP) {
|
||||||
|
if (input::mouse::discard_buttons)
|
||||||
|
input::mouse::discard_buttons = false;
|
||||||
|
else
|
||||||
|
if (e.button.clicks==2 && e.button.button==SDL_BUTTON_LEFT) {
|
||||||
|
input::mouse::double_click = true;
|
||||||
|
} else {
|
||||||
|
input::mouse::just_pressed = e.button.button;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (e.type == SDL_EVENT_MOUSE_WHEEL) {
|
||||||
|
input::mouse::w = e.wheel.y;
|
||||||
|
}
|
||||||
|
else if (e.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) {
|
||||||
|
input::pad::just_pressed = e.gbutton.button;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input::key::keys = SDL_GetKeyboardState(NULL);
|
||||||
|
|
||||||
|
// Update mouse
|
||||||
|
float real_mouse_x, real_mouse_y;
|
||||||
|
input::mouse::buttons = SDL_GetMouseState(&real_mouse_x, &real_mouse_y);
|
||||||
|
float mx, my;
|
||||||
|
SDL_RenderCoordinatesFromWindow(video::renderer, real_mouse_x, real_mouse_y, &mx, &my);
|
||||||
|
input::mouse::x = int(mx/mini::win::state.zoom);
|
||||||
|
input::mouse::y = int(my/mini::win::state.zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
const state_t& state() {
|
||||||
|
return current_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *clipboard() {
|
||||||
|
return SDL_GetClipboardText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clipboard(const char* value) {
|
||||||
|
SDL_SetClipboardText(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
#if BACKEND == SDL3
|
||||||
|
|
||||||
|
#include "backends/backend.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "mini/view/view.h"
|
||||||
|
|
||||||
|
namespace backend
|
||||||
|
{
|
||||||
|
namespace input
|
||||||
|
{
|
||||||
|
void reset() {
|
||||||
|
key::just_pressed = 0;
|
||||||
|
key::has_text_input = false;
|
||||||
|
key::text_input_buffer[0] = '\0';
|
||||||
|
mouse::just_pressed = 0;
|
||||||
|
mouse::double_click = false;
|
||||||
|
mouse::w = 0;
|
||||||
|
pad::just_pressed = SDL_GAMEPAD_BUTTON_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace key
|
||||||
|
{
|
||||||
|
const bool *keys;
|
||||||
|
uint8_t just_pressed = 0;
|
||||||
|
char text_input_buffer[10];
|
||||||
|
bool has_text_input = false;
|
||||||
|
|
||||||
|
bool down(uint8_t i) {
|
||||||
|
return keys[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool press(uint8_t i) {
|
||||||
|
if (just_pressed == i) {
|
||||||
|
just_pressed=0;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int press() {
|
||||||
|
return just_pressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool any() {
|
||||||
|
const bool something_pressed = (just_pressed != 0) || (pad::just_pressed != -1);
|
||||||
|
just_pressed=0;
|
||||||
|
pad::just_pressed=-1;
|
||||||
|
return something_pressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void text(const bool enable) {
|
||||||
|
if (enable)
|
||||||
|
SDL_StartTextInput(backend::video::window);
|
||||||
|
else
|
||||||
|
SDL_StopTextInput(backend::video::window);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *utf8char() {
|
||||||
|
return has_text_input ? text_input_buffer : nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace mouse
|
||||||
|
{
|
||||||
|
int x, y, w;
|
||||||
|
uint32_t buttons;
|
||||||
|
uint8_t just_pressed = 0;
|
||||||
|
bool double_click = false;
|
||||||
|
bool discard_buttons = false;
|
||||||
|
|
||||||
|
int posx() {
|
||||||
|
return x - mini::view::state.origin[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int posy() {
|
||||||
|
return y - mini::view::state.origin[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
int wheel() {
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool down(uint8_t i) {
|
||||||
|
if (discard_buttons) return false;
|
||||||
|
return buttons & SDL_BUTTON_MASK(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool press(uint8_t i) {
|
||||||
|
return just_pressed == i;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dblclick() {
|
||||||
|
return double_click;
|
||||||
|
}
|
||||||
|
|
||||||
|
void discard() {
|
||||||
|
discard_buttons = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool inside(int x, int y, int w, int h) {
|
||||||
|
const int mx = x - mini::view::state.origin[0];
|
||||||
|
const int my = y - mini::view::state.origin[1];
|
||||||
|
return (mx>=x) && (my>=y) && (mx<x+w) && (my<y+h);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace pad
|
||||||
|
{
|
||||||
|
SDL_Gamepad *gamepad = nullptr;
|
||||||
|
int8_t just_pressed = -1;
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
int num_joysticks;
|
||||||
|
SDL_JoystickID *joysticks = SDL_GetJoysticks(&num_joysticks);
|
||||||
|
if (joysticks) {
|
||||||
|
for (int i=0; i<num_joysticks; ++i) {
|
||||||
|
if (SDL_IsGamepad(joysticks[i])) {
|
||||||
|
gamepad = SDL_OpenGamepad(joysticks[i]);
|
||||||
|
if (SDL_GamepadConnected(gamepad)) {
|
||||||
|
SDL_SetGamepadEventsEnabled(true);
|
||||||
|
// [TODO]
|
||||||
|
//log_msg(LOG_OK, "Gamepad found and initialized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool down(int8_t i) {
|
||||||
|
if (!gamepad) return false;
|
||||||
|
return SDL_GetGamepadButton(gamepad, SDL_GamepadButton(i)) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool press(int8_t i) {
|
||||||
|
if (just_pressed == i) {
|
||||||
|
just_pressed = -1;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int press() {
|
||||||
|
return just_pressed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#if BACKEND == SDL3
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
namespace backend
|
||||||
|
{
|
||||||
|
namespace video
|
||||||
|
{
|
||||||
|
extern SDL_Window *window;
|
||||||
|
extern SDL_Renderer *renderer;
|
||||||
|
extern SDL_Texture *tex_back;
|
||||||
|
extern SDL_Texture *tex_shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace input
|
||||||
|
{
|
||||||
|
namespace key
|
||||||
|
{
|
||||||
|
extern const bool *keys;
|
||||||
|
extern uint8_t just_pressed;
|
||||||
|
extern char text_input_buffer[10];
|
||||||
|
extern bool has_text_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace mouse
|
||||||
|
{
|
||||||
|
extern int x, y, w;
|
||||||
|
extern uint32_t buttons;
|
||||||
|
extern uint8_t just_pressed;
|
||||||
|
extern bool double_click;
|
||||||
|
extern bool discard_buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace pad
|
||||||
|
{
|
||||||
|
extern SDL_Gamepad *gamepad;
|
||||||
|
extern int8_t just_pressed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#if BACKEND == SDL3
|
||||||
|
|
||||||
|
#include "backends/backend.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "mini/win/win.h"
|
||||||
|
#include "mini/surf/surf.h"
|
||||||
|
#include "mini/pal/pal.h"
|
||||||
|
#include "mini/shader/shader.h"
|
||||||
|
|
||||||
|
namespace backend
|
||||||
|
{
|
||||||
|
namespace video
|
||||||
|
{
|
||||||
|
SDL_Window *window { nullptr };
|
||||||
|
SDL_Renderer *renderer { nullptr };
|
||||||
|
SDL_Texture *tex_back { nullptr };
|
||||||
|
SDL_Texture *tex_shader { nullptr };
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
const auto &title = mini::win::state.title;
|
||||||
|
const auto &width = mini::win::state.width;
|
||||||
|
const auto &height = mini::win::state.height;
|
||||||
|
auto &zoom = mini::win::state.zoom;
|
||||||
|
|
||||||
|
// Ajustar el zoom a un valor vàlid
|
||||||
|
if (zoom <= 0) zoom = 1;
|
||||||
|
const SDL_DisplayMode *dm = SDL_GetDesktopDisplayMode(SDL_GetPrimaryDisplay());
|
||||||
|
while ( width * zoom > dm->w || height * zoom > dm->h) zoom--;
|
||||||
|
|
||||||
|
// Crear SDL_Window i SDL_Renderer
|
||||||
|
window = SDL_CreateWindow(title, width*zoom, height*zoom, SDL_WINDOW_OPENGL|(mini::win::state.fullscreen?SDL_WINDOW_FULLSCREEN:0));
|
||||||
|
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
|
||||||
|
renderer = SDL_CreateRenderer(window, NULL);
|
||||||
|
SDL_SetRenderVSync(renderer, SDL_RENDERER_VSYNC_DISABLED);
|
||||||
|
|
||||||
|
// Mostrar o ocultar el cursor
|
||||||
|
if (mini::win::state.cursor) SDL_ShowCursor(); else SDL_HideCursor();
|
||||||
|
|
||||||
|
// Crear textura backbuffer
|
||||||
|
tex_back = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||||
|
SDL_SetTextureScaleMode(tex_back, SDL_SCALEMODE_NEAREST);
|
||||||
|
|
||||||
|
// Crear textura shaders i inicialitzar shaders
|
||||||
|
tex_shader = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, width*zoom, height*zoom);
|
||||||
|
SDL_SetTextureScaleMode(tex_shader, SDL_SCALEMODE_NEAREST);
|
||||||
|
|
||||||
|
mini::shader::init(window, tex_shader, nullptr);
|
||||||
|
|
||||||
|
// [TODO]
|
||||||
|
//log_msg(LOG_OK, "Graphics subsystem initialized\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void quit() {
|
||||||
|
SDL_DestroyTexture(tex_shader);
|
||||||
|
SDL_DestroyTexture(tex_back);
|
||||||
|
SDL_DestroyRenderer(renderer);
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render() {
|
||||||
|
// Render frame
|
||||||
|
SDL_SetRenderTarget(renderer, tex_shader);
|
||||||
|
//SDL_SetRenderDrawColor(win::state.renderer, 0, 0, 0, 255);
|
||||||
|
//SDL_RenderClear(win::state.renderer);
|
||||||
|
|
||||||
|
uint32_t *pixels;
|
||||||
|
int pitch;
|
||||||
|
SDL_LockTexture(tex_back, NULL, (void**)&pixels, &pitch);
|
||||||
|
auto &s = mini::surf::state.surfaces[SCREEN];
|
||||||
|
uint8_t *p = s.p;
|
||||||
|
for (uint32_t i=0;i<s.size;++i) pixels[i] = mini::pal::palette[p[i]];
|
||||||
|
SDL_UnlockTexture(tex_back);
|
||||||
|
SDL_RenderTexture(renderer, tex_back, NULL, NULL); //NEW
|
||||||
|
|
||||||
|
mini::shader::render();
|
||||||
|
|
||||||
|
//SDL_RenderTexture(mini_ren, mini_bak, NULL, NULL);
|
||||||
|
//SDL_RenderPresent(mini_ren);
|
||||||
|
}
|
||||||
|
|
||||||
|
void raise_window() {
|
||||||
|
SDL_RaiseWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cursor(const bool value) {
|
||||||
|
if (value) SDL_ShowCursor(); else SDL_HideCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#include "backend.h"
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace backend
|
||||||
|
{
|
||||||
|
uint32_t get_time_ms() {
|
||||||
|
using namespace std::chrono;
|
||||||
|
return duration_cast<milliseconds>(
|
||||||
|
steady_clock::now().time_since_epoch()
|
||||||
|
).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
void exit() {
|
||||||
|
current_state = quitting;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define SDL3 1
|
||||||
|
#define SFML 2
|
||||||
|
#define EMSCRIPTEN 3
|
||||||
|
|
||||||
|
#ifndef BACKEND
|
||||||
|
#define BACKEND SDL3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace backend
|
||||||
|
{
|
||||||
|
enum state_t { running=0, exiting=1, quitting=2 };
|
||||||
|
extern state_t current_state;
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void quit();
|
||||||
|
void poll_events();
|
||||||
|
const state_t& state();
|
||||||
|
void exit();
|
||||||
|
uint32_t get_time_ms();
|
||||||
|
char* clipboard();
|
||||||
|
void clipboard(const char* value);
|
||||||
|
|
||||||
|
namespace video
|
||||||
|
{
|
||||||
|
void init();
|
||||||
|
void quit();
|
||||||
|
void render();
|
||||||
|
void raise_window();
|
||||||
|
void cursor(const bool value);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace audio
|
||||||
|
{
|
||||||
|
void init();
|
||||||
|
void quit();
|
||||||
|
void render();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace input
|
||||||
|
{
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
namespace key
|
||||||
|
{
|
||||||
|
bool down(uint8_t i);
|
||||||
|
bool press(uint8_t i);
|
||||||
|
int press();
|
||||||
|
bool any();
|
||||||
|
void text(const bool enable);
|
||||||
|
const char *utf8char();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace mouse
|
||||||
|
{
|
||||||
|
int posx();
|
||||||
|
int posy();
|
||||||
|
int wheel();
|
||||||
|
bool down(uint8_t i);
|
||||||
|
bool press(uint8_t i);
|
||||||
|
bool dblclick();
|
||||||
|
void discard();
|
||||||
|
bool inside(int x, int y, int w, int h);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace pad
|
||||||
|
{
|
||||||
|
void init();
|
||||||
|
bool down(int8_t i);
|
||||||
|
bool press(int8_t i);
|
||||||
|
int press();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+297
-279
File diff suppressed because it is too large
Load Diff
Vendored
+65
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
** $Id: lapi.h $
|
||||||
|
** Auxiliary functions from Lua API
|
||||||
|
** See Copyright Notice in lua.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef lapi_h
|
||||||
|
#define lapi_h
|
||||||
|
|
||||||
|
|
||||||
|
#include "llimits.h"
|
||||||
|
#include "lstate.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(LUA_USE_APICHECK)
|
||||||
|
#include <assert.h>
|
||||||
|
#define api_check(l,e,msg) assert(e)
|
||||||
|
#else /* for testing */
|
||||||
|
#define api_check(l,e,msg) ((void)(l), lua_assert((e) && msg))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Increments 'L->top.p', checking for stack overflows */
|
||||||
|
#define api_incr_top(L) \
|
||||||
|
(L->top.p++, api_check(L, L->top.p <= L->ci->top.p, "stack overflow"))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** macros that are executed whenever program enters the Lua core
|
||||||
|
** ('lua_lock') and leaves the core ('lua_unlock')
|
||||||
|
*/
|
||||||
|
#if !defined(lua_lock)
|
||||||
|
#define lua_lock(L) ((void) 0)
|
||||||
|
#define lua_unlock(L) ((void) 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** If a call returns too many multiple returns, the callee may not have
|
||||||
|
** stack space to accommodate all results. In this case, this macro
|
||||||
|
** increases its stack space ('L->ci->top.p').
|
||||||
|
*/
|
||||||
|
#define adjustresults(L,nres) \
|
||||||
|
{ if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
|
||||||
|
L->ci->top.p = L->top.p; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Ensure the stack has at least 'n' elements */
|
||||||
|
#define api_checknelems(L,n) \
|
||||||
|
api_check(L, (n) < (L->top.p - L->ci->func.p), \
|
||||||
|
"not enough elements in the stack")
|
||||||
|
|
||||||
|
|
||||||
|
/* Ensure the stack has at least 'n' elements to be popped. (Some
|
||||||
|
** functions only update a slot after checking it for popping, but that
|
||||||
|
** is only an optimization for a pop followed by a push.)
|
||||||
|
*/
|
||||||
|
#define api_checkpop(L,n) \
|
||||||
|
api_check(L, (n) < L->top.p - L->ci->func.p && \
|
||||||
|
L->tbclist.p < L->top.p - (n), \
|
||||||
|
"not enough free elements in the stack")
|
||||||
|
|
||||||
|
#endif
|
||||||
+193
-96
@@ -25,12 +25,7 @@
|
|||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
#if !defined(MAX_SIZET)
|
|
||||||
/* maximum value for size_t */
|
|
||||||
#define MAX_SIZET ((size_t)(~(size_t)0))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -80,6 +75,7 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
|
|||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
lua_getinfo(L, "f", ar); /* push function */
|
lua_getinfo(L, "f", ar); /* push function */
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
|
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
|
||||||
|
luaL_checkstack(L, 6, "not enough stack"); /* slots for 'findfield' */
|
||||||
if (findfield(L, top + 1, 2)) {
|
if (findfield(L, top + 1, 2)) {
|
||||||
const char *name = lua_tostring(L, -1);
|
const char *name = lua_tostring(L, -1);
|
||||||
if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */
|
if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */
|
||||||
@@ -98,14 +94,14 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
|
|||||||
|
|
||||||
|
|
||||||
static void pushfuncname (lua_State *L, lua_Debug *ar) {
|
static void pushfuncname (lua_State *L, lua_Debug *ar) {
|
||||||
if (pushglobalfuncname(L, ar)) { /* try first a global name */
|
if (*ar->namewhat != '\0') /* is there a name from code? */
|
||||||
lua_pushfstring(L, "function '%s'", lua_tostring(L, -1));
|
|
||||||
lua_remove(L, -2); /* remove name */
|
|
||||||
}
|
|
||||||
else if (*ar->namewhat != '\0') /* is there a name from code? */
|
|
||||||
lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */
|
lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */
|
||||||
else if (*ar->what == 'm') /* main? */
|
else if (*ar->what == 'm') /* main? */
|
||||||
lua_pushliteral(L, "main chunk");
|
lua_pushliteral(L, "main chunk");
|
||||||
|
else if (pushglobalfuncname(L, ar)) { /* try a global name */
|
||||||
|
lua_pushfstring(L, "function '%s'", lua_tostring(L, -1));
|
||||||
|
lua_remove(L, -2); /* remove name */
|
||||||
|
}
|
||||||
else if (*ar->what != 'C') /* for Lua functions, use <file:line> */
|
else if (*ar->what != 'C') /* for Lua functions, use <file:line> */
|
||||||
lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
|
lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
|
||||||
else /* nothing left... */
|
else /* nothing left... */
|
||||||
@@ -174,19 +170,27 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
|
|||||||
|
|
||||||
LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
|
LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
|
const char *argword;
|
||||||
if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
|
if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
|
||||||
return luaL_error(L, "bad argument #%d (%s)", arg, extramsg);
|
return luaL_error(L, "bad argument #%d (%s)", arg, extramsg);
|
||||||
lua_getinfo(L, "n", &ar);
|
lua_getinfo(L, "nt", &ar);
|
||||||
if (strcmp(ar.namewhat, "method") == 0) {
|
if (arg <= ar.extraargs) /* error in an extra argument? */
|
||||||
arg--; /* do not count 'self' */
|
argword = "extra argument";
|
||||||
if (arg == 0) /* error is in the self argument itself? */
|
else {
|
||||||
return luaL_error(L, "calling '%s' on bad self (%s)",
|
arg -= ar.extraargs; /* do not count extra arguments */
|
||||||
ar.name, extramsg);
|
if (strcmp(ar.namewhat, "method") == 0) { /* colon syntax? */
|
||||||
|
arg--; /* do not count (extra) self argument */
|
||||||
|
if (arg == 0) /* error in self argument? */
|
||||||
|
return luaL_error(L, "calling '%s' on bad self (%s)",
|
||||||
|
ar.name, extramsg);
|
||||||
|
/* else go through; error in a regular argument */
|
||||||
|
}
|
||||||
|
argword = "argument";
|
||||||
}
|
}
|
||||||
if (ar.name == NULL)
|
if (ar.name == NULL)
|
||||||
ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
|
ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
|
||||||
return luaL_error(L, "bad argument #%d to '%s' (%s)",
|
return luaL_error(L, "bad %s #%d to '%s' (%s)",
|
||||||
arg, ar.name, extramsg);
|
argword, arg, ar.name, extramsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -229,7 +233,7 @@ LUALIB_API void luaL_where (lua_State *L, int level) {
|
|||||||
/*
|
/*
|
||||||
** Again, the use of 'lua_pushvfstring' ensures this function does
|
** Again, the use of 'lua_pushvfstring' ensures this function does
|
||||||
** not need reserved stack space when called. (At worst, it generates
|
** not need reserved stack space when called. (At worst, it generates
|
||||||
** an error with "stack overflow" instead of the given message.)
|
** a memory error instead of the given message.)
|
||||||
*/
|
*/
|
||||||
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
|
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
|
||||||
va_list argp;
|
va_list argp;
|
||||||
@@ -249,11 +253,13 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
const char *msg;
|
||||||
luaL_pushfail(L);
|
luaL_pushfail(L);
|
||||||
|
msg = (en != 0) ? strerror(en) : "(no extra info)";
|
||||||
if (fname)
|
if (fname)
|
||||||
lua_pushfstring(L, "%s: %s", fname, strerror(en));
|
lua_pushfstring(L, "%s: %s", fname, msg);
|
||||||
else
|
else
|
||||||
lua_pushstring(L, strerror(en));
|
lua_pushstring(L, msg);
|
||||||
lua_pushinteger(L, en);
|
lua_pushinteger(L, en);
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
@@ -470,18 +476,27 @@ typedef struct UBox {
|
|||||||
} UBox;
|
} UBox;
|
||||||
|
|
||||||
|
|
||||||
|
/* Resize the buffer used by a box. Optimize for the common case of
|
||||||
|
** resizing to the old size. (For instance, __gc will resize the box
|
||||||
|
** to 0 even after it was closed. 'pushresult' may also resize it to a
|
||||||
|
** final size that is equal to the one set when the buffer was created.)
|
||||||
|
*/
|
||||||
static void *resizebox (lua_State *L, int idx, size_t newsize) {
|
static void *resizebox (lua_State *L, int idx, size_t newsize) {
|
||||||
void *ud;
|
|
||||||
lua_Alloc allocf = lua_getallocf(L, &ud);
|
|
||||||
UBox *box = (UBox *)lua_touserdata(L, idx);
|
UBox *box = (UBox *)lua_touserdata(L, idx);
|
||||||
void *temp = allocf(ud, box->box, box->bsize, newsize);
|
if (box->bsize == newsize) /* not changing size? */
|
||||||
if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */
|
return box->box; /* keep the buffer */
|
||||||
lua_pushliteral(L, "not enough memory");
|
else {
|
||||||
lua_error(L); /* raise a memory error */
|
void *ud;
|
||||||
|
lua_Alloc allocf = lua_getallocf(L, &ud);
|
||||||
|
void *temp = allocf(ud, box->box, box->bsize, newsize);
|
||||||
|
if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */
|
||||||
|
lua_pushliteral(L, "not enough memory");
|
||||||
|
lua_error(L); /* raise a memory error */
|
||||||
|
}
|
||||||
|
box->box = temp;
|
||||||
|
box->bsize = newsize;
|
||||||
|
return temp;
|
||||||
}
|
}
|
||||||
box->box = temp;
|
|
||||||
box->bsize = newsize;
|
|
||||||
return temp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -526,14 +541,17 @@ static void newbox (lua_State *L) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Compute new size for buffer 'B', enough to accommodate extra 'sz'
|
** Compute new size for buffer 'B', enough to accommodate extra 'sz'
|
||||||
** bytes.
|
** bytes plus one for a terminating zero.
|
||||||
*/
|
*/
|
||||||
static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
|
static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
|
||||||
size_t newsize = B->size * 2; /* double buffer size */
|
size_t newsize = B->size;
|
||||||
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
|
if (l_unlikely(sz >= MAX_SIZE - B->n))
|
||||||
return luaL_error(B->L, "buffer too large");
|
return cast_sizet(luaL_error(B->L, "resulting string too large"));
|
||||||
if (newsize < B->n + sz) /* double is not big enough? */
|
/* else B->n + sz + 1 <= MAX_SIZE */
|
||||||
newsize = B->n + sz;
|
if (newsize <= MAX_SIZE/3 * 2) /* no overflow? */
|
||||||
|
newsize += (newsize >> 1); /* new size *= 1.5 */
|
||||||
|
if (newsize < B->n + sz + 1) /* not big enough? */
|
||||||
|
newsize = B->n + sz + 1;
|
||||||
return newsize;
|
return newsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,9 +611,23 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
|
|||||||
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
|
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
|
||||||
lua_State *L = B->L;
|
lua_State *L = B->L;
|
||||||
checkbufferlevel(B, -1);
|
checkbufferlevel(B, -1);
|
||||||
lua_pushlstring(L, B->b, B->n);
|
if (!buffonstack(B)) /* using static buffer? */
|
||||||
if (buffonstack(B))
|
lua_pushlstring(L, B->b, B->n); /* save result as regular string */
|
||||||
|
else { /* reuse buffer already allocated */
|
||||||
|
UBox *box = (UBox *)lua_touserdata(L, -1);
|
||||||
|
void *ud;
|
||||||
|
lua_Alloc allocf = lua_getallocf(L, &ud); /* function to free buffer */
|
||||||
|
size_t len = B->n; /* final string length */
|
||||||
|
char *s;
|
||||||
|
resizebox(L, -1, len + 1); /* adjust box size to content size */
|
||||||
|
s = (char*)box->box; /* final buffer address */
|
||||||
|
s[len] = '\0'; /* add ending zero */
|
||||||
|
/* clear box, as Lua will take control of the buffer */
|
||||||
|
box->bsize = 0; box->box = NULL;
|
||||||
|
lua_pushexternalstring(L, s, len, allocf, ud);
|
||||||
lua_closeslot(L, -2); /* close the box */
|
lua_closeslot(L, -2); /* close the box */
|
||||||
|
lua_gc(L, LUA_GCSTEP, len);
|
||||||
|
}
|
||||||
lua_remove(L, -2); /* remove box or placeholder from the stack */
|
lua_remove(L, -2); /* remove box or placeholder from the stack */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,7 +643,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
|
|||||||
** box (if existent) is not on the top of the stack. So, instead of
|
** box (if existent) is not on the top of the stack. So, instead of
|
||||||
** calling 'luaL_addlstring', it replicates the code using -2 as the
|
** calling 'luaL_addlstring', it replicates the code using -2 as the
|
||||||
** last argument to 'prepbuffsize', signaling that the box is (or will
|
** last argument to 'prepbuffsize', signaling that the box is (or will
|
||||||
** be) bellow the string being added to the buffer. (Box creation can
|
** be) below the string being added to the buffer. (Box creation can
|
||||||
** trigger an emergency GC, so we should not remove the string from the
|
** trigger an emergency GC, so we should not remove the string from the
|
||||||
** stack before we have the space guaranteed.)
|
** stack before we have the space guaranteed.)
|
||||||
*/
|
*/
|
||||||
@@ -649,13 +681,10 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
|
|||||||
** =======================================================
|
** =======================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* index of free-list header (after the predefined values) */
|
|
||||||
#define freelist (LUA_RIDX_LAST + 1)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The previously freed references form a linked list:
|
** The previously freed references form a linked list: t[1] is the index
|
||||||
** t[freelist] is the index of a first free index, or zero if list is
|
** of a first free index, t[t[1]] is the index of the second element,
|
||||||
** empty; t[t[freelist]] is the index of the second element; etc.
|
** etc. A zero signals the end of the list.
|
||||||
*/
|
*/
|
||||||
LUALIB_API int luaL_ref (lua_State *L, int t) {
|
LUALIB_API int luaL_ref (lua_State *L, int t) {
|
||||||
int ref;
|
int ref;
|
||||||
@@ -664,19 +693,18 @@ LUALIB_API int luaL_ref (lua_State *L, int t) {
|
|||||||
return LUA_REFNIL; /* 'nil' has a unique fixed reference */
|
return LUA_REFNIL; /* 'nil' has a unique fixed reference */
|
||||||
}
|
}
|
||||||
t = lua_absindex(L, t);
|
t = lua_absindex(L, t);
|
||||||
if (lua_rawgeti(L, t, freelist) == LUA_TNIL) { /* first access? */
|
if (lua_rawgeti(L, t, 1) == LUA_TNUMBER) /* already initialized? */
|
||||||
|
ref = (int)lua_tointeger(L, -1); /* ref = t[1] */
|
||||||
|
else { /* first access */
|
||||||
|
lua_assert(!lua_toboolean(L, -1)); /* must be nil or false */
|
||||||
ref = 0; /* list is empty */
|
ref = 0; /* list is empty */
|
||||||
lua_pushinteger(L, 0); /* initialize as an empty list */
|
lua_pushinteger(L, 0); /* initialize as an empty list */
|
||||||
lua_rawseti(L, t, freelist); /* ref = t[freelist] = 0 */
|
lua_rawseti(L, t, 1); /* ref = t[1] = 0 */
|
||||||
}
|
|
||||||
else { /* already initialized */
|
|
||||||
lua_assert(lua_isinteger(L, -1));
|
|
||||||
ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */
|
|
||||||
}
|
}
|
||||||
lua_pop(L, 1); /* remove element from stack */
|
lua_pop(L, 1); /* remove element from stack */
|
||||||
if (ref != 0) { /* any free element? */
|
if (ref != 0) { /* any free element? */
|
||||||
lua_rawgeti(L, t, ref); /* remove it from list */
|
lua_rawgeti(L, t, ref); /* remove it from list */
|
||||||
lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */
|
lua_rawseti(L, t, 1); /* (t[1] = t[ref]) */
|
||||||
}
|
}
|
||||||
else /* no free elements */
|
else /* no free elements */
|
||||||
ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */
|
ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */
|
||||||
@@ -688,11 +716,11 @@ LUALIB_API int luaL_ref (lua_State *L, int t) {
|
|||||||
LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
|
LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
|
||||||
if (ref >= 0) {
|
if (ref >= 0) {
|
||||||
t = lua_absindex(L, t);
|
t = lua_absindex(L, t);
|
||||||
lua_rawgeti(L, t, freelist);
|
lua_rawgeti(L, t, 1);
|
||||||
lua_assert(lua_isinteger(L, -1));
|
lua_assert(lua_isinteger(L, -1));
|
||||||
lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */
|
lua_rawseti(L, t, ref); /* t[ref] = t[1] */
|
||||||
lua_pushinteger(L, ref);
|
lua_pushinteger(L, ref);
|
||||||
lua_rawseti(L, t, freelist); /* t[freelist] = ref */
|
lua_rawseti(L, t, 1); /* t[1] = ref */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -706,7 +734,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct LoadF {
|
typedef struct LoadF {
|
||||||
int n; /* number of pre-read characters */
|
unsigned n; /* number of pre-read characters */
|
||||||
FILE *f; /* file being read */
|
FILE *f; /* file being read */
|
||||||
char buff[BUFSIZ]; /* area for reading file */
|
char buff[BUFSIZ]; /* area for reading file */
|
||||||
} LoadF;
|
} LoadF;
|
||||||
@@ -714,7 +742,7 @@ typedef struct LoadF {
|
|||||||
|
|
||||||
static const char *getF (lua_State *L, void *ud, size_t *size) {
|
static const char *getF (lua_State *L, void *ud, size_t *size) {
|
||||||
LoadF *lf = (LoadF *)ud;
|
LoadF *lf = (LoadF *)ud;
|
||||||
(void)L; /* not used */
|
UNUSED(L);
|
||||||
if (lf->n > 0) { /* are there pre-read characters to be read? */
|
if (lf->n > 0) { /* are there pre-read characters to be read? */
|
||||||
*size = lf->n; /* return them (chars already in buffer) */
|
*size = lf->n; /* return them (chars already in buffer) */
|
||||||
lf->n = 0; /* no more pre-read characters */
|
lf->n = 0; /* no more pre-read characters */
|
||||||
@@ -731,25 +759,29 @@ static const char *getF (lua_State *L, void *ud, size_t *size) {
|
|||||||
|
|
||||||
|
|
||||||
static int errfile (lua_State *L, const char *what, int fnameindex) {
|
static int errfile (lua_State *L, const char *what, int fnameindex) {
|
||||||
const char *serr = strerror(errno);
|
int err = errno;
|
||||||
const char *filename = lua_tostring(L, fnameindex) + 1;
|
const char *filename = lua_tostring(L, fnameindex) + 1;
|
||||||
lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
|
if (err != 0)
|
||||||
|
lua_pushfstring(L, "cannot %s %s: %s", what, filename, strerror(err));
|
||||||
|
else
|
||||||
|
lua_pushfstring(L, "cannot %s %s", what, filename);
|
||||||
lua_remove(L, fnameindex);
|
lua_remove(L, fnameindex);
|
||||||
return LUA_ERRFILE;
|
return LUA_ERRFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int skipBOM (LoadF *lf) {
|
/*
|
||||||
const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
|
** Skip an optional BOM at the start of a stream. If there is an
|
||||||
int c;
|
** incomplete BOM (the first character is correct but the rest is
|
||||||
lf->n = 0;
|
** not), returns the first character anyway to force an error
|
||||||
do {
|
** (as no chunk can start with 0xEF).
|
||||||
c = getc(lf->f);
|
*/
|
||||||
if (c == EOF || c != *(const unsigned char *)p++) return c;
|
static int skipBOM (FILE *f) {
|
||||||
lf->buff[lf->n++] = c; /* to be read by the parser */
|
int c = getc(f); /* read first character */
|
||||||
} while (*p != '\0');
|
if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
|
||||||
lf->n = 0; /* prefix matched; discard it */
|
return getc(f); /* ignore BOM and return next char */
|
||||||
return getc(lf->f); /* return next character */
|
else /* no (valid) BOM */
|
||||||
|
return c; /* return first character */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -760,13 +792,13 @@ static int skipBOM (LoadF *lf) {
|
|||||||
** first "valid" character of the file (after the optional BOM and
|
** first "valid" character of the file (after the optional BOM and
|
||||||
** a first-line comment).
|
** a first-line comment).
|
||||||
*/
|
*/
|
||||||
static int skipcomment (LoadF *lf, int *cp) {
|
static int skipcomment (FILE *f, int *cp) {
|
||||||
int c = *cp = skipBOM(lf);
|
int c = *cp = skipBOM(f);
|
||||||
if (c == '#') { /* first line is a comment (Unix exec. file)? */
|
if (c == '#') { /* first line is a comment (Unix exec. file)? */
|
||||||
do { /* skip first line */
|
do { /* skip first line */
|
||||||
c = getc(lf->f);
|
c = getc(f);
|
||||||
} while (c != EOF && c != '\n');
|
} while (c != EOF && c != '\n');
|
||||||
*cp = getc(lf->f); /* skip end-of-line, if present */
|
*cp = getc(f); /* next character after comment, if present */
|
||||||
return 1; /* there was a comment */
|
return 1; /* there was a comment */
|
||||||
}
|
}
|
||||||
else return 0; /* no comment */
|
else return 0; /* no comment */
|
||||||
@@ -785,20 +817,27 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lua_pushfstring(L, "@%s", filename);
|
lua_pushfstring(L, "@%s", filename);
|
||||||
|
errno = 0;
|
||||||
lf.f = fopen(filename, "r");
|
lf.f = fopen(filename, "r");
|
||||||
if (lf.f == NULL) return errfile(L, "open", fnameindex);
|
if (lf.f == NULL) return errfile(L, "open", fnameindex);
|
||||||
}
|
}
|
||||||
if (skipcomment(&lf, &c)) /* read initial portion */
|
lf.n = 0;
|
||||||
lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
|
if (skipcomment(lf.f, &c)) /* read initial portion */
|
||||||
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
|
lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
|
||||||
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
|
if (c == LUA_SIGNATURE[0]) { /* binary file? */
|
||||||
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
|
lf.n = 0; /* remove possible newline */
|
||||||
skipcomment(&lf, &c); /* re-read initial portion */
|
if (filename) { /* "real" file? */
|
||||||
|
errno = 0;
|
||||||
|
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
|
||||||
|
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
|
||||||
|
skipcomment(lf.f, &c); /* re-read initial portion */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (c != EOF)
|
if (c != EOF)
|
||||||
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
|
lf.buff[lf.n++] = cast_char(c); /* 'c' is the first character */
|
||||||
status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
|
status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
|
||||||
readstatus = ferror(lf.f);
|
readstatus = ferror(lf.f);
|
||||||
|
errno = 0; /* no useful error number until here */
|
||||||
if (filename) fclose(lf.f); /* close file (even in case of errors) */
|
if (filename) fclose(lf.f); /* close file (even in case of errors) */
|
||||||
if (readstatus) {
|
if (readstatus) {
|
||||||
lua_settop(L, fnameindex); /* ignore results from 'lua_load' */
|
lua_settop(L, fnameindex); /* ignore results from 'lua_load' */
|
||||||
@@ -817,7 +856,7 @@ typedef struct LoadS {
|
|||||||
|
|
||||||
static const char *getS (lua_State *L, void *ud, size_t *size) {
|
static const char *getS (lua_State *L, void *ud, size_t *size) {
|
||||||
LoadS *ls = (LoadS *)ud;
|
LoadS *ls = (LoadS *)ud;
|
||||||
(void)L; /* not used */
|
UNUSED(L);
|
||||||
if (ls->size == 0) return NULL;
|
if (ls->size == 0) return NULL;
|
||||||
*size = ls->size;
|
*size = ls->size;
|
||||||
ls->size = 0;
|
ls->size = 0;
|
||||||
@@ -881,6 +920,7 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
|
|||||||
|
|
||||||
|
|
||||||
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
|
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
|
||||||
|
idx = lua_absindex(L,idx);
|
||||||
if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */
|
if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */
|
||||||
if (!lua_isstring(L, -1))
|
if (!lua_isstring(L, -1))
|
||||||
luaL_error(L, "'__tostring' must return a string");
|
luaL_error(L, "'__tostring' must return a string");
|
||||||
@@ -888,10 +928,9 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
|
|||||||
else {
|
else {
|
||||||
switch (lua_type(L, idx)) {
|
switch (lua_type(L, idx)) {
|
||||||
case LUA_TNUMBER: {
|
case LUA_TNUMBER: {
|
||||||
if (lua_isinteger(L, idx))
|
char buff[LUA_N2SBUFFSZ];
|
||||||
lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx));
|
lua_numbertocstring(L, idx, buff);
|
||||||
else
|
lua_pushstring(L, buff);
|
||||||
lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LUA_TSTRING:
|
case LUA_TSTRING:
|
||||||
@@ -926,7 +965,7 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
|
|||||||
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
|
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
|
||||||
luaL_checkstack(L, nup, "too many upvalues");
|
luaL_checkstack(L, nup, "too many upvalues");
|
||||||
for (; l->name != NULL; l++) { /* fill the table with given functions */
|
for (; l->name != NULL; l++) { /* fill the table with given functions */
|
||||||
if (l->func == NULL) /* place holder? */
|
if (l->func == NULL) /* placeholder? */
|
||||||
lua_pushboolean(L, 0);
|
lua_pushboolean(L, 0);
|
||||||
else {
|
else {
|
||||||
int i;
|
int i;
|
||||||
@@ -989,7 +1028,7 @@ LUALIB_API void luaL_addgsub (luaL_Buffer *b, const char *s,
|
|||||||
const char *wild;
|
const char *wild;
|
||||||
size_t l = strlen(p);
|
size_t l = strlen(p);
|
||||||
while ((wild = strstr(s, p)) != NULL) {
|
while ((wild = strstr(s, p)) != NULL) {
|
||||||
luaL_addlstring(b, s, wild - s); /* push prefix */
|
luaL_addlstring(b, s, ct_diff2sz(wild - s)); /* push prefix */
|
||||||
luaL_addstring(b, r); /* push replacement in place of pattern */
|
luaL_addstring(b, r); /* push replacement in place of pattern */
|
||||||
s = wild + l; /* continue after 'p' */
|
s = wild + l; /* continue after 'p' */
|
||||||
}
|
}
|
||||||
@@ -1007,8 +1046,8 @@ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
void *luaL_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||||
(void)ud; (void)osize; /* not used */
|
UNUSED(ud); UNUSED(osize);
|
||||||
if (nsize == 0) {
|
if (nsize == 0) {
|
||||||
free(ptr);
|
free(ptr);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1018,9 +1057,14 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Standard panic function just prints an error message. The test
|
||||||
|
** with 'lua_type' avoids possible memory errors in 'lua_tostring'.
|
||||||
|
*/
|
||||||
static int panic (lua_State *L) {
|
static int panic (lua_State *L) {
|
||||||
const char *msg = lua_tostring(L, -1);
|
const char *msg = (lua_type(L, -1) == LUA_TSTRING)
|
||||||
if (msg == NULL) msg = "error object is not a string";
|
? lua_tostring(L, -1)
|
||||||
|
: "error object is not a string";
|
||||||
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
|
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
|
||||||
msg);
|
msg);
|
||||||
return 0; /* return to Lua to abort */
|
return 0; /* return to Lua to abort */
|
||||||
@@ -1084,11 +1128,64 @@ static void warnfon (void *ud, const char *message, int tocont) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API lua_State *luaL_newstate (void) {
|
|
||||||
lua_State *L = lua_newstate(l_alloc, NULL);
|
/*
|
||||||
|
** A function to compute an unsigned int with some level of
|
||||||
|
** randomness. Rely on Address Space Layout Randomization (if present)
|
||||||
|
** and the current time.
|
||||||
|
*/
|
||||||
|
#if !defined(luai_makeseed)
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* Size for the buffer, in bytes */
|
||||||
|
#define BUFSEEDB (sizeof(void*) + sizeof(time_t))
|
||||||
|
|
||||||
|
/* Size for the buffer in int's, rounded up */
|
||||||
|
#define BUFSEED ((BUFSEEDB + sizeof(int) - 1) / sizeof(int))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copy the contents of variable 'v' into the buffer pointed by 'b'.
|
||||||
|
** (The '&b[0]' disguises 'b' to fix an absurd warning from clang.)
|
||||||
|
*/
|
||||||
|
#define addbuff(b,v) (memcpy(&b[0], &(v), sizeof(v)), b += sizeof(v))
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned int luai_makeseed (void) {
|
||||||
|
unsigned int buff[BUFSEED];
|
||||||
|
unsigned int res;
|
||||||
|
unsigned int i;
|
||||||
|
time_t t = time(NULL);
|
||||||
|
char *b = (char*)buff;
|
||||||
|
addbuff(b, b); /* local variable's address */
|
||||||
|
addbuff(b, t); /* time */
|
||||||
|
/* fill (rare but possible) remain of the buffer with zeros */
|
||||||
|
memset(b, 0, sizeof(buff) - BUFSEEDB);
|
||||||
|
res = buff[0];
|
||||||
|
for (i = 1; i < BUFSEED; i++)
|
||||||
|
res ^= (res >> 3) + (res << 7) + buff[i];
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API unsigned int luaL_makeseed (lua_State *L) {
|
||||||
|
UNUSED(L);
|
||||||
|
return luai_makeseed();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Use the name with parentheses so that headers can redefine it
|
||||||
|
** as a macro.
|
||||||
|
*/
|
||||||
|
LUALIB_API lua_State *(luaL_newstate) (void) {
|
||||||
|
lua_State *L = lua_newstate(luaL_alloc, NULL, luaL_makeseed(NULL));
|
||||||
if (l_likely(L)) {
|
if (l_likely(L)) {
|
||||||
lua_atpanic(L, &panic);
|
lua_atpanic(L, &panic);
|
||||||
lua_setwarnf(L, warnfoff, L); /* default is warnings off */
|
lua_setwarnf(L, warnfon, L);
|
||||||
}
|
}
|
||||||
return L;
|
return L;
|
||||||
}
|
}
|
||||||
+15
-37
@@ -81,6 +81,9 @@ LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
|
|||||||
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
|
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
|
||||||
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
|
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
|
||||||
|
|
||||||
|
LUALIB_API void *luaL_alloc (void *ud, void *ptr, size_t osize,
|
||||||
|
size_t nsize);
|
||||||
|
|
||||||
|
|
||||||
/* predefined references */
|
/* predefined references */
|
||||||
#define LUA_NOREF (-2)
|
#define LUA_NOREF (-2)
|
||||||
@@ -100,9 +103,11 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
|
|||||||
|
|
||||||
LUALIB_API lua_State *(luaL_newstate) (void);
|
LUALIB_API lua_State *(luaL_newstate) (void);
|
||||||
|
|
||||||
|
LUALIB_API unsigned luaL_makeseed (lua_State *L);
|
||||||
|
|
||||||
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
|
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
|
||||||
|
|
||||||
LUALIB_API void luaL_addgsub (luaL_Buffer *b, const char *s,
|
LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s,
|
||||||
const char *p, const char *r);
|
const char *p, const char *r);
|
||||||
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s,
|
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s,
|
||||||
const char *p, const char *r);
|
const char *p, const char *r);
|
||||||
@@ -154,22 +159,19 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
|
|||||||
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
|
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
|
||||||
|
|
||||||
|
|
||||||
/* push the value used to represent failure/error */
|
|
||||||
#define luaL_pushfail(L) lua_pushnil(L)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Internal assertions for in-house debugging
|
** Perform arithmetic operations on lua_Integer values with wrap-around
|
||||||
|
** semantics, as the Lua core does.
|
||||||
*/
|
*/
|
||||||
#if !defined(lua_assert)
|
#define luaL_intop(op,v1,v2) \
|
||||||
|
((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2)))
|
||||||
|
|
||||||
#if defined LUAI_ASSERT
|
|
||||||
#include <assert.h>
|
/* push the value used to represent failure/error */
|
||||||
#define lua_assert(c) assert(c)
|
#if defined(LUA_FAILISFALSE)
|
||||||
|
#define luaL_pushfail(L) lua_pushboolean(L, 0)
|
||||||
#else
|
#else
|
||||||
#define lua_assert(c) ((void)0)
|
#define luaL_pushfail(L) lua_pushnil(L)
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -241,30 +243,6 @@ typedef struct luaL_Stream {
|
|||||||
|
|
||||||
/* }====================================================== */
|
/* }====================================================== */
|
||||||
|
|
||||||
/*
|
|
||||||
** {==================================================================
|
|
||||||
** "Abstraction Layer" for basic report of messages and errors
|
|
||||||
** ===================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* print a string */
|
|
||||||
#if !defined(lua_writestring)
|
|
||||||
#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* print a newline and flush the output */
|
|
||||||
#if !defined(lua_writeline)
|
|
||||||
#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* print an error message */
|
|
||||||
#if !defined(lua_writestringerror)
|
|
||||||
#define lua_writestringerror(s,p) \
|
|
||||||
(fprintf(stderr, (s), (p)), fflush(stderr))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* }================================================================== */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** {============================================================
|
** {============================================================
|
||||||
+69
-38
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
static int luaB_print (lua_State *L) {
|
static int luaB_print (lua_State *L) {
|
||||||
@@ -57,21 +58,22 @@ static int luaB_warn (lua_State *L) {
|
|||||||
|
|
||||||
#define SPACECHARS " \f\n\r\t\v"
|
#define SPACECHARS " \f\n\r\t\v"
|
||||||
|
|
||||||
static const char *b_str2int (const char *s, int base, lua_Integer *pn) {
|
static const char *b_str2int (const char *s, unsigned base, lua_Integer *pn) {
|
||||||
lua_Unsigned n = 0;
|
lua_Unsigned n = 0;
|
||||||
int neg = 0;
|
int neg = 0;
|
||||||
s += strspn(s, SPACECHARS); /* skip initial spaces */
|
s += strspn(s, SPACECHARS); /* skip initial spaces */
|
||||||
if (*s == '-') { s++; neg = 1; } /* handle sign */
|
if (*s == '-') { s++; neg = 1; } /* handle sign */
|
||||||
else if (*s == '+') s++;
|
else if (*s == '+') s++;
|
||||||
if (!isalnum((unsigned char)*s)) /* no digit? */
|
if (!isalnum(cast_uchar(*s))) /* no digit? */
|
||||||
return NULL;
|
return NULL;
|
||||||
do {
|
do {
|
||||||
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
|
unsigned digit = cast_uint(isdigit(cast_uchar(*s))
|
||||||
: (toupper((unsigned char)*s) - 'A') + 10;
|
? *s - '0'
|
||||||
|
: (toupper(cast_uchar(*s)) - 'A') + 10);
|
||||||
if (digit >= base) return NULL; /* invalid numeral */
|
if (digit >= base) return NULL; /* invalid numeral */
|
||||||
n = n * base + digit;
|
n = n * base + digit;
|
||||||
s++;
|
s++;
|
||||||
} while (isalnum((unsigned char)*s));
|
} while (isalnum(cast_uchar(*s)));
|
||||||
s += strspn(s, SPACECHARS); /* skip trailing spaces */
|
s += strspn(s, SPACECHARS); /* skip trailing spaces */
|
||||||
*pn = (lua_Integer)((neg) ? (0u - n) : n);
|
*pn = (lua_Integer)((neg) ? (0u - n) : n);
|
||||||
return s;
|
return s;
|
||||||
@@ -101,7 +103,7 @@ static int luaB_tonumber (lua_State *L) {
|
|||||||
luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
|
luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
|
||||||
s = lua_tolstring(L, 1, &l);
|
s = lua_tolstring(L, 1, &l);
|
||||||
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
|
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
|
||||||
if (b_str2int(s, (int)base, &n) == s + l) {
|
if (b_str2int(s, cast_uint(base), &n) == s + l) {
|
||||||
lua_pushinteger(L, n);
|
lua_pushinteger(L, n);
|
||||||
return 1;
|
return 1;
|
||||||
} /* else not a number */
|
} /* else not a number */
|
||||||
@@ -158,7 +160,7 @@ static int luaB_rawlen (lua_State *L) {
|
|||||||
int t = lua_type(L, 1);
|
int t = lua_type(L, 1);
|
||||||
luaL_argexpected(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
|
luaL_argexpected(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
|
||||||
"table or string");
|
"table or string");
|
||||||
lua_pushinteger(L, lua_rawlen(L, 1));
|
lua_pushinteger(L, l_castU2S(lua_rawlen(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,62 +184,76 @@ static int luaB_rawset (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
static int pushmode (lua_State *L, int oldmode) {
|
static int pushmode (lua_State *L, int oldmode) {
|
||||||
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
|
if (oldmode == -1)
|
||||||
: "generational");
|
luaL_pushfail(L); /* invalid call to 'lua_gc' */
|
||||||
|
else
|
||||||
|
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
|
||||||
|
: "generational");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** check whether call to 'lua_gc' was valid (not inside a finalizer)
|
||||||
|
*/
|
||||||
|
#define checkvalres(res) { if (res == -1) break; }
|
||||||
|
|
||||||
static int luaB_collectgarbage (lua_State *L) {
|
static int luaB_collectgarbage (lua_State *L) {
|
||||||
static const char *const opts[] = {"stop", "restart", "collect",
|
static const char *const opts[] = {"stop", "restart", "collect",
|
||||||
"count", "step", "setpause", "setstepmul",
|
"count", "step", "isrunning", "generational", "incremental",
|
||||||
"isrunning", "generational", "incremental", NULL};
|
"param", NULL};
|
||||||
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
|
static const char optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
|
||||||
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
|
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC,
|
||||||
LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
|
LUA_GCPARAM};
|
||||||
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
|
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
|
||||||
switch (o) {
|
switch (o) {
|
||||||
case LUA_GCCOUNT: {
|
case LUA_GCCOUNT: {
|
||||||
int k = lua_gc(L, o);
|
int k = lua_gc(L, o);
|
||||||
int b = lua_gc(L, LUA_GCCOUNTB);
|
int b = lua_gc(L, LUA_GCCOUNTB);
|
||||||
|
checkvalres(k);
|
||||||
lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
|
lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case LUA_GCSTEP: {
|
case LUA_GCSTEP: {
|
||||||
int step = (int)luaL_optinteger(L, 2, 0);
|
lua_Integer n = luaL_optinteger(L, 2, 0);
|
||||||
int res = lua_gc(L, o, step);
|
int res = lua_gc(L, o, cast_sizet(n));
|
||||||
|
checkvalres(res);
|
||||||
lua_pushboolean(L, res);
|
lua_pushboolean(L, res);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case LUA_GCSETPAUSE:
|
|
||||||
case LUA_GCSETSTEPMUL: {
|
|
||||||
int p = (int)luaL_optinteger(L, 2, 0);
|
|
||||||
int previous = lua_gc(L, o, p);
|
|
||||||
lua_pushinteger(L, previous);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
case LUA_GCISRUNNING: {
|
case LUA_GCISRUNNING: {
|
||||||
int res = lua_gc(L, o);
|
int res = lua_gc(L, o);
|
||||||
|
checkvalres(res);
|
||||||
lua_pushboolean(L, res);
|
lua_pushboolean(L, res);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case LUA_GCGEN: {
|
case LUA_GCGEN: {
|
||||||
int minormul = (int)luaL_optinteger(L, 2, 0);
|
return pushmode(L, lua_gc(L, o));
|
||||||
int majormul = (int)luaL_optinteger(L, 3, 0);
|
|
||||||
return pushmode(L, lua_gc(L, o, minormul, majormul));
|
|
||||||
}
|
}
|
||||||
case LUA_GCINC: {
|
case LUA_GCINC: {
|
||||||
int pause = (int)luaL_optinteger(L, 2, 0);
|
return pushmode(L, lua_gc(L, o));
|
||||||
int stepmul = (int)luaL_optinteger(L, 3, 0);
|
}
|
||||||
int stepsize = (int)luaL_optinteger(L, 4, 0);
|
case LUA_GCPARAM: {
|
||||||
return pushmode(L, lua_gc(L, o, pause, stepmul, stepsize));
|
static const char *const params[] = {
|
||||||
|
"minormul", "majorminor", "minormajor",
|
||||||
|
"pause", "stepmul", "stepsize", NULL};
|
||||||
|
static const char pnum[] = {
|
||||||
|
LUA_GCPMINORMUL, LUA_GCPMAJORMINOR, LUA_GCPMINORMAJOR,
|
||||||
|
LUA_GCPPAUSE, LUA_GCPSTEPMUL, LUA_GCPSTEPSIZE};
|
||||||
|
int p = pnum[luaL_checkoption(L, 2, NULL, params)];
|
||||||
|
lua_Integer value = luaL_optinteger(L, 3, -1);
|
||||||
|
lua_pushinteger(L, lua_gc(L, o, p, (int)value));
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
int res = lua_gc(L, o);
|
int res = lua_gc(L, o);
|
||||||
|
checkvalres(res);
|
||||||
lua_pushinteger(L, res);
|
lua_pushinteger(L, res);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
luaL_pushfail(L); /* invalid call (inside a finalizer) */
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -261,18 +277,24 @@ static int luaB_next (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int pairscont (lua_State *L, int status, lua_KContext k) {
|
||||||
|
(void)L; (void)status; (void)k; /* unused */
|
||||||
|
return 4; /* __pairs did all the work, just return its results */
|
||||||
|
}
|
||||||
|
|
||||||
static int luaB_pairs (lua_State *L) {
|
static int luaB_pairs (lua_State *L) {
|
||||||
luaL_checkany(L, 1);
|
luaL_checkany(L, 1);
|
||||||
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
|
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
|
||||||
lua_pushcfunction(L, luaB_next); /* will return generator, */
|
lua_pushcfunction(L, luaB_next); /* will return generator and */
|
||||||
lua_pushvalue(L, 1); /* state, */
|
lua_pushvalue(L, 1); /* state */
|
||||||
lua_pushnil(L); /* and initial value */
|
lua_pushnil(L); /* initial value */
|
||||||
|
lua_pushnil(L); /* to-be-closed object */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
|
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
|
||||||
lua_call(L, 1, 3); /* get 3 values from metamethod */
|
lua_callk(L, 1, 4, 0, pairscont); /* get 4 values from metamethod */
|
||||||
}
|
}
|
||||||
return 3;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -280,7 +302,8 @@ static int luaB_pairs (lua_State *L) {
|
|||||||
** Traversal function for 'ipairs'
|
** Traversal function for 'ipairs'
|
||||||
*/
|
*/
|
||||||
static int ipairsaux (lua_State *L) {
|
static int ipairsaux (lua_State *L) {
|
||||||
lua_Integer i = luaL_checkinteger(L, 2) + 1;
|
lua_Integer i = luaL_checkinteger(L, 2);
|
||||||
|
i = luaL_intop(+, i, 1);
|
||||||
lua_pushinteger(L, i);
|
lua_pushinteger(L, i);
|
||||||
return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
|
return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
|
||||||
}
|
}
|
||||||
@@ -316,9 +339,17 @@ static int load_aux (lua_State *L, int status, int envidx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *getMode (lua_State *L, int idx) {
|
||||||
|
const char *mode = luaL_optstring(L, idx, "bt");
|
||||||
|
if (strchr(mode, 'B') != NULL) /* Lua code cannot use fixed buffers */
|
||||||
|
luaL_argerror(L, idx, "invalid mode");
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int luaB_loadfile (lua_State *L) {
|
static int luaB_loadfile (lua_State *L) {
|
||||||
const char *fname = luaL_optstring(L, 1, NULL);
|
const char *fname = luaL_optstring(L, 1, NULL);
|
||||||
const char *mode = luaL_optstring(L, 2, NULL);
|
const char *mode = getMode(L, 2);
|
||||||
int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */
|
int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */
|
||||||
int status = luaL_loadfilex(L, fname, mode);
|
int status = luaL_loadfilex(L, fname, mode);
|
||||||
return load_aux(L, status, env);
|
return load_aux(L, status, env);
|
||||||
@@ -367,7 +398,7 @@ static int luaB_load (lua_State *L) {
|
|||||||
int status;
|
int status;
|
||||||
size_t l;
|
size_t l;
|
||||||
const char *s = lua_tolstring(L, 1, &l);
|
const char *s = lua_tolstring(L, 1, &l);
|
||||||
const char *mode = luaL_optstring(L, 3, "bt");
|
const char *mode = getMode(L, 3);
|
||||||
int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
|
int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
|
||||||
if (s != NULL) { /* loading a string? */
|
if (s != NULL) { /* loading a string? */
|
||||||
const char *chunkname = luaL_optstring(L, 2, s);
|
const char *chunkname = luaL_optstring(L, 2, s);
|
||||||
+351
-194
File diff suppressed because it is too large
Load Diff
+9
-8
@@ -60,27 +60,28 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
|
|||||||
#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
|
#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
|
||||||
|
|
||||||
LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
|
LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
|
||||||
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
|
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, int Bx);
|
||||||
LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
|
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, int B, int C,
|
||||||
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
|
int k);
|
||||||
int B, int C, int k);
|
LUAI_FUNC int luaK_codevABCk (FuncState *fs, OpCode o, int A, int B, int C,
|
||||||
LUAI_FUNC int luaK_isKint (expdesc *e);
|
int k);
|
||||||
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
|
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
|
||||||
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
|
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
|
||||||
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
|
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
|
||||||
|
LUAI_FUNC void luaK_codecheckglobal (FuncState *fs, expdesc *var, int k,
|
||||||
|
int line);
|
||||||
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
|
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
|
||||||
LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
|
LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
|
||||||
LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n);
|
LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n);
|
||||||
|
LUAI_FUNC void luaK_vapar2local (FuncState *fs, expdesc *var);
|
||||||
LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
|
|
||||||
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
||||||
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
|
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
|
||||||
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e);
|
|
||||||
LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
|
LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
|
||||||
LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
|
LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
|
||||||
LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
|
||||||
@@ -98,7 +99,7 @@ LUAI_FUNC void luaK_settablesize (FuncState *fs, int pc,
|
|||||||
int ra, int asize, int hsize);
|
int ra, int asize, int hsize);
|
||||||
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
|
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
|
||||||
LUAI_FUNC void luaK_finish (FuncState *fs);
|
LUAI_FUNC void luaK_finish (FuncState *fs);
|
||||||
LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg);
|
LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+22
-7
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
static lua_State *getco (lua_State *L) {
|
static lua_State *getco (lua_State *L) {
|
||||||
@@ -76,9 +77,9 @@ static int luaB_auxwrap (lua_State *L) {
|
|||||||
if (l_unlikely(r < 0)) { /* error? */
|
if (l_unlikely(r < 0)) { /* error? */
|
||||||
int stat = lua_status(co);
|
int stat = lua_status(co);
|
||||||
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
|
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
|
||||||
stat = lua_resetthread(co); /* close its tbc variables */
|
stat = lua_closethread(co, L); /* close its tbc variables */
|
||||||
lua_assert(stat != LUA_OK);
|
lua_assert(stat != LUA_OK);
|
||||||
lua_xmove(co, L, 1); /* copy error message */
|
lua_xmove(co, L, 1); /* move error message to the caller */
|
||||||
}
|
}
|
||||||
if (stat != LUA_ERRMEM && /* not a memory error and ... */
|
if (stat != LUA_ERRMEM && /* not a memory error and ... */
|
||||||
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
|
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
|
||||||
@@ -153,8 +154,13 @@ static int luaB_costatus (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static lua_State *getoptco (lua_State *L) {
|
||||||
|
return (lua_isnone(L, 1) ? L : getco(L));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int luaB_yieldable (lua_State *L) {
|
static int luaB_yieldable (lua_State *L) {
|
||||||
lua_State *co = lua_isnone(L, 1) ? L : getco(L);
|
lua_State *co = getoptco(L);
|
||||||
lua_pushboolean(L, lua_isyieldable(co));
|
lua_pushboolean(L, lua_isyieldable(co));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -168,23 +174,32 @@ static int luaB_corunning (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
static int luaB_close (lua_State *L) {
|
static int luaB_close (lua_State *L) {
|
||||||
lua_State *co = getco(L);
|
lua_State *co = getoptco(L);
|
||||||
int status = auxstatus(L, co);
|
int status = auxstatus(L, co);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case COS_DEAD: case COS_YIELD: {
|
case COS_DEAD: case COS_YIELD: {
|
||||||
status = lua_resetthread(co);
|
status = lua_closethread(co, L);
|
||||||
if (status == LUA_OK) {
|
if (status == LUA_OK) {
|
||||||
lua_pushboolean(L, 1);
|
lua_pushboolean(L, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lua_pushboolean(L, 0);
|
lua_pushboolean(L, 0);
|
||||||
lua_xmove(co, L, 1); /* copy error message */
|
lua_xmove(co, L, 1); /* move error message */
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default: /* normal or running coroutine */
|
case COS_NORM:
|
||||||
return luaL_error(L, "cannot close a %s coroutine", statname[status]);
|
return luaL_error(L, "cannot close a %s coroutine", statname[status]);
|
||||||
|
case COS_RUN:
|
||||||
|
lua_geti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); /* get main */
|
||||||
|
if (lua_tothread(L, -1) == co)
|
||||||
|
return luaL_error(L, "cannot close main thread");
|
||||||
|
lua_closethread(co, L); /* close itself */
|
||||||
|
/* previous call does not return *//* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
lua_assert(0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#if defined (LUA_UCID) /* accept UniCode IDentifiers? */
|
#if defined (LUA_UCID) /* accept UniCode IDentifiers? */
|
||||||
/* consider all non-ascii codepoints to be alphabetic */
|
/* consider all non-ASCII codepoints to be alphabetic */
|
||||||
#define NONA 0x01
|
#define NONA 0x01
|
||||||
#else
|
#else
|
||||||
#define NONA 0x00 /* default */
|
#define NONA 0x00 /* default */
|
||||||
+4
-10
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -190,8 +191,10 @@ static int db_getinfo (lua_State *L) {
|
|||||||
settabsi(L, "ftransfer", ar.ftransfer);
|
settabsi(L, "ftransfer", ar.ftransfer);
|
||||||
settabsi(L, "ntransfer", ar.ntransfer);
|
settabsi(L, "ntransfer", ar.ntransfer);
|
||||||
}
|
}
|
||||||
if (strchr(options, 't'))
|
if (strchr(options, 't')) {
|
||||||
settabsb(L, "istailcall", ar.istailcall);
|
settabsb(L, "istailcall", ar.istailcall);
|
||||||
|
settabsi(L, "extraargs", ar.extraargs);
|
||||||
|
}
|
||||||
if (strchr(options, 'L'))
|
if (strchr(options, 'L'))
|
||||||
treatstackoption(L, L1, "activelines");
|
treatstackoption(L, L1, "activelines");
|
||||||
if (strchr(options, 'f'))
|
if (strchr(options, 'f'))
|
||||||
@@ -446,14 +449,6 @@ static int db_traceback (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int db_setcstacklimit (lua_State *L) {
|
|
||||||
int limit = (int)luaL_checkinteger(L, 1);
|
|
||||||
int res = lua_setcstacklimit(L, limit);
|
|
||||||
lua_pushinteger(L, res);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const luaL_Reg dblib[] = {
|
static const luaL_Reg dblib[] = {
|
||||||
{"debug", db_debug},
|
{"debug", db_debug},
|
||||||
{"getuservalue", db_getuservalue},
|
{"getuservalue", db_getuservalue},
|
||||||
@@ -471,7 +466,6 @@ static const luaL_Reg dblib[] = {
|
|||||||
{"setmetatable", db_setmetatable},
|
{"setmetatable", db_setmetatable},
|
||||||
{"setupvalue", db_setupvalue},
|
{"setupvalue", db_setupvalue},
|
||||||
{"traceback", db_traceback},
|
{"traceback", db_traceback},
|
||||||
{"setcstacklimit", db_setcstacklimit},
|
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
+274
-172
@@ -31,11 +31,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL)
|
#define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL)
|
||||||
|
|
||||||
|
static const char strlocal[] = "local";
|
||||||
|
static const char strupval[] = "upvalue";
|
||||||
|
|
||||||
static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
|
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
|
||||||
const char **name);
|
const char **name);
|
||||||
|
|
||||||
|
|
||||||
static int currentpc (CallInfo *ci) {
|
static int currentpc (CallInfo *ci) {
|
||||||
@@ -63,8 +65,8 @@ static int getbaseline (const Proto *f, int pc, int *basepc) {
|
|||||||
return f->linedefined;
|
return f->linedefined;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */
|
int i = pc / MAXIWTHABS - 1; /* get an estimate */
|
||||||
/* estimate must be a lower bond of the correct base */
|
/* estimate must be a lower bound of the correct base */
|
||||||
lua_assert(i < 0 ||
|
lua_assert(i < 0 ||
|
||||||
(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
|
(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
|
||||||
while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
|
while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
|
||||||
@@ -182,10 +184,10 @@ static const char *upvalname (const Proto *p, int uv) {
|
|||||||
|
|
||||||
|
|
||||||
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
||||||
if (clLvalue(s2v(ci->func))->p->is_vararg) {
|
if (clLvalue(s2v(ci->func.p))->p->flag & PF_VAHID) {
|
||||||
int nextra = ci->u.l.nextraargs;
|
int nextra = ci->u.l.nextraargs;
|
||||||
if (n >= -nextra) { /* 'n' is negative */
|
if (n >= -nextra) { /* 'n' is negative */
|
||||||
*pos = ci->func - nextra - (n + 1);
|
*pos = ci->func.p - nextra - (n + 1);
|
||||||
return "(vararg)"; /* generic name for any vararg */
|
return "(vararg)"; /* generic name for any vararg */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,7 +196,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
|||||||
|
|
||||||
|
|
||||||
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
|
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
|
||||||
StkId base = ci->func + 1;
|
StkId base = ci->func.p + 1;
|
||||||
const char *name = NULL;
|
const char *name = NULL;
|
||||||
if (isLua(ci)) {
|
if (isLua(ci)) {
|
||||||
if (n < 0) /* access to vararg values? */
|
if (n < 0) /* access to vararg values? */
|
||||||
@@ -203,7 +205,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
|
|||||||
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
|
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
|
||||||
}
|
}
|
||||||
if (name == NULL) { /* no 'standard' name? */
|
if (name == NULL) { /* no 'standard' name? */
|
||||||
StkId limit = (ci == L->ci) ? L->top : ci->next->func;
|
StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
|
||||||
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
|
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
|
||||||
/* generic name for any valid slot */
|
/* generic name for any valid slot */
|
||||||
name = isLua(ci) ? "(temporary)" : "(C temporary)";
|
name = isLua(ci) ? "(temporary)" : "(C temporary)";
|
||||||
@@ -221,16 +223,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
|
|||||||
const char *name;
|
const char *name;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
if (ar == NULL) { /* information about non-active function? */
|
if (ar == NULL) { /* information about non-active function? */
|
||||||
if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */
|
if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
|
||||||
name = NULL;
|
name = NULL;
|
||||||
else /* consider live variables at function start (parameters) */
|
else /* consider live variables at function start (parameters) */
|
||||||
name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0);
|
name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
|
||||||
}
|
}
|
||||||
else { /* active function; get information through 'ar' */
|
else { /* active function; get information through 'ar' */
|
||||||
StkId pos = NULL; /* to avoid warnings */
|
StkId pos = NULL; /* to avoid warnings */
|
||||||
name = luaG_findlocal(L, ar->i_ci, n, &pos);
|
name = luaG_findlocal(L, ar->i_ci, n, &pos);
|
||||||
if (name) {
|
if (name) {
|
||||||
setobjs2s(L, L->top, pos);
|
setobjs2s(L, L->top.p, pos);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,8 +247,9 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
|||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
name = luaG_findlocal(L, ar->i_ci, n, &pos);
|
name = luaG_findlocal(L, ar->i_ci, n, &pos);
|
||||||
if (name) {
|
if (name) {
|
||||||
setobjs2s(L, pos, L->top - 1);
|
api_checkpop(L, 1);
|
||||||
L->top--; /* pop value */
|
setobjs2s(L, pos, L->top.p - 1);
|
||||||
|
L->top.p--; /* pop value */
|
||||||
}
|
}
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return name;
|
return name;
|
||||||
@@ -254,7 +257,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
|||||||
|
|
||||||
|
|
||||||
static void funcinfo (lua_Debug *ar, Closure *cl) {
|
static void funcinfo (lua_Debug *ar, Closure *cl) {
|
||||||
if (noLuaClosure(cl)) {
|
if (!LuaClosure(cl)) {
|
||||||
ar->source = "=[C]";
|
ar->source = "=[C]";
|
||||||
ar->srclen = LL("=[C]");
|
ar->srclen = LL("=[C]");
|
||||||
ar->linedefined = -1;
|
ar->linedefined = -1;
|
||||||
@@ -264,8 +267,7 @@ static void funcinfo (lua_Debug *ar, Closure *cl) {
|
|||||||
else {
|
else {
|
||||||
const Proto *p = cl->l.p;
|
const Proto *p = cl->l.p;
|
||||||
if (p->source) {
|
if (p->source) {
|
||||||
ar->source = getstr(p->source);
|
ar->source = getlstr(p->source, ar->srclen);
|
||||||
ar->srclen = tsslen(p->source);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ar->source = "=?";
|
ar->source = "=?";
|
||||||
@@ -288,37 +290,40 @@ static int nextline (const Proto *p, int currentline, int pc) {
|
|||||||
|
|
||||||
|
|
||||||
static void collectvalidlines (lua_State *L, Closure *f) {
|
static void collectvalidlines (lua_State *L, Closure *f) {
|
||||||
if (noLuaClosure(f)) {
|
if (!LuaClosure(f)) {
|
||||||
setnilvalue(s2v(L->top));
|
setnilvalue(s2v(L->top.p));
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int i;
|
|
||||||
TValue v;
|
|
||||||
const Proto *p = f->l.p;
|
const Proto *p = f->l.p;
|
||||||
int currentline = p->linedefined;
|
int currentline = p->linedefined;
|
||||||
Table *t = luaH_new(L); /* new table to store active lines */
|
Table *t = luaH_new(L); /* new table to store active lines */
|
||||||
sethvalue2s(L, L->top, t); /* push it on stack */
|
sethvalue2s(L, L->top.p, t); /* push it on stack */
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
|
if (p->lineinfo != NULL) { /* proto with debug information? */
|
||||||
for (i = 0; i < p->sizelineinfo; i++) { /* for all instructions */
|
int i;
|
||||||
currentline = nextline(p, currentline, i); /* get its line */
|
TValue v;
|
||||||
luaH_setint(L, t, currentline, &v); /* table[line] = true */
|
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
|
||||||
|
if (!(isvararg(p))) /* regular function? */
|
||||||
|
i = 0; /* consider all instructions */
|
||||||
|
else { /* vararg function */
|
||||||
|
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
|
||||||
|
currentline = nextline(p, currentline, 0);
|
||||||
|
i = 1; /* skip first instruction (OP_VARARGPREP) */
|
||||||
|
}
|
||||||
|
for (; i < p->sizelineinfo; i++) { /* for each instruction */
|
||||||
|
currentline = nextline(p, currentline, i); /* get its line */
|
||||||
|
luaH_setint(L, t, currentline, &v); /* table[line] = true */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
|
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
|
||||||
if (ci == NULL) /* no 'ci'? */
|
/* calling function is a known function? */
|
||||||
return NULL; /* no info */
|
if (ci != NULL && !(ci->callstatus & CIST_TAIL))
|
||||||
else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */
|
return funcnamefromcall(L, ci->previous, name);
|
||||||
*name = "__gc";
|
|
||||||
return "metamethod"; /* report it as such */
|
|
||||||
}
|
|
||||||
/* calling function is a known Lua function? */
|
|
||||||
else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
|
|
||||||
return funcnamefromcode(L, ci->previous, name);
|
|
||||||
else return NULL; /* no way to find a name */
|
else return NULL; /* no way to find a name */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,18 +343,26 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
|||||||
}
|
}
|
||||||
case 'u': {
|
case 'u': {
|
||||||
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
|
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
|
||||||
if (noLuaClosure(f)) {
|
if (!LuaClosure(f)) {
|
||||||
ar->isvararg = 1;
|
ar->isvararg = 1;
|
||||||
ar->nparams = 0;
|
ar->nparams = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ar->isvararg = f->l.p->is_vararg;
|
ar->isvararg = (isvararg(f->l.p)) ? 1 : 0;
|
||||||
ar->nparams = f->l.p->numparams;
|
ar->nparams = f->l.p->numparams;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 't': {
|
case 't': {
|
||||||
ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
|
if (ci != NULL) {
|
||||||
|
ar->istailcall = !!(ci->callstatus & CIST_TAIL);
|
||||||
|
ar->extraargs =
|
||||||
|
cast_uchar((ci->callstatus & MAX_CCMT) >> CIST_CCMT);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ar->istailcall = 0;
|
||||||
|
ar->extraargs = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'n': {
|
case 'n': {
|
||||||
@@ -361,11 +374,11 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'r': {
|
case 'r': {
|
||||||
if (ci == NULL || !(ci->callstatus & CIST_TRAN))
|
if (ci == NULL || !(ci->callstatus & CIST_HOOKED))
|
||||||
ar->ftransfer = ar->ntransfer = 0;
|
ar->ftransfer = ar->ntransfer = 0;
|
||||||
else {
|
else {
|
||||||
ar->ftransfer = ci->u2.transferinfo.ftransfer;
|
ar->ftransfer = L->transferinfo.ftransfer;
|
||||||
ar->ntransfer = ci->u2.transferinfo.ntransfer;
|
ar->ntransfer = L->transferinfo.ntransfer;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -387,20 +400,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
|||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
if (*what == '>') {
|
if (*what == '>') {
|
||||||
ci = NULL;
|
ci = NULL;
|
||||||
func = s2v(L->top - 1);
|
func = s2v(L->top.p - 1);
|
||||||
api_check(L, ttisfunction(func), "function expected");
|
api_check(L, ttisfunction(func), "function expected");
|
||||||
what++; /* skip the '>' */
|
what++; /* skip the '>' */
|
||||||
L->top--; /* pop function */
|
L->top.p--; /* pop function */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ci = ar->i_ci;
|
ci = ar->i_ci;
|
||||||
func = s2v(ci->func);
|
func = s2v(ci->func.p);
|
||||||
lua_assert(ttisfunction(func));
|
lua_assert(ttisfunction(func));
|
||||||
}
|
}
|
||||||
cl = ttisclosure(func) ? clvalue(func) : NULL;
|
cl = ttisclosure(func) ? clvalue(func) : NULL;
|
||||||
status = auxgetinfo(L, what, ar, cl, ci);
|
status = auxgetinfo(L, what, ar, cl, ci);
|
||||||
if (strchr(what, 'f')) {
|
if (strchr(what, 'f')) {
|
||||||
setobj2s(L, L->top, func);
|
setobj2s(L, L->top.p, func);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
}
|
}
|
||||||
if (strchr(what, 'L'))
|
if (strchr(what, 'L'))
|
||||||
@@ -416,40 +429,6 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
|||||||
** =======================================================
|
** =======================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const char *getobjname (const Proto *p, int lastpc, int reg,
|
|
||||||
const char **name);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Find a "name" for the constant 'c'.
|
|
||||||
*/
|
|
||||||
static void kname (const Proto *p, int c, const char **name) {
|
|
||||||
TValue *kvalue = &p->k[c];
|
|
||||||
*name = (ttisstring(kvalue)) ? svalue(kvalue) : "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Find a "name" for the register 'c'.
|
|
||||||
*/
|
|
||||||
static void rname (const Proto *p, int pc, int c, const char **name) {
|
|
||||||
const char *what = getobjname(p, pc, c, name); /* search for 'c' */
|
|
||||||
if (!(what && *what == 'c')) /* did not find a constant name? */
|
|
||||||
*name = "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Find a "name" for a 'C' value in an RK instruction.
|
|
||||||
*/
|
|
||||||
static void rkname (const Proto *p, int pc, Instruction i, const char **name) {
|
|
||||||
int c = GETARG_C(i); /* key index */
|
|
||||||
if (GETARG_k(i)) /* is 'c' a constant? */
|
|
||||||
kname(p, c, name);
|
|
||||||
else /* 'c' is a register */
|
|
||||||
rname(p, pc, c, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int filterpc (int pc, int jmptarget) {
|
static int filterpc (int pc, int jmptarget) {
|
||||||
if (pc < jmptarget) /* is code conditional (inside a jump)? */
|
if (pc < jmptarget) /* is code conditional (inside a jump)? */
|
||||||
@@ -508,28 +487,29 @@ static int findsetreg (const Proto *p, int lastpc, int reg) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Check whether table being indexed by instruction 'i' is the
|
** Find a "name" for the constant 'c'.
|
||||||
** environment '_ENV'
|
|
||||||
*/
|
*/
|
||||||
static const char *gxf (const Proto *p, int pc, Instruction i, int isup) {
|
static const char *kname (const Proto *p, int index, const char **name) {
|
||||||
int t = GETARG_B(i); /* table index */
|
TValue *kvalue = &p->k[index];
|
||||||
const char *name; /* name of indexed variable */
|
if (ttisstring(kvalue)) {
|
||||||
if (isup) /* is an upvalue? */
|
*name = getstr(tsvalue(kvalue));
|
||||||
name = upvalname(p, t);
|
return "constant";
|
||||||
else
|
}
|
||||||
getobjname(p, pc, t, &name);
|
else {
|
||||||
return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
|
*name = "?";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char *getobjname (const Proto *p, int lastpc, int reg,
|
static const char *basicgetobjname (const Proto *p, int *ppc, int reg,
|
||||||
const char **name) {
|
const char **name) {
|
||||||
int pc;
|
int pc = *ppc;
|
||||||
*name = luaF_getlocalname(p, reg + 1, lastpc);
|
*name = luaF_getlocalname(p, reg + 1, pc);
|
||||||
if (*name) /* is a local? */
|
if (*name) /* is a local? */
|
||||||
return "local";
|
return strlocal;
|
||||||
/* else try symbolic execution */
|
/* else try symbolic execution */
|
||||||
pc = findsetreg(p, lastpc, reg);
|
*ppc = pc = findsetreg(p, pc, reg);
|
||||||
if (pc != -1) { /* could find instruction? */
|
if (pc != -1) { /* could find instruction? */
|
||||||
Instruction i = p->code[pc];
|
Instruction i = p->code[pc];
|
||||||
OpCode op = GET_OPCODE(i);
|
OpCode op = GET_OPCODE(i);
|
||||||
@@ -537,18 +517,73 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
|
|||||||
case OP_MOVE: {
|
case OP_MOVE: {
|
||||||
int b = GETARG_B(i); /* move from 'b' to 'a' */
|
int b = GETARG_B(i); /* move from 'b' to 'a' */
|
||||||
if (b < GETARG_A(i))
|
if (b < GETARG_A(i))
|
||||||
return getobjname(p, pc, b, name); /* get name for 'b' */
|
return basicgetobjname(p, ppc, b, name); /* get name for 'b' */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OP_GETUPVAL: {
|
||||||
|
*name = upvalname(p, GETARG_B(i));
|
||||||
|
return strupval;
|
||||||
|
}
|
||||||
|
case OP_LOADK: return kname(p, GETARG_Bx(i), name);
|
||||||
|
case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name);
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL; /* could not find reasonable name */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Find a "name" for the register 'c'.
|
||||||
|
*/
|
||||||
|
static void rname (const Proto *p, int pc, int c, const char **name) {
|
||||||
|
const char *what = basicgetobjname(p, &pc, c, name); /* search for 'c' */
|
||||||
|
if (!(what && *what == 'c')) /* did not find a constant name? */
|
||||||
|
*name = "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Check whether table being indexed by instruction 'i' is the
|
||||||
|
** environment '_ENV'
|
||||||
|
*/
|
||||||
|
static const char *isEnv (const Proto *p, int pc, Instruction i, int isup) {
|
||||||
|
int t = GETARG_B(i); /* table index */
|
||||||
|
const char *name; /* name of indexed variable */
|
||||||
|
if (isup) /* is 't' an upvalue? */
|
||||||
|
name = upvalname(p, t);
|
||||||
|
else { /* 't' is a register */
|
||||||
|
const char *what = basicgetobjname(p, &pc, t, &name);
|
||||||
|
/* 'name' must be the name of a local variable (at the current
|
||||||
|
level or an upvalue) */
|
||||||
|
if (what != strlocal && what != strupval)
|
||||||
|
name = NULL; /* cannot be the variable _ENV */
|
||||||
|
}
|
||||||
|
return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Extend 'basicgetobjname' to handle table accesses
|
||||||
|
*/
|
||||||
|
static const char *getobjname (const Proto *p, int lastpc, int reg,
|
||||||
|
const char **name) {
|
||||||
|
const char *kind = basicgetobjname(p, &lastpc, reg, name);
|
||||||
|
if (kind != NULL)
|
||||||
|
return kind;
|
||||||
|
else if (lastpc != -1) { /* could find instruction? */
|
||||||
|
Instruction i = p->code[lastpc];
|
||||||
|
OpCode op = GET_OPCODE(i);
|
||||||
|
switch (op) {
|
||||||
case OP_GETTABUP: {
|
case OP_GETTABUP: {
|
||||||
int k = GETARG_C(i); /* key index */
|
int k = GETARG_C(i); /* key index */
|
||||||
kname(p, k, name);
|
kname(p, k, name);
|
||||||
return gxf(p, pc, i, 1);
|
return isEnv(p, lastpc, i, 1);
|
||||||
}
|
}
|
||||||
case OP_GETTABLE: {
|
case OP_GETTABLE: {
|
||||||
int k = GETARG_C(i); /* key index */
|
int k = GETARG_C(i); /* key index */
|
||||||
rname(p, pc, k, name);
|
rname(p, lastpc, k, name);
|
||||||
return gxf(p, pc, i, 0);
|
return isEnv(p, lastpc, i, 0);
|
||||||
}
|
}
|
||||||
case OP_GETI: {
|
case OP_GETI: {
|
||||||
*name = "integer index";
|
*name = "integer index";
|
||||||
@@ -557,24 +592,11 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
|
|||||||
case OP_GETFIELD: {
|
case OP_GETFIELD: {
|
||||||
int k = GETARG_C(i); /* key index */
|
int k = GETARG_C(i); /* key index */
|
||||||
kname(p, k, name);
|
kname(p, k, name);
|
||||||
return gxf(p, pc, i, 0);
|
return isEnv(p, lastpc, i, 0);
|
||||||
}
|
|
||||||
case OP_GETUPVAL: {
|
|
||||||
*name = upvalname(p, GETARG_B(i));
|
|
||||||
return "upvalue";
|
|
||||||
}
|
|
||||||
case OP_LOADK:
|
|
||||||
case OP_LOADKX: {
|
|
||||||
int b = (op == OP_LOADK) ? GETARG_Bx(i)
|
|
||||||
: GETARG_Ax(p->code[pc + 1]);
|
|
||||||
if (ttisstring(&p->k[b])) {
|
|
||||||
*name = svalue(&p->k[b]);
|
|
||||||
return "constant";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case OP_SELF: {
|
case OP_SELF: {
|
||||||
rkname(p, pc, i, name);
|
int k = GETARG_C(i); /* key index */
|
||||||
|
kname(p, k, name);
|
||||||
return "method";
|
return "method";
|
||||||
}
|
}
|
||||||
default: break; /* go through to return NULL */
|
default: break; /* go through to return NULL */
|
||||||
@@ -590,16 +612,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
|
|||||||
** Returns what the name is (e.g., "for iterator", "method",
|
** Returns what the name is (e.g., "for iterator", "method",
|
||||||
** "metamethod") and sets '*name' to point to the name.
|
** "metamethod") and sets '*name' to point to the name.
|
||||||
*/
|
*/
|
||||||
static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
|
static const char *funcnamefromcode (lua_State *L, const Proto *p,
|
||||||
const char **name) {
|
int pc, const char **name) {
|
||||||
TMS tm = (TMS)0; /* (initial value avoids warnings) */
|
TMS tm = (TMS)0; /* (initial value avoids warnings) */
|
||||||
const Proto *p = ci_func(ci)->p; /* calling function */
|
|
||||||
int pc = currentpc(ci); /* calling instruction index */
|
|
||||||
Instruction i = p->code[pc]; /* calling instruction */
|
Instruction i = p->code[pc]; /* calling instruction */
|
||||||
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
|
|
||||||
*name = "?";
|
|
||||||
return "hook";
|
|
||||||
}
|
|
||||||
switch (GET_OPCODE(i)) {
|
switch (GET_OPCODE(i)) {
|
||||||
case OP_CALL:
|
case OP_CALL:
|
||||||
case OP_TAILCALL:
|
case OP_TAILCALL:
|
||||||
@@ -632,27 +648,48 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
|
|||||||
default:
|
default:
|
||||||
return NULL; /* cannot find a reasonable name */
|
return NULL; /* cannot find a reasonable name */
|
||||||
}
|
}
|
||||||
*name = getstr(G(L)->tmname[tm]) + 2;
|
*name = getshrstr(G(L)->tmname[tm]) + 2;
|
||||||
return "metamethod";
|
return "metamethod";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Try to find a name for a function based on how it was called.
|
||||||
|
*/
|
||||||
|
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
|
||||||
|
const char **name) {
|
||||||
|
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
|
||||||
|
*name = "?";
|
||||||
|
return "hook";
|
||||||
|
}
|
||||||
|
else if (ci->callstatus & CIST_FIN) { /* was it called as a finalizer? */
|
||||||
|
*name = "__gc";
|
||||||
|
return "metamethod"; /* report it as such */
|
||||||
|
}
|
||||||
|
else if (isLua(ci))
|
||||||
|
return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* }====================================================== */
|
/* }====================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Check whether pointer 'o' points to some value in the stack
|
** Check whether pointer 'o' points to some value in the stack frame of
|
||||||
** frame of the current function. Because 'o' may not point to a
|
** the current function and, if so, returns its index. Because 'o' may
|
||||||
** value in this stack, we cannot compare it with the region
|
** not point to a value in this stack, we cannot compare it with the
|
||||||
** boundaries (undefined behaviour in ISO C).
|
** region boundaries (undefined behavior in ISO C).
|
||||||
*/
|
*/
|
||||||
static int isinstack (CallInfo *ci, const TValue *o) {
|
static int instack (CallInfo *ci, const TValue *o) {
|
||||||
StkId pos;
|
int pos;
|
||||||
for (pos = ci->func + 1; pos < ci->top; pos++) {
|
StkId base = ci->func.p + 1;
|
||||||
if (o == s2v(pos))
|
for (pos = 0; base + pos < ci->top.p; pos++) {
|
||||||
return 1;
|
if (o == s2v(base + pos))
|
||||||
|
return pos;
|
||||||
}
|
}
|
||||||
return 0; /* not found */
|
return -1; /* not found */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -666,45 +703,73 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
|
|||||||
LClosure *c = ci_func(ci);
|
LClosure *c = ci_func(ci);
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < c->nupvalues; i++) {
|
for (i = 0; i < c->nupvalues; i++) {
|
||||||
if (c->upvals[i]->v == o) {
|
if (c->upvals[i]->v.p == o) {
|
||||||
*name = upvalname(c->p, i);
|
*name = upvalname(c->p, i);
|
||||||
return "upvalue";
|
return strupval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *formatvarinfo (lua_State *L, const char *kind,
|
||||||
|
const char *name) {
|
||||||
|
if (kind == NULL)
|
||||||
|
return ""; /* no information */
|
||||||
|
else
|
||||||
|
return luaO_pushfstring(L, " (%s '%s')", kind, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Build a string with a "description" for the value 'o', such as
|
||||||
|
** "variable 'x'" or "upvalue 'y'".
|
||||||
|
*/
|
||||||
static const char *varinfo (lua_State *L, const TValue *o) {
|
static const char *varinfo (lua_State *L, const TValue *o) {
|
||||||
const char *name = NULL; /* to avoid warnings */
|
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
|
const char *name = NULL; /* to avoid warnings */
|
||||||
const char *kind = NULL;
|
const char *kind = NULL;
|
||||||
if (isLua(ci)) {
|
if (isLua(ci)) {
|
||||||
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
|
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
|
||||||
if (!kind && isinstack(ci, o)) /* no? try a register */
|
if (!kind) { /* not an upvalue? */
|
||||||
kind = getobjname(ci_func(ci)->p, currentpc(ci),
|
int reg = instack(ci, o); /* try a register */
|
||||||
cast_int(cast(StkId, o) - (ci->func + 1)), &name);
|
if (reg >= 0) /* is 'o' a register? */
|
||||||
|
kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : "";
|
return formatvarinfo(L, kind, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
|
/*
|
||||||
|
** Raise a type error
|
||||||
|
*/
|
||||||
|
static l_noret typeerror (lua_State *L, const TValue *o, const char *op,
|
||||||
|
const char *extra) {
|
||||||
const char *t = luaT_objtypename(L, o);
|
const char *t = luaT_objtypename(L, o);
|
||||||
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
|
luaG_runerror(L, "attempt to %s a %s value%s", op, t, extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Raise a type error with "standard" information about the faulty
|
||||||
|
** object 'o' (using 'varinfo').
|
||||||
|
*/
|
||||||
|
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
|
||||||
|
typeerror(L, o, op, varinfo(L, o));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Raise an error for calling a non-callable object. Try to find a name
|
||||||
|
** for the object based on how it was called ('funcnamefromcall'); if it
|
||||||
|
** cannot get a name there, try 'varinfo'.
|
||||||
|
*/
|
||||||
l_noret luaG_callerror (lua_State *L, const TValue *o) {
|
l_noret luaG_callerror (lua_State *L, const TValue *o) {
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
const char *name = NULL; /* to avoid warnings */
|
const char *name = NULL; /* to avoid warnings */
|
||||||
const char *what = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL;
|
const char *kind = funcnamefromcall(L, ci, &name);
|
||||||
if (what != NULL) {
|
const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o);
|
||||||
const char *t = luaT_objtypename(L, o);
|
typeerror(L, o, "call", extra);
|
||||||
luaG_runerror(L, "%s '%s' is not callable (a %s value)", what, name, t);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
luaG_typeerror(L, o, "call");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -749,16 +814,26 @@ l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
l_noret luaG_errnnil (lua_State *L, LClosure *cl, int k) {
|
||||||
|
const char *globalname = "?"; /* default name if k == 0 */
|
||||||
|
if (k > 0)
|
||||||
|
kname(cl->p, k - 1, &globalname);
|
||||||
|
luaG_runerror(L, "global '%s' already defined", globalname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* add src:line information to 'msg' */
|
/* add src:line information to 'msg' */
|
||||||
const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
|
const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
|
||||||
int line) {
|
int line) {
|
||||||
char buff[LUA_IDSIZE];
|
if (src == NULL) /* no debug information? */
|
||||||
if (src)
|
return luaO_pushfstring(L, "?:?: %s", msg);
|
||||||
luaO_chunkid(buff, getstr(src), tsslen(src));
|
else {
|
||||||
else { /* no source available; use "?" instead */
|
char buff[LUA_IDSIZE];
|
||||||
buff[0] = '?'; buff[1] = '\0';
|
size_t idlen;
|
||||||
|
const char *id = getlstr(src, idlen);
|
||||||
|
luaO_chunkid(buff, id, idlen);
|
||||||
|
return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
|
||||||
}
|
}
|
||||||
return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -766,10 +841,14 @@ l_noret luaG_errormsg (lua_State *L) {
|
|||||||
if (L->errfunc != 0) { /* is there an error handling function? */
|
if (L->errfunc != 0) { /* is there an error handling function? */
|
||||||
StkId errfunc = restorestack(L, L->errfunc);
|
StkId errfunc = restorestack(L, L->errfunc);
|
||||||
lua_assert(ttisfunction(s2v(errfunc)));
|
lua_assert(ttisfunction(s2v(errfunc)));
|
||||||
setobjs2s(L, L->top, L->top - 1); /* move argument */
|
setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
|
||||||
setobjs2s(L, L->top - 1, errfunc); /* push function */
|
setobjs2s(L, L->top.p - 1, errfunc); /* push function */
|
||||||
L->top++; /* assume EXTRA_STACK */
|
L->top.p++; /* assume EXTRA_STACK */
|
||||||
luaD_callnoyield(L, L->top - 2, 1); /* call it */
|
luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
|
||||||
|
}
|
||||||
|
if (ttisnil(s2v(L->top.p - 1))) { /* error object is nil? */
|
||||||
|
/* change it to a proper message */
|
||||||
|
setsvalue2s(L, L->top.p - 1, luaS_newliteral(L, "<no error object>"));
|
||||||
}
|
}
|
||||||
luaD_throw(L, LUA_ERRRUN);
|
luaD_throw(L, LUA_ERRRUN);
|
||||||
}
|
}
|
||||||
@@ -780,11 +859,13 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
|
|||||||
const char *msg;
|
const char *msg;
|
||||||
va_list argp;
|
va_list argp;
|
||||||
luaC_checkGC(L); /* error message uses memory */
|
luaC_checkGC(L); /* error message uses memory */
|
||||||
va_start(argp, fmt);
|
pushvfstring(L, argp, fmt, msg);
|
||||||
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
|
if (isLua(ci)) { /* Lua function? */
|
||||||
va_end(argp);
|
/* add source:line information */
|
||||||
if (isLua(ci)) /* if Lua function, add source:line information */
|
|
||||||
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
|
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
|
||||||
|
setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
|
||||||
|
L->top.p--;
|
||||||
|
}
|
||||||
luaG_errormsg(L);
|
luaG_errormsg(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,7 +882,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
|
|||||||
if (p->lineinfo == NULL) /* no debug information? */
|
if (p->lineinfo == NULL) /* no debug information? */
|
||||||
return 0;
|
return 0;
|
||||||
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
|
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
|
||||||
int delta = 0; /* line diference */
|
int delta = 0; /* line difference */
|
||||||
int pc = oldpc;
|
int pc = oldpc;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int lineinfo = p->lineinfo[++pc];
|
int lineinfo = p->lineinfo[++pc];
|
||||||
@@ -818,6 +899,28 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Traces Lua calls. If code is running the first instruction of a function,
|
||||||
|
** and function is not vararg, and it is not coming from an yield,
|
||||||
|
** calls 'luaD_hookcall'. (Vararg functions will call 'luaD_hookcall'
|
||||||
|
** after adjusting its variable arguments; otherwise, they could call
|
||||||
|
** a line/count hook before the call hook. Functions coming from
|
||||||
|
** an yield already called 'luaD_hookcall' before yielding.)
|
||||||
|
*/
|
||||||
|
int luaG_tracecall (lua_State *L) {
|
||||||
|
CallInfo *ci = L->ci;
|
||||||
|
Proto *p = ci_func(ci)->p;
|
||||||
|
ci->u.l.trap = 1; /* ensure hooks will be checked */
|
||||||
|
if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */
|
||||||
|
if (isvararg(p))
|
||||||
|
return 0; /* hooks will start at VARARGPREP instruction */
|
||||||
|
else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yielded? */
|
||||||
|
luaD_hookcall(L, ci); /* check 'call' hook */
|
||||||
|
}
|
||||||
|
return 1; /* keep 'trap' on */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Traces the execution of a Lua function. Called before the execution
|
** Traces the execution of a Lua function. Called before the execution
|
||||||
** of each opcode, when debug is on. 'L->oldpc' stores the last
|
** of each opcode, when debug is on. 'L->oldpc' stores the last
|
||||||
@@ -828,11 +931,11 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
|
|||||||
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
|
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
|
||||||
** at most causes an extra call to a line hook.)
|
** at most causes an extra call to a line hook.)
|
||||||
** This function is not "Protected" when called, so it should correct
|
** This function is not "Protected" when called, so it should correct
|
||||||
** 'L->top' before calling anything that can run the GC.
|
** 'L->top.p' before calling anything that can run the GC.
|
||||||
*/
|
*/
|
||||||
int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
lu_byte mask = L->hookmask;
|
lu_byte mask = cast_byte(L->hookmask);
|
||||||
const Proto *p = ci_func(ci)->p;
|
const Proto *p = ci_func(ci)->p;
|
||||||
int counthook;
|
int counthook;
|
||||||
if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */
|
if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */
|
||||||
@@ -841,17 +944,17 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
|||||||
}
|
}
|
||||||
pc++; /* reference is always next instruction */
|
pc++; /* reference is always next instruction */
|
||||||
ci->u.l.savedpc = pc; /* save 'pc' */
|
ci->u.l.savedpc = pc; /* save 'pc' */
|
||||||
counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
|
counthook = (mask & LUA_MASKCOUNT) && (--L->hookcount == 0);
|
||||||
if (counthook)
|
if (counthook)
|
||||||
resethookcount(L); /* reset count */
|
resethookcount(L); /* reset count */
|
||||||
else if (!(mask & LUA_MASKLINE))
|
else if (!(mask & LUA_MASKLINE))
|
||||||
return 1; /* no line hook and count != 0; nothing to be done now */
|
return 1; /* no line hook and count != 0; nothing to be done now */
|
||||||
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
|
if (ci->callstatus & CIST_HOOKYIELD) { /* hook yielded last time? */
|
||||||
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
|
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
|
||||||
return 1; /* do not call hook again (VM yielded, so it did not move) */
|
return 1; /* do not call hook again (VM yielded, so it did not move) */
|
||||||
}
|
}
|
||||||
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
|
if (!luaP_isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
|
||||||
L->top = ci->top; /* correct top */
|
L->top.p = ci->top.p; /* correct top */
|
||||||
if (counthook)
|
if (counthook)
|
||||||
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
|
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
|
||||||
if (mask & LUA_MASKLINE) {
|
if (mask & LUA_MASKLINE) {
|
||||||
@@ -868,7 +971,6 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
|||||||
if (L->status == LUA_YIELD) { /* did hook yield? */
|
if (L->status == LUA_YIELD) { /* did hook yield? */
|
||||||
if (counthook)
|
if (counthook)
|
||||||
L->hookcount = 1; /* undo decrement to zero */
|
L->hookcount = 1; /* undo decrement to zero */
|
||||||
ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
|
|
||||||
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
|
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
|
||||||
luaD_throw(L, LUA_YIELD);
|
luaD_throw(L, LUA_YIELD);
|
||||||
}
|
}
|
||||||
+3
-1
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/* Active Lua function (given call info) */
|
/* Active Lua function (given call info) */
|
||||||
#define ci_func(ci) (clLvalue(s2v((ci)->func)))
|
#define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
|
||||||
|
|
||||||
|
|
||||||
#define resethookcount(L) (L->hookcount = L->basehookcount)
|
#define resethookcount(L) (L->hookcount = L->basehookcount)
|
||||||
@@ -53,11 +53,13 @@ LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
|
|||||||
const TValue *p2);
|
const TValue *p2);
|
||||||
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
|
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
|
||||||
const TValue *p2);
|
const TValue *p2);
|
||||||
|
LUAI_FUNC l_noret luaG_errnnil (lua_State *L, LClosure *cl, int k);
|
||||||
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
|
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
|
||||||
LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
|
LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
|
||||||
TString *src, int line);
|
TString *src, int line);
|
||||||
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
|
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
|
||||||
LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
|
LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
|
||||||
|
LUAI_FUNC int luaG_tracecall (lua_State *L);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+478
-277
File diff suppressed because it is too large
Load Diff
+38
-18
@@ -8,6 +8,7 @@
|
|||||||
#define ldo_h
|
#define ldo_h
|
||||||
|
|
||||||
|
|
||||||
|
#include "llimits.h"
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
#include "lzio.h"
|
#include "lzio.h"
|
||||||
@@ -22,58 +23,77 @@
|
|||||||
** 'condmovestack' is used in heavy tests to force a stack reallocation
|
** 'condmovestack' is used in heavy tests to force a stack reallocation
|
||||||
** at every check.
|
** at every check.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if !defined(HARDSTACKTESTS)
|
||||||
|
#define condmovestack(L,pre,pos) ((void)0)
|
||||||
|
#else
|
||||||
|
/* realloc stack keeping its size */
|
||||||
|
#define condmovestack(L,pre,pos) \
|
||||||
|
{ int sz_ = stacksize(L); pre; luaD_reallocstack((L), sz_, 0); pos; }
|
||||||
|
#endif
|
||||||
|
|
||||||
#define luaD_checkstackaux(L,n,pre,pos) \
|
#define luaD_checkstackaux(L,n,pre,pos) \
|
||||||
if (l_unlikely(L->stack_last - L->top <= (n))) \
|
if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
|
||||||
{ pre; luaD_growstack(L, n, 1); pos; } \
|
{ pre; luaD_growstack(L, n, 1); pos; } \
|
||||||
else { condmovestack(L,pre,pos); }
|
else { condmovestack(L,pre,pos); }
|
||||||
|
|
||||||
/* In general, 'pre'/'pos' are empty (nothing to save) */
|
/* In general, 'pre'/'pos' are empty (nothing to save) */
|
||||||
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
|
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
|
#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
|
||||||
#define restorestack(L,n) ((StkId)((char *)L->stack + (n)))
|
#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
|
||||||
|
|
||||||
|
|
||||||
/* macro to check stack size, preserving 'p' */
|
/* macro to check stack size, preserving 'p' */
|
||||||
#define checkstackGCp(L,n,p) \
|
#define checkstackp(L,n,p) \
|
||||||
luaD_checkstackaux(L, n, \
|
luaD_checkstackaux(L, n, \
|
||||||
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
|
ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
|
||||||
luaC_checkGC(L), /* stack grow uses memory */ \
|
|
||||||
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
|
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
|
||||||
|
|
||||||
|
|
||||||
/* macro to check stack size and GC */
|
/*
|
||||||
#define checkstackGC(L,fsize) \
|
** Maximum depth for nested C calls, syntactical nested non-terminals,
|
||||||
luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0)
|
** and other features implemented through recursion in C. (Value must
|
||||||
|
** fit in a 16-bit unsigned integer. It must also be compatible with
|
||||||
|
** the size of the C stack.)
|
||||||
|
*/
|
||||||
|
#if !defined(LUAI_MAXCCALLS)
|
||||||
|
#define LUAI_MAXCCALLS 200
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* type of protected functions, to be ran by 'runprotected' */
|
/* type of protected functions, to be ran by 'runprotected' */
|
||||||
typedef void (*Pfunc) (lua_State *L, void *ud);
|
typedef void (*Pfunc) (lua_State *L, void *ud);
|
||||||
|
|
||||||
LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
|
LUAI_FUNC l_noret luaD_errerr (lua_State *L);
|
||||||
LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
|
LUAI_FUNC void luaD_seterrorobj (lua_State *L, TStatus errcode, StkId oldtop);
|
||||||
|
LUAI_FUNC TStatus luaD_protectedparser (lua_State *L, ZIO *z,
|
||||||
|
const char *name,
|
||||||
const char *mode);
|
const char *mode);
|
||||||
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
|
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
|
||||||
int fTransfer, int nTransfer);
|
int fTransfer, int nTransfer);
|
||||||
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
|
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
|
||||||
LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n);
|
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
|
||||||
|
int narg1, int delta);
|
||||||
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
|
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
|
||||||
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
|
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
|
||||||
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
|
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
|
||||||
LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func);
|
LUAI_FUNC TStatus luaD_closeprotected (lua_State *L, ptrdiff_t level,
|
||||||
LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
|
TStatus status);
|
||||||
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
LUAI_FUNC TStatus luaD_pcall (lua_State *L, Pfunc func, void *u,
|
||||||
ptrdiff_t oldtop, ptrdiff_t ef);
|
ptrdiff_t oldtop, ptrdiff_t ef);
|
||||||
LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres);
|
LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres);
|
||||||
LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror);
|
LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror);
|
||||||
LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
|
LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
|
||||||
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
|
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
|
||||||
LUAI_FUNC void luaD_inctop (lua_State *L);
|
LUAI_FUNC void luaD_inctop (lua_State *L);
|
||||||
|
LUAI_FUNC int luaD_checkminstack (lua_State *L);
|
||||||
|
|
||||||
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
|
LUAI_FUNC l_noret luaD_throw (lua_State *L, TStatus errcode);
|
||||||
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
|
LUAI_FUNC l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode);
|
||||||
|
LUAI_FUNC TStatus luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Vendored
+307
@@ -0,0 +1,307 @@
|
|||||||
|
/*
|
||||||
|
** $Id: ldump.c $
|
||||||
|
** save precompiled Lua chunks
|
||||||
|
** See Copyright Notice in lua.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ldump_c
|
||||||
|
#define LUA_CORE
|
||||||
|
|
||||||
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "lapi.h"
|
||||||
|
#include "lgc.h"
|
||||||
|
#include "lobject.h"
|
||||||
|
#include "lstate.h"
|
||||||
|
#include "ltable.h"
|
||||||
|
#include "lundump.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
lua_State *L;
|
||||||
|
lua_Writer writer;
|
||||||
|
void *data;
|
||||||
|
size_t offset; /* current position relative to beginning of dump */
|
||||||
|
int strip;
|
||||||
|
int status;
|
||||||
|
Table *h; /* table to track saved strings */
|
||||||
|
lua_Unsigned nstr; /* counter for counting saved strings */
|
||||||
|
} DumpState;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** All high-level dumps go through dumpVector; you can change it to
|
||||||
|
** change the endianness of the result
|
||||||
|
*/
|
||||||
|
#define dumpVector(D,v,n) dumpBlock(D,v,(n)*sizeof((v)[0]))
|
||||||
|
|
||||||
|
#define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Dump the block of memory pointed by 'b' with given 'size'.
|
||||||
|
** 'b' should not be NULL, except for the last call signaling the end
|
||||||
|
** of the dump.
|
||||||
|
*/
|
||||||
|
static void dumpBlock (DumpState *D, const void *b, size_t size) {
|
||||||
|
if (D->status == 0) { /* do not write anything after an error */
|
||||||
|
lua_unlock(D->L);
|
||||||
|
D->status = (*D->writer)(D->L, b, size, D->data);
|
||||||
|
lua_lock(D->L);
|
||||||
|
D->offset += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Dump enough zeros to ensure that current position is a multiple of
|
||||||
|
** 'align'.
|
||||||
|
*/
|
||||||
|
static void dumpAlign (DumpState *D, unsigned align) {
|
||||||
|
unsigned padding = align - cast_uint(D->offset % align);
|
||||||
|
if (padding < align) { /* padding == align means no padding */
|
||||||
|
static lua_Integer paddingContent = 0;
|
||||||
|
lua_assert(align <= sizeof(lua_Integer));
|
||||||
|
dumpBlock(D, &paddingContent, padding);
|
||||||
|
}
|
||||||
|
lua_assert(D->offset % align == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define dumpVar(D,x) dumpVector(D,&x,1)
|
||||||
|
|
||||||
|
|
||||||
|
static void dumpByte (DumpState *D, int y) {
|
||||||
|
lu_byte x = (lu_byte)y;
|
||||||
|
dumpVar(D, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** size for 'dumpVarint' buffer: each byte can store up to 7 bits.
|
||||||
|
** (The "+6" rounds up the division.)
|
||||||
|
*/
|
||||||
|
#define DIBS ((l_numbits(lua_Unsigned) + 6) / 7)
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Dumps an unsigned integer using the MSB Varint encoding
|
||||||
|
*/
|
||||||
|
static void dumpVarint (DumpState *D, lua_Unsigned x) {
|
||||||
|
lu_byte buff[DIBS];
|
||||||
|
unsigned n = 1;
|
||||||
|
buff[DIBS - 1] = x & 0x7f; /* fill least-significant byte */
|
||||||
|
while ((x >>= 7) != 0) /* fill other bytes in reverse order */
|
||||||
|
buff[DIBS - (++n)] = cast_byte((x & 0x7f) | 0x80);
|
||||||
|
dumpVector(D, buff + DIBS - n, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dumpSize (DumpState *D, size_t sz) {
|
||||||
|
dumpVarint(D, cast(lua_Unsigned, sz));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dumpInt (DumpState *D, int x) {
|
||||||
|
lua_assert(x >= 0);
|
||||||
|
dumpVarint(D, cast_uint(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dumpNumber (DumpState *D, lua_Number x) {
|
||||||
|
dumpVar(D, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Signed integers are coded to keep small values small. (Coding -1 as
|
||||||
|
** 0xfff...fff would use too many bytes to save a quite common value.)
|
||||||
|
** A non-negative x is coded as 2x; a negative x is coded as -2x - 1.
|
||||||
|
** (0 => 0; -1 => 1; 1 => 2; -2 => 3; 2 => 4; ...)
|
||||||
|
*/
|
||||||
|
static void dumpInteger (DumpState *D, lua_Integer x) {
|
||||||
|
lua_Unsigned cx = (x >= 0) ? 2u * l_castS2U(x)
|
||||||
|
: (2u * ~l_castS2U(x)) + 1;
|
||||||
|
dumpVarint(D, cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Dump a String. First dump its "size":
|
||||||
|
** size==0 is followed by an index and means "reuse saved string with
|
||||||
|
** that index"; index==0 means NULL.
|
||||||
|
** size>=1 is followed by the string contents with real size==size-1 and
|
||||||
|
** means that string, which will be saved with the next available index.
|
||||||
|
** The real size does not include the ending '\0' (which is not dumped),
|
||||||
|
** so adding 1 to it cannot overflow a size_t.
|
||||||
|
*/
|
||||||
|
static void dumpString (DumpState *D, TString *ts) {
|
||||||
|
if (ts == NULL) {
|
||||||
|
dumpVarint(D, 0); /* will "reuse" NULL */
|
||||||
|
dumpVarint(D, 0); /* special index for NULL */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TValue idx;
|
||||||
|
int tag = luaH_getstr(D->h, ts, &idx);
|
||||||
|
if (!tagisempty(tag)) { /* string already saved? */
|
||||||
|
dumpVarint(D, 0); /* reuse a saved string */
|
||||||
|
dumpVarint(D, l_castS2U(ivalue(&idx))); /* index of saved string */
|
||||||
|
}
|
||||||
|
else { /* must write and save the string */
|
||||||
|
TValue key, value; /* to save the string in the hash */
|
||||||
|
size_t size;
|
||||||
|
const char *s = getlstr(ts, size);
|
||||||
|
dumpSize(D, size + 1);
|
||||||
|
dumpVector(D, s, size + 1); /* include ending '\0' */
|
||||||
|
D->nstr++; /* one more saved string */
|
||||||
|
setsvalue(D->L, &key, ts); /* the string is the key */
|
||||||
|
setivalue(&value, l_castU2S(D->nstr)); /* its index is the value */
|
||||||
|
luaH_set(D->L, D->h, &key, &value); /* h[ts] = nstr */
|
||||||
|
/* integer value does not need barrier */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dumpCode (DumpState *D, const Proto *f) {
|
||||||
|
dumpInt(D, f->sizecode);
|
||||||
|
dumpAlign(D, sizeof(f->code[0]));
|
||||||
|
lua_assert(f->code != NULL);
|
||||||
|
dumpVector(D, f->code, cast_uint(f->sizecode));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dumpFunction (DumpState *D, const Proto *f);
|
||||||
|
|
||||||
|
static void dumpConstants (DumpState *D, const Proto *f) {
|
||||||
|
int i;
|
||||||
|
int n = f->sizek;
|
||||||
|
dumpInt(D, n);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
const TValue *o = &f->k[i];
|
||||||
|
int tt = ttypetag(o);
|
||||||
|
dumpByte(D, tt);
|
||||||
|
switch (tt) {
|
||||||
|
case LUA_VNUMFLT:
|
||||||
|
dumpNumber(D, fltvalue(o));
|
||||||
|
break;
|
||||||
|
case LUA_VNUMINT:
|
||||||
|
dumpInteger(D, ivalue(o));
|
||||||
|
break;
|
||||||
|
case LUA_VSHRSTR:
|
||||||
|
case LUA_VLNGSTR:
|
||||||
|
dumpString(D, tsvalue(o));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lua_assert(tt == LUA_VNIL || tt == LUA_VFALSE || tt == LUA_VTRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dumpProtos (DumpState *D, const Proto *f) {
|
||||||
|
int i;
|
||||||
|
int n = f->sizep;
|
||||||
|
dumpInt(D, n);
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
dumpFunction(D, f->p[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dumpUpvalues (DumpState *D, const Proto *f) {
|
||||||
|
int i, n = f->sizeupvalues;
|
||||||
|
dumpInt(D, n);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
dumpByte(D, f->upvalues[i].instack);
|
||||||
|
dumpByte(D, f->upvalues[i].idx);
|
||||||
|
dumpByte(D, f->upvalues[i].kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dumpDebug (DumpState *D, const Proto *f) {
|
||||||
|
int i, n;
|
||||||
|
n = (D->strip) ? 0 : f->sizelineinfo;
|
||||||
|
dumpInt(D, n);
|
||||||
|
if (f->lineinfo != NULL)
|
||||||
|
dumpVector(D, f->lineinfo, cast_uint(n));
|
||||||
|
n = (D->strip) ? 0 : f->sizeabslineinfo;
|
||||||
|
dumpInt(D, n);
|
||||||
|
if (n > 0) {
|
||||||
|
/* 'abslineinfo' is an array of structures of int's */
|
||||||
|
dumpAlign(D, sizeof(int));
|
||||||
|
dumpVector(D, f->abslineinfo, cast_uint(n));
|
||||||
|
}
|
||||||
|
n = (D->strip) ? 0 : f->sizelocvars;
|
||||||
|
dumpInt(D, n);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
dumpString(D, f->locvars[i].varname);
|
||||||
|
dumpInt(D, f->locvars[i].startpc);
|
||||||
|
dumpInt(D, f->locvars[i].endpc);
|
||||||
|
}
|
||||||
|
n = (D->strip) ? 0 : f->sizeupvalues;
|
||||||
|
dumpInt(D, n);
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
dumpString(D, f->upvalues[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dumpFunction (DumpState *D, const Proto *f) {
|
||||||
|
dumpInt(D, f->linedefined);
|
||||||
|
dumpInt(D, f->lastlinedefined);
|
||||||
|
dumpByte(D, f->numparams);
|
||||||
|
dumpByte(D, f->flag);
|
||||||
|
dumpByte(D, f->maxstacksize);
|
||||||
|
dumpCode(D, f);
|
||||||
|
dumpConstants(D, f);
|
||||||
|
dumpUpvalues(D, f);
|
||||||
|
dumpProtos(D, f);
|
||||||
|
dumpString(D, D->strip ? NULL : f->source);
|
||||||
|
dumpDebug(D, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define dumpNumInfo(D, tvar, value) \
|
||||||
|
{ tvar i = value; dumpByte(D, sizeof(tvar)); dumpVar(D, i); }
|
||||||
|
|
||||||
|
|
||||||
|
static void dumpHeader (DumpState *D) {
|
||||||
|
dumpLiteral(D, LUA_SIGNATURE);
|
||||||
|
dumpByte(D, LUAC_VERSION);
|
||||||
|
dumpByte(D, LUAC_FORMAT);
|
||||||
|
dumpLiteral(D, LUAC_DATA);
|
||||||
|
dumpNumInfo(D, int, LUAC_INT);
|
||||||
|
dumpNumInfo(D, Instruction, LUAC_INST);
|
||||||
|
dumpNumInfo(D, lua_Integer, LUAC_INT);
|
||||||
|
dumpNumInfo(D, lua_Number, LUAC_NUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** dump Lua function as precompiled chunk
|
||||||
|
*/
|
||||||
|
int luaU_dump (lua_State *L, const Proto *f, lua_Writer w, void *data,
|
||||||
|
int strip) {
|
||||||
|
DumpState D;
|
||||||
|
D.h = luaH_new(L); /* aux. table to keep strings already dumped */
|
||||||
|
sethvalue2s(L, L->top.p, D.h); /* anchor it */
|
||||||
|
L->top.p++;
|
||||||
|
D.L = L;
|
||||||
|
D.writer = w;
|
||||||
|
D.offset = 0;
|
||||||
|
D.data = data;
|
||||||
|
D.strip = strip;
|
||||||
|
D.status = 0;
|
||||||
|
D.nstr = 0;
|
||||||
|
dumpHeader(&D);
|
||||||
|
dumpByte(&D, f->sizeupvalues);
|
||||||
|
dumpFunction(&D, f);
|
||||||
|
dumpBlock(&D, NULL, 0); /* signal end of dump */
|
||||||
|
return D.status;
|
||||||
|
}
|
||||||
|
|
||||||
+75
-55
@@ -50,8 +50,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
|
|||||||
for (i = 0; i < cl->nupvalues; i++) {
|
for (i = 0; i < cl->nupvalues; i++) {
|
||||||
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
|
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
|
||||||
UpVal *uv = gco2upv(o);
|
UpVal *uv = gco2upv(o);
|
||||||
uv->v = &uv->u.value; /* make it closed */
|
uv->v.p = &uv->u.value; /* make it closed */
|
||||||
setnilvalue(uv->v);
|
setnilvalue(uv->v.p);
|
||||||
cl->upvals[i] = uv;
|
cl->upvals[i] = uv;
|
||||||
luaC_objbarrier(L, cl, uv);
|
luaC_objbarrier(L, cl, uv);
|
||||||
}
|
}
|
||||||
@@ -62,12 +62,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
|
|||||||
** Create a new upvalue at the given level, and link it to the list of
|
** Create a new upvalue at the given level, and link it to the list of
|
||||||
** open upvalues of 'L' after entry 'prev'.
|
** open upvalues of 'L' after entry 'prev'.
|
||||||
**/
|
**/
|
||||||
static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) {
|
static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
|
||||||
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
|
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
|
||||||
UpVal *uv = gco2upv(o);
|
UpVal *uv = gco2upv(o);
|
||||||
UpVal *next = *prev;
|
UpVal *next = *prev;
|
||||||
uv->v = s2v(level); /* current value lives in the stack */
|
uv->v.p = s2v(level); /* current value lives in the stack */
|
||||||
uv->tbc = tbc;
|
|
||||||
uv->u.open.next = next; /* link it to list of open upvalues */
|
uv->u.open.next = next; /* link it to list of open upvalues */
|
||||||
uv->u.open.previous = prev;
|
uv->u.open.previous = prev;
|
||||||
if (next)
|
if (next)
|
||||||
@@ -96,26 +95,28 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
|
|||||||
pp = &p->u.open.next;
|
pp = &p->u.open.next;
|
||||||
}
|
}
|
||||||
/* not found: create a new upvalue after 'pp' */
|
/* not found: create a new upvalue after 'pp' */
|
||||||
return newupval(L, 0, level, pp);
|
return newupval(L, level, pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Call closing method for object 'obj' with error message 'err'. The
|
** Call closing method for object 'obj' with error object 'err'. The
|
||||||
** boolean 'yy' controls whether the call is yieldable.
|
** boolean 'yy' controls whether the call is yieldable.
|
||||||
** (This function assumes EXTRA_STACK.)
|
** (This function assumes EXTRA_STACK.)
|
||||||
*/
|
*/
|
||||||
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
|
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
|
||||||
StkId top = L->top;
|
StkId top = L->top.p;
|
||||||
|
StkId func = top;
|
||||||
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
|
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
|
||||||
setobj2s(L, top, tm); /* will call metamethod... */
|
setobj2s(L, top++, tm); /* will call metamethod... */
|
||||||
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
|
setobj2s(L, top++, obj); /* with 'self' as the 1st argument */
|
||||||
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
|
if (err != NULL) /* if there was an error... */
|
||||||
L->top = top + 3; /* add function and arguments */
|
setobj2s(L, top++, err); /* then error object will be 2nd argument */
|
||||||
|
L->top.p = top; /* add function and arguments */
|
||||||
if (yy)
|
if (yy)
|
||||||
luaD_call(L, top, 0);
|
luaD_call(L, func, 0);
|
||||||
else
|
else
|
||||||
luaD_callnoyield(L, top, 0);
|
luaD_callnoyield(L, func, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -126,7 +127,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
|
|||||||
static void checkclosemth (lua_State *L, StkId level) {
|
static void checkclosemth (lua_State *L, StkId level) {
|
||||||
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
|
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
|
||||||
if (ttisnil(tm)) { /* no metamethod? */
|
if (ttisnil(tm)) { /* no metamethod? */
|
||||||
int idx = cast_int(level - L->ci->func); /* variable index */
|
int idx = cast_int(level - L->ci->func.p); /* variable index */
|
||||||
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
|
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
|
||||||
if (vname == NULL) vname = "?";
|
if (vname == NULL) vname = "?";
|
||||||
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
|
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
|
||||||
@@ -141,42 +142,44 @@ static void checkclosemth (lua_State *L, StkId level) {
|
|||||||
** the 'level' of the upvalue being closed, as everything after that
|
** the 'level' of the upvalue being closed, as everything after that
|
||||||
** won't be used again.
|
** won't be used again.
|
||||||
*/
|
*/
|
||||||
static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
|
static void prepcallclosemth (lua_State *L, StkId level, TStatus status,
|
||||||
|
int yy) {
|
||||||
TValue *uv = s2v(level); /* value being closed */
|
TValue *uv = s2v(level); /* value being closed */
|
||||||
TValue *errobj;
|
TValue *errobj;
|
||||||
if (status == CLOSEKTOP)
|
switch (status) {
|
||||||
errobj = &G(L)->nilvalue; /* error object is nil */
|
case LUA_OK:
|
||||||
else { /* 'luaD_seterrorobj' will set top to level + 2 */
|
L->top.p = level + 1; /* call will be at this level */
|
||||||
errobj = s2v(level + 1); /* error object goes after 'uv' */
|
/* FALLTHROUGH */
|
||||||
luaD_seterrorobj(L, status, level + 1); /* set error object */
|
case CLOSEKTOP: /* don't need to change top */
|
||||||
|
errobj = NULL; /* no error object */
|
||||||
|
break;
|
||||||
|
default: /* 'luaD_seterrorobj' will set top to level + 2 */
|
||||||
|
errobj = s2v(level + 1); /* error object goes after 'uv' */
|
||||||
|
luaD_seterrorobj(L, status, level + 1); /* set error object */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
callclosemethod(L, uv, errobj, yy);
|
callclosemethod(L, uv, errobj, yy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/* Maximum value for deltas in 'tbclist' */
|
||||||
** Maximum value for deltas in 'tbclist', dependent on the type
|
#define MAXDELTA USHRT_MAX
|
||||||
** of delta. (This macro assumes that an 'L' is in scope where it
|
|
||||||
** is used.)
|
|
||||||
*/
|
|
||||||
#define MAXDELTA \
|
|
||||||
((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Insert a variable in the list of to-be-closed variables.
|
** Insert a variable in the list of to-be-closed variables.
|
||||||
*/
|
*/
|
||||||
void luaF_newtbcupval (lua_State *L, StkId level) {
|
void luaF_newtbcupval (lua_State *L, StkId level) {
|
||||||
lua_assert(level > L->tbclist);
|
lua_assert(level > L->tbclist.p);
|
||||||
if (l_isfalse(s2v(level)))
|
if (l_isfalse(s2v(level)))
|
||||||
return; /* false doesn't need to be closed */
|
return; /* false doesn't need to be closed */
|
||||||
checkclosemth(L, level); /* value must have a close method */
|
checkclosemth(L, level); /* value must have a close method */
|
||||||
while (cast_uint(level - L->tbclist) > MAXDELTA) {
|
while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
|
||||||
L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
|
L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
|
||||||
L->tbclist->tbclist.delta = 0;
|
L->tbclist.p->tbclist.delta = 0;
|
||||||
}
|
}
|
||||||
level->tbclist.delta = cast(unsigned short, level - L->tbclist);
|
level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
|
||||||
L->tbclist = level;
|
L->tbclist.p = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -193,13 +196,12 @@ void luaF_unlinkupval (UpVal *uv) {
|
|||||||
*/
|
*/
|
||||||
void luaF_closeupval (lua_State *L, StkId level) {
|
void luaF_closeupval (lua_State *L, StkId level) {
|
||||||
UpVal *uv;
|
UpVal *uv;
|
||||||
StkId upl; /* stack index pointed by 'uv' */
|
while ((uv = L->openupval) != NULL && uplevel(uv) >= level) {
|
||||||
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
|
|
||||||
TValue *slot = &uv->u.value; /* new position for value */
|
TValue *slot = &uv->u.value; /* new position for value */
|
||||||
lua_assert(uplevel(uv) < L->top);
|
lua_assert(uplevel(uv) < L->top.p);
|
||||||
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
|
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
|
||||||
setobj(L, slot, uv->v); /* move value to upvalue slot */
|
setobj(L, slot, uv->v.p); /* move value to upvalue slot */
|
||||||
uv->v = slot; /* now current value lives here */
|
uv->v.p = slot; /* now current value lives here */
|
||||||
if (!iswhite(uv)) { /* neither white nor dead? */
|
if (!iswhite(uv)) { /* neither white nor dead? */
|
||||||
nw2black(uv); /* closed upvalues cannot be gray */
|
nw2black(uv); /* closed upvalues cannot be gray */
|
||||||
luaC_barrier(L, uv, slot);
|
luaC_barrier(L, uv, slot);
|
||||||
@@ -209,31 +211,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Remove firt element from the tbclist plus its dummy nodes.
|
** Remove first element from the tbclist plus its dummy nodes.
|
||||||
*/
|
*/
|
||||||
static void poptbclist (lua_State *L) {
|
static void poptbclist (lua_State *L) {
|
||||||
StkId tbc = L->tbclist;
|
StkId tbc = L->tbclist.p;
|
||||||
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
|
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
|
||||||
tbc -= tbc->tbclist.delta;
|
tbc -= tbc->tbclist.delta;
|
||||||
while (tbc > L->stack && tbc->tbclist.delta == 0)
|
while (tbc > L->stack.p && tbc->tbclist.delta == 0)
|
||||||
tbc -= MAXDELTA; /* remove dummy nodes */
|
tbc -= MAXDELTA; /* remove dummy nodes */
|
||||||
L->tbclist = tbc;
|
L->tbclist.p = tbc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Close all upvalues and to-be-closed variables up to the given stack
|
** Close all upvalues and to-be-closed variables up to the given stack
|
||||||
** level.
|
** level. Return restored 'level'.
|
||||||
*/
|
*/
|
||||||
void luaF_close (lua_State *L, StkId level, int status, int yy) {
|
StkId luaF_close (lua_State *L, StkId level, TStatus status, int yy) {
|
||||||
ptrdiff_t levelrel = savestack(L, level);
|
ptrdiff_t levelrel = savestack(L, level);
|
||||||
luaF_closeupval(L, level); /* first, close the upvalues */
|
luaF_closeupval(L, level); /* first, close the upvalues */
|
||||||
while (L->tbclist >= level) { /* traverse tbc's down to that level */
|
while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
|
||||||
StkId tbc = L->tbclist; /* get variable index */
|
StkId tbc = L->tbclist.p; /* get variable index */
|
||||||
poptbclist(L); /* remove it from list */
|
poptbclist(L); /* remove it from list */
|
||||||
prepcallclosemth(L, tbc, status, yy); /* close variable */
|
prepcallclosemth(L, tbc, status, yy); /* close variable */
|
||||||
level = restorestack(L, levelrel);
|
level = restorestack(L, levelrel);
|
||||||
}
|
}
|
||||||
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -253,7 +256,7 @@ Proto *luaF_newproto (lua_State *L) {
|
|||||||
f->upvalues = NULL;
|
f->upvalues = NULL;
|
||||||
f->sizeupvalues = 0;
|
f->sizeupvalues = 0;
|
||||||
f->numparams = 0;
|
f->numparams = 0;
|
||||||
f->is_vararg = 0;
|
f->flag = 0;
|
||||||
f->maxstacksize = 0;
|
f->maxstacksize = 0;
|
||||||
f->locvars = NULL;
|
f->locvars = NULL;
|
||||||
f->sizelocvars = 0;
|
f->sizelocvars = 0;
|
||||||
@@ -264,14 +267,31 @@ Proto *luaF_newproto (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lu_mem luaF_protosize (Proto *p) {
|
||||||
|
lu_mem sz = cast(lu_mem, sizeof(Proto))
|
||||||
|
+ cast_uint(p->sizep) * sizeof(Proto*)
|
||||||
|
+ cast_uint(p->sizek) * sizeof(TValue)
|
||||||
|
+ cast_uint(p->sizelocvars) * sizeof(LocVar)
|
||||||
|
+ cast_uint(p->sizeupvalues) * sizeof(Upvaldesc);
|
||||||
|
if (!(p->flag & PF_FIXED)) {
|
||||||
|
sz += cast_uint(p->sizecode) * sizeof(Instruction);
|
||||||
|
sz += cast_uint(p->sizelineinfo) * sizeof(lu_byte);
|
||||||
|
sz += cast_uint(p->sizeabslineinfo) * sizeof(AbsLineInfo);
|
||||||
|
}
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaF_freeproto (lua_State *L, Proto *f) {
|
void luaF_freeproto (lua_State *L, Proto *f) {
|
||||||
luaM_freearray(L, f->code, f->sizecode);
|
if (!(f->flag & PF_FIXED)) {
|
||||||
luaM_freearray(L, f->p, f->sizep);
|
luaM_freearray(L, f->code, cast_sizet(f->sizecode));
|
||||||
luaM_freearray(L, f->k, f->sizek);
|
luaM_freearray(L, f->lineinfo, cast_sizet(f->sizelineinfo));
|
||||||
luaM_freearray(L, f->lineinfo, f->sizelineinfo);
|
luaM_freearray(L, f->abslineinfo, cast_sizet(f->sizeabslineinfo));
|
||||||
luaM_freearray(L, f->abslineinfo, f->sizeabslineinfo);
|
}
|
||||||
luaM_freearray(L, f->locvars, f->sizelocvars);
|
luaM_freearray(L, f->p, cast_sizet(f->sizep));
|
||||||
luaM_freearray(L, f->upvalues, f->sizeupvalues);
|
luaM_freearray(L, f->k, cast_sizet(f->sizek));
|
||||||
|
luaM_freearray(L, f->locvars, cast_sizet(f->sizelocvars));
|
||||||
|
luaM_freearray(L, f->upvalues, cast_sizet(f->sizeupvalues));
|
||||||
luaM_free(L, f);
|
luaM_free(L, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
+9
-8
@@ -11,11 +11,11 @@
|
|||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
|
|
||||||
|
|
||||||
#define sizeCclosure(n) (cast_int(offsetof(CClosure, upvalue)) + \
|
#define sizeCclosure(n) \
|
||||||
cast_int(sizeof(TValue)) * (n))
|
(offsetof(CClosure, upvalue) + sizeof(TValue) * cast_uint(n))
|
||||||
|
|
||||||
#define sizeLclosure(n) (cast_int(offsetof(LClosure, upvals)) + \
|
#define sizeLclosure(n) \
|
||||||
cast_int(sizeof(TValue *)) * (n))
|
(offsetof(LClosure, upvals) + sizeof(UpVal *) * cast_uint(n))
|
||||||
|
|
||||||
|
|
||||||
/* test whether thread is in 'twups' list */
|
/* test whether thread is in 'twups' list */
|
||||||
@@ -29,10 +29,10 @@
|
|||||||
#define MAXUPVAL 255
|
#define MAXUPVAL 255
|
||||||
|
|
||||||
|
|
||||||
#define upisopen(up) ((up)->v != &(up)->u.value)
|
#define upisopen(up) ((up)->v.p != &(up)->u.value)
|
||||||
|
|
||||||
|
|
||||||
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v))
|
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/* special status to close upvalues preserving the top of the stack */
|
/* special status to close upvalues preserving the top of the stack */
|
||||||
#define CLOSEKTOP (-1)
|
#define CLOSEKTOP (LUA_ERRERR + 1)
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
|
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
|
||||||
@@ -54,8 +54,9 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
|
|||||||
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
|
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
|
||||||
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
|
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
|
||||||
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
|
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
|
||||||
LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
|
LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, TStatus status, int yy);
|
||||||
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
|
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
|
||||||
|
LUAI_FUNC lu_mem luaF_protosize (Proto *p);
|
||||||
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
|
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
|
||||||
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
|
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
|
||||||
int pc);
|
int pc);
|
||||||
+482
-406
File diff suppressed because it is too large
Load Diff
Vendored
+268
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
** $Id: lgc.h $
|
||||||
|
** Garbage Collector
|
||||||
|
** See Copyright Notice in lua.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef lgc_h
|
||||||
|
#define lgc_h
|
||||||
|
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "lobject.h"
|
||||||
|
#include "lstate.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Collectable objects may have one of three colors: white, which means
|
||||||
|
** the object is not marked; gray, which means the object is marked, but
|
||||||
|
** its references may be not marked; and black, which means that the
|
||||||
|
** object and all its references are marked. The main invariant of the
|
||||||
|
** garbage collector, while marking objects, is that a black object can
|
||||||
|
** never point to a white one. Moreover, any gray object must be in a
|
||||||
|
** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it
|
||||||
|
** can be visited again before finishing the collection cycle. (Open
|
||||||
|
** upvalues are an exception to this rule, as they are attached to
|
||||||
|
** a corresponding thread.) These lists have no meaning when the
|
||||||
|
** invariant is not being enforced (e.g., sweep phase).
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Possible states of the Garbage Collector
|
||||||
|
*/
|
||||||
|
#define GCSpropagate 0
|
||||||
|
#define GCSenteratomic 1
|
||||||
|
#define GCSatomic 2
|
||||||
|
#define GCSswpallgc 3
|
||||||
|
#define GCSswpfinobj 4
|
||||||
|
#define GCSswptobefnz 5
|
||||||
|
#define GCSswpend 6
|
||||||
|
#define GCScallfin 7
|
||||||
|
#define GCSpause 8
|
||||||
|
|
||||||
|
|
||||||
|
#define issweepphase(g) \
|
||||||
|
(GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** macro to tell when main invariant (white objects cannot point to black
|
||||||
|
** ones) must be kept. During a collection, the sweep phase may break
|
||||||
|
** the invariant, as objects turned white may point to still-black
|
||||||
|
** objects. The invariant is restored when sweep ends and all objects
|
||||||
|
** are white again.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define keepinvariant(g) ((g)->gcstate <= GCSatomic)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** some useful bit tricks
|
||||||
|
*/
|
||||||
|
#define resetbits(x,m) ((x) &= cast_byte(~(m)))
|
||||||
|
#define setbits(x,m) ((x) |= (m))
|
||||||
|
#define testbits(x,m) ((x) & (m))
|
||||||
|
#define bitmask(b) (1<<(b))
|
||||||
|
#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2))
|
||||||
|
#define l_setbit(x,b) setbits(x, bitmask(b))
|
||||||
|
#define resetbit(x,b) resetbits(x, bitmask(b))
|
||||||
|
#define testbit(x,b) testbits(x, bitmask(b))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Layout for bit use in 'marked' field. First three bits are
|
||||||
|
** used for object "age" in generational mode. Last bit is used
|
||||||
|
** by tests.
|
||||||
|
*/
|
||||||
|
#define WHITE0BIT 3 /* object is white (type 0) */
|
||||||
|
#define WHITE1BIT 4 /* object is white (type 1) */
|
||||||
|
#define BLACKBIT 5 /* object is black */
|
||||||
|
#define FINALIZEDBIT 6 /* object has been marked for finalization */
|
||||||
|
|
||||||
|
#define TESTBIT 7
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
|
||||||
|
|
||||||
|
|
||||||
|
#define iswhite(x) testbits((x)->marked, WHITEBITS)
|
||||||
|
#define isblack(x) testbit((x)->marked, BLACKBIT)
|
||||||
|
#define isgray(x) /* neither white nor black */ \
|
||||||
|
(!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT)))
|
||||||
|
|
||||||
|
#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT)
|
||||||
|
|
||||||
|
#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS)
|
||||||
|
#define isdeadm(ow,m) ((m) & (ow))
|
||||||
|
#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
|
||||||
|
|
||||||
|
#define changewhite(x) ((x)->marked ^= WHITEBITS)
|
||||||
|
#define nw2black(x) \
|
||||||
|
check_exp(!iswhite(x), l_setbit((x)->marked, BLACKBIT))
|
||||||
|
|
||||||
|
#define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS)
|
||||||
|
|
||||||
|
|
||||||
|
/* object age in generational mode */
|
||||||
|
#define G_NEW 0 /* created in current cycle */
|
||||||
|
#define G_SURVIVAL 1 /* created in previous cycle */
|
||||||
|
#define G_OLD0 2 /* marked old by frw. barrier in this cycle */
|
||||||
|
#define G_OLD1 3 /* first full cycle as old */
|
||||||
|
#define G_OLD 4 /* really old object (not to be visited) */
|
||||||
|
#define G_TOUCHED1 5 /* old object touched this cycle */
|
||||||
|
#define G_TOUCHED2 6 /* old object touched in previous cycle */
|
||||||
|
|
||||||
|
#define AGEBITS 7 /* all age bits (111) */
|
||||||
|
|
||||||
|
#define getage(o) ((o)->marked & AGEBITS)
|
||||||
|
#define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a))
|
||||||
|
#define isold(o) (getage(o) > G_SURVIVAL)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** In generational mode, objects are created 'new'. After surviving one
|
||||||
|
** cycle, they become 'survival'. Both 'new' and 'survival' can point
|
||||||
|
** to any other object, as they are traversed at the end of the cycle.
|
||||||
|
** We call them both 'young' objects.
|
||||||
|
** If a survival object survives another cycle, it becomes 'old1'.
|
||||||
|
** 'old1' objects can still point to survival objects (but not to
|
||||||
|
** new objects), so they still must be traversed. After another cycle
|
||||||
|
** (that, being old, 'old1' objects will "survive" no matter what)
|
||||||
|
** finally the 'old1' object becomes really 'old', and then they
|
||||||
|
** are no more traversed.
|
||||||
|
**
|
||||||
|
** To keep its invariants, the generational mode uses the same barriers
|
||||||
|
** also used by the incremental mode. If a young object is caught in a
|
||||||
|
** forward barrier, it cannot become old immediately, because it can
|
||||||
|
** still point to other young objects. Instead, it becomes 'old0',
|
||||||
|
** which in the next cycle becomes 'old1'. So, 'old0' objects is
|
||||||
|
** old but can point to new and survival objects; 'old1' is old
|
||||||
|
** but cannot point to new objects; and 'old' cannot point to any
|
||||||
|
** young object.
|
||||||
|
**
|
||||||
|
** If any old object ('old0', 'old1', 'old') is caught in a back
|
||||||
|
** barrier, it becomes 'touched1' and goes into a gray list, to be
|
||||||
|
** visited at the end of the cycle. There it evolves to 'touched2',
|
||||||
|
** which can point to survivals but not to new objects. In yet another
|
||||||
|
** cycle then it becomes 'old' again.
|
||||||
|
**
|
||||||
|
** The generational mode must also control the colors of objects,
|
||||||
|
** because of the barriers. While the mutator is running, young objects
|
||||||
|
** are kept white. 'old', 'old1', and 'touched2' objects are kept black,
|
||||||
|
** as they cannot point to new objects; exceptions are threads and open
|
||||||
|
** upvalues, which age to 'old1' and 'old' but are kept gray. 'old0'
|
||||||
|
** objects may be gray or black, as in the incremental mode. 'touched1'
|
||||||
|
** objects are kept gray, as they must be visited again at the end of
|
||||||
|
** the cycle.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {======================================================
|
||||||
|
** Default Values for GC parameters
|
||||||
|
** =======================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Minor collections will shift to major ones after LUAI_MINORMAJOR%
|
||||||
|
** bytes become old.
|
||||||
|
*/
|
||||||
|
#define LUAI_MINORMAJOR 70
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Major collections will shift to minor ones after a collection
|
||||||
|
** collects at least LUAI_MAJORMINOR% of the new bytes.
|
||||||
|
*/
|
||||||
|
#define LUAI_MAJORMINOR 50
|
||||||
|
|
||||||
|
/*
|
||||||
|
** A young (minor) collection will run after creating LUAI_GENMINORMUL%
|
||||||
|
** new bytes.
|
||||||
|
*/
|
||||||
|
#define LUAI_GENMINORMUL 20
|
||||||
|
|
||||||
|
|
||||||
|
/* incremental */
|
||||||
|
|
||||||
|
/* Number of bytes must be LUAI_GCPAUSE% before starting new cycle */
|
||||||
|
#define LUAI_GCPAUSE 250
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Step multiplier: The collector handles LUAI_GCMUL% work units for
|
||||||
|
** each new allocated word. (Each "work unit" corresponds roughly to
|
||||||
|
** sweeping one object or traversing one slot.)
|
||||||
|
*/
|
||||||
|
#define LUAI_GCMUL 200
|
||||||
|
|
||||||
|
/* How many bytes to allocate before next GC step */
|
||||||
|
#define LUAI_GCSTEPSIZE (200 * sizeof(Table))
|
||||||
|
|
||||||
|
|
||||||
|
#define setgcparam(g,p,v) (g->gcparams[LUA_GCP##p] = luaO_codeparam(v))
|
||||||
|
#define applygcparam(g,p,x) luaO_applyparam(g->gcparams[LUA_GCP##p], x)
|
||||||
|
|
||||||
|
/* }====================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Control when GC is running:
|
||||||
|
*/
|
||||||
|
#define GCSTPUSR 1 /* bit true when GC stopped by user */
|
||||||
|
#define GCSTPGC 2 /* bit true when GC stopped by itself */
|
||||||
|
#define GCSTPCLS 4 /* bit true when closing Lua state */
|
||||||
|
#define gcrunning(g) ((g)->gcstp == 0)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Does one step of collection when debt becomes zero. 'pre'/'pos'
|
||||||
|
** allows some adjustments to be done only when needed. macro
|
||||||
|
** 'condchangemem' is used only for heavy tests (forcing a full
|
||||||
|
** GC cycle on every opportunity)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(HARDMEMTESTS)
|
||||||
|
#define condchangemem(L,pre,pos,emg) ((void)0)
|
||||||
|
#else
|
||||||
|
#define condchangemem(L,pre,pos,emg) \
|
||||||
|
{ if (gcrunning(G(L))) { pre; luaC_fullgc(L, emg); pos; } }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define luaC_condGC(L,pre,pos) \
|
||||||
|
{ if (G(L)->GCdebt <= 0) { pre; luaC_step(L); pos;}; \
|
||||||
|
condchangemem(L,pre,pos,0); }
|
||||||
|
|
||||||
|
/* more often than not, 'pre'/'pos' are empty */
|
||||||
|
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
|
||||||
|
|
||||||
|
|
||||||
|
#define luaC_objbarrier(L,p,o) ( \
|
||||||
|
(isblack(p) && iswhite(o)) ? \
|
||||||
|
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
|
||||||
|
|
||||||
|
#define luaC_barrier(L,p,v) ( \
|
||||||
|
iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
|
||||||
|
|
||||||
|
#define luaC_objbarrierback(L,p,o) ( \
|
||||||
|
(isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
|
||||||
|
|
||||||
|
#define luaC_barrierback(L,p,v) ( \
|
||||||
|
iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
|
||||||
|
|
||||||
|
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
|
||||||
|
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
|
||||||
|
LUAI_FUNC void luaC_step (lua_State *L);
|
||||||
|
LUAI_FUNC void luaC_runtilstate (lua_State *L, int state, int fast);
|
||||||
|
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
|
||||||
|
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, lu_byte tt, size_t sz);
|
||||||
|
LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, lu_byte tt, size_t sz,
|
||||||
|
size_t offset);
|
||||||
|
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
|
||||||
|
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
|
||||||
|
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
|
||||||
|
LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
Vendored
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
** $Id: linit.c $
|
||||||
|
** Initialization of libraries for lua.c and other clients
|
||||||
|
** See Copyright Notice in lua.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define linit_c
|
||||||
|
#define LUA_LIB
|
||||||
|
|
||||||
|
|
||||||
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "lualib.h"
|
||||||
|
#include "lauxlib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Standard Libraries. (Must be listed in the same ORDER of their
|
||||||
|
** respective constants LUA_<libname>K.)
|
||||||
|
*/
|
||||||
|
static const luaL_Reg stdlibs[] = {
|
||||||
|
{LUA_GNAME, luaopen_base},
|
||||||
|
{LUA_LOADLIBNAME, luaopen_package},
|
||||||
|
{LUA_COLIBNAME, luaopen_coroutine},
|
||||||
|
{LUA_DBLIBNAME, luaopen_debug},
|
||||||
|
{LUA_IOLIBNAME, luaopen_io},
|
||||||
|
{LUA_MATHLIBNAME, luaopen_math},
|
||||||
|
{LUA_OSLIBNAME, luaopen_os},
|
||||||
|
{LUA_STRLIBNAME, luaopen_string},
|
||||||
|
{LUA_TABLIBNAME, luaopen_table},
|
||||||
|
{LUA_UTF8LIBNAME, luaopen_utf8},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** require and preload selected standard libraries
|
||||||
|
*/
|
||||||
|
LUALIB_API void luaL_openselectedlibs (lua_State *L, int load, int preload) {
|
||||||
|
int mask;
|
||||||
|
const luaL_Reg *lib;
|
||||||
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
|
||||||
|
for (lib = stdlibs, mask = 1; lib->name != NULL; lib++, mask <<= 1) {
|
||||||
|
if (load & mask) { /* selected? */
|
||||||
|
luaL_requiref(L, lib->name, lib->func, 1); /* require library */
|
||||||
|
lua_pop(L, 1); /* remove result from the stack */
|
||||||
|
}
|
||||||
|
else if (preload & mask) { /* selected? */
|
||||||
|
lua_pushcfunction(L, lib->func);
|
||||||
|
lua_setfield(L, -2, lib->name); /* add library to PRELOAD table */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_assert((mask >> 1) == LUA_UTF8LIBK);
|
||||||
|
lua_pop(L, 1); /* remove PRELOAD table */
|
||||||
|
}
|
||||||
|
|
||||||
+45
-32
@@ -21,8 +21,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -115,7 +114,7 @@ static int l_checkmode (const char *mode) {
|
|||||||
|
|
||||||
#if !defined(l_fseek) /* { */
|
#if !defined(l_fseek) /* { */
|
||||||
|
|
||||||
#if defined(LUA_USE_POSIX) /* { */
|
#if defined(LUA_USE_POSIX) || defined(LUA_USE_OFF_T) /* { */
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
@@ -245,8 +244,8 @@ static int f_gc (lua_State *L) {
|
|||||||
*/
|
*/
|
||||||
static int io_fclose (lua_State *L) {
|
static int io_fclose (lua_State *L) {
|
||||||
LStream *p = tolstream(L);
|
LStream *p = tolstream(L);
|
||||||
int res = fclose(p->f);
|
errno = 0;
|
||||||
return luaL_fileresult(L, (res == 0), NULL);
|
return luaL_fileresult(L, (fclose(p->f) == 0), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -272,6 +271,7 @@ static int io_open (lua_State *L) {
|
|||||||
LStream *p = newfile(L);
|
LStream *p = newfile(L);
|
||||||
const char *md = mode; /* to traverse/check mode */
|
const char *md = mode; /* to traverse/check mode */
|
||||||
luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
|
luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
|
||||||
|
errno = 0;
|
||||||
p->f = fopen(filename, mode);
|
p->f = fopen(filename, mode);
|
||||||
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
|
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
|
||||||
}
|
}
|
||||||
@@ -292,6 +292,7 @@ static int io_popen (lua_State *L) {
|
|||||||
const char *mode = luaL_optstring(L, 2, "r");
|
const char *mode = luaL_optstring(L, 2, "r");
|
||||||
LStream *p = newprefile(L);
|
LStream *p = newprefile(L);
|
||||||
luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
|
luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
|
||||||
|
errno = 0;
|
||||||
p->f = l_popen(L, filename, mode);
|
p->f = l_popen(L, filename, mode);
|
||||||
p->closef = &io_pclose;
|
p->closef = &io_pclose;
|
||||||
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
|
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
|
||||||
@@ -300,6 +301,7 @@ static int io_popen (lua_State *L) {
|
|||||||
|
|
||||||
static int io_tmpfile (lua_State *L) {
|
static int io_tmpfile (lua_State *L) {
|
||||||
LStream *p = newfile(L);
|
LStream *p = newfile(L);
|
||||||
|
errno = 0;
|
||||||
p->f = tmpfile();
|
p->f = tmpfile();
|
||||||
return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
|
return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
|
||||||
}
|
}
|
||||||
@@ -441,7 +443,7 @@ static int nextc (RN *rn) {
|
|||||||
return 0; /* fail */
|
return 0; /* fail */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rn->buff[rn->n++] = rn->c; /* save current char */
|
rn->buff[rn->n++] = cast_char(rn->c); /* save current char */
|
||||||
rn->c = l_getc(rn->f); /* read next one */
|
rn->c = l_getc(rn->f); /* read next one */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -522,15 +524,15 @@ static int read_line (lua_State *L, FILE *f, int chop) {
|
|||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
do { /* may need to read several chunks to get whole line */
|
do { /* may need to read several chunks to get whole line */
|
||||||
char *buff = luaL_prepbuffer(&b); /* preallocate buffer space */
|
char *buff = luaL_prepbuffer(&b); /* preallocate buffer space */
|
||||||
int i = 0;
|
unsigned i = 0;
|
||||||
l_lockfile(f); /* no memory errors can happen inside the lock */
|
l_lockfile(f); /* no memory errors can happen inside the lock */
|
||||||
while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n')
|
while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n')
|
||||||
buff[i++] = c; /* read up to end of line or buffer limit */
|
buff[i++] = cast_char(c); /* read up to end of line or buffer limit */
|
||||||
l_unlockfile(f);
|
l_unlockfile(f);
|
||||||
luaL_addsize(&b, i);
|
luaL_addsize(&b, i);
|
||||||
} while (c != EOF && c != '\n'); /* repeat until end of line */
|
} while (c != EOF && c != '\n'); /* repeat until end of line */
|
||||||
if (!chop && c == '\n') /* want a newline and have one? */
|
if (!chop && c == '\n') /* want a newline and have one? */
|
||||||
luaL_addchar(&b, c); /* add ending newline to result */
|
luaL_addchar(&b, '\n'); /* add ending newline to result */
|
||||||
luaL_pushresult(&b); /* close buffer */
|
luaL_pushresult(&b); /* close buffer */
|
||||||
/* return ok if read something (either a newline or something else) */
|
/* return ok if read something (either a newline or something else) */
|
||||||
return (c == '\n' || lua_rawlen(L, -1) > 0);
|
return (c == '\n' || lua_rawlen(L, -1) > 0);
|
||||||
@@ -567,6 +569,7 @@ static int g_read (lua_State *L, FILE *f, int first) {
|
|||||||
int nargs = lua_gettop(L) - 1;
|
int nargs = lua_gettop(L) - 1;
|
||||||
int n, success;
|
int n, success;
|
||||||
clearerr(f);
|
clearerr(f);
|
||||||
|
errno = 0;
|
||||||
if (nargs == 0) { /* no arguments? */
|
if (nargs == 0) { /* no arguments? */
|
||||||
success = read_line(L, f, 1);
|
success = read_line(L, f, 1);
|
||||||
n = first + 1; /* to return 1 result */
|
n = first + 1; /* to return 1 result */
|
||||||
@@ -659,26 +662,28 @@ static int io_readline (lua_State *L) {
|
|||||||
|
|
||||||
static int g_write (lua_State *L, FILE *f, int arg) {
|
static int g_write (lua_State *L, FILE *f, int arg) {
|
||||||
int nargs = lua_gettop(L) - arg;
|
int nargs = lua_gettop(L) - arg;
|
||||||
int status = 1;
|
size_t totalbytes = 0; /* total number of bytes written */
|
||||||
for (; nargs--; arg++) {
|
errno = 0;
|
||||||
if (lua_type(L, arg) == LUA_TNUMBER) {
|
for (; nargs--; arg++) { /* for each argument */
|
||||||
/* optimization: could be done exactly as for strings */
|
char buff[LUA_N2SBUFFSZ];
|
||||||
int len = lua_isinteger(L, arg)
|
const char *s;
|
||||||
? fprintf(f, LUA_INTEGER_FMT,
|
size_t numbytes; /* bytes written in one call to 'fwrite' */
|
||||||
(LUAI_UACINT)lua_tointeger(L, arg))
|
size_t len = lua_numbertocstring(L, arg, buff); /* try as a number */
|
||||||
: fprintf(f, LUA_NUMBER_FMT,
|
if (len > 0) { /* did conversion work (value was a number)? */
|
||||||
(LUAI_UACNUMBER)lua_tonumber(L, arg));
|
s = buff;
|
||||||
status = status && (len > 0);
|
len--;
|
||||||
}
|
}
|
||||||
else {
|
else /* must be a string */
|
||||||
size_t l;
|
s = luaL_checklstring(L, arg, &len);
|
||||||
const char *s = luaL_checklstring(L, arg, &l);
|
numbytes = fwrite(s, sizeof(char), len, f);
|
||||||
status = status && (fwrite(s, sizeof(char), l, f) == l);
|
totalbytes += numbytes;
|
||||||
|
if (numbytes < len) { /* write error? */
|
||||||
|
int n = luaL_fileresult(L, 0, NULL);
|
||||||
|
lua_pushinteger(L, cast_st2S(totalbytes));
|
||||||
|
return n + 1; /* return fail, error msg., error code, and counter */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (l_likely(status))
|
return 1; /* no errors; file handle already on stack top */
|
||||||
return 1; /* file handle already on stack top */
|
|
||||||
else return luaL_fileresult(L, status, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -703,6 +708,7 @@ static int f_seek (lua_State *L) {
|
|||||||
l_seeknum offset = (l_seeknum)p3;
|
l_seeknum offset = (l_seeknum)p3;
|
||||||
luaL_argcheck(L, (lua_Integer)offset == p3, 3,
|
luaL_argcheck(L, (lua_Integer)offset == p3, 3,
|
||||||
"not an integer in proper range");
|
"not an integer in proper range");
|
||||||
|
errno = 0;
|
||||||
op = l_fseek(f, offset, mode[op]);
|
op = l_fseek(f, offset, mode[op]);
|
||||||
if (l_unlikely(op))
|
if (l_unlikely(op))
|
||||||
return luaL_fileresult(L, 0, NULL); /* error */
|
return luaL_fileresult(L, 0, NULL); /* error */
|
||||||
@@ -719,19 +725,26 @@ static int f_setvbuf (lua_State *L) {
|
|||||||
FILE *f = tofile(L);
|
FILE *f = tofile(L);
|
||||||
int op = luaL_checkoption(L, 2, NULL, modenames);
|
int op = luaL_checkoption(L, 2, NULL, modenames);
|
||||||
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
|
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
|
||||||
int res = setvbuf(f, NULL, mode[op], (size_t)sz);
|
int res;
|
||||||
|
errno = 0;
|
||||||
|
res = setvbuf(f, NULL, mode[op], (size_t)sz);
|
||||||
return luaL_fileresult(L, res == 0, NULL);
|
return luaL_fileresult(L, res == 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int aux_flush (lua_State *L, FILE *f) {
|
||||||
static int io_flush (lua_State *L) {
|
errno = 0;
|
||||||
return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
|
return luaL_fileresult(L, fflush(f) == 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_flush (lua_State *L) {
|
static int f_flush (lua_State *L) {
|
||||||
return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL);
|
return aux_flush(L, tofile(L));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int io_flush (lua_State *L) {
|
||||||
|
return aux_flush(L, getiofile(L, IO_OUTPUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -773,7 +786,7 @@ static const luaL_Reg meth[] = {
|
|||||||
** metamethods for file handles
|
** metamethods for file handles
|
||||||
*/
|
*/
|
||||||
static const luaL_Reg metameth[] = {
|
static const luaL_Reg metameth[] = {
|
||||||
{"__index", NULL}, /* place holder */
|
{"__index", NULL}, /* placeholder */
|
||||||
{"__gc", f_gc},
|
{"__gc", f_gc},
|
||||||
{"__close", f_gc},
|
{"__close", f_gc},
|
||||||
{"__tostring", f_tostring},
|
{"__tostring", f_tostring},
|
||||||
+4
-2
@@ -21,7 +21,7 @@ static const void *const disptab[NUM_OPCODES] = {
|
|||||||
#if 0
|
#if 0
|
||||||
** you can update the following list with this command:
|
** you can update the following list with this command:
|
||||||
**
|
**
|
||||||
** sed -n '/^OP_/\!d; s/OP_/\&\&L_OP_/ ; s/,.*/,/ ; s/\/.*// ; p' lopcodes.h
|
** sed -n '/^OP_/!d; s/OP_/\&\&L_OP_/ ; s/,.*/,/ ; s/\/.*// ; p' lopcodes.h
|
||||||
**
|
**
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -57,8 +57,8 @@ static const void *const disptab[NUM_OPCODES] = {
|
|||||||
&&L_OP_BANDK,
|
&&L_OP_BANDK,
|
||||||
&&L_OP_BORK,
|
&&L_OP_BORK,
|
||||||
&&L_OP_BXORK,
|
&&L_OP_BXORK,
|
||||||
&&L_OP_SHRI,
|
|
||||||
&&L_OP_SHLI,
|
&&L_OP_SHLI,
|
||||||
|
&&L_OP_SHRI,
|
||||||
&&L_OP_ADD,
|
&&L_OP_ADD,
|
||||||
&&L_OP_SUB,
|
&&L_OP_SUB,
|
||||||
&&L_OP_MUL,
|
&&L_OP_MUL,
|
||||||
@@ -106,6 +106,8 @@ static const void *const disptab[NUM_OPCODES] = {
|
|||||||
&&L_OP_SETLIST,
|
&&L_OP_SETLIST,
|
||||||
&&L_OP_CLOSURE,
|
&&L_OP_CLOSURE,
|
||||||
&&L_OP_VARARG,
|
&&L_OP_VARARG,
|
||||||
|
&&L_OP_GETVARG,
|
||||||
|
&&L_OP_ERRNNIL,
|
||||||
&&L_OP_VARARGPREP,
|
&&L_OP_VARARGPREP,
|
||||||
&&L_OP_EXTRAARG
|
&&L_OP_EXTRAARG
|
||||||
|
|
||||||
+56
-33
@@ -32,6 +32,11 @@
|
|||||||
#define next(ls) (ls->current = zgetc(ls->z))
|
#define next(ls) (ls->current = zgetc(ls->z))
|
||||||
|
|
||||||
|
|
||||||
|
/* minimum size for string buffer */
|
||||||
|
#if !defined(LUA_MINBUFFER)
|
||||||
|
#define LUA_MINBUFFER 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')
|
#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')
|
||||||
|
|
||||||
@@ -39,7 +44,7 @@
|
|||||||
/* ORDER RESERVED */
|
/* ORDER RESERVED */
|
||||||
static const char *const luaX_tokens [] = {
|
static const char *const luaX_tokens [] = {
|
||||||
"and", "break", "do", "else", "elseif",
|
"and", "break", "do", "else", "elseif",
|
||||||
"end", "false", "for", "function", "goto", "if",
|
"end", "false", "for", "function", "global", "goto", "if",
|
||||||
"in", "local", "nil", "not", "or", "repeat",
|
"in", "local", "nil", "not", "or", "repeat",
|
||||||
"return", "then", "true", "until", "while",
|
"return", "then", "true", "until", "while",
|
||||||
"//", "..", "...", "==", ">=", "<=", "~=",
|
"//", "..", "...", "==", ">=", "<=", "~=",
|
||||||
@@ -57,10 +62,10 @@ static l_noret lexerror (LexState *ls, const char *msg, int token);
|
|||||||
static void save (LexState *ls, int c) {
|
static void save (LexState *ls, int c) {
|
||||||
Mbuffer *b = ls->buff;
|
Mbuffer *b = ls->buff;
|
||||||
if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) {
|
if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) {
|
||||||
size_t newsize;
|
size_t newsize = luaZ_sizebuffer(b); /* get old size */;
|
||||||
if (luaZ_sizebuffer(b) >= MAX_SIZE/2)
|
if (newsize >= (MAX_SIZE/3 * 2)) /* larger than MAX_SIZE/1.5 ? */
|
||||||
lexerror(ls, "lexical element too long", 0);
|
lexerror(ls, "lexical element too long", 0);
|
||||||
newsize = luaZ_sizebuffer(b) * 2;
|
newsize += (newsize >> 1); /* new size is 1.5 times the old one */
|
||||||
luaZ_resizebuffer(ls->L, b, newsize);
|
luaZ_resizebuffer(ls->L, b, newsize);
|
||||||
}
|
}
|
||||||
b->buffer[luaZ_bufflen(b)++] = cast_char(c);
|
b->buffer[luaZ_bufflen(b)++] = cast_char(c);
|
||||||
@@ -122,30 +127,34 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Creates a new string and anchors it in scanner's table so that it
|
** Anchors a string in scanner's table so that it will not be collected
|
||||||
** will not be collected until the end of the compilation; by that time
|
** until the end of the compilation; by that time it should be anchored
|
||||||
** it should be anchored somewhere. It also internalizes long strings,
|
** somewhere. It also internalizes long strings, ensuring there is only
|
||||||
** ensuring there is only one copy of each unique string. The table
|
** one copy of each unique string.
|
||||||
** here is used as a set: the string enters as the key, while its value
|
|
||||||
** is irrelevant. We use the string itself as the value only because it
|
|
||||||
** is a TValue readly available. Later, the code generation can change
|
|
||||||
** this value.
|
|
||||||
*/
|
*/
|
||||||
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
|
static TString *anchorstr (LexState *ls, TString *ts) {
|
||||||
lua_State *L = ls->L;
|
lua_State *L = ls->L;
|
||||||
TString *ts = luaS_newlstr(L, str, l); /* create new string */
|
TValue oldts;
|
||||||
const TValue *o = luaH_getstr(ls->h, ts);
|
int tag = luaH_getstr(ls->h, ts, &oldts);
|
||||||
if (!ttisnil(o)) /* string already present? */
|
if (!tagisempty(tag)) /* string already present? */
|
||||||
ts = keystrval(nodefromval(o)); /* get saved copy */
|
return tsvalue(&oldts); /* use stored value */
|
||||||
else { /* not in use yet */
|
else { /* create a new entry */
|
||||||
TValue *stv = s2v(L->top++); /* reserve stack space for string */
|
TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
|
||||||
setsvalue(L, stv, ts); /* temporarily anchor the string */
|
setsvalue(L, stv, ts); /* push (anchor) the string on the stack */
|
||||||
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
|
luaH_set(L, ls->h, stv, stv); /* t[string] = string */
|
||||||
/* table is not a metatable, so it does not need to invalidate cache */
|
/* table is not a metatable, so it does not need to invalidate cache */
|
||||||
luaC_checkGC(L);
|
luaC_checkGC(L);
|
||||||
L->top--; /* remove string from stack */
|
L->top.p--; /* remove string from stack */
|
||||||
|
return ts;
|
||||||
}
|
}
|
||||||
return ts;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Creates a new string and anchors it in scanner's table.
|
||||||
|
*/
|
||||||
|
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
|
||||||
|
return anchorstr(ls, luaS_newlstr(ls->L, str, l));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -159,7 +168,7 @@ static void inclinenumber (LexState *ls) {
|
|||||||
next(ls); /* skip '\n' or '\r' */
|
next(ls); /* skip '\n' or '\r' */
|
||||||
if (currIsNewline(ls) && ls->current != old)
|
if (currIsNewline(ls) && ls->current != old)
|
||||||
next(ls); /* skip '\n\r' or '\r\n' */
|
next(ls); /* skip '\n\r' or '\r\n' */
|
||||||
if (++ls->linenumber >= MAX_INT)
|
if (++ls->linenumber >= INT_MAX)
|
||||||
lexerror(ls, "chunk has too many lines", 0);
|
lexerror(ls, "chunk has too many lines", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +184,15 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
|
|||||||
ls->linenumber = 1;
|
ls->linenumber = 1;
|
||||||
ls->lastline = 1;
|
ls->lastline = 1;
|
||||||
ls->source = source;
|
ls->source = source;
|
||||||
ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */
|
/* all three strings here ("_ENV", "break", "global") were fixed,
|
||||||
|
so they cannot be collected */
|
||||||
|
ls->envn = luaS_newliteral(L, LUA_ENV); /* get env string */
|
||||||
|
ls->brkn = luaS_newliteral(L, "break"); /* get "break" string */
|
||||||
|
#if defined(LUA_COMPAT_GLOBAL)
|
||||||
|
/* compatibility mode: "global" is not a reserved word */
|
||||||
|
ls->glbn = luaS_newliteral(L, "global"); /* get "global" string */
|
||||||
|
ls->glbn->extra = 0; /* mark it as not reserved */
|
||||||
|
#endif
|
||||||
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
|
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,12 +357,17 @@ static int readhexaesc (LexState *ls) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static unsigned long readutf8esc (LexState *ls) {
|
/*
|
||||||
unsigned long r;
|
** When reading a UTF-8 escape sequence, save everything to the buffer
|
||||||
int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */
|
** for error reporting in case of errors; 'i' counts the number of
|
||||||
|
** saved characters, so that they can be removed if case of success.
|
||||||
|
*/
|
||||||
|
static l_uint32 readutf8esc (LexState *ls) {
|
||||||
|
l_uint32 r;
|
||||||
|
int i = 4; /* number of chars to be removed: start with #"\u{X" */
|
||||||
save_and_next(ls); /* skip 'u' */
|
save_and_next(ls); /* skip 'u' */
|
||||||
esccheck(ls, ls->current == '{', "missing '{'");
|
esccheck(ls, ls->current == '{', "missing '{'");
|
||||||
r = gethexa(ls); /* must have at least one digit */
|
r = cast_uint(gethexa(ls)); /* must have at least one digit */
|
||||||
while (cast_void(save_and_next(ls)), lisxdigit(ls->current)) {
|
while (cast_void(save_and_next(ls)), lisxdigit(ls->current)) {
|
||||||
i++;
|
i++;
|
||||||
esccheck(ls, r <= (0x7FFFFFFFu >> 4), "UTF-8 value too large");
|
esccheck(ls, r <= (0x7FFFFFFFu >> 4), "UTF-8 value too large");
|
||||||
@@ -542,12 +564,13 @@ static int llex (LexState *ls, SemInfo *seminfo) {
|
|||||||
do {
|
do {
|
||||||
save_and_next(ls);
|
save_and_next(ls);
|
||||||
} while (lislalnum(ls->current));
|
} while (lislalnum(ls->current));
|
||||||
ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
|
/* find or create string */
|
||||||
luaZ_bufflen(ls->buff));
|
ts = luaS_newlstr(ls->L, luaZ_buffer(ls->buff),
|
||||||
seminfo->ts = ts;
|
luaZ_bufflen(ls->buff));
|
||||||
if (isreserved(ts)) /* reserved word? */
|
if (isreserved(ts)) /* reserved word? */
|
||||||
return ts->extra - 1 + FIRST_RESERVED;
|
return ts->extra - 1 + FIRST_RESERVED;
|
||||||
else {
|
else {
|
||||||
|
seminfo->ts = anchorstr(ls, ts);
|
||||||
return TK_NAME;
|
return TK_NAME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5
-3
@@ -33,8 +33,8 @@ enum RESERVED {
|
|||||||
/* terminal symbols denoted by reserved words */
|
/* terminal symbols denoted by reserved words */
|
||||||
TK_AND = FIRST_RESERVED, TK_BREAK,
|
TK_AND = FIRST_RESERVED, TK_BREAK,
|
||||||
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
|
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
|
||||||
TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
|
TK_GLOBAL, TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR,
|
||||||
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
|
TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
|
||||||
/* other terminal symbols */
|
/* other terminal symbols */
|
||||||
TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
|
TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
|
||||||
TK_SHL, TK_SHR,
|
TK_SHL, TK_SHR,
|
||||||
@@ -59,7 +59,7 @@ typedef struct Token {
|
|||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
|
|
||||||
/* state of the lexer plus state of the parser when shared by all
|
/* state of the scanner plus state of the parser when shared by all
|
||||||
functions */
|
functions */
|
||||||
typedef struct LexState {
|
typedef struct LexState {
|
||||||
int current; /* current character (charint) */
|
int current; /* current character (charint) */
|
||||||
@@ -75,6 +75,8 @@ typedef struct LexState {
|
|||||||
struct Dyndata *dyd; /* dynamic structures used by the parser */
|
struct Dyndata *dyd; /* dynamic structures used by the parser */
|
||||||
TString *source; /* current source name */
|
TString *source; /* current source name */
|
||||||
TString *envn; /* environment variable name */
|
TString *envn; /* environment variable name */
|
||||||
|
TString *brkn; /* "break" name (used as a label) */
|
||||||
|
TString *glbn; /* "global" name (when not a reserved word) */
|
||||||
} LexState;
|
} LexState;
|
||||||
|
|
||||||
|
|
||||||
Vendored
+357
@@ -0,0 +1,357 @@
|
|||||||
|
/*
|
||||||
|
** $Id: llimits.h $
|
||||||
|
** Limits, basic types, and some other 'installation-dependent' definitions
|
||||||
|
** See Copyright Notice in lua.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef llimits_h
|
||||||
|
#define llimits_h
|
||||||
|
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "lua.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define l_numbits(t) cast_int(sizeof(t) * CHAR_BIT)
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 'l_mem' is a signed integer big enough to count the total memory
|
||||||
|
** used by Lua. (It is signed due to the use of debt in several
|
||||||
|
** computations.) 'lu_mem' is a corresponding unsigned type. Usually,
|
||||||
|
** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines.
|
||||||
|
*/
|
||||||
|
#if defined(LUAI_MEM) /* { external definitions? */
|
||||||
|
typedef LUAI_MEM l_mem;
|
||||||
|
typedef LUAI_UMEM lu_mem;
|
||||||
|
#elif LUAI_IS32INT /* }{ */
|
||||||
|
typedef ptrdiff_t l_mem;
|
||||||
|
typedef size_t lu_mem;
|
||||||
|
#else /* 16-bit ints */ /* }{ */
|
||||||
|
typedef long l_mem;
|
||||||
|
typedef unsigned long lu_mem;
|
||||||
|
#endif /* } */
|
||||||
|
|
||||||
|
#define MAX_LMEM \
|
||||||
|
cast(l_mem, (cast(lu_mem, 1) << (l_numbits(l_mem) - 1)) - 1)
|
||||||
|
|
||||||
|
|
||||||
|
/* chars used as small naturals (so that 'char' is reserved for characters) */
|
||||||
|
typedef unsigned char lu_byte;
|
||||||
|
typedef signed char ls_byte;
|
||||||
|
|
||||||
|
|
||||||
|
/* Type for thread status/error codes */
|
||||||
|
typedef lu_byte TStatus;
|
||||||
|
|
||||||
|
/* The C API still uses 'int' for status/error codes */
|
||||||
|
#define APIstatus(st) cast_int(st)
|
||||||
|
|
||||||
|
/* maximum value for size_t */
|
||||||
|
#define MAX_SIZET ((size_t)(~(size_t)0))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Maximum size for strings and userdata visible for Lua; should be
|
||||||
|
** representable as a lua_Integer and as a size_t.
|
||||||
|
*/
|
||||||
|
#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \
|
||||||
|
: cast_sizet(LUA_MAXINTEGER))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** test whether an unsigned value is a power of 2 (or zero)
|
||||||
|
*/
|
||||||
|
#define ispow2(x) (((x) & ((x) - 1)) == 0)
|
||||||
|
|
||||||
|
|
||||||
|
/* number of chars of a literal string without the ending \0 */
|
||||||
|
#define LL(x) (sizeof(x)/sizeof(char) - 1)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** conversion of pointer to unsigned integer: this is for hashing only;
|
||||||
|
** there is no problem if the integer cannot hold the whole pointer
|
||||||
|
** value. (In strict ISO C this may cause undefined behavior, but no
|
||||||
|
** actual machine seems to bother.)
|
||||||
|
*/
|
||||||
|
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
|
||||||
|
__STDC_VERSION__ >= 199901L
|
||||||
|
#include <stdint.h>
|
||||||
|
#if defined(UINTPTR_MAX) /* even in C99 this type is optional */
|
||||||
|
#define L_P2I uintptr_t
|
||||||
|
#else /* no 'intptr'? */
|
||||||
|
#define L_P2I uintmax_t /* use the largest available integer */
|
||||||
|
#endif
|
||||||
|
#else /* C89 option */
|
||||||
|
#define L_P2I size_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define point2uint(p) cast_uint((L_P2I)(p) & UINT_MAX)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* types of 'usual argument conversions' for lua_Number and lua_Integer */
|
||||||
|
typedef LUAI_UACNUMBER l_uacNumber;
|
||||||
|
typedef LUAI_UACINT l_uacInt;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Internal assertions for in-house debugging
|
||||||
|
*/
|
||||||
|
#if defined LUAI_ASSERT
|
||||||
|
#undef NDEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
#define lua_assert(c) assert(c)
|
||||||
|
#define assert_code(c) c
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(lua_assert)
|
||||||
|
#else
|
||||||
|
#define lua_assert(c) ((void)0)
|
||||||
|
#define assert_code(c) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define check_exp(c,e) (lua_assert(c), (e))
|
||||||
|
/* to avoid problems with conditions too long */
|
||||||
|
#define lua_longassert(c) assert_code((c) ? (void)0 : lua_assert(0))
|
||||||
|
|
||||||
|
|
||||||
|
/* macro to avoid warnings about unused variables */
|
||||||
|
#if !defined(UNUSED)
|
||||||
|
#define UNUSED(x) ((void)(x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* type casts (a macro highlights casts in the code) */
|
||||||
|
#define cast(t, exp) ((t)(exp))
|
||||||
|
|
||||||
|
#define cast_void(i) cast(void, (i))
|
||||||
|
#define cast_voidp(i) cast(void *, (i))
|
||||||
|
#define cast_num(i) cast(lua_Number, (i))
|
||||||
|
#define cast_int(i) cast(int, (i))
|
||||||
|
#define cast_short(i) cast(short, (i))
|
||||||
|
#define cast_uint(i) cast(unsigned int, (i))
|
||||||
|
#define cast_byte(i) cast(lu_byte, (i))
|
||||||
|
#define cast_uchar(i) cast(unsigned char, (i))
|
||||||
|
#define cast_char(i) cast(char, (i))
|
||||||
|
#define cast_charp(i) cast(char *, (i))
|
||||||
|
#define cast_sizet(i) cast(size_t, (i))
|
||||||
|
#define cast_Integer(i) cast(lua_Integer, (i))
|
||||||
|
#define cast_Inst(i) cast(Instruction, (i))
|
||||||
|
|
||||||
|
|
||||||
|
/* cast a signed lua_Integer to lua_Unsigned */
|
||||||
|
#if !defined(l_castS2U)
|
||||||
|
#define l_castS2U(i) ((lua_Unsigned)(i))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** cast a lua_Unsigned to a signed lua_Integer; this cast is
|
||||||
|
** not strict ISO C, but two-complement architectures should
|
||||||
|
** work fine.
|
||||||
|
*/
|
||||||
|
#if !defined(l_castU2S)
|
||||||
|
#define l_castU2S(i) ((lua_Integer)(i))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** cast a size_t to lua_Integer: These casts are always valid for
|
||||||
|
** sizes of Lua objects (see MAX_SIZE)
|
||||||
|
*/
|
||||||
|
#define cast_st2S(sz) ((lua_Integer)(sz))
|
||||||
|
|
||||||
|
/* Cast a ptrdiff_t to size_t, when it is known that the minuend
|
||||||
|
** comes from the subtrahend (the base)
|
||||||
|
*/
|
||||||
|
#define ct_diff2sz(df) ((size_t)(df))
|
||||||
|
|
||||||
|
/* ptrdiff_t to lua_Integer */
|
||||||
|
#define ct_diff2S(df) cast_st2S(ct_diff2sz(df))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Special type equivalent to '(void*)' for functions (to suppress some
|
||||||
|
** warnings when converting function pointers)
|
||||||
|
*/
|
||||||
|
typedef void (*voidf)(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Macro to convert pointer-to-void* to pointer-to-function. This cast
|
||||||
|
** is undefined according to ISO C, but POSIX assumes that it works.
|
||||||
|
** (The '__extension__' in gnu compilers is only to avoid warnings.)
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define cast_func(p) (__extension__ (voidf)(p))
|
||||||
|
#else
|
||||||
|
#define cast_func(p) ((voidf)(p))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** non-return type
|
||||||
|
*/
|
||||||
|
#if !defined(l_noret)
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define l_noret void __attribute__((noreturn))
|
||||||
|
#elif defined(_MSC_VER) && _MSC_VER >= 1200
|
||||||
|
#define l_noret void __declspec(noreturn)
|
||||||
|
#else
|
||||||
|
#define l_noret void
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Inline functions
|
||||||
|
*/
|
||||||
|
#if !defined(LUA_USE_C89)
|
||||||
|
#define l_inline inline
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define l_inline __inline__
|
||||||
|
#else
|
||||||
|
#define l_inline /* empty */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define l_sinline static l_inline
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An unsigned with (at least) 4 bytes
|
||||||
|
*/
|
||||||
|
#if LUAI_IS32INT
|
||||||
|
typedef unsigned int l_uint32;
|
||||||
|
#else
|
||||||
|
typedef unsigned long l_uint32;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The luai_num* macros define the primitive operations over numbers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* floor division (defined as 'floor(a/b)') */
|
||||||
|
#if !defined(luai_numidiv)
|
||||||
|
#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* float division */
|
||||||
|
#if !defined(luai_numdiv)
|
||||||
|
#define luai_numdiv(L,a,b) ((a)/(b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** modulo: defined as 'a - floor(a/b)*b'; the direct computation
|
||||||
|
** using this definition has several problems with rounding errors,
|
||||||
|
** so it is better to use 'fmod'. 'fmod' gives the result of
|
||||||
|
** 'a - trunc(a/b)*b', and therefore must be corrected when
|
||||||
|
** 'trunc(a/b) ~= floor(a/b)'. That happens when the division has a
|
||||||
|
** non-integer negative result: non-integer result is equivalent to
|
||||||
|
** a non-zero remainder 'm'; negative result is equivalent to 'a' and
|
||||||
|
** 'b' with different signs, or 'm' and 'b' with different signs
|
||||||
|
** (as the result 'm' of 'fmod' has the same sign of 'a').
|
||||||
|
*/
|
||||||
|
#if !defined(luai_nummod)
|
||||||
|
#define luai_nummod(L,a,b,m) \
|
||||||
|
{ (void)L; (m) = l_mathop(fmod)(a,b); \
|
||||||
|
if (((m) > 0) ? (b) < 0 : ((m) < 0 && (b) > 0)) (m) += (b); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* exponentiation */
|
||||||
|
#if !defined(luai_numpow)
|
||||||
|
#define luai_numpow(L,a,b) \
|
||||||
|
((void)L, (b == 2) ? (a)*(a) : l_mathop(pow)(a,b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* the others are quite standard operations */
|
||||||
|
#if !defined(luai_numadd)
|
||||||
|
#define luai_numadd(L,a,b) ((a)+(b))
|
||||||
|
#define luai_numsub(L,a,b) ((a)-(b))
|
||||||
|
#define luai_nummul(L,a,b) ((a)*(b))
|
||||||
|
#define luai_numunm(L,a) (-(a))
|
||||||
|
#define luai_numeq(a,b) ((a)==(b))
|
||||||
|
#define luai_numlt(a,b) ((a)<(b))
|
||||||
|
#define luai_numle(a,b) ((a)<=(b))
|
||||||
|
#define luai_numgt(a,b) ((a)>(b))
|
||||||
|
#define luai_numge(a,b) ((a)>=(b))
|
||||||
|
#define luai_numisnan(a) (!luai_numeq((a), (a)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** lua_numbertointeger converts a float number with an integral value
|
||||||
|
** to an integer, or returns 0 if the float is not within the range of
|
||||||
|
** a lua_Integer. (The range comparisons are tricky because of
|
||||||
|
** rounding. The tests here assume a two-complement representation,
|
||||||
|
** where MININTEGER always has an exact representation as a float;
|
||||||
|
** MAXINTEGER may not have one, and therefore its conversion to float
|
||||||
|
** may have an ill-defined value.)
|
||||||
|
*/
|
||||||
|
#define lua_numbertointeger(n,p) \
|
||||||
|
((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
|
||||||
|
(n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
|
||||||
|
(*(p) = (LUA_INTEGER)(n), 1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** LUAI_FUNC is a mark for all extern functions that are not to be
|
||||||
|
** exported to outside modules.
|
||||||
|
** LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables,
|
||||||
|
** none of which to be exported to outside modules (LUAI_DDEF for
|
||||||
|
** definitions and LUAI_DDEC for declarations).
|
||||||
|
** Elf and MACH/gcc (versions 3.2 and later) mark them as "hidden" to
|
||||||
|
** optimize access when Lua is compiled as a shared library. Not all elf
|
||||||
|
** targets support this attribute. Unfortunately, gcc does not offer
|
||||||
|
** a way to check whether the target offers that support, and those
|
||||||
|
** without support give a warning about it. To avoid these warnings,
|
||||||
|
** change to the default definition.
|
||||||
|
*/
|
||||||
|
#if !defined(LUAI_FUNC)
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
|
||||||
|
(defined(__ELF__) || defined(__MACH__))
|
||||||
|
#define LUAI_FUNC __attribute__((visibility("internal"))) extern
|
||||||
|
#else
|
||||||
|
#define LUAI_FUNC extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LUAI_DDEC(dec) LUAI_FUNC dec
|
||||||
|
#define LUAI_DDEF /* empty */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Give these macros simpler names for internal use */
|
||||||
|
#define l_likely(x) luai_likely(x)
|
||||||
|
#define l_unlikely(x) luai_unlikely(x)
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {==================================================================
|
||||||
|
** "Abstraction Layer" for basic report of messages and errors
|
||||||
|
** ===================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* print a string */
|
||||||
|
#if !defined(lua_writestring)
|
||||||
|
#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* print a newline and flush the output */
|
||||||
|
#if !defined(lua_writeline)
|
||||||
|
#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* print an error message */
|
||||||
|
#if !defined(lua_writestringerror)
|
||||||
|
#define lua_writestringerror(s,p) \
|
||||||
|
(fprintf(stderr, (s), (p)), fflush(stderr))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* }================================================================== */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+88
-87
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
#undef PI
|
#undef PI
|
||||||
@@ -37,31 +38,37 @@ static int math_abs (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_sin (lua_State *L) {
|
static int math_sin (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_cos (lua_State *L) {
|
static int math_cos (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_tan (lua_State *L) {
|
static int math_tan (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_asin (lua_State *L) {
|
static int math_asin (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_acos (lua_State *L) {
|
static int math_acos (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_atan (lua_State *L) {
|
static int math_atan (lua_State *L) {
|
||||||
lua_Number y = luaL_checknumber(L, 1);
|
lua_Number y = luaL_checknumber(L, 1);
|
||||||
lua_Number x = luaL_optnumber(L, 2, 1);
|
lua_Number x = luaL_optnumber(L, 2, 1);
|
||||||
@@ -105,7 +112,7 @@ static int math_floor (lua_State *L) {
|
|||||||
|
|
||||||
static int math_ceil (lua_State *L) {
|
static int math_ceil (lua_State *L) {
|
||||||
if (lua_isinteger(L, 1))
|
if (lua_isinteger(L, 1))
|
||||||
lua_settop(L, 1); /* integer is its own ceil */
|
lua_settop(L, 1); /* integer is its own ceiling */
|
||||||
else {
|
else {
|
||||||
lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1));
|
lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1));
|
||||||
pushnumint(L, d);
|
pushnumint(L, d);
|
||||||
@@ -166,6 +173,7 @@ static int math_ult (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_log (lua_State *L) {
|
static int math_log (lua_State *L) {
|
||||||
lua_Number x = luaL_checknumber(L, 1);
|
lua_Number x = luaL_checknumber(L, 1);
|
||||||
lua_Number res;
|
lua_Number res;
|
||||||
@@ -187,22 +195,42 @@ static int math_log (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_exp (lua_State *L) {
|
static int math_exp (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_deg (lua_State *L) {
|
static int math_deg (lua_State *L) {
|
||||||
lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI));
|
lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_rad (lua_State *L) {
|
static int math_rad (lua_State *L) {
|
||||||
lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0)));
|
lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int math_frexp (lua_State *L) {
|
||||||
|
lua_Number x = luaL_checknumber(L, 1);
|
||||||
|
int ep;
|
||||||
|
lua_pushnumber(L, l_mathop(frexp)(x, &ep));
|
||||||
|
lua_pushinteger(L, ep);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int math_ldexp (lua_State *L) {
|
||||||
|
lua_Number x = luaL_checknumber(L, 1);
|
||||||
|
int ep = (int)luaL_checkinteger(L, 2);
|
||||||
|
lua_pushnumber(L, l_mathop(ldexp)(x, ep));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_min (lua_State *L) {
|
static int math_min (lua_State *L) {
|
||||||
int n = lua_gettop(L); /* number of arguments */
|
int n = lua_gettop(L); /* number of arguments */
|
||||||
int imin = 1; /* index of current minimum value */
|
int imin = 1; /* index of current minimum value */
|
||||||
@@ -249,6 +277,15 @@ static int math_type (lua_State *L) {
|
|||||||
** ===================================================================
|
** ===================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This code uses lots of shifts. ISO C does not allow shifts greater
|
||||||
|
** than or equal to the width of the type being shifted, so some shifts
|
||||||
|
** are written in convoluted ways to match that restriction. For
|
||||||
|
** preprocessor tests, it assumes a width of 32 bits, so the maximum
|
||||||
|
** shift there is 31 bits.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* number of binary digits in the mantissa of a float */
|
/* number of binary digits in the mantissa of a float */
|
||||||
#define FIGS l_floatatt(MANT_DIG)
|
#define FIGS l_floatatt(MANT_DIG)
|
||||||
|
|
||||||
@@ -267,20 +304,23 @@ static int math_type (lua_State *L) {
|
|||||||
|
|
||||||
/* try to find an integer type with at least 64 bits */
|
/* try to find an integer type with at least 64 bits */
|
||||||
|
|
||||||
#if (ULONG_MAX >> 31 >> 31) >= 3
|
#if ((ULONG_MAX >> 31) >> 31) >= 3
|
||||||
|
|
||||||
/* 'long' has at least 64 bits */
|
/* 'long' has at least 64 bits */
|
||||||
#define Rand64 unsigned long
|
#define Rand64 unsigned long
|
||||||
|
#define SRand64 long
|
||||||
|
|
||||||
#elif !defined(LUA_USE_C89) && defined(LLONG_MAX)
|
#elif !defined(LUA_USE_C89) && defined(LLONG_MAX)
|
||||||
|
|
||||||
/* there is a 'long long' type (which must have at least 64 bits) */
|
/* there is a 'long long' type (which must have at least 64 bits) */
|
||||||
#define Rand64 unsigned long long
|
#define Rand64 unsigned long long
|
||||||
|
#define SRand64 long long
|
||||||
|
|
||||||
#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3
|
#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
|
||||||
|
|
||||||
/* 'lua_Integer' has at least 64 bits */
|
/* 'lua_Unsigned' has at least 64 bits */
|
||||||
#define Rand64 lua_Unsigned
|
#define Rand64 lua_Unsigned
|
||||||
|
#define SRand64 lua_Integer
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -319,23 +359,30 @@ static Rand64 nextrand (Rand64 *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* must take care to not shift stuff by more than 63 slots */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Convert bits from a random integer into a float in the
|
** Convert bits from a random integer into a float in the
|
||||||
** interval [0,1), getting the higher FIG bits from the
|
** interval [0,1), getting the higher FIG bits from the
|
||||||
** random unsigned integer and converting that to a float.
|
** random unsigned integer and converting that to a float.
|
||||||
|
** Some old Microsoft compilers cannot cast an unsigned long
|
||||||
|
** to a floating-point number, so we use a signed long as an
|
||||||
|
** intermediary. When lua_Number is float or double, the shift ensures
|
||||||
|
** that 'sx' is non negative; in that case, a good compiler will remove
|
||||||
|
** the correction.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* must throw out the extra (64 - FIGS) bits */
|
/* must throw out the extra (64 - FIGS) bits */
|
||||||
#define shift64_FIG (64 - FIGS)
|
#define shift64_FIG (64 - FIGS)
|
||||||
|
|
||||||
/* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */
|
/* 2^(-FIGS) == 2^-1 / 2^(FIGS-1) */
|
||||||
#define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1)))
|
#define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1)))
|
||||||
|
|
||||||
static lua_Number I2d (Rand64 x) {
|
static lua_Number I2d (Rand64 x) {
|
||||||
return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG;
|
SRand64 sx = (SRand64)(trim64(x) >> shift64_FIG);
|
||||||
|
lua_Number res = (lua_Number)(sx) * scaleFIG;
|
||||||
|
if (sx < 0)
|
||||||
|
res += l_mathop(1.0); /* correct the two's complement if negative */
|
||||||
|
lua_assert(0 <= res && res < 1);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert a 'Rand64' to a 'lua_Unsigned' */
|
/* convert a 'Rand64' to a 'lua_Unsigned' */
|
||||||
@@ -347,25 +394,17 @@ static lua_Number I2d (Rand64 x) {
|
|||||||
|
|
||||||
#else /* no 'Rand64' }{ */
|
#else /* no 'Rand64' }{ */
|
||||||
|
|
||||||
/* get an integer with at least 32 bits */
|
|
||||||
#if LUAI_IS32INT
|
|
||||||
typedef unsigned int lu_int32;
|
|
||||||
#else
|
|
||||||
typedef unsigned long lu_int32;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Use two 32-bit integers to represent a 64-bit quantity.
|
** Use two 32-bit integers to represent a 64-bit quantity.
|
||||||
*/
|
*/
|
||||||
typedef struct Rand64 {
|
typedef struct Rand64 {
|
||||||
lu_int32 h; /* higher half */
|
l_uint32 h; /* higher half */
|
||||||
lu_int32 l; /* lower half */
|
l_uint32 l; /* lower half */
|
||||||
} Rand64;
|
} Rand64;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If 'lu_int32' has more than 32 bits, the extra bits do not interfere
|
** If 'l_uint32' has more than 32 bits, the extra bits do not interfere
|
||||||
** with the 32 initial bits, except in a right shift and comparisons.
|
** with the 32 initial bits, except in a right shift and comparisons.
|
||||||
** Moreover, the final result has to discard the extra bits.
|
** Moreover, the final result has to discard the extra bits.
|
||||||
*/
|
*/
|
||||||
@@ -379,7 +418,7 @@ typedef struct Rand64 {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* build a new Rand64 value */
|
/* build a new Rand64 value */
|
||||||
static Rand64 packI (lu_int32 h, lu_int32 l) {
|
static Rand64 packI (l_uint32 h, l_uint32 l) {
|
||||||
Rand64 result;
|
Rand64 result;
|
||||||
result.h = h;
|
result.h = h;
|
||||||
result.l = l;
|
result.l = l;
|
||||||
@@ -452,7 +491,7 @@ static Rand64 nextrand (Rand64 *state) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* an unsigned 1 with proper type */
|
/* an unsigned 1 with proper type */
|
||||||
#define UONE ((lu_int32)1)
|
#define UONE ((l_uint32)1)
|
||||||
|
|
||||||
|
|
||||||
#if FIGS <= 32
|
#if FIGS <= 32
|
||||||
@@ -471,11 +510,9 @@ static lua_Number I2d (Rand64 x) {
|
|||||||
|
|
||||||
#else /* 32 < FIGS <= 64 */
|
#else /* 32 < FIGS <= 64 */
|
||||||
|
|
||||||
/* must take care to not shift stuff by more than 31 slots */
|
|
||||||
|
|
||||||
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
|
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
|
||||||
#define scaleFIG \
|
#define scaleFIG \
|
||||||
((lua_Number)1.0 / (UONE << 30) / 8.0 / (UONE << (FIGS - 33)))
|
(l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33)))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** use FIGS - 32 bits from lower half, throwing out the other
|
** use FIGS - 32 bits from lower half, throwing out the other
|
||||||
@@ -486,7 +523,7 @@ static lua_Number I2d (Rand64 x) {
|
|||||||
/*
|
/*
|
||||||
** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32)
|
** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32)
|
||||||
*/
|
*/
|
||||||
#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * 2.0)
|
#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * l_mathop(2.0))
|
||||||
|
|
||||||
|
|
||||||
static lua_Number I2d (Rand64 x) {
|
static lua_Number I2d (Rand64 x) {
|
||||||
@@ -500,12 +537,12 @@ static lua_Number I2d (Rand64 x) {
|
|||||||
|
|
||||||
/* convert a 'Rand64' to a 'lua_Unsigned' */
|
/* convert a 'Rand64' to a 'lua_Unsigned' */
|
||||||
static lua_Unsigned I2UInt (Rand64 x) {
|
static lua_Unsigned I2UInt (Rand64 x) {
|
||||||
return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l);
|
return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert a 'lua_Unsigned' to a 'Rand64' */
|
/* convert a 'lua_Unsigned' to a 'Rand64' */
|
||||||
static Rand64 Int2I (lua_Unsigned n) {
|
static Rand64 Int2I (lua_Unsigned n) {
|
||||||
return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n);
|
return packI((l_uint32)((n >> 31) >> 1), (l_uint32)n);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
@@ -523,7 +560,7 @@ typedef struct {
|
|||||||
** Project the random integer 'ran' into the interval [0, n].
|
** Project the random integer 'ran' into the interval [0, n].
|
||||||
** Because 'ran' has 2^B possible values, the projection can only be
|
** Because 'ran' has 2^B possible values, the projection can only be
|
||||||
** uniform when the size of the interval is a power of 2 (exact
|
** uniform when the size of the interval is a power of 2 (exact
|
||||||
** division). Otherwise, to get a uniform projection into [0, n], we
|
** division). So, to get a uniform projection into [0, n], we
|
||||||
** first compute 'lim', the smallest Mersenne number not smaller than
|
** first compute 'lim', the smallest Mersenne number not smaller than
|
||||||
** 'n'. We then project 'ran' into the interval [0, lim]. If the result
|
** 'n'. We then project 'ran' into the interval [0, lim]. If the result
|
||||||
** is inside [0, n], we are done. Otherwise, we try with another 'ran',
|
** is inside [0, n], we are done. Otherwise, we try with another 'ran',
|
||||||
@@ -531,26 +568,14 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n,
|
static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n,
|
||||||
RanState *state) {
|
RanState *state) {
|
||||||
if ((n & (n + 1)) == 0) /* is 'n + 1' a power of 2? */
|
lua_Unsigned lim = n; /* to compute the Mersenne number */
|
||||||
return ran & n; /* no bias */
|
int sh; /* how much to spread bits to the right in 'lim' */
|
||||||
else {
|
/* spread '1' bits in 'lim' until it becomes a Mersenne number */
|
||||||
lua_Unsigned lim = n;
|
for (sh = 1; (lim & (lim + 1)) != 0; sh *= 2)
|
||||||
/* compute the smallest (2^b - 1) not smaller than 'n' */
|
lim |= (lim >> sh); /* spread '1's to the right */
|
||||||
lim |= (lim >> 1);
|
while ((ran &= lim) > n) /* project 'ran' into [0..lim] and test */
|
||||||
lim |= (lim >> 2);
|
ran = I2UInt(nextrand(state->s)); /* not inside [0..n]? try again */
|
||||||
lim |= (lim >> 4);
|
return ran;
|
||||||
lim |= (lim >> 8);
|
|
||||||
lim |= (lim >> 16);
|
|
||||||
#if (LUA_MAXUNSIGNED >> 31) >= 3
|
|
||||||
lim |= (lim >> 32); /* integer type has more than 32 bits */
|
|
||||||
#endif
|
|
||||||
lua_assert((lim & (lim + 1)) == 0 /* 'lim + 1' is a power of 2, */
|
|
||||||
&& lim >= n /* not smaller than 'n', */
|
|
||||||
&& (lim >> 1) < n); /* and it is the smallest one */
|
|
||||||
while ((ran &= lim) > n) /* project 'ran' into [0..lim] */
|
|
||||||
ran = I2UInt(nextrand(state->s)); /* not inside [0..n]? try again */
|
|
||||||
return ran;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -568,7 +593,7 @@ static int math_random (lua_State *L) {
|
|||||||
low = 1;
|
low = 1;
|
||||||
up = luaL_checkinteger(L, 1);
|
up = luaL_checkinteger(L, 1);
|
||||||
if (up == 0) { /* single 0 as argument? */
|
if (up == 0) { /* single 0 as argument? */
|
||||||
lua_pushinteger(L, I2UInt(rv)); /* full random integer */
|
lua_pushinteger(L, l_castU2S(I2UInt(rv))); /* full random integer */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -583,8 +608,8 @@ static int math_random (lua_State *L) {
|
|||||||
/* random integer in the interval [low, up] */
|
/* random integer in the interval [low, up] */
|
||||||
luaL_argcheck(L, low <= up, 1, "interval is empty");
|
luaL_argcheck(L, low <= up, 1, "interval is empty");
|
||||||
/* project random integer into the interval [0, up - low] */
|
/* project random integer into the interval [0, up - low] */
|
||||||
p = project(I2UInt(rv), (lua_Unsigned)up - (lua_Unsigned)low, state);
|
p = project(I2UInt(rv), l_castS2U(up) - l_castS2U(low), state);
|
||||||
lua_pushinteger(L, p + (lua_Unsigned)low);
|
lua_pushinteger(L, l_castU2S(p + l_castS2U(low)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,33 +623,23 @@ static void setseed (lua_State *L, Rand64 *state,
|
|||||||
state[3] = Int2I(0);
|
state[3] = Int2I(0);
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
nextrand(state); /* discard initial values to "spread" seed */
|
nextrand(state); /* discard initial values to "spread" seed */
|
||||||
lua_pushinteger(L, n1);
|
lua_pushinteger(L, l_castU2S(n1));
|
||||||
lua_pushinteger(L, n2);
|
lua_pushinteger(L, l_castU2S(n2));
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Set a "random" seed. To get some randomness, use the current time
|
|
||||||
** and the address of 'L' (in case the machine does address space layout
|
|
||||||
** randomization).
|
|
||||||
*/
|
|
||||||
static void randseed (lua_State *L, RanState *state) {
|
|
||||||
lua_Unsigned seed1 = (lua_Unsigned)time(NULL);
|
|
||||||
lua_Unsigned seed2 = (lua_Unsigned)(size_t)L;
|
|
||||||
setseed(L, state->s, seed1, seed2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_randomseed (lua_State *L) {
|
static int math_randomseed (lua_State *L) {
|
||||||
RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1));
|
RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1));
|
||||||
|
lua_Unsigned n1, n2;
|
||||||
if (lua_isnone(L, 1)) {
|
if (lua_isnone(L, 1)) {
|
||||||
randseed(L, state);
|
n1 = luaL_makeseed(L); /* "random" seed */
|
||||||
|
n2 = I2UInt(nextrand(state->s)); /* in case seed is not that random... */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lua_Integer n1 = luaL_checkinteger(L, 1);
|
n1 = l_castS2U(luaL_checkinteger(L, 1));
|
||||||
lua_Integer n2 = luaL_optinteger(L, 2, 0);
|
n2 = l_castS2U(luaL_optinteger(L, 2, 0));
|
||||||
setseed(L, state->s, n1, n2);
|
|
||||||
}
|
}
|
||||||
|
setseed(L, state->s, n1, n2);
|
||||||
return 2; /* return seeds */
|
return 2; /* return seeds */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,7 +656,7 @@ static const luaL_Reg randfuncs[] = {
|
|||||||
*/
|
*/
|
||||||
static void setrandfunc (lua_State *L) {
|
static void setrandfunc (lua_State *L) {
|
||||||
RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0);
|
RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0);
|
||||||
randseed(L, state); /* initialize with a "random" seed */
|
setseed(L, state->s, luaL_makeseed(L), 0); /* initialize with random seed */
|
||||||
lua_pop(L, 2); /* remove pushed seeds */
|
lua_pop(L, 2); /* remove pushed seeds */
|
||||||
luaL_setfuncs(L, randfuncs, 1);
|
luaL_setfuncs(L, randfuncs, 1);
|
||||||
}
|
}
|
||||||
@@ -678,20 +693,6 @@ static int math_pow (lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_frexp (lua_State *L) {
|
|
||||||
int e;
|
|
||||||
lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e));
|
|
||||||
lua_pushinteger(L, e);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int math_ldexp (lua_State *L) {
|
|
||||||
lua_Number x = luaL_checknumber(L, 1);
|
|
||||||
int ep = (int)luaL_checkinteger(L, 2);
|
|
||||||
lua_pushnumber(L, l_mathop(ldexp)(x, ep));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int math_log10 (lua_State *L) {
|
static int math_log10 (lua_State *L) {
|
||||||
lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
|
lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
@@ -714,7 +715,9 @@ static const luaL_Reg mathlib[] = {
|
|||||||
{"tointeger", math_toint},
|
{"tointeger", math_toint},
|
||||||
{"floor", math_floor},
|
{"floor", math_floor},
|
||||||
{"fmod", math_fmod},
|
{"fmod", math_fmod},
|
||||||
|
{"frexp", math_frexp},
|
||||||
{"ult", math_ult},
|
{"ult", math_ult},
|
||||||
|
{"ldexp", math_ldexp},
|
||||||
{"log", math_log},
|
{"log", math_log},
|
||||||
{"max", math_max},
|
{"max", math_max},
|
||||||
{"min", math_min},
|
{"min", math_min},
|
||||||
@@ -730,8 +733,6 @@ static const luaL_Reg mathlib[] = {
|
|||||||
{"sinh", math_sinh},
|
{"sinh", math_sinh},
|
||||||
{"tanh", math_tanh},
|
{"tanh", math_tanh},
|
||||||
{"pow", math_pow},
|
{"pow", math_pow},
|
||||||
{"frexp", math_frexp},
|
|
||||||
{"ldexp", math_ldexp},
|
|
||||||
{"log10", math_log10},
|
{"log10", math_log10},
|
||||||
#endif
|
#endif
|
||||||
/* placeholders */
|
/* placeholders */
|
||||||
+50
-36
@@ -22,25 +22,6 @@
|
|||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
|
|
||||||
|
|
||||||
#if defined(EMERGENCYGCTESTS)
|
|
||||||
/*
|
|
||||||
** First allocation will fail whenever not building initial state.
|
|
||||||
** (This fail will trigger 'tryagain' and a full GC cycle at every
|
|
||||||
** allocation.)
|
|
||||||
*/
|
|
||||||
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
|
|
||||||
if (completestate(g) && ns > 0) /* frees never fail */
|
|
||||||
return NULL; /* fail */
|
|
||||||
else /* normal allocation */
|
|
||||||
return (*g->frealloc)(g->ud, block, os, ns);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** About the realloc function:
|
** About the realloc function:
|
||||||
@@ -60,6 +41,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Macro to call the allocation function.
|
||||||
|
*/
|
||||||
|
#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** When an allocation fails, it will try again after an emergency
|
||||||
|
** collection, except when it cannot run a collection. The GC should
|
||||||
|
** not be called while the state is not fully built, as the collector
|
||||||
|
** is not yet fully initialized. Also, it should not be called when
|
||||||
|
** 'gcstopem' is true, because then the interpreter is in the middle of
|
||||||
|
** a collection step.
|
||||||
|
*/
|
||||||
|
#define cantryagain(g) (completestate(g) && !g->gcstopem)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(EMERGENCYGCTESTS)
|
||||||
|
/*
|
||||||
|
** First allocation will fail except when freeing a block (frees never
|
||||||
|
** fail) and when it cannot try again; this fail will trigger 'tryagain'
|
||||||
|
** and a full GC cycle at every allocation.
|
||||||
|
*/
|
||||||
|
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
|
||||||
|
if (ns > 0 && cantryagain(g))
|
||||||
|
return NULL; /* fail */
|
||||||
|
else /* normal allocation */
|
||||||
|
return callfrealloc(g, block, os, ns);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -77,7 +95,7 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
|
|||||||
|
|
||||||
|
|
||||||
void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
|
void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
|
||||||
int size_elems, int limit, const char *what) {
|
unsigned size_elems, int limit, const char *what) {
|
||||||
void *newblock;
|
void *newblock;
|
||||||
int size = *psize;
|
int size = *psize;
|
||||||
if (nelems + 1 <= size) /* does one extra element still fit? */
|
if (nelems + 1 <= size) /* does one extra element still fit? */
|
||||||
@@ -108,10 +126,10 @@ void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
|
|||||||
** error.
|
** error.
|
||||||
*/
|
*/
|
||||||
void *luaM_shrinkvector_ (lua_State *L, void *block, int *size,
|
void *luaM_shrinkvector_ (lua_State *L, void *block, int *size,
|
||||||
int final_n, int size_elem) {
|
int final_n, unsigned size_elem) {
|
||||||
void *newblock;
|
void *newblock;
|
||||||
size_t oldsize = cast_sizet((*size) * size_elem);
|
size_t oldsize = cast_sizet(*size) * size_elem;
|
||||||
size_t newsize = cast_sizet(final_n * size_elem);
|
size_t newsize = cast_sizet(final_n) * size_elem;
|
||||||
lua_assert(newsize <= oldsize);
|
lua_assert(newsize <= oldsize);
|
||||||
newblock = luaM_saferealloc_(L, block, oldsize, newsize);
|
newblock = luaM_saferealloc_(L, block, oldsize, newsize);
|
||||||
*size = final_n;
|
*size = final_n;
|
||||||
@@ -132,27 +150,23 @@ l_noret luaM_toobig (lua_State *L) {
|
|||||||
void luaM_free_ (lua_State *L, void *block, size_t osize) {
|
void luaM_free_ (lua_State *L, void *block, size_t osize) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
lua_assert((osize == 0) == (block == NULL));
|
lua_assert((osize == 0) == (block == NULL));
|
||||||
(*g->frealloc)(g->ud, block, osize, 0);
|
callfrealloc(g, block, osize, 0);
|
||||||
g->GCdebt -= osize;
|
g->GCdebt += cast(l_mem, osize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** In case of allocation fail, this function will do an emergency
|
** In case of allocation fail, this function will do an emergency
|
||||||
** collection to free some memory and then try the allocation again.
|
** collection to free some memory and then try the allocation again.
|
||||||
** The GC should not be called while state is not fully built, as the
|
|
||||||
** collector is not yet fully initialized. Also, it should not be called
|
|
||||||
** when 'gcstopem' is true, because then the interpreter is in the
|
|
||||||
** middle of a collection step.
|
|
||||||
*/
|
*/
|
||||||
static void *tryagain (lua_State *L, void *block,
|
static void *tryagain (lua_State *L, void *block,
|
||||||
size_t osize, size_t nsize) {
|
size_t osize, size_t nsize) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
if (completestate(g) && !g->gcstopem) {
|
if (cantryagain(g)) {
|
||||||
luaC_fullgc(L, 1); /* try to free some memory... */
|
luaC_fullgc(L, 1); /* try to free some memory... */
|
||||||
return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
|
return callfrealloc(g, block, osize, nsize); /* try again */
|
||||||
}
|
}
|
||||||
else return NULL; /* cannot free any memory without a full state */
|
else return NULL; /* cannot run an emergency collection */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -170,7 +184,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
|
|||||||
return NULL; /* do not update 'GCdebt' */
|
return NULL; /* do not update 'GCdebt' */
|
||||||
}
|
}
|
||||||
lua_assert((nsize == 0) == (newblock == NULL));
|
lua_assert((nsize == 0) == (newblock == NULL));
|
||||||
g->GCdebt = (g->GCdebt + nsize) - osize;
|
g->GCdebt -= cast(l_mem, nsize) - cast(l_mem, osize);
|
||||||
return newblock;
|
return newblock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,13 +203,13 @@ void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
|
|||||||
return NULL; /* that's all */
|
return NULL; /* that's all */
|
||||||
else {
|
else {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
void *newblock = firsttry(g, NULL, tag, size);
|
void *newblock = firsttry(g, NULL, cast_sizet(tag), size);
|
||||||
if (l_unlikely(newblock == NULL)) {
|
if (l_unlikely(newblock == NULL)) {
|
||||||
newblock = tryagain(L, NULL, tag, size);
|
newblock = tryagain(L, NULL, cast_sizet(tag), size);
|
||||||
if (newblock == NULL)
|
if (newblock == NULL)
|
||||||
luaM_error(L);
|
luaM_error(L);
|
||||||
}
|
}
|
||||||
g->GCdebt += size;
|
g->GCdebt -= cast(l_mem, size);
|
||||||
return newblock;
|
return newblock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+8
-5
@@ -39,11 +39,11 @@
|
|||||||
** Computes the minimum between 'n' and 'MAX_SIZET/sizeof(t)', so that
|
** Computes the minimum between 'n' and 'MAX_SIZET/sizeof(t)', so that
|
||||||
** the result is not larger than 'n' and cannot overflow a 'size_t'
|
** the result is not larger than 'n' and cannot overflow a 'size_t'
|
||||||
** when multiplied by the size of type 't'. (Assumes that 'n' is an
|
** when multiplied by the size of type 't'. (Assumes that 'n' is an
|
||||||
** 'int' or 'unsigned int' and that 'int' is not larger than 'size_t'.)
|
** 'int' and that 'int' is not larger than 'size_t'.)
|
||||||
*/
|
*/
|
||||||
#define luaM_limitN(n,t) \
|
#define luaM_limitN(n,t) \
|
||||||
((cast_sizet(n) <= MAX_SIZET/sizeof(t)) ? (n) : \
|
((cast_sizet(n) <= MAX_SIZET/sizeof(t)) ? (n) : \
|
||||||
cast_uint((MAX_SIZET/sizeof(t))))
|
cast_int((MAX_SIZET/sizeof(t))))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -57,12 +57,15 @@
|
|||||||
#define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b)))
|
#define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b)))
|
||||||
|
|
||||||
#define luaM_new(L,t) cast(t*, luaM_malloc_(L, sizeof(t), 0))
|
#define luaM_new(L,t) cast(t*, luaM_malloc_(L, sizeof(t), 0))
|
||||||
#define luaM_newvector(L,n,t) cast(t*, luaM_malloc_(L, (n)*sizeof(t), 0))
|
#define luaM_newvector(L,n,t) \
|
||||||
|
cast(t*, luaM_malloc_(L, cast_sizet(n)*sizeof(t), 0))
|
||||||
#define luaM_newvectorchecked(L,n,t) \
|
#define luaM_newvectorchecked(L,n,t) \
|
||||||
(luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t))
|
(luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t))
|
||||||
|
|
||||||
#define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag)
|
#define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag)
|
||||||
|
|
||||||
|
#define luaM_newblock(L, size) luaM_newvector(L, size, char)
|
||||||
|
|
||||||
#define luaM_growvector(L,v,nelems,size,t,limit,e) \
|
#define luaM_growvector(L,v,nelems,size,t,limit,e) \
|
||||||
((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \
|
((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \
|
||||||
luaM_limitN(limit,t),e)))
|
luaM_limitN(limit,t),e)))
|
||||||
@@ -83,10 +86,10 @@ LUAI_FUNC void *luaM_saferealloc_ (lua_State *L, void *block, size_t oldsize,
|
|||||||
size_t size);
|
size_t size);
|
||||||
LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize);
|
LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize);
|
||||||
LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems,
|
LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems,
|
||||||
int *size, int size_elem, int limit,
|
int *size, unsigned size_elem, int limit,
|
||||||
const char *what);
|
const char *what);
|
||||||
LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem,
|
LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem,
|
||||||
int final_n, int size_elem);
|
int final_n, unsigned size_elem);
|
||||||
LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag);
|
LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+65
-79
@@ -22,15 +22,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
/*
|
|
||||||
** LUA_IGMARK is a mark to ignore all before it when building the
|
|
||||||
** luaopen_ function name.
|
|
||||||
*/
|
|
||||||
#if !defined (LUA_IGMARK)
|
|
||||||
#define LUA_IGMARK "-"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -67,11 +59,8 @@ static const char *const CLIBS = "_CLIBS";
|
|||||||
#define setprogdir(L) ((void)0)
|
#define setprogdir(L) ((void)0)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/* cast void* to a Lua function */
|
||||||
** Special type equivalent to '(void*)' for functions in gcc
|
#define cast_Lfunc(p) cast(lua_CFunction, cast_func(p))
|
||||||
** (to suppress warnings when converting function pointers)
|
|
||||||
*/
|
|
||||||
typedef void (*voidf)(void);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -104,26 +93,13 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym);
|
|||||||
#if defined(LUA_USE_DLOPEN) /* { */
|
#if defined(LUA_USE_DLOPEN) /* { */
|
||||||
/*
|
/*
|
||||||
** {========================================================================
|
** {========================================================================
|
||||||
** This is an implementation of loadlib based on the dlfcn interface.
|
** This is an implementation of loadlib based on the dlfcn interface,
|
||||||
** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
|
** which is available in all POSIX systems.
|
||||||
** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
|
|
||||||
** as an emulation layer on top of native functions.
|
|
||||||
** =========================================================================
|
** =========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
/*
|
|
||||||
** Macro to convert pointer-to-void* to pointer-to-function. This cast
|
|
||||||
** is undefined according to ISO C, but POSIX assumes that it works.
|
|
||||||
** (The '__extension__' in gnu compilers is only to avoid warnings.)
|
|
||||||
*/
|
|
||||||
#if defined(__GNUC__)
|
|
||||||
#define cast_func(p) (__extension__ (lua_CFunction)(p))
|
|
||||||
#else
|
|
||||||
#define cast_func(p) ((lua_CFunction)(p))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static void lsys_unloadlib (void *lib) {
|
static void lsys_unloadlib (void *lib) {
|
||||||
dlclose(lib);
|
dlclose(lib);
|
||||||
@@ -139,7 +115,7 @@ static void *lsys_load (lua_State *L, const char *path, int seeglb) {
|
|||||||
|
|
||||||
|
|
||||||
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
||||||
lua_CFunction f = cast_func(dlsym(lib, sym));
|
lua_CFunction f = cast_Lfunc(dlsym(lib, sym));
|
||||||
if (l_unlikely(f == NULL))
|
if (l_unlikely(f == NULL))
|
||||||
lua_pushstring(L, dlerror());
|
lua_pushstring(L, dlerror());
|
||||||
return f;
|
return f;
|
||||||
@@ -215,7 +191,7 @@ static void *lsys_load (lua_State *L, const char *path, int seeglb) {
|
|||||||
|
|
||||||
|
|
||||||
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
|
||||||
lua_CFunction f = (lua_CFunction)(voidf)GetProcAddress((HMODULE)lib, sym);
|
lua_CFunction f = cast_Lfunc(GetProcAddress((HMODULE)lib, sym));
|
||||||
if (f == NULL) pusherror(L);
|
if (f == NULL) pusherror(L);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
@@ -292,7 +268,8 @@ static int noenv (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Set a path
|
** Set a path. (If using the default path, assume it is a string
|
||||||
|
** literal in C and create it as an external string.)
|
||||||
*/
|
*/
|
||||||
static void setpath (lua_State *L, const char *fieldname,
|
static void setpath (lua_State *L, const char *fieldname,
|
||||||
const char *envname,
|
const char *envname,
|
||||||
@@ -303,7 +280,7 @@ static void setpath (lua_State *L, const char *fieldname,
|
|||||||
if (path == NULL) /* no versioned environment variable? */
|
if (path == NULL) /* no versioned environment variable? */
|
||||||
path = getenv(envname); /* try unversioned name */
|
path = getenv(envname); /* try unversioned name */
|
||||||
if (path == NULL || noenv(L)) /* no environment variable? */
|
if (path == NULL || noenv(L)) /* no environment variable? */
|
||||||
lua_pushstring(L, dft); /* use default */
|
lua_pushexternalstring(L, dft, strlen(dft), NULL, NULL); /* use default */
|
||||||
else if ((dftmark = strstr(path, LUA_PATH_SEP LUA_PATH_SEP)) == NULL)
|
else if ((dftmark = strstr(path, LUA_PATH_SEP LUA_PATH_SEP)) == NULL)
|
||||||
lua_pushstring(L, path); /* nothing to change */
|
lua_pushstring(L, path); /* nothing to change */
|
||||||
else { /* path contains a ";;": insert default path in its place */
|
else { /* path contains a ";;": insert default path in its place */
|
||||||
@@ -311,13 +288,13 @@ static void setpath (lua_State *L, const char *fieldname,
|
|||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
if (path < dftmark) { /* is there a prefix before ';;'? */
|
if (path < dftmark) { /* is there a prefix before ';;'? */
|
||||||
luaL_addlstring(&b, path, dftmark - path); /* add it */
|
luaL_addlstring(&b, path, ct_diff2sz(dftmark - path)); /* add it */
|
||||||
luaL_addchar(&b, *LUA_PATH_SEP);
|
luaL_addchar(&b, *LUA_PATH_SEP);
|
||||||
}
|
}
|
||||||
luaL_addstring(&b, dft); /* add default */
|
luaL_addstring(&b, dft); /* add default */
|
||||||
if (dftmark < path + len - 2) { /* is there a suffix after ';;'? */
|
if (dftmark < path + len - 2) { /* is there a suffix after ';;'? */
|
||||||
luaL_addchar(&b, *LUA_PATH_SEP);
|
luaL_addchar(&b, *LUA_PATH_SEP);
|
||||||
luaL_addlstring(&b, dftmark + 2, (path + len - 2) - dftmark);
|
luaL_addlstring(&b, dftmark + 2, ct_diff2sz((path + len - 2) - dftmark));
|
||||||
}
|
}
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
}
|
}
|
||||||
@@ -329,6 +306,16 @@ static void setpath (lua_State *L, const char *fieldname,
|
|||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** External strings created by DLLs may need the DLL code to be
|
||||||
|
** deallocated. This implies that a DLL can only be unloaded after all
|
||||||
|
** its strings were deallocated. To ensure that, we create a 'library
|
||||||
|
** string' to represent each DLL, and when this string is deallocated
|
||||||
|
** it closes its corresponding DLL.
|
||||||
|
** (The string itself is irrelevant; its userdata is the DLL pointer.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** return registry.CLIBS[path]
|
** return registry.CLIBS[path]
|
||||||
*/
|
*/
|
||||||
@@ -343,34 +330,41 @@ static void *checkclib (lua_State *L, const char *path) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** registry.CLIBS[path] = plib -- for queries
|
** Deallocate function for library strings.
|
||||||
** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries
|
** Unload the DLL associated with the string being deallocated.
|
||||||
*/
|
*/
|
||||||
static void addtoclib (lua_State *L, const char *path, void *plib) {
|
static void *freelib (void *ud, void *ptr, size_t osize, size_t nsize) {
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
|
/* string itself is irrelevant and static */
|
||||||
lua_pushlightuserdata(L, plib);
|
(void)ptr; (void)osize; (void)nsize;
|
||||||
lua_pushvalue(L, -1);
|
lsys_unloadlib(ud); /* unload library represented by the string */
|
||||||
lua_setfield(L, -3, path); /* CLIBS[path] = plib */
|
return NULL;
|
||||||
lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */
|
|
||||||
lua_pop(L, 1); /* pop CLIBS table */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib
|
** Create a library string that, when deallocated, will unload 'plib'
|
||||||
** handles in list CLIBS
|
|
||||||
*/
|
*/
|
||||||
static int gctm (lua_State *L) {
|
static void createlibstr (lua_State *L, void *plib) {
|
||||||
lua_Integer n = luaL_len(L, 1);
|
/* common content for all library strings */
|
||||||
for (; n >= 1; n--) { /* for each handle, in reverse order */
|
static const char dummy[] = "01234567890";
|
||||||
lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */
|
lua_pushexternalstring(L, dummy, sizeof(dummy) - 1, freelib, plib);
|
||||||
lsys_unloadlib(lua_touserdata(L, -1));
|
|
||||||
lua_pop(L, 1); /* pop handle */
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** registry.CLIBS[path] = plib -- for queries.
|
||||||
|
** Also create a reference to strlib, so that the library string will
|
||||||
|
** only be collected when registry.CLIBS is collected.
|
||||||
|
*/
|
||||||
|
static void addtoclib (lua_State *L, const char *path, void *plib) {
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
|
||||||
|
lua_pushlightuserdata(L, plib);
|
||||||
|
lua_setfield(L, -2, path); /* CLIBS[path] = plib */
|
||||||
|
createlibstr(L, plib);
|
||||||
|
luaL_ref(L, -2); /* keep library string in CLIBS */
|
||||||
|
lua_pop(L, 1); /* pop CLIBS table */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* error codes for 'lookforfunc' */
|
/* error codes for 'lookforfunc' */
|
||||||
#define ERRLIB 1
|
#define ERRLIB 1
|
||||||
@@ -384,8 +378,8 @@ static int gctm (lua_State *L) {
|
|||||||
** Then, if 'sym' is '*', return true (as library has been loaded).
|
** Then, if 'sym' is '*', return true (as library has been loaded).
|
||||||
** Otherwise, look for symbol 'sym' in the library and push a
|
** Otherwise, look for symbol 'sym' in the library and push a
|
||||||
** C function with that symbol.
|
** C function with that symbol.
|
||||||
** Return 0 and 'true' or a function in the stack; in case of
|
** Return 0 with 'true' or a function in the stack; in case of
|
||||||
** errors, return an error code and an error message in the stack.
|
** errors, return an error code with an error message in the stack.
|
||||||
*/
|
*/
|
||||||
static int lookforfunc (lua_State *L, const char *path, const char *sym) {
|
static int lookforfunc (lua_State *L, const char *path, const char *sym) {
|
||||||
void *reg = checkclib(L, path); /* check loaded C libraries */
|
void *reg = checkclib(L, path); /* check loaded C libraries */
|
||||||
@@ -566,7 +560,7 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) {
|
|||||||
mark = strchr(modname, *LUA_IGMARK);
|
mark = strchr(modname, *LUA_IGMARK);
|
||||||
if (mark) {
|
if (mark) {
|
||||||
int stat;
|
int stat;
|
||||||
openfunc = lua_pushlstring(L, modname, mark - modname);
|
openfunc = lua_pushlstring(L, modname, ct_diff2sz(mark - modname));
|
||||||
openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc);
|
openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc);
|
||||||
stat = lookforfunc(L, filename, openfunc);
|
stat = lookforfunc(L, filename, openfunc);
|
||||||
if (stat != ERRFUNC) return stat;
|
if (stat != ERRFUNC) return stat;
|
||||||
@@ -591,7 +585,7 @@ static int searcher_Croot (lua_State *L) {
|
|||||||
const char *p = strchr(name, '.');
|
const char *p = strchr(name, '.');
|
||||||
int stat;
|
int stat;
|
||||||
if (p == NULL) return 0; /* is root */
|
if (p == NULL) return 0; /* is root */
|
||||||
lua_pushlstring(L, name, p - name);
|
lua_pushlstring(L, name, ct_diff2sz(p - name));
|
||||||
filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP);
|
filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP);
|
||||||
if (filename == NULL) return 1; /* root not found */
|
if (filename == NULL) return 1; /* root not found */
|
||||||
if ((stat = loadfunc(L, filename, name)) != 0) {
|
if ((stat = loadfunc(L, filename, name)) != 0) {
|
||||||
@@ -629,12 +623,12 @@ static void findloader (lua_State *L, const char *name) {
|
|||||||
!= LUA_TTABLE))
|
!= LUA_TTABLE))
|
||||||
luaL_error(L, "'package.searchers' must be a table");
|
luaL_error(L, "'package.searchers' must be a table");
|
||||||
luaL_buffinit(L, &msg);
|
luaL_buffinit(L, &msg);
|
||||||
|
luaL_addstring(&msg, "\n\t"); /* error-message prefix for first message */
|
||||||
/* iterate over available searchers to find a loader */
|
/* iterate over available searchers to find a loader */
|
||||||
for (i = 1; ; i++) {
|
for (i = 1; ; i++) {
|
||||||
luaL_addstring(&msg, "\n\t"); /* error-message prefix */
|
|
||||||
if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */
|
if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */
|
||||||
lua_pop(L, 1); /* remove nil */
|
lua_pop(L, 1); /* remove nil */
|
||||||
luaL_buffsub(&msg, 2); /* remove prefix */
|
luaL_buffsub(&msg, 2); /* remove last prefix */
|
||||||
luaL_pushresult(&msg); /* create error message */
|
luaL_pushresult(&msg); /* create error message */
|
||||||
luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1));
|
luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1));
|
||||||
}
|
}
|
||||||
@@ -645,11 +639,10 @@ static void findloader (lua_State *L, const char *name) {
|
|||||||
else if (lua_isstring(L, -2)) { /* searcher returned error message? */
|
else if (lua_isstring(L, -2)) { /* searcher returned error message? */
|
||||||
lua_pop(L, 1); /* remove extra return */
|
lua_pop(L, 1); /* remove extra return */
|
||||||
luaL_addvalue(&msg); /* concatenate error message */
|
luaL_addvalue(&msg); /* concatenate error message */
|
||||||
|
luaL_addstring(&msg, "\n\t"); /* prefix for next message */
|
||||||
}
|
}
|
||||||
else { /* no error message */
|
else /* no error message */
|
||||||
lua_pop(L, 2); /* remove both returns */
|
lua_pop(L, 2); /* remove both returns */
|
||||||
luaL_buffsub(&msg, 2); /* remove prefix */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -818,8 +811,13 @@ static const luaL_Reg ll_funcs[] = {
|
|||||||
|
|
||||||
|
|
||||||
static void createsearcherstable (lua_State *L) {
|
static void createsearcherstable (lua_State *L) {
|
||||||
static const lua_CFunction searchers[] =
|
static const lua_CFunction searchers[] = {
|
||||||
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
|
searcher_preload,
|
||||||
|
searcher_Lua,
|
||||||
|
searcher_C,
|
||||||
|
searcher_Croot,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
int i;
|
int i;
|
||||||
/* create 'searchers' table */
|
/* create 'searchers' table */
|
||||||
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
|
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
|
||||||
@@ -833,21 +831,9 @@ static void createsearcherstable (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** create table CLIBS to keep track of loaded C libraries,
|
|
||||||
** setting a finalizer to close all libraries when closing state.
|
|
||||||
*/
|
|
||||||
static void createclibstable (lua_State *L) {
|
|
||||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */
|
|
||||||
lua_createtable(L, 0, 1); /* create metatable for CLIBS */
|
|
||||||
lua_pushcfunction(L, gctm);
|
|
||||||
lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */
|
|
||||||
lua_setmetatable(L, -2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LUAMOD_API int luaopen_package (lua_State *L) {
|
LUAMOD_API int luaopen_package (lua_State *L) {
|
||||||
createclibstable(L);
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */
|
||||||
|
lua_pop(L, 1); /* will not use it now */
|
||||||
luaL_newlib(L, pk_funcs); /* create 'package' table */
|
luaL_newlib(L, pk_funcs); /* create 'package' table */
|
||||||
createsearcherstable(L);
|
createsearcherstable(L);
|
||||||
/* set paths */
|
/* set paths */
|
||||||
+236
-110
@@ -10,6 +10,7 @@
|
|||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <float.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@@ -30,10 +31,11 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Computes ceil(log2(x))
|
** Computes ceil(log2(x)), which is the smallest integer n such that
|
||||||
|
** x <= (1 << n).
|
||||||
*/
|
*/
|
||||||
int luaO_ceillog2 (unsigned int x) {
|
lu_byte luaO_ceillog2 (unsigned int x) {
|
||||||
static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */
|
static const lu_byte log_2[256] = { /* log_2[i - 1] = ceil(log2(i)) */
|
||||||
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||||
@@ -46,7 +48,67 @@ int luaO_ceillog2 (unsigned int x) {
|
|||||||
int l = 0;
|
int l = 0;
|
||||||
x--;
|
x--;
|
||||||
while (x >= 256) { l += 8; x >>= 8; }
|
while (x >= 256) { l += 8; x >>= 8; }
|
||||||
return l + log_2[x];
|
return cast_byte(l + log_2[x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Encodes 'p'% as a floating-point byte, represented as (eeeexxxx).
|
||||||
|
** The exponent is represented using excess-7. Mimicking IEEE 754, the
|
||||||
|
** representation normalizes the number when possible, assuming an extra
|
||||||
|
** 1 before the mantissa (xxxx) and adding one to the exponent (eeee)
|
||||||
|
** to signal that. So, the real value is (1xxxx) * 2^(eeee - 7 - 1) if
|
||||||
|
** eeee != 0, and (xxxx) * 2^-7 otherwise (subnormal numbers).
|
||||||
|
*/
|
||||||
|
lu_byte luaO_codeparam (unsigned int p) {
|
||||||
|
if (p >= (cast(lu_mem, 0x1F) << (0xF - 7 - 1)) * 100u) /* overflow? */
|
||||||
|
return 0xFF; /* return maximum value */
|
||||||
|
else {
|
||||||
|
p = (cast(l_uint32, p) * 128 + 99) / 100; /* round up the division */
|
||||||
|
if (p < 0x10) { /* subnormal number? */
|
||||||
|
/* exponent bits are already zero; nothing else to do */
|
||||||
|
return cast_byte(p);
|
||||||
|
}
|
||||||
|
else { /* p >= 0x10 implies ceil(log2(p + 1)) >= 5 */
|
||||||
|
/* preserve 5 bits in 'p' */
|
||||||
|
unsigned log = luaO_ceillog2(p + 1) - 5u;
|
||||||
|
return cast_byte(((p >> log) - 0x10) | ((log + 1) << 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Computes 'p' times 'x', where 'p' is a floating-point byte. Roughly,
|
||||||
|
** we have to multiply 'x' by the mantissa and then shift accordingly to
|
||||||
|
** the exponent. If the exponent is positive, both the multiplication
|
||||||
|
** and the shift increase 'x', so we have to care only about overflows.
|
||||||
|
** For negative exponents, however, multiplying before the shift keeps
|
||||||
|
** more significant bits, as long as the multiplication does not
|
||||||
|
** overflow, so we check which order is best.
|
||||||
|
*/
|
||||||
|
l_mem luaO_applyparam (lu_byte p, l_mem x) {
|
||||||
|
int m = p & 0xF; /* mantissa */
|
||||||
|
int e = (p >> 4); /* exponent */
|
||||||
|
if (e > 0) { /* normalized? */
|
||||||
|
e--; /* correct exponent */
|
||||||
|
m += 0x10; /* correct mantissa; maximum value is 0x1F */
|
||||||
|
}
|
||||||
|
e -= 7; /* correct excess-7 */
|
||||||
|
if (e >= 0) {
|
||||||
|
if (x < (MAX_LMEM / 0x1F) >> e) /* no overflow? */
|
||||||
|
return (x * m) << e; /* order doesn't matter here */
|
||||||
|
else /* real overflow */
|
||||||
|
return MAX_LMEM;
|
||||||
|
}
|
||||||
|
else { /* negative exponent */
|
||||||
|
e = -e;
|
||||||
|
if (x < MAX_LMEM / 0x1F) /* multiplication cannot overflow? */
|
||||||
|
return (x * m) >> e; /* multiplying first gives more precision */
|
||||||
|
else if ((x >> e) < MAX_LMEM / 0x1F) /* cannot overflow after shift? */
|
||||||
|
return (x >> e) * m;
|
||||||
|
else /* real overflow */
|
||||||
|
return MAX_LMEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -62,7 +124,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
|
|||||||
case LUA_OPBOR: return intop(|, v1, v2);
|
case LUA_OPBOR: return intop(|, v1, v2);
|
||||||
case LUA_OPBXOR: return intop(^, v1, v2);
|
case LUA_OPBXOR: return intop(^, v1, v2);
|
||||||
case LUA_OPSHL: return luaV_shiftl(v1, v2);
|
case LUA_OPSHL: return luaV_shiftl(v1, v2);
|
||||||
case LUA_OPSHR: return luaV_shiftl(v1, -v2);
|
case LUA_OPSHR: return luaV_shiftr(v1, v2);
|
||||||
case LUA_OPUNM: return intop(-, 0, v1);
|
case LUA_OPUNM: return intop(-, 0, v1);
|
||||||
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
|
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
|
||||||
default: lua_assert(0); return 0;
|
default: lua_assert(0); return 0;
|
||||||
@@ -132,9 +194,10 @@ void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaO_hexavalue (int c) {
|
lu_byte luaO_hexavalue (int c) {
|
||||||
if (lisdigit(c)) return c - '0';
|
lua_assert(lisxdigit(c));
|
||||||
else return (ltolower(c) - 'a') + 10;
|
if (lisdigit(c)) return cast_byte(c - '0');
|
||||||
|
else return cast_byte((ltolower(c) - 'a') + 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -164,7 +227,7 @@ static int isneg (const char **s) {
|
|||||||
*/
|
*/
|
||||||
static lua_Number lua_strx2number (const char *s, char **endptr) {
|
static lua_Number lua_strx2number (const char *s, char **endptr) {
|
||||||
int dot = lua_getlocaledecpoint();
|
int dot = lua_getlocaledecpoint();
|
||||||
lua_Number r = 0.0; /* result (accumulator) */
|
lua_Number r = l_mathop(0.0); /* result (accumulator) */
|
||||||
int sigdig = 0; /* number of significant digits */
|
int sigdig = 0; /* number of significant digits */
|
||||||
int nosigdig = 0; /* number of non-significant digits */
|
int nosigdig = 0; /* number of non-significant digits */
|
||||||
int e = 0; /* exponent correction */
|
int e = 0; /* exponent correction */
|
||||||
@@ -174,7 +237,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
|
|||||||
while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
|
while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
|
||||||
neg = isneg(&s); /* check sign */
|
neg = isneg(&s); /* check sign */
|
||||||
if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
|
if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
|
||||||
return 0.0; /* invalid format (no '0x') */
|
return l_mathop(0.0); /* invalid format (no '0x') */
|
||||||
for (s += 2; ; s++) { /* skip '0x' and read numeral */
|
for (s += 2; ; s++) { /* skip '0x' and read numeral */
|
||||||
if (*s == dot) {
|
if (*s == dot) {
|
||||||
if (hasdot) break; /* second dot? stop loop */
|
if (hasdot) break; /* second dot? stop loop */
|
||||||
@@ -184,14 +247,14 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
|
|||||||
if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */
|
if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */
|
||||||
nosigdig++;
|
nosigdig++;
|
||||||
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
|
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
|
||||||
r = (r * cast_num(16.0)) + luaO_hexavalue(*s);
|
r = (r * l_mathop(16.0)) + luaO_hexavalue(*s);
|
||||||
else e++; /* too many digits; ignore, but still count for exponent */
|
else e++; /* too many digits; ignore, but still count for exponent */
|
||||||
if (hasdot) e--; /* decimal digit? correct exponent */
|
if (hasdot) e--; /* decimal digit? correct exponent */
|
||||||
}
|
}
|
||||||
else break; /* neither a dot nor a digit */
|
else break; /* neither a dot nor a digit */
|
||||||
}
|
}
|
||||||
if (nosigdig + sigdig == 0) /* no digits? */
|
if (nosigdig + sigdig == 0) /* no digits? */
|
||||||
return 0.0; /* invalid format */
|
return l_mathop(0.0); /* invalid format */
|
||||||
*endptr = cast_charp(s); /* valid up to here */
|
*endptr = cast_charp(s); /* valid up to here */
|
||||||
e *= 4; /* each digit multiplies/divides value by 2^4 */
|
e *= 4; /* each digit multiplies/divides value by 2^4 */
|
||||||
if (*s == 'p' || *s == 'P') { /* exponent part? */
|
if (*s == 'p' || *s == 'P') { /* exponent part? */
|
||||||
@@ -200,7 +263,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
|
|||||||
s++; /* skip 'p' */
|
s++; /* skip 'p' */
|
||||||
neg1 = isneg(&s); /* sign */
|
neg1 = isneg(&s); /* sign */
|
||||||
if (!lisdigit(cast_uchar(*s)))
|
if (!lisdigit(cast_uchar(*s)))
|
||||||
return 0.0; /* invalid; must have at least one digit */
|
return l_mathop(0.0); /* invalid; must have at least one digit */
|
||||||
while (lisdigit(cast_uchar(*s))) /* read exponent */
|
while (lisdigit(cast_uchar(*s))) /* read exponent */
|
||||||
exp1 = exp1 * 10 + *(s++) - '0';
|
exp1 = exp1 * 10 + *(s++) - '0';
|
||||||
if (neg1) exp1 = -exp1;
|
if (neg1) exp1 = -exp1;
|
||||||
@@ -292,7 +355,7 @@ static const char *l_str2int (const char *s, lua_Integer *result) {
|
|||||||
int d = *s - '0';
|
int d = *s - '0';
|
||||||
if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
|
if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
|
||||||
return NULL; /* do not accept it (as integer) */
|
return NULL; /* do not accept it (as integer) */
|
||||||
a = a * 10 + d;
|
a = a * 10 + cast_uint(d);
|
||||||
empty = 0;
|
empty = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,14 +379,14 @@ size_t luaO_str2num (const char *s, TValue *o) {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
return 0; /* conversion failed */
|
return 0; /* conversion failed */
|
||||||
return (e - s) + 1; /* success; return string size */
|
return ct_diff2sz(e - s) + 1; /* success; return string size */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaO_utf8esc (char *buff, unsigned long x) {
|
int luaO_utf8esc (char *buff, l_uint32 x) {
|
||||||
int n = 1; /* number of bytes put in buffer (backwards) */
|
int n = 1; /* number of bytes put in buffer (backwards) */
|
||||||
lua_assert(x <= 0x7FFFFFFFu);
|
lua_assert(x <= 0x7FFFFFFFu);
|
||||||
if (x < 0x80) /* ascii? */
|
if (x < 0x80) /* ASCII? */
|
||||||
buff[UTF8BUFFSZ - 1] = cast_char(x);
|
buff[UTF8BUFFSZ - 1] = cast_char(x);
|
||||||
else { /* need continuation bytes */
|
else { /* need continuation bytes */
|
||||||
unsigned int mfb = 0x3f; /* maximum that fits in first byte */
|
unsigned int mfb = 0x3f; /* maximum that fits in first byte */
|
||||||
@@ -339,32 +402,59 @@ int luaO_utf8esc (char *buff, unsigned long x) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Maximum length of the conversion of a number to a string. Must be
|
** The size of the buffer for the conversion of a number to a string
|
||||||
** enough to accommodate both LUA_INTEGER_FMT and LUA_NUMBER_FMT.
|
** 'LUA_N2SBUFFSZ' must be enough to accommodate both LUA_INTEGER_FMT
|
||||||
** (For a long long int, this is 19 digits plus a sign and a final '\0',
|
** and LUA_NUMBER_FMT. For a long long int, this is 19 digits plus a
|
||||||
** adding to 21. For a long double, it can go to a sign, 33 digits,
|
** sign and a final '\0', adding to 21. For a long double, it can go to
|
||||||
** the dot, an exponent letter, an exponent sign, 5 exponent digits,
|
** a sign, the dot, an exponent letter, an exponent sign, 4 exponent
|
||||||
** and a final '\0', adding to 43.)
|
** digits, the final '\0', plus the significant digits, which are
|
||||||
|
** approximately the *_DIG attribute.
|
||||||
*/
|
*/
|
||||||
#define MAXNUMBER2STR 44
|
#if LUA_N2SBUFFSZ < (20 + l_floatatt(DIG))
|
||||||
|
#error "invalid value for LUA_N2SBUFFSZ"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Convert a number object to a string, adding it to a buffer
|
** Convert a float to a string, adding it to a buffer. First try with
|
||||||
|
** a not too large number of digits, to avoid noise (for instance,
|
||||||
|
** 1.1 going to "1.1000000000000001"). If that lose precision, so
|
||||||
|
** that reading the result back gives a different number, then do the
|
||||||
|
** conversion again with extra precision. Moreover, if the numeral looks
|
||||||
|
** like an integer (without a decimal point or an exponent), add ".0" to
|
||||||
|
** its end.
|
||||||
*/
|
*/
|
||||||
static int tostringbuff (TValue *obj, char *buff) {
|
static int tostringbuffFloat (lua_Number n, char *buff) {
|
||||||
|
/* first conversion */
|
||||||
|
int len = l_sprintf(buff, LUA_N2SBUFFSZ, LUA_NUMBER_FMT,
|
||||||
|
(LUAI_UACNUMBER)n);
|
||||||
|
lua_Number check = lua_str2number(buff, NULL); /* read it back */
|
||||||
|
if (check != n) { /* not enough precision? */
|
||||||
|
/* convert again with more precision */
|
||||||
|
len = l_sprintf(buff, LUA_N2SBUFFSZ, LUA_NUMBER_FMT_N,
|
||||||
|
(LUAI_UACNUMBER)n);
|
||||||
|
}
|
||||||
|
/* looks like an integer? */
|
||||||
|
if (buff[strspn(buff, "-0123456789")] == '\0') {
|
||||||
|
buff[len++] = lua_getlocaledecpoint();
|
||||||
|
buff[len++] = '0'; /* adds '.0' to result */
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Convert a number object to a string, adding it to a buffer.
|
||||||
|
*/
|
||||||
|
unsigned luaO_tostringbuff (const TValue *obj, char *buff) {
|
||||||
int len;
|
int len;
|
||||||
lua_assert(ttisnumber(obj));
|
lua_assert(ttisnumber(obj));
|
||||||
if (ttisinteger(obj))
|
if (ttisinteger(obj))
|
||||||
len = lua_integer2str(buff, MAXNUMBER2STR, ivalue(obj));
|
len = lua_integer2str(buff, LUA_N2SBUFFSZ, ivalue(obj));
|
||||||
else {
|
else
|
||||||
len = lua_number2str(buff, MAXNUMBER2STR, fltvalue(obj));
|
len = tostringbuffFloat(fltvalue(obj), buff);
|
||||||
if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */
|
lua_assert(len < LUA_N2SBUFFSZ);
|
||||||
buff[len++] = lua_getlocaledecpoint();
|
return cast_uint(len);
|
||||||
buff[len++] = '0'; /* adds '.0' to result */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -372,8 +462,8 @@ static int tostringbuff (TValue *obj, char *buff) {
|
|||||||
** Convert a number object to a Lua string, replacing the value at 'obj'
|
** Convert a number object to a Lua string, replacing the value at 'obj'
|
||||||
*/
|
*/
|
||||||
void luaO_tostring (lua_State *L, TValue *obj) {
|
void luaO_tostring (lua_State *L, TValue *obj) {
|
||||||
char buff[MAXNUMBER2STR];
|
char buff[LUA_N2SBUFFSZ];
|
||||||
int len = tostringbuff(obj, buff);
|
unsigned len = luaO_tostringbuff(obj, buff);
|
||||||
setsvalue(L, obj, luaS_newlstr(L, buff, len));
|
setsvalue(L, obj, luaS_newlstr(L, buff, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,80 +476,116 @@ void luaO_tostring (lua_State *L, TValue *obj) {
|
|||||||
** ===================================================================
|
** ===================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* size for buffer space used by 'luaO_pushvfstring' */
|
/*
|
||||||
#define BUFVFS 200
|
** Size for buffer space used by 'luaO_pushvfstring'. It should be
|
||||||
|
** (LUA_IDSIZE + LUA_N2SBUFFSZ) + a minimal space for basic messages,
|
||||||
|
** so that 'luaG_addinfo' can work directly on the static buffer.
|
||||||
|
*/
|
||||||
|
#define BUFVFS cast_uint(LUA_IDSIZE + LUA_N2SBUFFSZ + 95)
|
||||||
|
|
||||||
/* buffer used by 'luaO_pushvfstring' */
|
/*
|
||||||
|
** Buffer used by 'luaO_pushvfstring'. 'err' signals an error while
|
||||||
|
** building result (memory error [1] or buffer overflow [2]).
|
||||||
|
*/
|
||||||
typedef struct BuffFS {
|
typedef struct BuffFS {
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
int pushed; /* number of string pieces already on the stack */
|
char *b;
|
||||||
int blen; /* length of partial string in 'space' */
|
size_t buffsize;
|
||||||
char space[BUFVFS]; /* holds last part of the result */
|
size_t blen; /* length of string in 'buff' */
|
||||||
|
int err;
|
||||||
|
char space[BUFVFS]; /* initial buffer */
|
||||||
} BuffFS;
|
} BuffFS;
|
||||||
|
|
||||||
|
|
||||||
|
static void initbuff (lua_State *L, BuffFS *buff) {
|
||||||
|
buff->L = L;
|
||||||
|
buff->b = buff->space;
|
||||||
|
buff->buffsize = sizeof(buff->space);
|
||||||
|
buff->blen = 0;
|
||||||
|
buff->err = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Push given string to the stack, as part of the buffer, and
|
** Push final result from 'luaO_pushvfstring'. This function may raise
|
||||||
** join the partial strings in the stack into one.
|
** errors explicitly or through memory errors, so it must run protected.
|
||||||
*/
|
*/
|
||||||
static void pushstr (BuffFS *buff, const char *str, size_t l) {
|
static void pushbuff (lua_State *L, void *ud) {
|
||||||
|
BuffFS *buff = cast(BuffFS*, ud);
|
||||||
|
switch (buff->err) {
|
||||||
|
case 1: /* memory error */
|
||||||
|
luaD_throw(L, LUA_ERRMEM);
|
||||||
|
break;
|
||||||
|
case 2: /* length overflow: Add "..." at the end of result */
|
||||||
|
if (buff->buffsize - buff->blen < 3)
|
||||||
|
strcpy(buff->b + buff->blen - 3, "..."); /* 'blen' must be > 3 */
|
||||||
|
else { /* there is enough space left for the "..." */
|
||||||
|
strcpy(buff->b + buff->blen, "...");
|
||||||
|
buff->blen += 3;
|
||||||
|
}
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
default: { /* no errors, but it can raise one creating the new string */
|
||||||
|
TString *ts = luaS_newlstr(L, buff->b, buff->blen);
|
||||||
|
setsvalue2s(L, L->top.p, ts);
|
||||||
|
L->top.p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *clearbuff (BuffFS *buff) {
|
||||||
lua_State *L = buff->L;
|
lua_State *L = buff->L;
|
||||||
setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
|
const char *res;
|
||||||
L->top++; /* may use one extra slot */
|
if (luaD_rawrunprotected(L, pushbuff, buff) != LUA_OK) /* errors? */
|
||||||
buff->pushed++;
|
res = NULL; /* error message is on the top of the stack */
|
||||||
luaV_concat(L, buff->pushed); /* join partial results into one */
|
else
|
||||||
buff->pushed = 1;
|
res = getstr(tsvalue(s2v(L->top.p - 1)));
|
||||||
|
if (buff->b != buff->space) /* using dynamic buffer? */
|
||||||
|
luaM_freearray(L, buff->b, buff->buffsize); /* free it */
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** empty the buffer space into the stack
|
|
||||||
*/
|
|
||||||
static void clearbuff (BuffFS *buff) {
|
|
||||||
pushstr(buff, buff->space, buff->blen); /* push buffer contents */
|
|
||||||
buff->blen = 0; /* space now is empty */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Get a space of size 'sz' in the buffer. If buffer has not enough
|
|
||||||
** space, empty it. 'sz' must fit in an empty buffer.
|
|
||||||
*/
|
|
||||||
static char *getbuff (BuffFS *buff, int sz) {
|
|
||||||
lua_assert(buff->blen <= BUFVFS); lua_assert(sz <= BUFVFS);
|
|
||||||
if (sz > BUFVFS - buff->blen) /* not enough space? */
|
|
||||||
clearbuff(buff);
|
|
||||||
return buff->space + buff->blen;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define addsize(b,sz) ((b)->blen += (sz))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Add 'str' to the buffer. If string is larger than the buffer space,
|
|
||||||
** push the string directly to the stack.
|
|
||||||
*/
|
|
||||||
static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
|
static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
|
||||||
if (slen <= BUFVFS) { /* does string fit into buffer? */
|
size_t left = buff->buffsize - buff->blen; /* space left in the buffer */
|
||||||
char *bf = getbuff(buff, cast_int(slen));
|
if (buff->err) /* do nothing else after an error */
|
||||||
memcpy(bf, str, slen); /* add string to buffer */
|
return;
|
||||||
addsize(buff, cast_int(slen));
|
if (slen > left) { /* new string doesn't fit into current buffer? */
|
||||||
}
|
if (slen > ((MAX_SIZE/2) - buff->blen)) { /* overflow? */
|
||||||
else { /* string larger than buffer */
|
memcpy(buff->b + buff->blen, str, left); /* copy what it can */
|
||||||
clearbuff(buff); /* string comes after buffer's content */
|
buff->blen = buff->buffsize;
|
||||||
pushstr(buff, str, slen); /* push string */
|
buff->err = 2; /* doesn't add anything else */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
size_t newsize = buff->buffsize + slen; /* limited to MAX_SIZE/2 */
|
||||||
|
char *newb =
|
||||||
|
(buff->b == buff->space) /* still using static space? */
|
||||||
|
? luaM_reallocvector(buff->L, NULL, 0, newsize, char)
|
||||||
|
: luaM_reallocvector(buff->L, buff->b, buff->buffsize, newsize,
|
||||||
|
char);
|
||||||
|
if (newb == NULL) { /* allocation error? */
|
||||||
|
buff->err = 1; /* signal a memory error */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (buff->b == buff->space) /* new buffer (not reallocated)? */
|
||||||
|
memcpy(newb, buff->b, buff->blen); /* copy previous content */
|
||||||
|
buff->b = newb; /* set new (larger) buffer... */
|
||||||
|
buff->buffsize = newsize; /* ...and its new size */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
memcpy(buff->b + buff->blen, str, slen); /* copy new content */
|
||||||
|
buff->blen += slen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Add a number to the buffer.
|
** Add a numeral to the buffer.
|
||||||
*/
|
*/
|
||||||
static void addnum2buff (BuffFS *buff, TValue *num) {
|
static void addnum2buff (BuffFS *buff, TValue *num) {
|
||||||
char *numbuff = getbuff(buff, MAXNUMBER2STR);
|
char numbuff[LUA_N2SBUFFSZ];
|
||||||
int len = tostringbuff(num, numbuff); /* format number into 'numbuff' */
|
unsigned len = luaO_tostringbuff(num, numbuff);
|
||||||
addsize(buff, len);
|
addstr2buff(buff, numbuff, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -470,10 +596,9 @@ static void addnum2buff (BuffFS *buff, TValue *num) {
|
|||||||
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
||||||
BuffFS buff; /* holds last part of the result */
|
BuffFS buff; /* holds last part of the result */
|
||||||
const char *e; /* points to next '%' */
|
const char *e; /* points to next '%' */
|
||||||
buff.pushed = buff.blen = 0;
|
initbuff(L, &buff);
|
||||||
buff.L = L;
|
|
||||||
while ((e = strchr(fmt, '%')) != NULL) {
|
while ((e = strchr(fmt, '%')) != NULL) {
|
||||||
addstr2buff(&buff, fmt, e - fmt); /* add 'fmt' up to '%' */
|
addstr2buff(&buff, fmt, ct_diff2sz(e - fmt)); /* add 'fmt' up to '%' */
|
||||||
switch (*(e + 1)) { /* conversion specifier */
|
switch (*(e + 1)) { /* conversion specifier */
|
||||||
case 's': { /* zero-terminated string */
|
case 's': { /* zero-terminated string */
|
||||||
const char *s = va_arg(argp, char *);
|
const char *s = va_arg(argp, char *);
|
||||||
@@ -482,7 +607,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'c': { /* an 'int' as a character */
|
case 'c': { /* an 'int' as a character */
|
||||||
char c = cast_uchar(va_arg(argp, int));
|
char c = cast_char(va_arg(argp, int));
|
||||||
addstr2buff(&buff, &c, sizeof(char));
|
addstr2buff(&buff, &c, sizeof(char));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -494,7 +619,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
|||||||
}
|
}
|
||||||
case 'I': { /* a 'lua_Integer' */
|
case 'I': { /* a 'lua_Integer' */
|
||||||
TValue num;
|
TValue num;
|
||||||
setivalue(&num, cast(lua_Integer, va_arg(argp, l_uacInt)));
|
setivalue(&num, cast_Integer(va_arg(argp, l_uacInt)));
|
||||||
addnum2buff(&buff, &num);
|
addnum2buff(&buff, &num);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -505,17 +630,17 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'p': { /* a pointer */
|
case 'p': { /* a pointer */
|
||||||
const int sz = 3 * sizeof(void*) + 8; /* enough space for '%p' */
|
char bf[LUA_N2SBUFFSZ]; /* enough space for '%p' */
|
||||||
char *bf = getbuff(&buff, sz);
|
|
||||||
void *p = va_arg(argp, void *);
|
void *p = va_arg(argp, void *);
|
||||||
int len = lua_pointer2str(bf, sz, p);
|
int len = lua_pointer2str(bf, LUA_N2SBUFFSZ, p);
|
||||||
addsize(&buff, len);
|
addstr2buff(&buff, bf, cast_uint(len));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'U': { /* a 'long' as a UTF-8 sequence */
|
case 'U': { /* an 'unsigned long' as a UTF-8 sequence */
|
||||||
char bf[UTF8BUFFSZ];
|
char bf[UTF8BUFFSZ];
|
||||||
int len = luaO_utf8esc(bf, va_arg(argp, long));
|
unsigned long arg = va_arg(argp, unsigned long);
|
||||||
addstr2buff(&buff, bf + UTF8BUFFSZ - len, len);
|
int len = luaO_utf8esc(bf, cast(l_uint32, arg));
|
||||||
|
addstr2buff(&buff, bf + UTF8BUFFSZ - len, cast_uint(len));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case '%': {
|
case '%': {
|
||||||
@@ -523,16 +648,14 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'",
|
addstr2buff(&buff, e, 2); /* keep unknown format in the result */
|
||||||
*(e + 1));
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt = e + 2; /* skip '%' and the specifier */
|
fmt = e + 2; /* skip '%' and the specifier */
|
||||||
}
|
}
|
||||||
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
|
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
|
||||||
clearbuff(&buff); /* empty buffer into the stack */
|
return clearbuff(&buff); /* empty buffer into a new string */
|
||||||
lua_assert(buff.pushed == 1);
|
|
||||||
return svalue(s2v(L->top - 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -542,6 +665,8 @@ const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
|
|||||||
va_start(argp, fmt);
|
va_start(argp, fmt);
|
||||||
msg = luaO_pushvfstring(L, fmt, argp);
|
msg = luaO_pushvfstring(L, fmt, argp);
|
||||||
va_end(argp);
|
va_end(argp);
|
||||||
|
if (msg == NULL) /* error? */
|
||||||
|
luaD_throw(L, LUA_ERRMEM);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -581,7 +706,8 @@ void luaO_chunkid (char *out, const char *source, size_t srclen) {
|
|||||||
addstr(out, source, srclen); /* keep it */
|
addstr(out, source, srclen); /* keep it */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (nl != NULL) srclen = nl - source; /* stop at first newline */
|
if (nl != NULL)
|
||||||
|
srclen = ct_diff2sz(nl - source); /* stop at first newline */
|
||||||
if (srclen > bufflen) srclen = bufflen;
|
if (srclen > bufflen) srclen = bufflen;
|
||||||
addstr(out, source, srclen);
|
addstr(out, source, srclen);
|
||||||
addstr(out, RETS, LL(RETS));
|
addstr(out, RETS, LL(RETS));
|
||||||
+106
-42
@@ -52,6 +52,8 @@ typedef union Value {
|
|||||||
lua_CFunction f; /* light C functions */
|
lua_CFunction f; /* light C functions */
|
||||||
lua_Integer i; /* integer numbers */
|
lua_Integer i; /* integer numbers */
|
||||||
lua_Number n; /* float numbers */
|
lua_Number n; /* float numbers */
|
||||||
|
/* not used, but may avoid warnings for uninitialized value */
|
||||||
|
lu_byte ub;
|
||||||
} Value;
|
} Value;
|
||||||
|
|
||||||
|
|
||||||
@@ -68,7 +70,7 @@ typedef struct TValue {
|
|||||||
|
|
||||||
|
|
||||||
#define val_(o) ((o)->value_)
|
#define val_(o) ((o)->value_)
|
||||||
#define valraw(o) (&val_(o))
|
#define valraw(o) (val_(o))
|
||||||
|
|
||||||
|
|
||||||
/* raw type tag of a TValue */
|
/* raw type tag of a TValue */
|
||||||
@@ -112,7 +114,7 @@ typedef struct TValue {
|
|||||||
#define settt_(o,t) ((o)->tt_=(t))
|
#define settt_(o,t) ((o)->tt_=(t))
|
||||||
|
|
||||||
|
|
||||||
/* main macro to copy values (from 'obj1' to 'obj2') */
|
/* main macro to copy values (from 'obj2' to 'obj1') */
|
||||||
#define setobj(L,obj1,obj2) \
|
#define setobj(L,obj1,obj2) \
|
||||||
{ TValue *io1=(obj1); const TValue *io2=(obj2); \
|
{ TValue *io1=(obj1); const TValue *io2=(obj2); \
|
||||||
io1->value_ = io2->value_; settt_(io1, io2->tt_); \
|
io1->value_ = io2->value_; settt_(io1, io2->tt_); \
|
||||||
@@ -155,6 +157,17 @@ typedef union StackValue {
|
|||||||
/* index to stack elements */
|
/* index to stack elements */
|
||||||
typedef StackValue *StkId;
|
typedef StackValue *StkId;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** When reallocating the stack, change all pointers to the stack into
|
||||||
|
** proper offsets.
|
||||||
|
*/
|
||||||
|
typedef union {
|
||||||
|
StkId p; /* actual pointer */
|
||||||
|
ptrdiff_t offset; /* used while the stack is being reallocated */
|
||||||
|
} StkIdRel;
|
||||||
|
|
||||||
|
|
||||||
/* convert a 'StackValue' to a 'TValue' */
|
/* convert a 'StackValue' to a 'TValue' */
|
||||||
#define s2v(o) (&(o)->val)
|
#define s2v(o) (&(o)->val)
|
||||||
|
|
||||||
@@ -175,10 +188,21 @@ typedef StackValue *StkId;
|
|||||||
/* Value returned for a key not found in a table (absent key) */
|
/* Value returned for a key not found in a table (absent key) */
|
||||||
#define LUA_VABSTKEY makevariant(LUA_TNIL, 2)
|
#define LUA_VABSTKEY makevariant(LUA_TNIL, 2)
|
||||||
|
|
||||||
|
/* Special variant to signal that a fast get is accessing a non-table */
|
||||||
|
#define LUA_VNOTABLE makevariant(LUA_TNIL, 3)
|
||||||
|
|
||||||
|
|
||||||
/* macro to test for (any kind of) nil */
|
/* macro to test for (any kind of) nil */
|
||||||
#define ttisnil(v) checktype((v), LUA_TNIL)
|
#define ttisnil(v) checktype((v), LUA_TNIL)
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Macro to test the result of a table access. Formally, it should
|
||||||
|
** distinguish between LUA_VEMPTY/LUA_VABSTKEY/LUA_VNOTABLE and
|
||||||
|
** other tags. As currently nil is equivalent to LUA_VEMPTY, it is
|
||||||
|
** simpler to just test whether the value is nil.
|
||||||
|
*/
|
||||||
|
#define tagisempty(tag) (novariant(tag) == LUA_TNIL)
|
||||||
|
|
||||||
|
|
||||||
/* macro to test for a standard nil */
|
/* macro to test for a standard nil */
|
||||||
#define ttisstrictnil(o) checktag((o), LUA_VNIL)
|
#define ttisstrictnil(o) checktag((o), LUA_VNIL)
|
||||||
@@ -232,6 +256,8 @@ typedef StackValue *StkId;
|
|||||||
|
|
||||||
|
|
||||||
#define l_isfalse(o) (ttisfalse(o) || ttisnil(o))
|
#define l_isfalse(o) (ttisfalse(o) || ttisnil(o))
|
||||||
|
#define tagisfalse(t) ((t) == LUA_VFALSE || novariant(t) == LUA_TNIL)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define setbfvalue(obj) settt_(obj, LUA_VFALSE)
|
#define setbfvalue(obj) settt_(obj, LUA_VFALSE)
|
||||||
@@ -367,37 +393,54 @@ typedef struct GCObject {
|
|||||||
#define setsvalue2n setsvalue
|
#define setsvalue2n setsvalue
|
||||||
|
|
||||||
|
|
||||||
|
/* Kinds of long strings (stored in 'shrlen') */
|
||||||
|
#define LSTRREG -1 /* regular long string */
|
||||||
|
#define LSTRFIX -2 /* fixed external long string */
|
||||||
|
#define LSTRMEM -3 /* external long string with deallocation */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Header for a string value.
|
** Header for a string value.
|
||||||
*/
|
*/
|
||||||
typedef struct TString {
|
typedef struct TString {
|
||||||
CommonHeader;
|
CommonHeader;
|
||||||
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
|
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
|
||||||
lu_byte shrlen; /* length for short strings */
|
ls_byte shrlen; /* length for short strings, negative for long strings */
|
||||||
unsigned int hash;
|
unsigned int hash;
|
||||||
union {
|
union {
|
||||||
size_t lnglen; /* length for long strings */
|
size_t lnglen; /* length for long strings */
|
||||||
struct TString *hnext; /* linked list for hash table */
|
struct TString *hnext; /* linked list for hash table */
|
||||||
} u;
|
} u;
|
||||||
char contents[1];
|
char *contents; /* pointer to content in long strings */
|
||||||
|
lua_Alloc falloc; /* deallocation function for external strings */
|
||||||
|
void *ud; /* user data for external strings */
|
||||||
} TString;
|
} TString;
|
||||||
|
|
||||||
|
|
||||||
|
#define strisshr(ts) ((ts)->shrlen >= 0)
|
||||||
|
#define isextstr(ts) (ttislngstring(ts) && tsvalue(ts)->shrlen != LSTRREG)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Get the actual string (array of bytes) from a 'TString'.
|
** Get the actual string (array of bytes) from a 'TString'. (Generic
|
||||||
|
** version and specialized versions for long and short strings.)
|
||||||
*/
|
*/
|
||||||
#define getstr(ts) ((ts)->contents)
|
#define rawgetshrstr(ts) (cast_charp(&(ts)->contents))
|
||||||
|
#define getshrstr(ts) check_exp(strisshr(ts), rawgetshrstr(ts))
|
||||||
|
#define getlngstr(ts) check_exp(!strisshr(ts), (ts)->contents)
|
||||||
|
#define getstr(ts) (strisshr(ts) ? rawgetshrstr(ts) : (ts)->contents)
|
||||||
|
|
||||||
|
|
||||||
/* get the actual string (array of bytes) from a Lua value */
|
/* get string length from 'TString *ts' */
|
||||||
#define svalue(o) getstr(tsvalue(o))
|
#define tsslen(ts) \
|
||||||
|
(strisshr(ts) ? cast_sizet((ts)->shrlen) : (ts)->u.lnglen)
|
||||||
|
|
||||||
/* get string length from 'TString *s' */
|
/*
|
||||||
#define tsslen(s) ((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen)
|
** Get string and length */
|
||||||
|
#define getlstr(ts, len) \
|
||||||
/* get string length from 'TValue *o' */
|
(strisshr(ts) \
|
||||||
#define vslen(o) tsslen(tsvalue(o))
|
? (cast_void((len) = cast_sizet((ts)->shrlen)), rawgetshrstr(ts)) \
|
||||||
|
: (cast_void((len) = (ts)->u.lnglen), (ts)->contents))
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
@@ -475,8 +518,8 @@ typedef struct Udata0 {
|
|||||||
|
|
||||||
/* compute the offset of the memory area of a userdata */
|
/* compute the offset of the memory area of a userdata */
|
||||||
#define udatamemoffset(nuv) \
|
#define udatamemoffset(nuv) \
|
||||||
((nuv) == 0 ? offsetof(Udata0, bindata) \
|
((nuv) == 0 ? offsetof(Udata0, bindata) \
|
||||||
: offsetof(Udata, uv) + (sizeof(UValue) * (nuv)))
|
: offsetof(Udata, uv) + (sizeof(UValue) * (nuv)))
|
||||||
|
|
||||||
/* get the address of the memory block inside 'Udata' */
|
/* get the address of the memory block inside 'Udata' */
|
||||||
#define getudatamem(u) (cast_charp(u) + udatamemoffset((u)->nuvalue))
|
#define getudatamem(u) (cast_charp(u) + udatamemoffset((u)->nuvalue))
|
||||||
@@ -496,6 +539,9 @@ typedef struct Udata0 {
|
|||||||
#define LUA_VPROTO makevariant(LUA_TPROTO, 0)
|
#define LUA_VPROTO makevariant(LUA_TPROTO, 0)
|
||||||
|
|
||||||
|
|
||||||
|
typedef l_uint32 Instruction;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Description of an upvalue for function prototypes
|
** Description of an upvalue for function prototypes
|
||||||
*/
|
*/
|
||||||
@@ -533,13 +579,30 @@ typedef struct AbsLineInfo {
|
|||||||
int line;
|
int line;
|
||||||
} AbsLineInfo;
|
} AbsLineInfo;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Flags in Prototypes
|
||||||
|
*/
|
||||||
|
#define PF_VAHID 1 /* function has hidden vararg arguments */
|
||||||
|
#define PF_VATAB 2 /* function has vararg table */
|
||||||
|
#define PF_FIXED 4 /* prototype has parts in fixed memory */
|
||||||
|
|
||||||
|
/* a vararg function either has hidden args. or a vararg table */
|
||||||
|
#define isvararg(p) ((p)->flag & (PF_VAHID | PF_VATAB))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** mark that a function needs a vararg table. (The flag PF_VAHID will
|
||||||
|
** be cleared later.)
|
||||||
|
*/
|
||||||
|
#define needvatab(p) ((p)->flag |= PF_VATAB)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Function Prototypes
|
** Function Prototypes
|
||||||
*/
|
*/
|
||||||
typedef struct Proto {
|
typedef struct Proto {
|
||||||
CommonHeader;
|
CommonHeader;
|
||||||
lu_byte numparams; /* number of fixed (named) parameters */
|
lu_byte numparams; /* number of fixed (named) parameters */
|
||||||
lu_byte is_vararg;
|
lu_byte flag;
|
||||||
lu_byte maxstacksize; /* number of registers needed by this function */
|
lu_byte maxstacksize; /* number of registers needed by this function */
|
||||||
int sizeupvalues; /* size of 'upvalues' */
|
int sizeupvalues; /* size of 'upvalues' */
|
||||||
int sizek; /* size of 'k' */
|
int sizek; /* size of 'k' */
|
||||||
@@ -615,8 +678,10 @@ typedef struct Proto {
|
|||||||
*/
|
*/
|
||||||
typedef struct UpVal {
|
typedef struct UpVal {
|
||||||
CommonHeader;
|
CommonHeader;
|
||||||
lu_byte tbc; /* true if it represents a to-be-closed variable */
|
union {
|
||||||
TValue *v; /* points to stack or to its own value */
|
TValue *p; /* points to stack or to its own value */
|
||||||
|
ptrdiff_t offset; /* used while the stack is being reallocated */
|
||||||
|
} v;
|
||||||
union {
|
union {
|
||||||
struct { /* (when open) */
|
struct { /* (when open) */
|
||||||
struct UpVal *next; /* linked list */
|
struct UpVal *next; /* linked list */
|
||||||
@@ -695,10 +760,9 @@ typedef union Node {
|
|||||||
|
|
||||||
|
|
||||||
/* copy a value into a key */
|
/* copy a value into a key */
|
||||||
#define setnodekey(L,node,obj) \
|
#define setnodekey(node,obj) \
|
||||||
{ Node *n_=(node); const TValue *io_=(obj); \
|
{ Node *n_=(node); const TValue *io_=(obj); \
|
||||||
n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; \
|
n_->u.key_val = io_->value_; n_->u.key_tt = io_->tt_; }
|
||||||
checkliveness(L,io_); }
|
|
||||||
|
|
||||||
|
|
||||||
/* copy a value from a key */
|
/* copy a value from a key */
|
||||||
@@ -708,27 +772,14 @@ typedef union Node {
|
|||||||
checkliveness(L,io_); }
|
checkliveness(L,io_); }
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** About 'alimit': if 'isrealasize(t)' is true, then 'alimit' is the
|
|
||||||
** real size of 'array'. Otherwise, the real size of 'array' is the
|
|
||||||
** smallest power of two not smaller than 'alimit' (or zero iff 'alimit'
|
|
||||||
** is zero); 'alimit' is then used as a hint for #t.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define BITRAS (1 << 7)
|
|
||||||
#define isrealasize(t) (!((t)->flags & BITRAS))
|
|
||||||
#define setrealasize(t) ((t)->flags &= cast_byte(~BITRAS))
|
|
||||||
#define setnorealasize(t) ((t)->flags |= BITRAS)
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct Table {
|
typedef struct Table {
|
||||||
CommonHeader;
|
CommonHeader;
|
||||||
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
|
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
|
||||||
lu_byte lsizenode; /* log2 of size of 'node' array */
|
lu_byte lsizenode; /* log2 of number of slots of 'node' array */
|
||||||
unsigned int alimit; /* "limit" of 'array' array */
|
unsigned int asize; /* number of slots in 'array' array */
|
||||||
TValue *array; /* array part */
|
Value *array; /* array part */
|
||||||
Node *node;
|
Node *node;
|
||||||
Node *lastfree; /* any free position is before this position */
|
|
||||||
struct Table *metatable;
|
struct Table *metatable;
|
||||||
GCObject *gclist;
|
GCObject *gclist;
|
||||||
} Table;
|
} Table;
|
||||||
@@ -771,24 +822,37 @@ typedef struct Table {
|
|||||||
** 'module' operation for hashing (size is always a power of 2)
|
** 'module' operation for hashing (size is always a power of 2)
|
||||||
*/
|
*/
|
||||||
#define lmod(s,size) \
|
#define lmod(s,size) \
|
||||||
(check_exp((size&(size-1))==0, (cast_int((s) & ((size)-1)))))
|
(check_exp((size&(size-1))==0, (cast_uint(s) & cast_uint((size)-1))))
|
||||||
|
|
||||||
|
|
||||||
#define twoto(x) (1<<(x))
|
#define twoto(x) (1u<<(x))
|
||||||
#define sizenode(t) (twoto((t)->lsizenode))
|
#define sizenode(t) (twoto((t)->lsizenode))
|
||||||
|
|
||||||
|
|
||||||
/* size of buffer for 'luaO_utf8esc' function */
|
/* size of buffer for 'luaO_utf8esc' function */
|
||||||
#define UTF8BUFFSZ 8
|
#define UTF8BUFFSZ 8
|
||||||
|
|
||||||
LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x);
|
|
||||||
LUAI_FUNC int luaO_ceillog2 (unsigned int x);
|
/* macro to call 'luaO_pushvfstring' correctly */
|
||||||
|
#define pushvfstring(L, argp, fmt, msg) \
|
||||||
|
{ va_start(argp, fmt); \
|
||||||
|
msg = luaO_pushvfstring(L, fmt, argp); \
|
||||||
|
va_end(argp); \
|
||||||
|
if (msg == NULL) luaD_throw(L, LUA_ERRMEM); /* only after 'va_end' */ }
|
||||||
|
|
||||||
|
|
||||||
|
LUAI_FUNC int luaO_utf8esc (char *buff, l_uint32 x);
|
||||||
|
LUAI_FUNC lu_byte luaO_ceillog2 (unsigned int x);
|
||||||
|
LUAI_FUNC lu_byte luaO_codeparam (unsigned int p);
|
||||||
|
LUAI_FUNC l_mem luaO_applyparam (lu_byte p, l_mem x);
|
||||||
|
|
||||||
LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1,
|
LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1,
|
||||||
const TValue *p2, TValue *res);
|
const TValue *p2, TValue *res);
|
||||||
LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1,
|
LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1,
|
||||||
const TValue *p2, StkId res);
|
const TValue *p2, StkId res);
|
||||||
LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o);
|
LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o);
|
||||||
LUAI_FUNC int luaO_hexavalue (int c);
|
LUAI_FUNC unsigned luaO_tostringbuff (const TValue *obj, char *buff);
|
||||||
|
LUAI_FUNC lu_byte luaO_hexavalue (int c);
|
||||||
LUAI_FUNC void luaO_tostring (lua_State *L, TValue *obj);
|
LUAI_FUNC void luaO_tostring (lua_State *L, TValue *obj);
|
||||||
LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
|
LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
|
||||||
va_list argp);
|
va_list argp);
|
||||||
+41
-5
@@ -13,6 +13,10 @@
|
|||||||
#include "lopcodes.h"
|
#include "lopcodes.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define opmode(mm,ot,it,t,a,m) \
|
||||||
|
(((mm) << 7) | ((ot) << 6) | ((it) << 5) | ((t) << 4) | ((a) << 3) | (m))
|
||||||
|
|
||||||
|
|
||||||
/* ORDER OP */
|
/* ORDER OP */
|
||||||
|
|
||||||
LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
||||||
@@ -36,7 +40,7 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
|||||||
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABLE */
|
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABLE */
|
||||||
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETI */
|
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETI */
|
||||||
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETFIELD */
|
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETFIELD */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_NEWTABLE */
|
,opmode(0, 0, 0, 0, 1, ivABC) /* OP_NEWTABLE */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SELF */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SELF */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDI */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDI */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDK */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDK */
|
||||||
@@ -49,8 +53,8 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
|||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BANDK */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BANDK */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BORK */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BORK */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXORK */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXORK */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHRI */
|
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHLI */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHLI */
|
||||||
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHRI */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADD */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADD */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUB */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUB */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_MUL */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_MUL */
|
||||||
@@ -64,8 +68,8 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
|||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHL */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHL */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHR */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHR */
|
||||||
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBIN */
|
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBIN */
|
||||||
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINI*/
|
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINI */
|
||||||
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINK*/
|
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINK */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_UNM */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_UNM */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BNOT */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BNOT */
|
||||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_NOT */
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_NOT */
|
||||||
@@ -95,10 +99,42 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
|||||||
,opmode(0, 0, 0, 0, 0, iABx) /* OP_TFORPREP */
|
,opmode(0, 0, 0, 0, 0, iABx) /* OP_TFORPREP */
|
||||||
,opmode(0, 0, 0, 0, 0, iABC) /* OP_TFORCALL */
|
,opmode(0, 0, 0, 0, 0, iABC) /* OP_TFORCALL */
|
||||||
,opmode(0, 0, 0, 0, 1, iABx) /* OP_TFORLOOP */
|
,opmode(0, 0, 0, 0, 1, iABx) /* OP_TFORLOOP */
|
||||||
,opmode(0, 0, 1, 0, 0, iABC) /* OP_SETLIST */
|
,opmode(0, 0, 1, 0, 0, ivABC) /* OP_SETLIST */
|
||||||
,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */
|
,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */
|
||||||
,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
|
,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
|
||||||
|
,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETVARG */
|
||||||
|
,opmode(0, 0, 0, 0, 0, iABx) /* OP_ERRNNIL */
|
||||||
,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */
|
,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */
|
||||||
,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */
|
,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Check whether instruction sets top for next instruction, that is,
|
||||||
|
** it results in multiple values.
|
||||||
|
*/
|
||||||
|
int luaP_isOT (Instruction i) {
|
||||||
|
OpCode op = GET_OPCODE(i);
|
||||||
|
switch (op) {
|
||||||
|
case OP_TAILCALL: return 1;
|
||||||
|
default:
|
||||||
|
return testOTMode(op) && GETARG_C(i) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Check whether instruction uses top from previous instruction, that is,
|
||||||
|
** it accepts multiple results.
|
||||||
|
*/
|
||||||
|
int luaP_isIT (Instruction i) {
|
||||||
|
OpCode op = GET_OPCODE(i);
|
||||||
|
switch (op) {
|
||||||
|
case OP_SETLIST:
|
||||||
|
return testITMode(GET_OPCODE(i)) && GETARG_vB(i) == 0;
|
||||||
|
default:
|
||||||
|
return testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+110
-63
@@ -8,6 +8,7 @@
|
|||||||
#define lopcodes_h
|
#define lopcodes_h
|
||||||
|
|
||||||
#include "llimits.h"
|
#include "llimits.h"
|
||||||
|
#include "lobject.h"
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
@@ -18,25 +19,30 @@
|
|||||||
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
|
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
|
||||||
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||||
iABC C(8) | B(8) |k| A(8) | Op(7) |
|
iABC C(8) | B(8) |k| A(8) | Op(7) |
|
||||||
|
ivABC vC(10) | vB(6) |k| A(8) | Op(7) |
|
||||||
iABx Bx(17) | A(8) | Op(7) |
|
iABx Bx(17) | A(8) | Op(7) |
|
||||||
iAsBx sBx (signed)(17) | A(8) | Op(7) |
|
iAsBx sBx (signed)(17) | A(8) | Op(7) |
|
||||||
iAx Ax(25) | Op(7) |
|
iAx Ax(25) | Op(7) |
|
||||||
isJ sJ(25) | Op(7) |
|
isJ sJ (signed)(25) | Op(7) |
|
||||||
|
|
||||||
A signed argument is represented in excess K: the represented value is
|
('v' stands for "variant", 's' for "signed", 'x' for "extended".)
|
||||||
the written unsigned value minus K, where K is half the maximum for the
|
A signed argument is represented in excess K: The represented value is
|
||||||
corresponding unsigned argument.
|
the written unsigned value minus K, where K is half (rounded down) the
|
||||||
|
maximum value for the corresponding unsigned argument.
|
||||||
===========================================================================*/
|
===========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
/* basic instruction formats */
|
||||||
|
enum OpMode {iABC, ivABC, iABx, iAsBx, iAx, isJ};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** size and position of opcode arguments.
|
** size and position of opcode arguments.
|
||||||
*/
|
*/
|
||||||
#define SIZE_C 8
|
#define SIZE_C 8
|
||||||
|
#define SIZE_vC 10
|
||||||
#define SIZE_B 8
|
#define SIZE_B 8
|
||||||
|
#define SIZE_vB 6
|
||||||
#define SIZE_Bx (SIZE_C + SIZE_B + 1)
|
#define SIZE_Bx (SIZE_C + SIZE_B + 1)
|
||||||
#define SIZE_A 8
|
#define SIZE_A 8
|
||||||
#define SIZE_Ax (SIZE_Bx + SIZE_A)
|
#define SIZE_Ax (SIZE_Bx + SIZE_A)
|
||||||
@@ -49,7 +55,9 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
#define POS_A (POS_OP + SIZE_OP)
|
#define POS_A (POS_OP + SIZE_OP)
|
||||||
#define POS_k (POS_A + SIZE_A)
|
#define POS_k (POS_A + SIZE_A)
|
||||||
#define POS_B (POS_k + 1)
|
#define POS_B (POS_k + 1)
|
||||||
|
#define POS_vB (POS_k + 1)
|
||||||
#define POS_C (POS_B + SIZE_B)
|
#define POS_C (POS_B + SIZE_B)
|
||||||
|
#define POS_vC (POS_vB + SIZE_vB)
|
||||||
|
|
||||||
#define POS_Bx POS_k
|
#define POS_Bx POS_k
|
||||||
|
|
||||||
@@ -64,14 +72,17 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
** so they must fit in ints.
|
** so they must fit in ints.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Check whether type 'int' has at least 'b' bits ('b' < 32) */
|
/*
|
||||||
#define L_INTHASBITS(b) ((UINT_MAX >> ((b) - 1)) >= 1)
|
** Check whether type 'int' has at least 'b' + 1 bits.
|
||||||
|
** 'b' < 32; +1 for the sign bit.
|
||||||
|
*/
|
||||||
|
#define L_INTHASBITS(b) ((UINT_MAX >> (b)) >= 1)
|
||||||
|
|
||||||
|
|
||||||
#if L_INTHASBITS(SIZE_Bx)
|
#if L_INTHASBITS(SIZE_Bx)
|
||||||
#define MAXARG_Bx ((1<<SIZE_Bx)-1)
|
#define MAXARG_Bx ((1<<SIZE_Bx)-1)
|
||||||
#else
|
#else
|
||||||
#define MAXARG_Bx MAX_INT
|
#define MAXARG_Bx INT_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define OFFSET_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */
|
#define OFFSET_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */
|
||||||
@@ -80,13 +91,13 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
#if L_INTHASBITS(SIZE_Ax)
|
#if L_INTHASBITS(SIZE_Ax)
|
||||||
#define MAXARG_Ax ((1<<SIZE_Ax)-1)
|
#define MAXARG_Ax ((1<<SIZE_Ax)-1)
|
||||||
#else
|
#else
|
||||||
#define MAXARG_Ax MAX_INT
|
#define MAXARG_Ax INT_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if L_INTHASBITS(SIZE_sJ)
|
#if L_INTHASBITS(SIZE_sJ)
|
||||||
#define MAXARG_sJ ((1 << SIZE_sJ) - 1)
|
#define MAXARG_sJ ((1 << SIZE_sJ) - 1)
|
||||||
#else
|
#else
|
||||||
#define MAXARG_sJ MAX_INT
|
#define MAXARG_sJ INT_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define OFFSET_sJ (MAXARG_sJ >> 1)
|
#define OFFSET_sJ (MAXARG_sJ >> 1)
|
||||||
@@ -94,7 +105,9 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
|
|
||||||
#define MAXARG_A ((1<<SIZE_A)-1)
|
#define MAXARG_A ((1<<SIZE_A)-1)
|
||||||
#define MAXARG_B ((1<<SIZE_B)-1)
|
#define MAXARG_B ((1<<SIZE_B)-1)
|
||||||
|
#define MAXARG_vB ((1<<SIZE_vB)-1)
|
||||||
#define MAXARG_C ((1<<SIZE_C)-1)
|
#define MAXARG_C ((1<<SIZE_C)-1)
|
||||||
|
#define MAXARG_vC ((1<<SIZE_vC)-1)
|
||||||
#define OFFSET_sC (MAXARG_C >> 1)
|
#define OFFSET_sC (MAXARG_C >> 1)
|
||||||
|
|
||||||
#define int2sC(i) ((i) + OFFSET_sC)
|
#define int2sC(i) ((i) + OFFSET_sC)
|
||||||
@@ -113,28 +126,36 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
|
|
||||||
#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
|
#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
|
||||||
#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
|
#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
|
||||||
((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
|
((cast_Inst(o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
|
||||||
|
|
||||||
#define checkopm(i,m) (getOpMode(GET_OPCODE(i)) == m)
|
#define checkopm(i,m) (getOpMode(GET_OPCODE(i)) == m)
|
||||||
|
|
||||||
|
|
||||||
#define getarg(i,pos,size) (cast_int(((i)>>(pos)) & MASK1(size,0)))
|
#define getarg(i,pos,size) (cast_int(((i)>>(pos)) & MASK1(size,0)))
|
||||||
#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \
|
#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \
|
||||||
((cast(Instruction, v)<<pos)&MASK1(size,pos))))
|
((cast_Inst(v)<<pos)&MASK1(size,pos))))
|
||||||
|
|
||||||
#define GETARG_A(i) getarg(i, POS_A, SIZE_A)
|
#define GETARG_A(i) getarg(i, POS_A, SIZE_A)
|
||||||
#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A)
|
#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A)
|
||||||
|
|
||||||
#define GETARG_B(i) check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B))
|
#define GETARG_B(i) \
|
||||||
|
check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B))
|
||||||
|
#define GETARG_vB(i) \
|
||||||
|
check_exp(checkopm(i, ivABC), getarg(i, POS_vB, SIZE_vB))
|
||||||
#define GETARG_sB(i) sC2int(GETARG_B(i))
|
#define GETARG_sB(i) sC2int(GETARG_B(i))
|
||||||
#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B)
|
#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B)
|
||||||
|
#define SETARG_vB(i,v) setarg(i, v, POS_vB, SIZE_vB)
|
||||||
|
|
||||||
#define GETARG_C(i) check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C))
|
#define GETARG_C(i) \
|
||||||
|
check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C))
|
||||||
|
#define GETARG_vC(i) \
|
||||||
|
check_exp(checkopm(i, ivABC), getarg(i, POS_vC, SIZE_vC))
|
||||||
#define GETARG_sC(i) sC2int(GETARG_C(i))
|
#define GETARG_sC(i) sC2int(GETARG_C(i))
|
||||||
#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C)
|
#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C)
|
||||||
|
#define SETARG_vC(i,v) setarg(i, v, POS_vC, SIZE_vC)
|
||||||
|
|
||||||
#define TESTARG_k(i) check_exp(checkopm(i, iABC), (cast_int(((i) & (1u << POS_k)))))
|
#define TESTARG_k(i) (cast_int(((i) & (1u << POS_k))))
|
||||||
#define GETARG_k(i) check_exp(checkopm(i, iABC), getarg(i, POS_k, 1))
|
#define GETARG_k(i) getarg(i, POS_k, 1)
|
||||||
#define SETARG_k(i,v) setarg(i, v, POS_k, 1)
|
#define SETARG_k(i,v) setarg(i, v, POS_k, 1)
|
||||||
|
|
||||||
#define GETARG_Bx(i) check_exp(checkopm(i, iABx), getarg(i, POS_Bx, SIZE_Bx))
|
#define GETARG_Bx(i) check_exp(checkopm(i, iABx), getarg(i, POS_Bx, SIZE_Bx))
|
||||||
@@ -153,22 +174,28 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
setarg(i, cast_uint((j)+OFFSET_sJ), POS_sJ, SIZE_sJ)
|
setarg(i, cast_uint((j)+OFFSET_sJ), POS_sJ, SIZE_sJ)
|
||||||
|
|
||||||
|
|
||||||
#define CREATE_ABCk(o,a,b,c,k) ((cast(Instruction, o)<<POS_OP) \
|
#define CREATE_ABCk(o,a,b,c,k) ((cast_Inst(o)<<POS_OP) \
|
||||||
| (cast(Instruction, a)<<POS_A) \
|
| (cast_Inst(a)<<POS_A) \
|
||||||
| (cast(Instruction, b)<<POS_B) \
|
| (cast_Inst(b)<<POS_B) \
|
||||||
| (cast(Instruction, c)<<POS_C) \
|
| (cast_Inst(c)<<POS_C) \
|
||||||
| (cast(Instruction, k)<<POS_k))
|
| (cast_Inst(k)<<POS_k))
|
||||||
|
|
||||||
#define CREATE_ABx(o,a,bc) ((cast(Instruction, o)<<POS_OP) \
|
#define CREATE_vABCk(o,a,b,c,k) ((cast_Inst(o)<<POS_OP) \
|
||||||
| (cast(Instruction, a)<<POS_A) \
|
| (cast_Inst(a)<<POS_A) \
|
||||||
| (cast(Instruction, bc)<<POS_Bx))
|
| (cast_Inst(b)<<POS_vB) \
|
||||||
|
| (cast_Inst(c)<<POS_vC) \
|
||||||
|
| (cast_Inst(k)<<POS_k))
|
||||||
|
|
||||||
#define CREATE_Ax(o,a) ((cast(Instruction, o)<<POS_OP) \
|
#define CREATE_ABx(o,a,bc) ((cast_Inst(o)<<POS_OP) \
|
||||||
| (cast(Instruction, a)<<POS_Ax))
|
| (cast_Inst(a)<<POS_A) \
|
||||||
|
| (cast_Inst(bc)<<POS_Bx))
|
||||||
|
|
||||||
#define CREATE_sJ(o,j,k) ((cast(Instruction, o) << POS_OP) \
|
#define CREATE_Ax(o,a) ((cast_Inst(o)<<POS_OP) \
|
||||||
| (cast(Instruction, j) << POS_sJ) \
|
| (cast_Inst(a)<<POS_Ax))
|
||||||
| (cast(Instruction, k) << POS_k))
|
|
||||||
|
#define CREATE_sJ(o,j,k) ((cast_Inst(o) << POS_OP) \
|
||||||
|
| (cast_Inst(j) << POS_sJ) \
|
||||||
|
| (cast_Inst(k) << POS_k))
|
||||||
|
|
||||||
|
|
||||||
#if !defined(MAXINDEXRK) /* (for debugging only) */
|
#if !defined(MAXINDEXRK) /* (for debugging only) */
|
||||||
@@ -177,9 +204,16 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** invalid register that fits in 8 bits
|
** Maximum size for the stack of a Lua function. It must fit in 8 bits.
|
||||||
|
** The highest valid register is one less than this value.
|
||||||
*/
|
*/
|
||||||
#define NO_REG MAXARG_A
|
#define MAX_FSTACK MAXARG_A
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Invalid register (one more than last valid register).
|
||||||
|
*/
|
||||||
|
#define NO_REG MAX_FSTACK
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -190,7 +224,8 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** grep "ORDER OP" if you change these enums
|
** Grep "ORDER OP" if you change this enum.
|
||||||
|
** See "Notes" below for more information about some instructions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -209,19 +244,19 @@ OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
|
|||||||
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
|
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
|
||||||
OP_SETUPVAL,/* A B UpValue[B] := R[A] */
|
OP_SETUPVAL,/* A B UpValue[B] := R[A] */
|
||||||
|
|
||||||
OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:string] */
|
OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:shortstring] */
|
||||||
OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */
|
OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */
|
||||||
OP_GETI,/* A B C R[A] := R[B][C] */
|
OP_GETI,/* A B C R[A] := R[B][C] */
|
||||||
OP_GETFIELD,/* A B C R[A] := R[B][K[C]:string] */
|
OP_GETFIELD,/* A B C R[A] := R[B][K[C]:shortstring] */
|
||||||
|
|
||||||
OP_SETTABUP,/* A B C UpValue[A][K[B]:string] := RK(C) */
|
OP_SETTABUP,/* A B C UpValue[A][K[B]:shortstring] := RK(C) */
|
||||||
OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */
|
OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */
|
||||||
OP_SETI,/* A B C R[A][B] := RK(C) */
|
OP_SETI,/* A B C R[A][B] := RK(C) */
|
||||||
OP_SETFIELD,/* A B C R[A][K[B]:string] := RK(C) */
|
OP_SETFIELD,/* A B C R[A][K[B]:shortstring] := RK(C) */
|
||||||
|
|
||||||
OP_NEWTABLE,/* A B C k R[A] := {} */
|
OP_NEWTABLE,/* A vB vC k R[A] := {} */
|
||||||
|
|
||||||
OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][RK(C):string] */
|
OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][K[C]:shortstring] */
|
||||||
|
|
||||||
OP_ADDI,/* A B sC R[A] := R[B] + sC */
|
OP_ADDI,/* A B sC R[A] := R[B] + sC */
|
||||||
|
|
||||||
@@ -237,8 +272,8 @@ OP_BANDK,/* A B C R[A] := R[B] & K[C]:integer */
|
|||||||
OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */
|
OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */
|
||||||
OP_BXORK,/* A B C R[A] := R[B] ~ K[C]:integer */
|
OP_BXORK,/* A B C R[A] := R[B] ~ K[C]:integer */
|
||||||
|
|
||||||
OP_SHRI,/* A B sC R[A] := R[B] >> sC */
|
|
||||||
OP_SHLI,/* A B sC R[A] := sC << R[B] */
|
OP_SHLI,/* A B sC R[A] := sC << R[B] */
|
||||||
|
OP_SHRI,/* A B sC R[A] := R[B] >> sC */
|
||||||
|
|
||||||
OP_ADD,/* A B C R[A] := R[B] + R[C] */
|
OP_ADD,/* A B C R[A] := R[B] + R[C] */
|
||||||
OP_SUB,/* A B C R[A] := R[B] - R[C] */
|
OP_SUB,/* A B C R[A] := R[B] - R[C] */
|
||||||
@@ -280,12 +315,12 @@ OP_GTI,/* A sB k if ((R[A] > sB) ~= k) then pc++ */
|
|||||||
OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */
|
OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */
|
||||||
|
|
||||||
OP_TEST,/* A k if (not R[A] == k) then pc++ */
|
OP_TEST,/* A k if (not R[A] == k) then pc++ */
|
||||||
OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] */
|
OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] */
|
||||||
|
|
||||||
OP_CALL,/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */
|
OP_CALL,/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */
|
||||||
OP_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */
|
OP_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */
|
||||||
|
|
||||||
OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] (see note) */
|
OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] */
|
||||||
OP_RETURN0,/* return */
|
OP_RETURN0,/* return */
|
||||||
OP_RETURN1,/* A return R[A] */
|
OP_RETURN1,/* A return R[A] */
|
||||||
|
|
||||||
@@ -297,13 +332,17 @@ OP_TFORPREP,/* A Bx create upvalue for R[A + 3]; pc+=Bx */
|
|||||||
OP_TFORCALL,/* A C R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); */
|
OP_TFORCALL,/* A C R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); */
|
||||||
OP_TFORLOOP,/* A Bx if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx } */
|
OP_TFORLOOP,/* A Bx if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx } */
|
||||||
|
|
||||||
OP_SETLIST,/* A B C k R[A][C+i] := R[A+i], 1 <= i <= B */
|
OP_SETLIST,/* A vB vC k R[A][vC+i] := R[A+i], 1 <= i <= vB */
|
||||||
|
|
||||||
OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
|
OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
|
||||||
|
|
||||||
OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
|
OP_VARARG,/* A B C k R[A], ..., R[A+C-2] = varargs */
|
||||||
|
|
||||||
OP_VARARGPREP,/*A (adjust vararg parameters) */
|
OP_GETVARG, /* A B C R[A] := R[B][R[C]], R[B] is vararg parameter */
|
||||||
|
|
||||||
|
OP_ERRNNIL,/* A Bx raise error if R[A] ~= nil (K[Bx - 1] is global name)*/
|
||||||
|
|
||||||
|
OP_VARARGPREP,/* (adjust varargs) */
|
||||||
|
|
||||||
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
||||||
} OpCode;
|
} OpCode;
|
||||||
@@ -315,12 +354,25 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
|||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
|
(*) Opcode OP_LFALSESKIP is used to convert a condition to a boolean
|
||||||
|
value, in a code equivalent to (not cond ? false : true). (It
|
||||||
|
produces false and skips the next instruction producing true.)
|
||||||
|
|
||||||
|
(*) Opcodes OP_MMBIN and variants follow each arithmetic and
|
||||||
|
bitwise opcode. If the operation succeeds, it skips this next
|
||||||
|
opcode. Otherwise, this opcode calls the corresponding metamethod.
|
||||||
|
|
||||||
|
(*) Opcode OP_TESTSET is used in short-circuit expressions that need
|
||||||
|
both to jump and to produce a value, such as (a = b or c).
|
||||||
|
|
||||||
(*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then
|
(*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then
|
||||||
'top' is set to last_result+1, so next open instruction (OP_CALL,
|
'top' is set to last_result+1, so next open instruction (OP_CALL,
|
||||||
OP_RETURN*, OP_SETLIST) may use 'top'.
|
OP_RETURN*, OP_SETLIST) may use 'top'.
|
||||||
|
|
||||||
(*) In OP_VARARG, if (C == 0) then use actual number of varargs and
|
(*) In OP_VARARG, if (C == 0) then use actual number of varargs and
|
||||||
set top (like in OP_CALL with C == 0).
|
set top (like in OP_CALL with C == 0). 'k' means function has a
|
||||||
|
vararg table, which is in R[B].
|
||||||
|
|
||||||
(*) In OP_RETURN, if (B == 0) then return up to 'top'.
|
(*) In OP_RETURN, if (B == 0) then return up to 'top'.
|
||||||
|
|
||||||
@@ -331,22 +383,27 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
|||||||
real C = EXTRAARG _ C (the bits of EXTRAARG concatenated with the
|
real C = EXTRAARG _ C (the bits of EXTRAARG concatenated with the
|
||||||
bits of C).
|
bits of C).
|
||||||
|
|
||||||
(*) In OP_NEWTABLE, B is log2 of the hash size (which is always a
|
(*) In OP_NEWTABLE, vB is log2 of the hash size (which is always a
|
||||||
power of 2) plus 1, or zero for size zero. If not k, the array size
|
power of 2) plus 1, or zero for size zero. If not k, the array size
|
||||||
is C. Otherwise, the array size is EXTRAARG _ C.
|
is vC. Otherwise, the array size is EXTRAARG _ vC.
|
||||||
|
|
||||||
|
(*) In OP_ERRNNIL, (Bx == 0) means index of global name doesn't
|
||||||
|
fit in Bx. (So, that name is not available for the error message.)
|
||||||
|
|
||||||
(*) For comparisons, k specifies what condition the test should accept
|
(*) For comparisons, k specifies what condition the test should accept
|
||||||
(true or false).
|
(true or false).
|
||||||
|
|
||||||
(*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped
|
(*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped
|
||||||
(the constant is the first operand).
|
(the constant is the first operand).
|
||||||
|
|
||||||
(*) All 'skips' (pc++) assume that next instruction is a jump.
|
(*) All comparison and test instructions assume that the instruction
|
||||||
|
being skipped (pc++) is a jump.
|
||||||
|
|
||||||
(*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
|
(*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
|
||||||
function builds upvalues, which may need to be closed. C > 0 means
|
function builds upvalues, which may need to be closed. C > 0 means
|
||||||
the function is vararg, so that its 'func' must be corrected before
|
the function has hidden vararg arguments, so that its 'func' must be
|
||||||
returning; in this case, (C - 1) is its number of fixed parameters.
|
corrected before returning; in this case, (C - 1) is its number of
|
||||||
|
fixed parameters.
|
||||||
|
|
||||||
(*) In comparisons with an immediate operand, C signals whether the
|
(*) In comparisons with an immediate operand, C signals whether the
|
||||||
original operand was a float. (It must be corrected in case of
|
original operand was a float. (It must be corrected in case of
|
||||||
@@ -374,19 +431,9 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];)
|
|||||||
#define testOTMode(m) (luaP_opmodes[m] & (1 << 6))
|
#define testOTMode(m) (luaP_opmodes[m] & (1 << 6))
|
||||||
#define testMMMode(m) (luaP_opmodes[m] & (1 << 7))
|
#define testMMMode(m) (luaP_opmodes[m] & (1 << 7))
|
||||||
|
|
||||||
/* "out top" (set top for next instruction) */
|
|
||||||
#define isOT(i) \
|
|
||||||
((testOTMode(GET_OPCODE(i)) && GETARG_C(i) == 0) || \
|
|
||||||
GET_OPCODE(i) == OP_TAILCALL)
|
|
||||||
|
|
||||||
/* "in top" (uses top from previous instruction) */
|
LUAI_FUNC int luaP_isOT (Instruction i);
|
||||||
#define isIT(i) (testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0)
|
LUAI_FUNC int luaP_isIT (Instruction i);
|
||||||
|
|
||||||
#define opmode(mm,ot,it,t,a,m) \
|
|
||||||
(((mm) << 7) | ((ot) << 6) | ((it) << 5) | ((t) << 4) | ((a) << 3) | (m))
|
|
||||||
|
|
||||||
|
|
||||||
/* number of list items to accumulate before a SETLIST instruction */
|
|
||||||
#define LFIELDS_PER_FLUSH 50
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+3
-1
@@ -45,8 +45,8 @@ static const char *const opnames[] = {
|
|||||||
"BANDK",
|
"BANDK",
|
||||||
"BORK",
|
"BORK",
|
||||||
"BXORK",
|
"BXORK",
|
||||||
"SHRI",
|
|
||||||
"SHLI",
|
"SHLI",
|
||||||
|
"SHRI",
|
||||||
"ADD",
|
"ADD",
|
||||||
"SUB",
|
"SUB",
|
||||||
"MUL",
|
"MUL",
|
||||||
@@ -94,6 +94,8 @@ static const char *const opnames[] = {
|
|||||||
"SETLIST",
|
"SETLIST",
|
||||||
"CLOSURE",
|
"CLOSURE",
|
||||||
"VARARG",
|
"VARARG",
|
||||||
|
"GETVARG",
|
||||||
|
"ERRNNIL",
|
||||||
"VARARGPREP",
|
"VARARGPREP",
|
||||||
"EXTRAARG",
|
"EXTRAARG",
|
||||||
NULL
|
NULL
|
||||||
+24
-22
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -30,23 +31,14 @@
|
|||||||
*/
|
*/
|
||||||
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
|
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
|
||||||
|
|
||||||
/* options for ANSI C 89 (only 1-char options) */
|
|
||||||
#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
|
|
||||||
|
|
||||||
/* options for ISO C 99 and POSIX */
|
|
||||||
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
|
|
||||||
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
|
|
||||||
|
|
||||||
/* options for Windows */
|
|
||||||
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
|
|
||||||
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
|
|
||||||
|
|
||||||
#if defined(LUA_USE_WINDOWS)
|
#if defined(LUA_USE_WINDOWS)
|
||||||
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
|
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
|
||||||
#elif defined(LUA_USE_C89)
|
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
|
||||||
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
|
#elif defined(LUA_USE_C89) /* C89 (only 1-char options) */
|
||||||
|
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
|
||||||
#else /* C99 specification */
|
#else /* C99 specification */
|
||||||
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
|
#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
|
||||||
|
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
@@ -138,12 +130,21 @@
|
|||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(l_system)
|
||||||
|
#if defined(LUA_USE_IOS)
|
||||||
|
/* Despite claiming to be ISO C, iOS does not implement 'system'. */
|
||||||
|
#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
|
||||||
|
#else
|
||||||
|
#define l_system(cmd) system(cmd) /* default definition */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int os_execute (lua_State *L) {
|
static int os_execute (lua_State *L) {
|
||||||
const char *cmd = luaL_optstring(L, 1, NULL);
|
const char *cmd = luaL_optstring(L, 1, NULL);
|
||||||
int stat;
|
int stat;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
stat = system(cmd);
|
stat = l_system(cmd);
|
||||||
if (cmd != NULL)
|
if (cmd != NULL)
|
||||||
return luaL_execresult(L, stat);
|
return luaL_execresult(L, stat);
|
||||||
else {
|
else {
|
||||||
@@ -155,6 +156,7 @@ static int os_execute (lua_State *L) {
|
|||||||
|
|
||||||
static int os_remove (lua_State *L) {
|
static int os_remove (lua_State *L) {
|
||||||
const char *filename = luaL_checkstring(L, 1);
|
const char *filename = luaL_checkstring(L, 1);
|
||||||
|
errno = 0;
|
||||||
return luaL_fileresult(L, remove(filename) == 0, filename);
|
return luaL_fileresult(L, remove(filename) == 0, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +164,7 @@ static int os_remove (lua_State *L) {
|
|||||||
static int os_rename (lua_State *L) {
|
static int os_rename (lua_State *L) {
|
||||||
const char *fromname = luaL_checkstring(L, 1);
|
const char *fromname = luaL_checkstring(L, 1);
|
||||||
const char *toname = luaL_checkstring(L, 2);
|
const char *toname = luaL_checkstring(L, 2);
|
||||||
|
errno = 0;
|
||||||
return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
|
return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,9 +263,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
|
|||||||
res = d;
|
res = d;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* unsigned avoids overflow when lua_Integer has 32 bits */
|
if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
|
||||||
if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
|
|
||||||
: (lua_Integer)INT_MIN + delta <= res))
|
|
||||||
return luaL_error(L, "field '%s' is out-of-bound", key);
|
return luaL_error(L, "field '%s' is out-of-bound", key);
|
||||||
res -= delta;
|
res -= delta;
|
||||||
}
|
}
|
||||||
@@ -272,9 +273,9 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
|
|||||||
|
|
||||||
|
|
||||||
static const char *checkoption (lua_State *L, const char *conv,
|
static const char *checkoption (lua_State *L, const char *conv,
|
||||||
ptrdiff_t convlen, char *buff) {
|
size_t convlen, char *buff) {
|
||||||
const char *option = LUA_STRFTIMEOPTIONS;
|
const char *option = LUA_STRFTIMEOPTIONS;
|
||||||
int oplen = 1; /* length of options being checked */
|
unsigned oplen = 1; /* length of options being checked */
|
||||||
for (; *option != '\0' && oplen <= convlen; option += oplen) {
|
for (; *option != '\0' && oplen <= convlen; option += oplen) {
|
||||||
if (*option == '|') /* next block? */
|
if (*option == '|') /* next block? */
|
||||||
oplen++; /* will check options with next length (+1) */
|
oplen++; /* will check options with next length (+1) */
|
||||||
@@ -332,7 +333,8 @@ static int os_date (lua_State *L) {
|
|||||||
size_t reslen;
|
size_t reslen;
|
||||||
char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
|
char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
|
||||||
s++; /* skip '%' */
|
s++; /* skip '%' */
|
||||||
s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */
|
/* copy specifier to 'cc' */
|
||||||
|
s = checkoption(L, s, ct_diff2sz(se - s), cc + 1);
|
||||||
reslen = strftime(buff, SIZETIMEFMT, cc, stm);
|
reslen = strftime(buff, SIZETIMEFMT, cc, stm);
|
||||||
luaL_addsize(&b, reslen);
|
luaL_addsize(&b, reslen);
|
||||||
}
|
}
|
||||||
+512
-275
File diff suppressed because it is too large
Load Diff
+41
-16
@@ -32,26 +32,36 @@ typedef enum {
|
|||||||
VKFLT, /* floating constant; nval = numerical float value */
|
VKFLT, /* floating constant; nval = numerical float value */
|
||||||
VKINT, /* integer constant; ival = numerical integer value */
|
VKINT, /* integer constant; ival = numerical integer value */
|
||||||
VKSTR, /* string constant; strval = TString address;
|
VKSTR, /* string constant; strval = TString address;
|
||||||
(string is fixed by the lexer) */
|
(string is fixed by the scanner) */
|
||||||
VNONRELOC, /* expression has its value in a fixed register;
|
VNONRELOC, /* expression has its value in a fixed register;
|
||||||
info = result register */
|
info = result register */
|
||||||
VLOCAL, /* local variable; var.ridx = register index;
|
VLOCAL, /* local variable; var.ridx = register index;
|
||||||
var.vidx = relative index in 'actvar.arr' */
|
var.vidx = relative index in 'actvar.arr' */
|
||||||
|
VVARGVAR, /* vararg parameter; var.ridx = register index;
|
||||||
|
var.vidx = relative index in 'actvar.arr' */
|
||||||
|
VGLOBAL, /* global variable;
|
||||||
|
info = relative index in 'actvar.arr' (or -1 for
|
||||||
|
implicit declaration) */
|
||||||
VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
|
VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
|
||||||
VCONST, /* compile-time <const> variable;
|
VCONST, /* compile-time <const> variable;
|
||||||
info = absolute index in 'actvar.arr' */
|
info = absolute index in 'actvar.arr' */
|
||||||
VINDEXED, /* indexed variable;
|
VINDEXED, /* indexed variable;
|
||||||
ind.t = table register;
|
ind.t = table register;
|
||||||
ind.idx = key's R index */
|
ind.idx = key's R index;
|
||||||
|
ind.ro = true if it represents a read-only global;
|
||||||
|
ind.keystr = if key is a string, index in 'k' of that string;
|
||||||
|
-1 if key is not a string */
|
||||||
|
VVARGIND, /* indexed vararg parameter;
|
||||||
|
ind.* as in VINDEXED */
|
||||||
VINDEXUP, /* indexed upvalue;
|
VINDEXUP, /* indexed upvalue;
|
||||||
ind.t = table upvalue;
|
ind.idx = key's K index;
|
||||||
ind.idx = key's K index */
|
ind.* as in VINDEXED */
|
||||||
VINDEXI, /* indexed variable with constant integer;
|
VINDEXI, /* indexed variable with constant integer;
|
||||||
ind.t = table register;
|
ind.t = table register;
|
||||||
ind.idx = key's value */
|
ind.idx = key's value */
|
||||||
VINDEXSTR, /* indexed variable with literal string;
|
VINDEXSTR, /* indexed variable with literal string;
|
||||||
ind.t = table register;
|
ind.idx = key's K index;
|
||||||
ind.idx = key's K index */
|
ind.* as in VINDEXED */
|
||||||
VJMP, /* expression is a test/comparison;
|
VJMP, /* expression is a test/comparison;
|
||||||
info = pc of corresponding jump instruction */
|
info = pc of corresponding jump instruction */
|
||||||
VRELOC, /* expression can put result in any register;
|
VRELOC, /* expression can put result in any register;
|
||||||
@@ -75,10 +85,12 @@ typedef struct expdesc {
|
|||||||
struct { /* for indexed variables */
|
struct { /* for indexed variables */
|
||||||
short idx; /* index (R or "long" K) */
|
short idx; /* index (R or "long" K) */
|
||||||
lu_byte t; /* table (register or upvalue) */
|
lu_byte t; /* table (register or upvalue) */
|
||||||
|
lu_byte ro; /* true if variable is read-only */
|
||||||
|
int keystr; /* index in 'k' of string key, or -1 if not a string */
|
||||||
} ind;
|
} ind;
|
||||||
struct { /* for local variables */
|
struct { /* for local variables */
|
||||||
lu_byte ridx; /* register holding the variable */
|
lu_byte ridx; /* register holding the variable */
|
||||||
unsigned short vidx; /* compiler index (in 'actvar.arr') */
|
short vidx; /* index in 'actvar.arr' */
|
||||||
} var;
|
} var;
|
||||||
} u;
|
} u;
|
||||||
int t; /* patch list of 'exit when true' */
|
int t; /* patch list of 'exit when true' */
|
||||||
@@ -87,12 +99,22 @@ typedef struct expdesc {
|
|||||||
|
|
||||||
|
|
||||||
/* kinds of variables */
|
/* kinds of variables */
|
||||||
#define VDKREG 0 /* regular */
|
#define VDKREG 0 /* regular local */
|
||||||
#define RDKCONST 1 /* constant */
|
#define RDKCONST 1 /* local constant */
|
||||||
#define RDKTOCLOSE 2 /* to-be-closed */
|
#define RDKVAVAR 2 /* vararg parameter */
|
||||||
#define RDKCTC 3 /* compile-time constant */
|
#define RDKTOCLOSE 3 /* to-be-closed */
|
||||||
|
#define RDKCTC 4 /* local compile-time constant */
|
||||||
|
#define GDKREG 5 /* regular global */
|
||||||
|
#define GDKCONST 6 /* global constant */
|
||||||
|
|
||||||
/* description of an active local variable */
|
/* variables that live in registers */
|
||||||
|
#define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE)
|
||||||
|
|
||||||
|
/* test for global variables */
|
||||||
|
#define varglobal(v) ((v)->vd.kind >= GDKREG)
|
||||||
|
|
||||||
|
|
||||||
|
/* description of an active variable */
|
||||||
typedef union Vardesc {
|
typedef union Vardesc {
|
||||||
struct {
|
struct {
|
||||||
TValuefields; /* constant value (if it is a compile-time constant) */
|
TValuefields; /* constant value (if it is a compile-time constant) */
|
||||||
@@ -111,8 +133,8 @@ typedef struct Labeldesc {
|
|||||||
TString *name; /* label identifier */
|
TString *name; /* label identifier */
|
||||||
int pc; /* position in code */
|
int pc; /* position in code */
|
||||||
int line; /* line where it appeared */
|
int line; /* line where it appeared */
|
||||||
lu_byte nactvar; /* number of active variables in that position */
|
short nactvar; /* number of active variables in that position */
|
||||||
lu_byte close; /* goto that escapes upvalues */
|
lu_byte close; /* true for goto that escapes upvalues */
|
||||||
} Labeldesc;
|
} Labeldesc;
|
||||||
|
|
||||||
|
|
||||||
@@ -146,6 +168,7 @@ typedef struct FuncState {
|
|||||||
struct FuncState *prev; /* enclosing function */
|
struct FuncState *prev; /* enclosing function */
|
||||||
struct LexState *ls; /* lexical state */
|
struct LexState *ls; /* lexical state */
|
||||||
struct BlockCnt *bl; /* chain of current blocks */
|
struct BlockCnt *bl; /* chain of current blocks */
|
||||||
|
Table *kcache; /* cache for reusing constants */
|
||||||
int pc; /* next position to code (equivalent to 'ncode') */
|
int pc; /* next position to code (equivalent to 'ncode') */
|
||||||
int lasttarget; /* 'label' of last 'jump label' */
|
int lasttarget; /* 'label' of last 'jump label' */
|
||||||
int previousline; /* last line that was saved in 'lineinfo' */
|
int previousline; /* last line that was saved in 'lineinfo' */
|
||||||
@@ -155,7 +178,7 @@ typedef struct FuncState {
|
|||||||
int firstlocal; /* index of first local var (in Dyndata array) */
|
int firstlocal; /* index of first local var (in Dyndata array) */
|
||||||
int firstlabel; /* index of first label (in 'dyd->label->arr') */
|
int firstlabel; /* index of first label (in 'dyd->label->arr') */
|
||||||
short ndebugvars; /* number of elements in 'f->locvars' */
|
short ndebugvars; /* number of elements in 'f->locvars' */
|
||||||
lu_byte nactvar; /* number of active local variables */
|
short nactvar; /* number of active variable declarations */
|
||||||
lu_byte nups; /* number of upvalues */
|
lu_byte nups; /* number of upvalues */
|
||||||
lu_byte freereg; /* first free register */
|
lu_byte freereg; /* first free register */
|
||||||
lu_byte iwthabs; /* instructions issued since last absolute line info */
|
lu_byte iwthabs; /* instructions issued since last absolute line info */
|
||||||
@@ -163,7 +186,9 @@ typedef struct FuncState {
|
|||||||
} FuncState;
|
} FuncState;
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC int luaY_nvarstack (FuncState *fs);
|
LUAI_FUNC lu_byte luaY_nvarstack (FuncState *fs);
|
||||||
|
LUAI_FUNC void luaY_checklimit (FuncState *fs, int v, int l,
|
||||||
|
const char *what);
|
||||||
LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||||
Dyndata *dyd, const char *name, int firstchar);
|
Dyndata *dyd, const char *name, int firstchar);
|
||||||
|
|
||||||
+110
-129
@@ -29,79 +29,45 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** thread state + extra space
|
|
||||||
*/
|
|
||||||
typedef struct LX {
|
|
||||||
lu_byte extra_[LUA_EXTRASPACE];
|
|
||||||
lua_State l;
|
|
||||||
} LX;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Main thread combines a thread state and the global state
|
|
||||||
*/
|
|
||||||
typedef struct LG {
|
|
||||||
LX l;
|
|
||||||
global_State g;
|
|
||||||
} LG;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l)))
|
#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l)))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A macro to create a "random" seed when a state is created;
|
** these macros allow user-specific actions when a thread is
|
||||||
** the seed is used to randomize string hashes.
|
** created/deleted
|
||||||
*/
|
*/
|
||||||
#if !defined(luai_makeseed)
|
#if !defined(luai_userstateopen)
|
||||||
|
#define luai_userstateopen(L) ((void)L)
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <time.h>
|
#if !defined(luai_userstateclose)
|
||||||
|
#define luai_userstateclose(L) ((void)L)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
#if !defined(luai_userstatethread)
|
||||||
** Compute an initial seed with some level of randomness.
|
#define luai_userstatethread(L,L1) ((void)L)
|
||||||
** Rely on Address Space Layout Randomization (if present) and
|
#endif
|
||||||
** current time.
|
|
||||||
*/
|
|
||||||
#define addbuff(b,p,e) \
|
|
||||||
{ size_t t = cast_sizet(e); \
|
|
||||||
memcpy(b + p, &t, sizeof(t)); p += sizeof(t); }
|
|
||||||
|
|
||||||
static unsigned int luai_makeseed (lua_State *L) {
|
|
||||||
char buff[3 * sizeof(size_t)];
|
|
||||||
unsigned int h = cast_uint(time(NULL));
|
|
||||||
int p = 0;
|
|
||||||
addbuff(buff, p, L); /* heap variable */
|
|
||||||
addbuff(buff, p, &h); /* local variable */
|
|
||||||
addbuff(buff, p, &lua_newstate); /* public function */
|
|
||||||
lua_assert(p == sizeof(buff));
|
|
||||||
return luaS_hash(buff, p, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#if !defined(luai_userstatefree)
|
||||||
|
#define luai_userstatefree(L,L1) ((void)L)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
|
** set GCdebt to a new value keeping the real number of allocated
|
||||||
** invariant (and avoiding underflows in 'totalbytes')
|
** objects (GCtotalobjs - GCdebt) invariant and avoiding overflows in
|
||||||
|
** 'GCtotalobjs'.
|
||||||
*/
|
*/
|
||||||
void luaE_setdebt (global_State *g, l_mem debt) {
|
void luaE_setdebt (global_State *g, l_mem debt) {
|
||||||
l_mem tb = gettotalbytes(g);
|
l_mem tb = gettotalbytes(g);
|
||||||
lua_assert(tb > 0);
|
lua_assert(tb > 0);
|
||||||
if (debt < tb - MAX_LMEM)
|
if (debt > MAX_LMEM - tb)
|
||||||
debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */
|
debt = MAX_LMEM - tb; /* will make GCtotalbytes == MAX_LMEM */
|
||||||
g->totalbytes = tb - debt;
|
g->GCtotalbytes = tb + debt;
|
||||||
g->GCdebt = debt;
|
g->GCdebt = debt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) {
|
|
||||||
UNUSED(L); UNUSED(limit);
|
|
||||||
return LUAI_MAXCCALLS; /* warning?? */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CallInfo *luaE_extendCI (lua_State *L) {
|
CallInfo *luaE_extendCI (lua_State *L) {
|
||||||
CallInfo *ci;
|
CallInfo *ci;
|
||||||
lua_assert(L->ci->next == NULL);
|
lua_assert(L->ci->next == NULL);
|
||||||
@@ -119,7 +85,7 @@ CallInfo *luaE_extendCI (lua_State *L) {
|
|||||||
/*
|
/*
|
||||||
** free all CallInfo structures not in use by a thread
|
** free all CallInfo structures not in use by a thread
|
||||||
*/
|
*/
|
||||||
void luaE_freeCI (lua_State *L) {
|
static void freeCI (lua_State *L) {
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
CallInfo *next = ci->next;
|
CallInfo *next = ci->next;
|
||||||
ci->next = NULL;
|
ci->next = NULL;
|
||||||
@@ -166,7 +132,7 @@ void luaE_checkcstack (lua_State *L) {
|
|||||||
if (getCcalls(L) == LUAI_MAXCCALLS)
|
if (getCcalls(L) == LUAI_MAXCCALLS)
|
||||||
luaG_runerror(L, "C stack overflow");
|
luaG_runerror(L, "C stack overflow");
|
||||||
else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
|
else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
|
||||||
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
|
luaD_errerr(L); /* error while handling stack error */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -177,36 +143,40 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void stack_init (lua_State *L1, lua_State *L) {
|
static void resetCI (lua_State *L) {
|
||||||
int i; CallInfo *ci;
|
CallInfo *ci = L->ci = &L->base_ci;
|
||||||
/* initialize stack array */
|
ci->func.p = L->stack.p;
|
||||||
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
|
setnilvalue(s2v(ci->func.p)); /* 'function' entry for basic 'ci' */
|
||||||
L1->tbclist = L1->stack;
|
ci->top.p = ci->func.p + 1 + LUA_MINSTACK; /* +1 for 'function' entry */
|
||||||
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
|
|
||||||
setnilvalue(s2v(L1->stack + i)); /* erase new stack */
|
|
||||||
L1->top = L1->stack;
|
|
||||||
L1->stack_last = L1->stack + BASIC_STACK_SIZE;
|
|
||||||
/* initialize first ci */
|
|
||||||
ci = &L1->base_ci;
|
|
||||||
ci->next = ci->previous = NULL;
|
|
||||||
ci->callstatus = CIST_C;
|
|
||||||
ci->func = L1->top;
|
|
||||||
ci->u.c.k = NULL;
|
ci->u.c.k = NULL;
|
||||||
ci->nresults = 0;
|
ci->callstatus = CIST_C;
|
||||||
setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */
|
L->status = LUA_OK;
|
||||||
L1->top++;
|
L->errfunc = 0; /* stack unwind can "throw away" the error function */
|
||||||
ci->top = L1->top + LUA_MINSTACK;
|
}
|
||||||
L1->ci = ci;
|
|
||||||
|
|
||||||
|
static void stack_init (lua_State *L1, lua_State *L) {
|
||||||
|
int i;
|
||||||
|
/* initialize stack array */
|
||||||
|
L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
|
||||||
|
L1->tbclist.p = L1->stack.p;
|
||||||
|
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
|
||||||
|
setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
|
||||||
|
L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
|
||||||
|
/* initialize first ci */
|
||||||
|
resetCI(L1);
|
||||||
|
L1->top.p = L1->stack.p + 1; /* +1 for 'function' entry */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void freestack (lua_State *L) {
|
static void freestack (lua_State *L) {
|
||||||
if (L->stack == NULL)
|
if (L->stack.p == NULL)
|
||||||
return; /* stack not completely built yet */
|
return; /* stack not completely built yet */
|
||||||
L->ci = &L->base_ci; /* free the entire 'ci' list */
|
L->ci = &L->base_ci; /* free the entire 'ci' list */
|
||||||
luaE_freeCI(L);
|
freeCI(L);
|
||||||
lua_assert(L->nci == 0);
|
lua_assert(L->nci == 0);
|
||||||
luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */
|
/* free stack */
|
||||||
|
luaM_freearray(L, L->stack.p, cast_sizet(stacksize(L) + EXTRA_STACK));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -215,13 +185,19 @@ static void freestack (lua_State *L) {
|
|||||||
*/
|
*/
|
||||||
static void init_registry (lua_State *L, global_State *g) {
|
static void init_registry (lua_State *L, global_State *g) {
|
||||||
/* create registry */
|
/* create registry */
|
||||||
|
TValue aux;
|
||||||
Table *registry = luaH_new(L);
|
Table *registry = luaH_new(L);
|
||||||
sethvalue(L, &g->l_registry, registry);
|
sethvalue(L, &g->l_registry, registry);
|
||||||
luaH_resize(L, registry, LUA_RIDX_LAST, 0);
|
luaH_resize(L, registry, LUA_RIDX_LAST, 0);
|
||||||
|
/* registry[1] = false */
|
||||||
|
setbfvalue(&aux);
|
||||||
|
luaH_setint(L, registry, 1, &aux);
|
||||||
/* registry[LUA_RIDX_MAINTHREAD] = L */
|
/* registry[LUA_RIDX_MAINTHREAD] = L */
|
||||||
setthvalue(L, ®istry->array[LUA_RIDX_MAINTHREAD - 1], L);
|
setthvalue(L, &aux, L);
|
||||||
|
luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &aux);
|
||||||
/* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */
|
/* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */
|
||||||
sethvalue(L, ®istry->array[LUA_RIDX_GLOBALS - 1], luaH_new(L));
|
sethvalue(L, &aux, luaH_new(L));
|
||||||
|
luaH_setint(L, registry, LUA_RIDX_GLOBALS, &aux);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -236,7 +212,7 @@ static void f_luaopen (lua_State *L, void *ud) {
|
|||||||
luaS_init(L);
|
luaS_init(L);
|
||||||
luaT_init(L);
|
luaT_init(L);
|
||||||
luaX_init(L);
|
luaX_init(L);
|
||||||
g->gcrunning = 1; /* allow gc */
|
g->gcstp = 0; /* allow gc */
|
||||||
setnilvalue(&g->nilvalue); /* now state is complete */
|
setnilvalue(&g->nilvalue); /* now state is complete */
|
||||||
luai_userstateopen(L);
|
luai_userstateopen(L);
|
||||||
}
|
}
|
||||||
@@ -248,7 +224,7 @@ static void f_luaopen (lua_State *L, void *ud) {
|
|||||||
*/
|
*/
|
||||||
static void preinit_thread (lua_State *L, global_State *g) {
|
static void preinit_thread (lua_State *L, global_State *g) {
|
||||||
G(L) = g;
|
G(L) = g;
|
||||||
L->stack = NULL;
|
L->stack.p = NULL;
|
||||||
L->ci = NULL;
|
L->ci = NULL;
|
||||||
L->nci = 0;
|
L->nci = 0;
|
||||||
L->twups = L; /* thread has no upvalues */
|
L->twups = L; /* thread has no upvalues */
|
||||||
@@ -263,40 +239,48 @@ static void preinit_thread (lua_State *L, global_State *g) {
|
|||||||
L->status = LUA_OK;
|
L->status = LUA_OK;
|
||||||
L->errfunc = 0;
|
L->errfunc = 0;
|
||||||
L->oldpc = 0;
|
L->oldpc = 0;
|
||||||
|
L->base_ci.previous = L->base_ci.next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lu_mem luaE_threadsize (lua_State *L) {
|
||||||
|
lu_mem sz = cast(lu_mem, sizeof(LX))
|
||||||
|
+ cast_uint(L->nci) * sizeof(CallInfo);
|
||||||
|
if (L->stack.p != NULL)
|
||||||
|
sz += cast_uint(stacksize(L) + EXTRA_STACK) * sizeof(StackValue);
|
||||||
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void close_state (lua_State *L) {
|
static void close_state (lua_State *L) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
if (!completestate(g)) /* closing a partially built state? */
|
if (!completestate(g)) /* closing a partially built state? */
|
||||||
luaC_freeallobjects(L); /* jucst collect its objects */
|
luaC_freeallobjects(L); /* just collect its objects */
|
||||||
else { /* closing a fully built state */
|
else { /* closing a fully built state */
|
||||||
|
resetCI(L);
|
||||||
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
|
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
|
||||||
|
L->top.p = L->stack.p + 1; /* empty the stack to run finalizers */
|
||||||
luaC_freeallobjects(L); /* collect all objects */
|
luaC_freeallobjects(L); /* collect all objects */
|
||||||
luai_userstateclose(L);
|
luai_userstateclose(L);
|
||||||
}
|
}
|
||||||
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
|
luaM_freearray(L, G(L)->strt.hash, cast_sizet(G(L)->strt.size));
|
||||||
freestack(L);
|
freestack(L);
|
||||||
lua_assert(gettotalbytes(g) == sizeof(LG));
|
lua_assert(gettotalbytes(g) == sizeof(global_State));
|
||||||
(*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */
|
(*g->frealloc)(g->ud, g, sizeof(global_State), 0); /* free main block */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API lua_State *lua_newthread (lua_State *L) {
|
LUA_API lua_State *lua_newthread (lua_State *L) {
|
||||||
global_State *g;
|
global_State *g = G(L);
|
||||||
|
GCObject *o;
|
||||||
lua_State *L1;
|
lua_State *L1;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
g = G(L);
|
|
||||||
luaC_checkGC(L);
|
luaC_checkGC(L);
|
||||||
/* create new thread */
|
/* create new thread */
|
||||||
L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
|
o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
|
||||||
L1->marked = luaC_white(g);
|
L1 = gco2th(o);
|
||||||
L1->tt = LUA_VTHREAD;
|
|
||||||
/* link it on list 'allgc' */
|
|
||||||
L1->next = g->allgc;
|
|
||||||
g->allgc = obj2gco(L1);
|
|
||||||
/* anchor it on L stack */
|
/* anchor it on L stack */
|
||||||
setthvalue2s(L, L->top, L1);
|
setthvalue2s(L, L->top.p, L1);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
preinit_thread(L1, g);
|
preinit_thread(L1, g);
|
||||||
L1->hookmask = L->hookmask;
|
L1->hookmask = L->hookmask;
|
||||||
@@ -304,7 +288,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
|
|||||||
L1->hook = L->hook;
|
L1->hook = L->hook;
|
||||||
resethookcount(L1);
|
resethookcount(L1);
|
||||||
/* initialize L1 extra space */
|
/* initialize L1 extra space */
|
||||||
memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread),
|
memcpy(lua_getextraspace(L1), lua_getextraspace(mainthread(g)),
|
||||||
LUA_EXTRASPACE);
|
LUA_EXTRASPACE);
|
||||||
luai_userstatethread(L, L1);
|
luai_userstatethread(L, L1);
|
||||||
stack_init(L1, L); /* init stack */
|
stack_init(L1, L); /* init stack */
|
||||||
@@ -315,7 +299,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
|
|||||||
|
|
||||||
void luaE_freethread (lua_State *L, lua_State *L1) {
|
void luaE_freethread (lua_State *L, lua_State *L1) {
|
||||||
LX *l = fromstate(L1);
|
LX *l = fromstate(L1);
|
||||||
luaF_closeupval(L1, L1->stack); /* close all upvalues */
|
luaF_closeupval(L1, L1->stack.p); /* close all upvalues */
|
||||||
lua_assert(L1->openupval == NULL);
|
lua_assert(L1->openupval == NULL);
|
||||||
luai_userstatefree(L, L1);
|
luai_userstatefree(L, L1);
|
||||||
freestack(L1);
|
freestack(L1);
|
||||||
@@ -323,42 +307,39 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaE_resetthread (lua_State *L, int status) {
|
TStatus luaE_resetthread (lua_State *L, TStatus status) {
|
||||||
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
|
resetCI(L);
|
||||||
setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */
|
|
||||||
ci->func = L->stack;
|
|
||||||
ci->callstatus = CIST_C;
|
|
||||||
if (status == LUA_YIELD)
|
if (status == LUA_YIELD)
|
||||||
status = LUA_OK;
|
status = LUA_OK;
|
||||||
status = luaD_closeprotected(L, 1, status);
|
status = luaD_closeprotected(L, 1, status);
|
||||||
if (status != LUA_OK) /* errors? */
|
if (status != LUA_OK) /* errors? */
|
||||||
luaD_seterrorobj(L, status, L->stack + 1);
|
luaD_seterrorobj(L, status, L->stack.p + 1);
|
||||||
else
|
else
|
||||||
L->top = L->stack + 1;
|
L->top.p = L->stack.p + 1;
|
||||||
ci->top = L->top + LUA_MINSTACK;
|
luaD_reallocstack(L, cast_int(L->ci->top.p - L->stack.p), 0);
|
||||||
L->status = cast_byte(status);
|
|
||||||
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_resetthread (lua_State *L) {
|
LUA_API int lua_closethread (lua_State *L, lua_State *from) {
|
||||||
int status;
|
TStatus status;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
|
L->nCcalls = (from) ? getCcalls(from) : 0;
|
||||||
status = luaE_resetthread(L, L->status);
|
status = luaE_resetthread(L, L->status);
|
||||||
|
if (L == from) /* closing itself? */
|
||||||
|
luaD_throwbaselevel(L, status);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return status;
|
return APIstatus(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud, unsigned seed) {
|
||||||
int i;
|
int i;
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
global_State *g;
|
global_State *g = cast(global_State*,
|
||||||
LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));
|
(*f)(ud, NULL, LUA_TTHREAD, sizeof(global_State)));
|
||||||
if (l == NULL) return NULL;
|
if (g == NULL) return NULL;
|
||||||
L = &l->l.l;
|
L = &g->mainth.l;
|
||||||
g = &l->g;
|
|
||||||
L->tt = LUA_VTHREAD;
|
L->tt = LUA_VTHREAD;
|
||||||
g->currentwhite = bitmask(WHITE0BIT);
|
g->currentwhite = bitmask(WHITE0BIT);
|
||||||
L->marked = luaC_white(g);
|
L->marked = luaC_white(g);
|
||||||
@@ -370,9 +351,8 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||||||
g->ud = ud;
|
g->ud = ud;
|
||||||
g->warnf = NULL;
|
g->warnf = NULL;
|
||||||
g->ud_warn = NULL;
|
g->ud_warn = NULL;
|
||||||
g->mainthread = L;
|
g->seed = seed;
|
||||||
g->seed = luai_makeseed(L);
|
g->gcstp = GCSTPGC; /* no GC while building state */
|
||||||
g->gcrunning = 0; /* no GC while building state */
|
|
||||||
g->strt.size = g->strt.nuse = 0;
|
g->strt.size = g->strt.nuse = 0;
|
||||||
g->strt.hash = NULL;
|
g->strt.hash = NULL;
|
||||||
setnilvalue(&g->l_registry);
|
setnilvalue(&g->l_registry);
|
||||||
@@ -388,16 +368,17 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||||||
g->gray = g->grayagain = NULL;
|
g->gray = g->grayagain = NULL;
|
||||||
g->weak = g->ephemeron = g->allweak = NULL;
|
g->weak = g->ephemeron = g->allweak = NULL;
|
||||||
g->twups = NULL;
|
g->twups = NULL;
|
||||||
g->totalbytes = sizeof(LG);
|
g->GCtotalbytes = sizeof(global_State);
|
||||||
|
g->GCmarked = 0;
|
||||||
g->GCdebt = 0;
|
g->GCdebt = 0;
|
||||||
g->lastatomic = 0;
|
|
||||||
setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */
|
setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */
|
||||||
setgcparam(g->gcpause, LUAI_GCPAUSE);
|
setgcparam(g, PAUSE, LUAI_GCPAUSE);
|
||||||
setgcparam(g->gcstepmul, LUAI_GCMUL);
|
setgcparam(g, STEPMUL, LUAI_GCMUL);
|
||||||
g->gcstepsize = LUAI_GCSTEPSIZE;
|
setgcparam(g, STEPSIZE, LUAI_GCSTEPSIZE);
|
||||||
setgcparam(g->genmajormul, LUAI_GENMAJORMUL);
|
setgcparam(g, MINORMUL, LUAI_GENMINORMUL);
|
||||||
g->genminormul = LUAI_GENMINORMUL;
|
setgcparam(g, MINORMAJOR, LUAI_MINORMAJOR);
|
||||||
for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
|
setgcparam(g, MAJORMINOR, LUAI_MAJORMINOR);
|
||||||
|
for (i=0; i < LUA_NUMTYPES; i++) g->mt[i] = NULL;
|
||||||
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
|
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
|
||||||
/* memory allocation error: free partial state */
|
/* memory allocation error: free partial state */
|
||||||
close_state(L);
|
close_state(L);
|
||||||
@@ -409,7 +390,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||||||
|
|
||||||
LUA_API void lua_close (lua_State *L) {
|
LUA_API void lua_close (lua_State *L) {
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
L = G(L)->mainthread; /* only the main thread can be closed */
|
L = mainthread(G(L)); /* only the main thread can be closed */
|
||||||
close_state(L);
|
close_state(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,9 +406,9 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
|
|||||||
** Generate a warning from an error message
|
** Generate a warning from an error message
|
||||||
*/
|
*/
|
||||||
void luaE_warnerror (lua_State *L, const char *where) {
|
void luaE_warnerror (lua_State *L, const char *where) {
|
||||||
TValue *errobj = s2v(L->top - 1); /* error object */
|
TValue *errobj = s2v(L->top.p - 1); /* error object */
|
||||||
const char *msg = (ttisstring(errobj))
|
const char *msg = (ttisstring(errobj))
|
||||||
? svalue(errobj)
|
? getstr(tsvalue(errobj))
|
||||||
: "error object is not a string";
|
: "error object is not a string";
|
||||||
/* produce warning "error in %s (%s)" (where, msg) */
|
/* produce warning "error in %s (%s)" (where, msg) */
|
||||||
luaE_warning(L, "error in ", 1);
|
luaE_warning(L, "error in ", 1);
|
||||||
+133
-86
@@ -9,6 +9,11 @@
|
|||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Some header files included here need this definition */
|
||||||
|
typedef struct CallInfo CallInfo;
|
||||||
|
|
||||||
|
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "ltm.h"
|
#include "ltm.h"
|
||||||
#include "lzio.h"
|
#include "lzio.h"
|
||||||
@@ -80,7 +85,7 @@
|
|||||||
** they must be visited again at the end of the cycle), but they are
|
** they must be visited again at the end of the cycle), but they are
|
||||||
** marked black because assignments to them must activate barriers (to
|
** marked black because assignments to them must activate barriers (to
|
||||||
** move them back to TOUCHED1).
|
** move them back to TOUCHED1).
|
||||||
** - Open upvales are kept gray to avoid barriers, but they stay out
|
** - Open upvalues are kept gray to avoid barriers, but they stay out
|
||||||
** of gray lists. (They don't even have a 'gclist' field.)
|
** of gray lists. (They don't even have a 'gclist' field.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -137,20 +142,32 @@ struct lua_longjmp; /* defined in ldo.c */
|
|||||||
#define EXTRA_STACK 5
|
#define EXTRA_STACK 5
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Size of cache for strings in the API. 'N' is the number of
|
||||||
|
** sets (better be a prime) and "M" is the size of each set.
|
||||||
|
** (M == 1 makes a direct cache.)
|
||||||
|
*/
|
||||||
|
#if !defined(STRCACHE_N)
|
||||||
|
#define STRCACHE_N 53
|
||||||
|
#define STRCACHE_M 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
|
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
|
||||||
|
|
||||||
#define stacksize(th) cast_int((th)->stack_last - (th)->stack)
|
#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
|
||||||
|
|
||||||
|
|
||||||
/* kinds of Garbage Collection */
|
/* kinds of Garbage Collection */
|
||||||
#define KGC_INC 0 /* incremental gc */
|
#define KGC_INC 0 /* incremental gc */
|
||||||
#define KGC_GEN 1 /* generational gc */
|
#define KGC_GENMINOR 1 /* generational gc in minor (regular) mode */
|
||||||
|
#define KGC_GENMAJOR 2 /* generational in major mode */
|
||||||
|
|
||||||
|
|
||||||
typedef struct stringtable {
|
typedef struct stringtable {
|
||||||
TString **hash;
|
TString **hash; /* array of buckets (linked lists of strings) */
|
||||||
int nuse; /* number of elements */
|
int nuse; /* number of elements */
|
||||||
int size;
|
int size; /* number of buckets */
|
||||||
} stringtable;
|
} stringtable;
|
||||||
|
|
||||||
|
|
||||||
@@ -165,18 +182,16 @@ typedef struct stringtable {
|
|||||||
** - field 'nyield' is used only while a function is "doing" an
|
** - field 'nyield' is used only while a function is "doing" an
|
||||||
** yield (from the yield until the next resume);
|
** yield (from the yield until the next resume);
|
||||||
** - field 'nres' is used only while closing tbc variables when
|
** - field 'nres' is used only while closing tbc variables when
|
||||||
** returning from a C function;
|
** returning from a function;
|
||||||
** - field 'transferinfo' is used only during call/returnhooks,
|
|
||||||
** before the function starts or after it ends.
|
|
||||||
*/
|
*/
|
||||||
typedef struct CallInfo {
|
struct CallInfo {
|
||||||
StkId func; /* function index in the stack */
|
StkIdRel func; /* function index in the stack */
|
||||||
StkId top; /* top for this function */
|
StkIdRel top; /* top for this function */
|
||||||
struct CallInfo *previous, *next; /* dynamic call link */
|
struct CallInfo *previous, *next; /* dynamic call link */
|
||||||
union {
|
union {
|
||||||
struct { /* only for Lua functions */
|
struct { /* only for Lua functions */
|
||||||
const Instruction *savedpc;
|
const Instruction *savedpc;
|
||||||
volatile l_signalT trap;
|
volatile l_signalT trap; /* function is tracing lines/counts */
|
||||||
int nextraargs; /* # of extra arguments in vararg functions */
|
int nextraargs; /* # of extra arguments in vararg functions */
|
||||||
} l;
|
} l;
|
||||||
struct { /* only for C functions */
|
struct { /* only for C functions */
|
||||||
@@ -189,35 +204,54 @@ typedef struct CallInfo {
|
|||||||
int funcidx; /* called-function index */
|
int funcidx; /* called-function index */
|
||||||
int nyield; /* number of values yielded */
|
int nyield; /* number of values yielded */
|
||||||
int nres; /* number of values returned */
|
int nres; /* number of values returned */
|
||||||
struct { /* info about transferred values (for call/return hooks) */
|
|
||||||
unsigned short ftransfer; /* offset of first value transferred */
|
|
||||||
unsigned short ntransfer; /* number of values transferred */
|
|
||||||
} transferinfo;
|
|
||||||
} u2;
|
} u2;
|
||||||
short nresults; /* expected number of results from this function */
|
l_uint32 callstatus;
|
||||||
unsigned short callstatus;
|
};
|
||||||
} CallInfo;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Maximum expected number of results from a function
|
||||||
|
** (must fit in CIST_NRESULTS).
|
||||||
|
*/
|
||||||
|
#define MAXRESULTS 250
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Bits in CallInfo status
|
** Bits in CallInfo status
|
||||||
*/
|
*/
|
||||||
#define CIST_OAH (1<<0) /* original value of 'allowhook' */
|
/* bits 0-7 are the expected number of results from this function + 1 */
|
||||||
#define CIST_C (1<<1) /* call is running a C function */
|
#define CIST_NRESULTS 0xffu
|
||||||
#define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */
|
|
||||||
#define CIST_HOOKED (1<<3) /* call is running a debug hook */
|
|
||||||
#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */
|
|
||||||
#define CIST_TAIL (1<<5) /* call was tail called */
|
|
||||||
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
|
|
||||||
#define CIST_FIN (1<<7) /* call is running a finalizer */
|
|
||||||
#define CIST_TRAN (1<<8) /* 'ci' has transfer information */
|
|
||||||
#define CIST_CLSRET (1<<9) /* function is closing tbc variables */
|
|
||||||
/* Bits 10-12 are used for CIST_RECST (see below) */
|
|
||||||
#define CIST_RECST 10
|
|
||||||
#if defined(LUA_COMPAT_LT_LE)
|
|
||||||
#define CIST_LEQ (1<<13) /* using __lt for __le */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
/* bits 8-11 count call metamethods (and their extra arguments) */
|
||||||
|
#define CIST_CCMT 8 /* the offset, not the mask */
|
||||||
|
#define MAX_CCMT (0xfu << CIST_CCMT)
|
||||||
|
|
||||||
|
/* Bits 12-14 are used for CIST_RECST (see below) */
|
||||||
|
#define CIST_RECST 12 /* the offset, not the mask */
|
||||||
|
|
||||||
|
/* call is running a C function (still in first 16 bits) */
|
||||||
|
#define CIST_C (1u << (CIST_RECST + 3))
|
||||||
|
/* call is on a fresh "luaV_execute" frame */
|
||||||
|
#define CIST_FRESH (cast(l_uint32, CIST_C) << 1)
|
||||||
|
/* function is closing tbc variables */
|
||||||
|
#define CIST_CLSRET (CIST_FRESH << 1)
|
||||||
|
/* function has tbc variables to close */
|
||||||
|
#define CIST_TBC (CIST_CLSRET << 1)
|
||||||
|
/* original value of 'allowhook' */
|
||||||
|
#define CIST_OAH (CIST_TBC << 1)
|
||||||
|
/* call is running a debug hook */
|
||||||
|
#define CIST_HOOKED (CIST_OAH << 1)
|
||||||
|
/* doing a yieldable protected call */
|
||||||
|
#define CIST_YPCALL (CIST_HOOKED << 1)
|
||||||
|
/* call was tail called */
|
||||||
|
#define CIST_TAIL (CIST_YPCALL << 1)
|
||||||
|
/* last hook called yielded */
|
||||||
|
#define CIST_HOOKYIELD (CIST_TAIL << 1)
|
||||||
|
/* function "called" a finalizer */
|
||||||
|
#define CIST_FIN (CIST_HOOKYIELD << 1)
|
||||||
|
|
||||||
|
|
||||||
|
#define get_nresults(cs) (cast_int((cs) & CIST_NRESULTS) - 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Field CIST_RECST stores the "recover status", used to keep the error
|
** Field CIST_RECST stores the "recover status", used to keep the error
|
||||||
@@ -228,8 +262,8 @@ typedef struct CallInfo {
|
|||||||
#define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7)
|
#define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7)
|
||||||
#define setcistrecst(ci,st) \
|
#define setcistrecst(ci,st) \
|
||||||
check_exp(((st) & 7) == (st), /* status must fit in three bits */ \
|
check_exp(((st) & 7) == (st), /* status must fit in three bits */ \
|
||||||
((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST)) \
|
((ci)->callstatus = ((ci)->callstatus & ~(7u << CIST_RECST)) \
|
||||||
| ((st) << CIST_RECST)))
|
| (cast(l_uint32, st) << CIST_RECST)))
|
||||||
|
|
||||||
|
|
||||||
/* active function is a Lua function */
|
/* active function is a Lua function */
|
||||||
@@ -238,9 +272,53 @@ typedef struct CallInfo {
|
|||||||
/* call is running Lua code (not a hook) */
|
/* call is running Lua code (not a hook) */
|
||||||
#define isLuacode(ci) (!((ci)->callstatus & (CIST_C | CIST_HOOKED)))
|
#define isLuacode(ci) (!((ci)->callstatus & (CIST_C | CIST_HOOKED)))
|
||||||
|
|
||||||
/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */
|
|
||||||
#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v))
|
#define setoah(ci,v) \
|
||||||
#define getoah(st) ((st) & CIST_OAH)
|
((ci)->callstatus = ((v) ? (ci)->callstatus | CIST_OAH \
|
||||||
|
: (ci)->callstatus & ~CIST_OAH))
|
||||||
|
#define getoah(ci) (((ci)->callstatus & CIST_OAH) ? 1 : 0)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 'per thread' state
|
||||||
|
*/
|
||||||
|
struct lua_State {
|
||||||
|
CommonHeader;
|
||||||
|
lu_byte allowhook;
|
||||||
|
TStatus status;
|
||||||
|
StkIdRel top; /* first free slot in the stack */
|
||||||
|
struct global_State *l_G;
|
||||||
|
CallInfo *ci; /* call info for current function */
|
||||||
|
StkIdRel stack_last; /* end of stack (last element + 1) */
|
||||||
|
StkIdRel stack; /* stack base */
|
||||||
|
UpVal *openupval; /* list of open upvalues in this stack */
|
||||||
|
StkIdRel tbclist; /* list of to-be-closed variables */
|
||||||
|
GCObject *gclist;
|
||||||
|
struct lua_State *twups; /* list of threads with open upvalues */
|
||||||
|
struct lua_longjmp *errorJmp; /* current error recover point */
|
||||||
|
CallInfo base_ci; /* CallInfo for first level (C host) */
|
||||||
|
volatile lua_Hook hook;
|
||||||
|
ptrdiff_t errfunc; /* current error handling function (stack index) */
|
||||||
|
l_uint32 nCcalls; /* number of nested non-yieldable or C calls */
|
||||||
|
int oldpc; /* last pc traced */
|
||||||
|
int nci; /* number of items in 'ci' list */
|
||||||
|
int basehookcount;
|
||||||
|
int hookcount;
|
||||||
|
volatile l_signalT hookmask;
|
||||||
|
struct { /* info about transferred values (for call/return hooks) */
|
||||||
|
int ftransfer; /* offset of first value transferred */
|
||||||
|
int ntransfer; /* number of values transferred */
|
||||||
|
} transferinfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** thread state + extra space
|
||||||
|
*/
|
||||||
|
typedef struct LX {
|
||||||
|
lu_byte extra_[LUA_EXTRASPACE];
|
||||||
|
lua_State l;
|
||||||
|
} LX;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -249,25 +327,21 @@ typedef struct CallInfo {
|
|||||||
typedef struct global_State {
|
typedef struct global_State {
|
||||||
lua_Alloc frealloc; /* function to reallocate memory */
|
lua_Alloc frealloc; /* function to reallocate memory */
|
||||||
void *ud; /* auxiliary data to 'frealloc' */
|
void *ud; /* auxiliary data to 'frealloc' */
|
||||||
l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
|
l_mem GCtotalbytes; /* number of bytes currently allocated + debt */
|
||||||
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
|
l_mem GCdebt; /* bytes counted but not yet allocated */
|
||||||
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
|
l_mem GCmarked; /* number of objects marked in a GC cycle */
|
||||||
lu_mem lastatomic; /* see function 'genstep' in file 'lgc.c' */
|
l_mem GCmajorminor; /* auxiliary counter to control major-minor shifts */
|
||||||
stringtable strt; /* hash table for strings */
|
stringtable strt; /* hash table for strings */
|
||||||
TValue l_registry;
|
TValue l_registry;
|
||||||
TValue nilvalue; /* a nil value */
|
TValue nilvalue; /* a nil value */
|
||||||
unsigned int seed; /* randomized seed for hashes */
|
unsigned int seed; /* randomized seed for hashes */
|
||||||
|
lu_byte gcparams[LUA_GCPN];
|
||||||
lu_byte currentwhite;
|
lu_byte currentwhite;
|
||||||
lu_byte gcstate; /* state of garbage collector */
|
lu_byte gcstate; /* state of garbage collector */
|
||||||
lu_byte gckind; /* kind of GC running */
|
lu_byte gckind; /* kind of GC running */
|
||||||
lu_byte gcstopem; /* stops emergency collections */
|
lu_byte gcstopem; /* stops emergency collections */
|
||||||
lu_byte genminormul; /* control for minor generational collections */
|
lu_byte gcstp; /* control whether GC is running */
|
||||||
lu_byte genmajormul; /* control for major generational collections */
|
|
||||||
lu_byte gcrunning; /* true if GC is running */
|
|
||||||
lu_byte gcemergency; /* true if this is an emergency collection */
|
lu_byte gcemergency; /* true if this is an emergency collection */
|
||||||
lu_byte gcpause; /* size of pause between successive GCs */
|
|
||||||
lu_byte gcstepmul; /* GC "speed" */
|
|
||||||
lu_byte gcstepsize; /* (log2 of) GC granularity */
|
|
||||||
GCObject *allgc; /* list of all collectable objects */
|
GCObject *allgc; /* list of all collectable objects */
|
||||||
GCObject **sweepgc; /* current position of sweep in list */
|
GCObject **sweepgc; /* current position of sweep in list */
|
||||||
GCObject *finobj; /* list of collectable objects with finalizers */
|
GCObject *finobj; /* list of collectable objects with finalizers */
|
||||||
@@ -288,46 +362,18 @@ typedef struct global_State {
|
|||||||
GCObject *finobjrold; /* list of really old objects with finalizers */
|
GCObject *finobjrold; /* list of really old objects with finalizers */
|
||||||
struct lua_State *twups; /* list of threads with open upvalues */
|
struct lua_State *twups; /* list of threads with open upvalues */
|
||||||
lua_CFunction panic; /* to be called in unprotected errors */
|
lua_CFunction panic; /* to be called in unprotected errors */
|
||||||
struct lua_State *mainthread;
|
|
||||||
TString *memerrmsg; /* message for memory-allocation errors */
|
TString *memerrmsg; /* message for memory-allocation errors */
|
||||||
TString *tmname[TM_N]; /* array with tag-method names */
|
TString *tmname[TM_N]; /* array with tag-method names */
|
||||||
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
|
struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
|
||||||
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
|
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
|
||||||
lua_WarnFunction warnf; /* warning function */
|
lua_WarnFunction warnf; /* warning function */
|
||||||
void *ud_warn; /* auxiliary data to 'warnf' */
|
void *ud_warn; /* auxiliary data to 'warnf' */
|
||||||
|
LX mainth; /* main thread of this state */
|
||||||
} global_State;
|
} global_State;
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** 'per thread' state
|
|
||||||
*/
|
|
||||||
struct lua_State {
|
|
||||||
CommonHeader;
|
|
||||||
lu_byte status;
|
|
||||||
lu_byte allowhook;
|
|
||||||
unsigned short nci; /* number of items in 'ci' list */
|
|
||||||
StkId top; /* first free slot in the stack */
|
|
||||||
global_State *l_G;
|
|
||||||
CallInfo *ci; /* call info for current function */
|
|
||||||
StkId stack_last; /* end of stack (last element + 1) */
|
|
||||||
StkId stack; /* stack base */
|
|
||||||
UpVal *openupval; /* list of open upvalues in this stack */
|
|
||||||
StkId tbclist; /* list of to-be-closed variables */
|
|
||||||
GCObject *gclist;
|
|
||||||
struct lua_State *twups; /* list of threads with open upvalues */
|
|
||||||
struct lua_longjmp *errorJmp; /* current error recover point */
|
|
||||||
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
|
|
||||||
volatile lua_Hook hook;
|
|
||||||
ptrdiff_t errfunc; /* current error handling function (stack index) */
|
|
||||||
l_uint32 nCcalls; /* number of nested (non-yieldable | C) calls */
|
|
||||||
int oldpc; /* last pc traced */
|
|
||||||
int basehookcount;
|
|
||||||
int hookcount;
|
|
||||||
volatile l_signalT hookmask;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define G(L) (L->l_G)
|
#define G(L) (L->l_G)
|
||||||
|
#define mainthread(G) (&(G)->mainth.l)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** 'g->nilvalue' being a nil value flags that the state was completely
|
** 'g->nilvalue' being a nil value flags that the state was completely
|
||||||
@@ -380,24 +426,25 @@ union GCUnion {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** macro to convert a Lua object into a GCObject
|
** macro to convert a Lua object into a GCObject
|
||||||
** (The access to 'tt' tries to ensure that 'v' is actually a Lua object.)
|
|
||||||
*/
|
*/
|
||||||
#define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc))
|
#define obj2gco(v) \
|
||||||
|
check_exp(novariant((v)->tt) >= LUA_TSTRING, &(cast_u(v)->gc))
|
||||||
|
|
||||||
|
|
||||||
/* actual number of total bytes allocated */
|
/* actual number of total memory allocated */
|
||||||
#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt)
|
#define gettotalbytes(g) ((g)->GCtotalbytes - (g)->GCdebt)
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
|
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
|
||||||
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
||||||
|
LUAI_FUNC lu_mem luaE_threadsize (lua_State *L);
|
||||||
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
|
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
|
||||||
LUAI_FUNC void luaE_freeCI (lua_State *L);
|
|
||||||
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
||||||
LUAI_FUNC void luaE_checkcstack (lua_State *L);
|
LUAI_FUNC void luaE_checkcstack (lua_State *L);
|
||||||
LUAI_FUNC void luaE_incCstack (lua_State *L);
|
LUAI_FUNC void luaE_incCstack (lua_State *L);
|
||||||
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
|
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
|
||||||
LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
|
LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
|
||||||
LUAI_FUNC int luaE_resetthread (lua_State *L, int status);
|
LUAI_FUNC TStatus luaE_resetthread (lua_State *L, TStatus status);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+105
-25
@@ -25,22 +25,32 @@
|
|||||||
/*
|
/*
|
||||||
** Maximum size for string table.
|
** Maximum size for string table.
|
||||||
*/
|
*/
|
||||||
#define MAXSTRTB cast_int(luaM_limitN(MAX_INT, TString*))
|
#define MAXSTRTB cast_int(luaM_limitN(INT_MAX, TString*))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Initial size for the string table (must be power of 2).
|
||||||
|
** The Lua core alone registers ~50 strings (reserved words +
|
||||||
|
** metaevent keys + a few others). Libraries would typically add
|
||||||
|
** a few dozens more.
|
||||||
|
*/
|
||||||
|
#if !defined(MINSTRTABSIZE)
|
||||||
|
#define MINSTRTABSIZE 128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** equality for long strings
|
** generic equality for strings
|
||||||
*/
|
*/
|
||||||
int luaS_eqlngstr (TString *a, TString *b) {
|
int luaS_eqstr (TString *a, TString *b) {
|
||||||
size_t len = a->u.lnglen;
|
size_t len1, len2;
|
||||||
lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR);
|
const char *s1 = getlstr(a, len1);
|
||||||
return (a == b) || /* same instance or... */
|
const char *s2 = getlstr(b, len2);
|
||||||
((len == b->u.lnglen) && /* equal length and ... */
|
return ((len1 == len2) && /* equal length and ... */
|
||||||
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
|
(memcmp(s1, s2, len1) == 0)); /* equal contents */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
|
static unsigned luaS_hash (const char *str, size_t l, unsigned seed) {
|
||||||
unsigned int h = seed ^ cast_uint(l);
|
unsigned int h = seed ^ cast_uint(l);
|
||||||
for (; l > 0; l--)
|
for (; l > 0; l--)
|
||||||
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
|
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
|
||||||
@@ -48,11 +58,11 @@ unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int luaS_hashlongstr (TString *ts) {
|
unsigned luaS_hashlongstr (TString *ts) {
|
||||||
lua_assert(ts->tt == LUA_VLNGSTR);
|
lua_assert(ts->tt == LUA_VLNGSTR);
|
||||||
if (ts->extra == 0) { /* no hash? */
|
if (ts->extra == 0) { /* no hash? */
|
||||||
size_t len = ts->u.lnglen;
|
size_t len = ts->u.lnglen;
|
||||||
ts->hash = luaS_hash(getstr(ts), len, ts->hash);
|
ts->hash = luaS_hash(getlngstr(ts), len, ts->hash);
|
||||||
ts->extra = 1; /* now it has its hash */
|
ts->extra = 1; /* now it has its hash */
|
||||||
}
|
}
|
||||||
return ts->hash;
|
return ts->hash;
|
||||||
@@ -136,27 +146,43 @@ void luaS_init (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t luaS_sizelngstr (size_t len, int kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case LSTRREG: /* regular long string */
|
||||||
|
/* don't need 'falloc'/'ud', but need space for content */
|
||||||
|
return offsetof(TString, falloc) + (len + 1) * sizeof(char);
|
||||||
|
case LSTRFIX: /* fixed external long string */
|
||||||
|
/* don't need 'falloc'/'ud' */
|
||||||
|
return offsetof(TString, falloc);
|
||||||
|
default: /* external long string with deallocation */
|
||||||
|
lua_assert(kind == LSTRMEM);
|
||||||
|
return sizeof(TString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** creates a new string object
|
** creates a new string object
|
||||||
*/
|
*/
|
||||||
static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
|
static TString *createstrobj (lua_State *L, size_t totalsize, lu_byte tag,
|
||||||
|
unsigned h) {
|
||||||
TString *ts;
|
TString *ts;
|
||||||
GCObject *o;
|
GCObject *o;
|
||||||
size_t totalsize; /* total size of TString object */
|
|
||||||
totalsize = sizelstring(l);
|
|
||||||
o = luaC_newobj(L, tag, totalsize);
|
o = luaC_newobj(L, tag, totalsize);
|
||||||
ts = gco2ts(o);
|
ts = gco2ts(o);
|
||||||
ts->hash = h;
|
ts->hash = h;
|
||||||
ts->extra = 0;
|
ts->extra = 0;
|
||||||
getstr(ts)[l] = '\0'; /* ending 0 */
|
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TString *luaS_createlngstrobj (lua_State *L, size_t l) {
|
TString *luaS_createlngstrobj (lua_State *L, size_t l) {
|
||||||
TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed);
|
size_t totalsize = luaS_sizelngstr(l, LSTRREG);
|
||||||
|
TString *ts = createstrobj(L, totalsize, LUA_VLNGSTR, G(L)->seed);
|
||||||
ts->u.lnglen = l;
|
ts->u.lnglen = l;
|
||||||
|
ts->shrlen = LSTRREG; /* signals that it is a regular long string */
|
||||||
|
ts->contents = cast_charp(ts) + offsetof(TString, falloc);
|
||||||
|
ts->contents[l] = '\0'; /* ending 0 */
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,9 +198,9 @@ void luaS_remove (lua_State *L, TString *ts) {
|
|||||||
|
|
||||||
|
|
||||||
static void growstrtab (lua_State *L, stringtable *tb) {
|
static void growstrtab (lua_State *L, stringtable *tb) {
|
||||||
if (l_unlikely(tb->nuse == MAX_INT)) { /* too many strings? */
|
if (l_unlikely(tb->nuse == INT_MAX)) { /* too many strings? */
|
||||||
luaC_fullgc(L, 1); /* try to free some... */
|
luaC_fullgc(L, 1); /* try to free some... */
|
||||||
if (tb->nuse == MAX_INT) /* still too many? */
|
if (tb->nuse == INT_MAX) /* still too many? */
|
||||||
luaM_error(L); /* cannot even create a message... */
|
luaM_error(L); /* cannot even create a message... */
|
||||||
}
|
}
|
||||||
if (tb->size <= MAXSTRTB / 2) /* can grow string table? */
|
if (tb->size <= MAXSTRTB / 2) /* can grow string table? */
|
||||||
@@ -193,7 +219,8 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
|
|||||||
TString **list = &tb->hash[lmod(h, tb->size)];
|
TString **list = &tb->hash[lmod(h, tb->size)];
|
||||||
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
|
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
|
||||||
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
|
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
|
||||||
if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
|
if (l == cast_uint(ts->shrlen) &&
|
||||||
|
(memcmp(str, getshrstr(ts), l * sizeof(char)) == 0)) {
|
||||||
/* found! */
|
/* found! */
|
||||||
if (isdead(g, ts)) /* dead (but not collected yet)? */
|
if (isdead(g, ts)) /* dead (but not collected yet)? */
|
||||||
changewhite(ts); /* resurrect it */
|
changewhite(ts); /* resurrect it */
|
||||||
@@ -205,9 +232,10 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
|
|||||||
growstrtab(L, tb);
|
growstrtab(L, tb);
|
||||||
list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */
|
list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */
|
||||||
}
|
}
|
||||||
ts = createstrobj(L, l, LUA_VSHRSTR, h);
|
ts = createstrobj(L, sizestrshr(l), LUA_VSHRSTR, h);
|
||||||
memcpy(getstr(ts), str, l * sizeof(char));
|
ts->shrlen = cast(ls_byte, l);
|
||||||
ts->shrlen = cast_byte(l);
|
getshrstr(ts)[l] = '\0'; /* ending 0 */
|
||||||
|
memcpy(getshrstr(ts), str, l * sizeof(char));
|
||||||
ts->u.hnext = *list;
|
ts->u.hnext = *list;
|
||||||
*list = ts;
|
*list = ts;
|
||||||
tb->nuse++;
|
tb->nuse++;
|
||||||
@@ -223,10 +251,10 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
|
|||||||
return internshrstr(L, str, l);
|
return internshrstr(L, str, l);
|
||||||
else {
|
else {
|
||||||
TString *ts;
|
TString *ts;
|
||||||
if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char)))
|
if (l_unlikely(l * sizeof(char) >= (MAX_SIZE - sizeof(TString))))
|
||||||
luaM_toobig(L);
|
luaM_toobig(L);
|
||||||
ts = luaS_createlngstrobj(L, l);
|
ts = luaS_createlngstrobj(L, l);
|
||||||
memcpy(getstr(ts), str, l * sizeof(char));
|
memcpy(getlngstr(ts), str, l * sizeof(char));
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,7 +283,7 @@ TString *luaS_new (lua_State *L, const char *str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) {
|
Udata *luaS_newudata (lua_State *L, size_t s, unsigned short nuvalue) {
|
||||||
Udata *u;
|
Udata *u;
|
||||||
int i;
|
int i;
|
||||||
GCObject *o;
|
GCObject *o;
|
||||||
@@ -271,3 +299,55 @@ Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) {
|
|||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct NewExt {
|
||||||
|
ls_byte kind;
|
||||||
|
const char *s;
|
||||||
|
size_t len;
|
||||||
|
TString *ts; /* output */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void f_newext (lua_State *L, void *ud) {
|
||||||
|
struct NewExt *ne = cast(struct NewExt *, ud);
|
||||||
|
size_t size = luaS_sizelngstr(0, ne->kind);
|
||||||
|
ne->ts = createstrobj(L, size, LUA_VLNGSTR, G(L)->seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TString *luaS_newextlstr (lua_State *L,
|
||||||
|
const char *s, size_t len, lua_Alloc falloc, void *ud) {
|
||||||
|
struct NewExt ne;
|
||||||
|
if (!falloc) {
|
||||||
|
ne.kind = LSTRFIX;
|
||||||
|
f_newext(L, &ne); /* just create header */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ne.kind = LSTRMEM;
|
||||||
|
if (luaD_rawrunprotected(L, f_newext, &ne) != LUA_OK) { /* mem. error? */
|
||||||
|
(*falloc)(ud, cast_voidp(s), len + 1, 0); /* free external string */
|
||||||
|
luaM_error(L); /* re-raise memory error */
|
||||||
|
}
|
||||||
|
ne.ts->falloc = falloc;
|
||||||
|
ne.ts->ud = ud;
|
||||||
|
}
|
||||||
|
ne.ts->shrlen = ne.kind;
|
||||||
|
ne.ts->u.lnglen = len;
|
||||||
|
ne.ts->contents = cast_charp(s);
|
||||||
|
return ne.ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Normalize an external string: If it is short, internalize it.
|
||||||
|
*/
|
||||||
|
TString *luaS_normstr (lua_State *L, TString *ts) {
|
||||||
|
size_t len = ts->u.lnglen;
|
||||||
|
if (len > LUAI_MAXSHORTLEN)
|
||||||
|
return ts; /* long string; keep the original */
|
||||||
|
else {
|
||||||
|
const char *str = getlngstr(ts);
|
||||||
|
return internshrstr(L, str, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+24
-8
@@ -20,10 +20,23 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Size of a TString: Size of the header plus space for the string
|
** Maximum length for short strings, that is, strings that are
|
||||||
|
** internalized. (Cannot be smaller than reserved words or tags for
|
||||||
|
** metamethods, as these strings must be internalized;
|
||||||
|
** #("function") = 8, #("__newindex") = 10.)
|
||||||
|
*/
|
||||||
|
#if !defined(LUAI_MAXSHORTLEN)
|
||||||
|
#define LUAI_MAXSHORTLEN 40
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Size of a short TString: Size of the header plus space for the string
|
||||||
** itself (including final '\0').
|
** itself (including final '\0').
|
||||||
*/
|
*/
|
||||||
#define sizelstring(l) (offsetof(TString, contents) + ((l) + 1) * sizeof(char))
|
#define sizestrshr(l) \
|
||||||
|
(offsetof(TString, contents) + ((l) + 1) * sizeof(char))
|
||||||
|
|
||||||
|
|
||||||
#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
|
#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
|
||||||
(sizeof(s)/sizeof(char))-1))
|
(sizeof(s)/sizeof(char))-1))
|
||||||
@@ -32,7 +45,7 @@
|
|||||||
/*
|
/*
|
||||||
** test whether a string is a reserved word
|
** test whether a string is a reserved word
|
||||||
*/
|
*/
|
||||||
#define isreserved(s) ((s)->tt == LUA_VSHRSTR && (s)->extra > 0)
|
#define isreserved(s) (strisshr(s) && (s)->extra > 0)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -41,17 +54,20 @@
|
|||||||
#define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b))
|
#define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b))
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
|
LUAI_FUNC unsigned luaS_hashlongstr (TString *ts);
|
||||||
LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
|
LUAI_FUNC int luaS_eqstr (TString *a, TString *b);
|
||||||
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
|
|
||||||
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
|
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
|
||||||
LUAI_FUNC void luaS_clearcache (global_State *g);
|
LUAI_FUNC void luaS_clearcache (global_State *g);
|
||||||
LUAI_FUNC void luaS_init (lua_State *L);
|
LUAI_FUNC void luaS_init (lua_State *L);
|
||||||
LUAI_FUNC void luaS_remove (lua_State *L, TString *ts);
|
LUAI_FUNC void luaS_remove (lua_State *L, TString *ts);
|
||||||
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue);
|
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s,
|
||||||
|
unsigned short nuvalue);
|
||||||
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
|
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
|
||||||
LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
|
LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
|
||||||
LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
|
LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
|
||||||
|
LUAI_FUNC TString *luaS_newextlstr (lua_State *L,
|
||||||
|
const char *s, size_t len, lua_Alloc falloc, void *ud);
|
||||||
|
LUAI_FUNC size_t luaS_sizelngstr (size_t len, int kind);
|
||||||
|
LUAI_FUNC TString *luaS_normstr (lua_State *L, TString *ts);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+245
-168
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -36,22 +37,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* macro to 'unsign' a character */
|
|
||||||
#define uchar(c) ((unsigned char)(c))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Some sizes are better limited to fit in 'int', but must also fit in
|
|
||||||
** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
|
|
||||||
*/
|
|
||||||
#define MAX_SIZET ((size_t)(~(size_t)0))
|
|
||||||
|
|
||||||
#define MAXSIZE \
|
|
||||||
(sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int str_len (lua_State *L) {
|
static int str_len (lua_State *L) {
|
||||||
size_t l;
|
size_t l;
|
||||||
luaL_checklstring(L, 1, &l);
|
luaL_checklstring(L, 1, &l);
|
||||||
@@ -128,7 +113,7 @@ static int str_lower (lua_State *L) {
|
|||||||
const char *s = luaL_checklstring(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &l);
|
||||||
char *p = luaL_buffinitsize(L, &b, l);
|
char *p = luaL_buffinitsize(L, &b, l);
|
||||||
for (i=0; i<l; i++)
|
for (i=0; i<l; i++)
|
||||||
p[i] = tolower(uchar(s[i]));
|
p[i] = cast_char(tolower(cast_uchar(s[i])));
|
||||||
luaL_pushresultsize(&b, l);
|
luaL_pushresultsize(&b, l);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -141,33 +126,37 @@ static int str_upper (lua_State *L) {
|
|||||||
const char *s = luaL_checklstring(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &l);
|
||||||
char *p = luaL_buffinitsize(L, &b, l);
|
char *p = luaL_buffinitsize(L, &b, l);
|
||||||
for (i=0; i<l; i++)
|
for (i=0; i<l; i++)
|
||||||
p[i] = toupper(uchar(s[i]));
|
p[i] = cast_char(toupper(cast_uchar(s[i])));
|
||||||
luaL_pushresultsize(&b, l);
|
luaL_pushresultsize(&b, l);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** MAX_SIZE is limited both by size_t and lua_Integer.
|
||||||
|
** When x <= MAX_SIZE, x can be safely cast to size_t or lua_Integer.
|
||||||
|
*/
|
||||||
static int str_rep (lua_State *L) {
|
static int str_rep (lua_State *L) {
|
||||||
size_t l, lsep;
|
size_t len, lsep;
|
||||||
const char *s = luaL_checklstring(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &len);
|
||||||
lua_Integer n = luaL_checkinteger(L, 2);
|
lua_Integer n = luaL_checkinteger(L, 2);
|
||||||
const char *sep = luaL_optlstring(L, 3, "", &lsep);
|
const char *sep = luaL_optlstring(L, 3, "", &lsep);
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
lua_pushliteral(L, "");
|
lua_pushliteral(L, "");
|
||||||
else if (l_unlikely(l + lsep < l || l + lsep > MAXSIZE / n))
|
else if (l_unlikely(len > MAX_SIZE - lsep ||
|
||||||
|
cast_st2S(len + lsep) > cast_st2S(MAX_SIZE) / n))
|
||||||
return luaL_error(L, "resulting string too large");
|
return luaL_error(L, "resulting string too large");
|
||||||
else {
|
else {
|
||||||
size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep;
|
size_t totallen = (cast_sizet(n) * (len + lsep)) - lsep;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
char *p = luaL_buffinitsize(L, &b, totallen);
|
char *p = luaL_buffinitsize(L, &b, totallen);
|
||||||
while (n-- > 1) { /* first n-1 copies (followed by separator) */
|
while (n-- > 1) { /* first n-1 copies (followed by separator) */
|
||||||
memcpy(p, s, l * sizeof(char)); p += l;
|
memcpy(p, s, len * sizeof(char)); p += len;
|
||||||
if (lsep > 0) { /* empty 'memcpy' is not that cheap */
|
if (lsep > 0) { /* empty 'memcpy' is not that cheap */
|
||||||
memcpy(p, sep, lsep * sizeof(char));
|
memcpy(p, sep, lsep * sizeof(char)); p += lsep;
|
||||||
p += lsep;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */
|
memcpy(p, s, len * sizeof(char)); /* last copy without separator */
|
||||||
luaL_pushresultsize(&b, totallen);
|
luaL_pushresultsize(&b, totallen);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -187,7 +176,7 @@ static int str_byte (lua_State *L) {
|
|||||||
n = (int)(pose - posi) + 1;
|
n = (int)(pose - posi) + 1;
|
||||||
luaL_checkstack(L, n, "string slice too long");
|
luaL_checkstack(L, n, "string slice too long");
|
||||||
for (i=0; i<n; i++)
|
for (i=0; i<n; i++)
|
||||||
lua_pushinteger(L, uchar(s[posi+i-1]));
|
lua_pushinteger(L, cast_uchar(s[posi + cast_uint(i) - 1]));
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,13 +185,13 @@ static int str_char (lua_State *L) {
|
|||||||
int n = lua_gettop(L); /* number of arguments */
|
int n = lua_gettop(L); /* number of arguments */
|
||||||
int i;
|
int i;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
char *p = luaL_buffinitsize(L, &b, n);
|
char *p = luaL_buffinitsize(L, &b, cast_uint(n));
|
||||||
for (i=1; i<=n; i++) {
|
for (i=1; i<=n; i++) {
|
||||||
lua_Unsigned c = (lua_Unsigned)luaL_checkinteger(L, i);
|
lua_Unsigned c = (lua_Unsigned)luaL_checkinteger(L, i);
|
||||||
luaL_argcheck(L, c <= (lua_Unsigned)UCHAR_MAX, i, "value out of range");
|
luaL_argcheck(L, c <= (lua_Unsigned)UCHAR_MAX, i, "value out of range");
|
||||||
p[i - 1] = uchar(c);
|
p[i - 1] = cast_char(cast_uchar(c));
|
||||||
}
|
}
|
||||||
luaL_pushresultsize(&b, n);
|
luaL_pushresultsize(&b, cast_uint(n));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +214,12 @@ static int writer (lua_State *L, const void *b, size_t size, void *ud) {
|
|||||||
state->init = 1;
|
state->init = 1;
|
||||||
luaL_buffinit(L, &state->B);
|
luaL_buffinit(L, &state->B);
|
||||||
}
|
}
|
||||||
luaL_addlstring(&state->B, (const char *)b, size);
|
if (b == NULL) { /* finishing dump? */
|
||||||
|
luaL_pushresult(&state->B); /* push result */
|
||||||
|
lua_replace(L, 1); /* move it to reserved slot */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
luaL_addlstring(&state->B, (const char *)b, size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,12 +227,13 @@ static int writer (lua_State *L, const void *b, size_t size, void *ud) {
|
|||||||
static int str_dump (lua_State *L) {
|
static int str_dump (lua_State *L) {
|
||||||
struct str_Writer state;
|
struct str_Writer state;
|
||||||
int strip = lua_toboolean(L, 2);
|
int strip = lua_toboolean(L, 2);
|
||||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
luaL_argcheck(L, lua_type(L, 1) == LUA_TFUNCTION && !lua_iscfunction(L, 1),
|
||||||
lua_settop(L, 1); /* ensure function is on the top of the stack */
|
1, "Lua function expected");
|
||||||
|
/* ensure function is on the top of the stack and vacate slot 1 */
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
state.init = 0;
|
state.init = 0;
|
||||||
if (l_unlikely(lua_dump(L, writer, &state, strip) != 0))
|
lua_dump(L, writer, &state, strip);
|
||||||
return luaL_error(L, "unable to dump given function");
|
lua_settop(L, 1); /* leave final result on top */
|
||||||
luaL_pushresult(&state.B);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,11 +269,18 @@ static int tonum (lua_State *L, int arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void trymt (lua_State *L, const char *mtname) {
|
/*
|
||||||
|
** To be here, either the first operand was a string or the first
|
||||||
|
** operand didn't have a corresponding metamethod. (Otherwise, that
|
||||||
|
** other metamethod would have been called.) So, if this metamethod
|
||||||
|
** doesn't work, the only other option would be for the second
|
||||||
|
** operand to have a different metamethod.
|
||||||
|
*/
|
||||||
|
static void trymt (lua_State *L, const char *mtkey, const char *opname) {
|
||||||
lua_settop(L, 2); /* back to the original arguments */
|
lua_settop(L, 2); /* back to the original arguments */
|
||||||
if (l_unlikely(lua_type(L, 2) == LUA_TSTRING ||
|
if (l_unlikely(lua_type(L, 2) == LUA_TSTRING ||
|
||||||
!luaL_getmetafield(L, 2, mtname)))
|
!luaL_getmetafield(L, 2, mtkey)))
|
||||||
luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2,
|
luaL_error(L, "attempt to %s a '%s' with a '%s'", opname,
|
||||||
luaL_typename(L, -2), luaL_typename(L, -1));
|
luaL_typename(L, -2), luaL_typename(L, -1));
|
||||||
lua_insert(L, -3); /* put metamethod before arguments */
|
lua_insert(L, -3); /* put metamethod before arguments */
|
||||||
lua_call(L, 2, 1); /* call metamethod */
|
lua_call(L, 2, 1); /* call metamethod */
|
||||||
@@ -289,7 +291,7 @@ static int arith (lua_State *L, int op, const char *mtname) {
|
|||||||
if (tonum(L, 1) && tonum(L, 2))
|
if (tonum(L, 1) && tonum(L, 2))
|
||||||
lua_arith(L, op); /* result will be on the top */
|
lua_arith(L, op); /* result will be on the top */
|
||||||
else
|
else
|
||||||
trymt(L, mtname);
|
trymt(L, mtname, mtname + 2);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,10 +363,10 @@ typedef struct MatchState {
|
|||||||
const char *p_end; /* end ('\0') of pattern */
|
const char *p_end; /* end ('\0') of pattern */
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
|
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
|
||||||
unsigned char level; /* total number of captures (finished or unfinished) */
|
int level; /* total number of captures (finished or unfinished) */
|
||||||
struct {
|
struct {
|
||||||
const char *init;
|
const char *init;
|
||||||
ptrdiff_t len;
|
ptrdiff_t len; /* length or special value (CAP_*) */
|
||||||
} capture[LUA_MAXCAPTURES];
|
} capture[LUA_MAXCAPTURES];
|
||||||
} MatchState;
|
} MatchState;
|
||||||
|
|
||||||
@@ -453,15 +455,15 @@ static int matchbracketclass (int c, const char *p, const char *ec) {
|
|||||||
while (++p < ec) {
|
while (++p < ec) {
|
||||||
if (*p == L_ESC) {
|
if (*p == L_ESC) {
|
||||||
p++;
|
p++;
|
||||||
if (match_class(c, uchar(*p)))
|
if (match_class(c, cast_uchar(*p)))
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
else if ((*(p+1) == '-') && (p+2 < ec)) {
|
else if ((*(p+1) == '-') && (p+2 < ec)) {
|
||||||
p+=2;
|
p+=2;
|
||||||
if (uchar(*(p-2)) <= c && c <= uchar(*p))
|
if (cast_uchar(*(p-2)) <= c && c <= cast_uchar(*p))
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
else if (uchar(*p) == c) return sig;
|
else if (cast_uchar(*p) == c) return sig;
|
||||||
}
|
}
|
||||||
return !sig;
|
return !sig;
|
||||||
}
|
}
|
||||||
@@ -472,12 +474,12 @@ static int singlematch (MatchState *ms, const char *s, const char *p,
|
|||||||
if (s >= ms->src_end)
|
if (s >= ms->src_end)
|
||||||
return 0;
|
return 0;
|
||||||
else {
|
else {
|
||||||
int c = uchar(*s);
|
int c = cast_uchar(*s);
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
case '.': return 1; /* matches any char */
|
case '.': return 1; /* matches any char */
|
||||||
case L_ESC: return match_class(c, uchar(*(p+1)));
|
case L_ESC: return match_class(c, cast_uchar(*(p+1)));
|
||||||
case '[': return matchbracketclass(c, p, ep-1);
|
case '[': return matchbracketclass(c, p, ep-1);
|
||||||
default: return (uchar(*p) == c);
|
default: return (cast_uchar(*p) == c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -559,7 +561,7 @@ static const char *end_capture (MatchState *ms, const char *s,
|
|||||||
static const char *match_capture (MatchState *ms, const char *s, int l) {
|
static const char *match_capture (MatchState *ms, const char *s, int l) {
|
||||||
size_t len;
|
size_t len;
|
||||||
l = check_capture(ms, l);
|
l = check_capture(ms, l);
|
||||||
len = ms->capture[l].len;
|
len = cast_sizet(ms->capture[l].len);
|
||||||
if ((size_t)(ms->src_end-s) >= len &&
|
if ((size_t)(ms->src_end-s) >= len &&
|
||||||
memcmp(ms->capture[l].init, s, len) == 0)
|
memcmp(ms->capture[l].init, s, len) == 0)
|
||||||
return s+len;
|
return s+len;
|
||||||
@@ -570,7 +572,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
|
|||||||
static const char *match (MatchState *ms, const char *s, const char *p) {
|
static const char *match (MatchState *ms, const char *s, const char *p) {
|
||||||
if (l_unlikely(ms->matchdepth-- == 0))
|
if (l_unlikely(ms->matchdepth-- == 0))
|
||||||
luaL_error(ms->L, "pattern too complex");
|
luaL_error(ms->L, "pattern too complex");
|
||||||
init: /* using goto's to optimize tail recursion */
|
init: /* using goto to optimize tail recursion */
|
||||||
if (p != ms->p_end) { /* end of pattern? */
|
if (p != ms->p_end) { /* end of pattern? */
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
case '(': { /* start capture */
|
case '(': { /* start capture */
|
||||||
@@ -606,8 +608,8 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
|
|||||||
luaL_error(ms->L, "missing '[' after '%%f' in pattern");
|
luaL_error(ms->L, "missing '[' after '%%f' in pattern");
|
||||||
ep = classend(ms, p); /* points to what is next */
|
ep = classend(ms, p); /* points to what is next */
|
||||||
previous = (s == ms->src_init) ? '\0' : *(s - 1);
|
previous = (s == ms->src_init) ? '\0' : *(s - 1);
|
||||||
if (!matchbracketclass(uchar(previous), p, ep - 1) &&
|
if (!matchbracketclass(cast_uchar(previous), p, ep - 1) &&
|
||||||
matchbracketclass(uchar(*s), p, ep - 1)) {
|
matchbracketclass(cast_uchar(*s), p, ep - 1)) {
|
||||||
p = ep; goto init; /* return match(ms, s, ep); */
|
p = ep; goto init; /* return match(ms, s, ep); */
|
||||||
}
|
}
|
||||||
s = NULL; /* match failed */
|
s = NULL; /* match failed */
|
||||||
@@ -616,7 +618,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
|
|||||||
case '0': case '1': case '2': case '3':
|
case '0': case '1': case '2': case '3':
|
||||||
case '4': case '5': case '6': case '7':
|
case '4': case '5': case '6': case '7':
|
||||||
case '8': case '9': { /* capture results (%0-%9)? */
|
case '8': case '9': { /* capture results (%0-%9)? */
|
||||||
s = match_capture(ms, s, uchar(*(p + 1)));
|
s = match_capture(ms, s, cast_uchar(*(p + 1)));
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
p += 2; goto init; /* return match(ms, s, p + 2) */
|
p += 2; goto init; /* return match(ms, s, p + 2) */
|
||||||
}
|
}
|
||||||
@@ -683,7 +685,7 @@ static const char *lmemfind (const char *s1, size_t l1,
|
|||||||
if (memcmp(init, s2+1, l2) == 0)
|
if (memcmp(init, s2+1, l2) == 0)
|
||||||
return init-1;
|
return init-1;
|
||||||
else { /* correct 'l1' and 's1' to try again */
|
else { /* correct 'l1' and 's1' to try again */
|
||||||
l1 -= init-s1;
|
l1 -= ct_diff2sz(init - s1);
|
||||||
s1 = init;
|
s1 = init;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -699,13 +701,13 @@ static const char *lmemfind (const char *s1, size_t l1,
|
|||||||
** its length and put its address in '*cap'. If it is an integer
|
** its length and put its address in '*cap'. If it is an integer
|
||||||
** (a position), push it on the stack and return CAP_POSITION.
|
** (a position), push it on the stack and return CAP_POSITION.
|
||||||
*/
|
*/
|
||||||
static size_t get_onecapture (MatchState *ms, int i, const char *s,
|
static ptrdiff_t get_onecapture (MatchState *ms, int i, const char *s,
|
||||||
const char *e, const char **cap) {
|
const char *e, const char **cap) {
|
||||||
if (i >= ms->level) {
|
if (i >= ms->level) {
|
||||||
if (l_unlikely(i != 0))
|
if (l_unlikely(i != 0))
|
||||||
luaL_error(ms->L, "invalid capture index %%%d", i + 1);
|
luaL_error(ms->L, "invalid capture index %%%d", i + 1);
|
||||||
*cap = s;
|
*cap = s;
|
||||||
return e - s;
|
return (e - s);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ptrdiff_t capl = ms->capture[i].len;
|
ptrdiff_t capl = ms->capture[i].len;
|
||||||
@@ -713,7 +715,8 @@ static size_t get_onecapture (MatchState *ms, int i, const char *s,
|
|||||||
if (l_unlikely(capl == CAP_UNFINISHED))
|
if (l_unlikely(capl == CAP_UNFINISHED))
|
||||||
luaL_error(ms->L, "unfinished capture");
|
luaL_error(ms->L, "unfinished capture");
|
||||||
else if (capl == CAP_POSITION)
|
else if (capl == CAP_POSITION)
|
||||||
lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
|
lua_pushinteger(ms->L,
|
||||||
|
ct_diff2S(ms->capture[i].init - ms->src_init) + 1);
|
||||||
return capl;
|
return capl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -727,7 +730,7 @@ static void push_onecapture (MatchState *ms, int i, const char *s,
|
|||||||
const char *cap;
|
const char *cap;
|
||||||
ptrdiff_t l = get_onecapture(ms, i, s, e, &cap);
|
ptrdiff_t l = get_onecapture(ms, i, s, e, &cap);
|
||||||
if (l != CAP_POSITION)
|
if (l != CAP_POSITION)
|
||||||
lua_pushlstring(ms->L, cap, l);
|
lua_pushlstring(ms->L, cap, cast_sizet(l));
|
||||||
/* else position was already pushed */
|
/* else position was already pushed */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -784,8 +787,8 @@ static int str_find_aux (lua_State *L, int find) {
|
|||||||
/* do a plain search */
|
/* do a plain search */
|
||||||
const char *s2 = lmemfind(s + init, ls - init, p, lp);
|
const char *s2 = lmemfind(s + init, ls - init, p, lp);
|
||||||
if (s2) {
|
if (s2) {
|
||||||
lua_pushinteger(L, (s2 - s) + 1);
|
lua_pushinteger(L, ct_diff2S(s2 - s) + 1);
|
||||||
lua_pushinteger(L, (s2 - s) + lp);
|
lua_pushinteger(L, cast_st2S(ct_diff2sz(s2 - s) + lp));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -802,8 +805,8 @@ static int str_find_aux (lua_State *L, int find) {
|
|||||||
reprepstate(&ms);
|
reprepstate(&ms);
|
||||||
if ((res=match(&ms, s1, p)) != NULL) {
|
if ((res=match(&ms, s1, p)) != NULL) {
|
||||||
if (find) {
|
if (find) {
|
||||||
lua_pushinteger(L, (s1 - s) + 1); /* start */
|
lua_pushinteger(L, ct_diff2S(s1 - s) + 1); /* start */
|
||||||
lua_pushinteger(L, res - s); /* end */
|
lua_pushinteger(L, ct_diff2S(res - s)); /* end */
|
||||||
return push_captures(&ms, NULL, 0) + 2;
|
return push_captures(&ms, NULL, 0) + 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -875,23 +878,23 @@ static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
|
|||||||
const char *news = lua_tolstring(L, 3, &l);
|
const char *news = lua_tolstring(L, 3, &l);
|
||||||
const char *p;
|
const char *p;
|
||||||
while ((p = (char *)memchr(news, L_ESC, l)) != NULL) {
|
while ((p = (char *)memchr(news, L_ESC, l)) != NULL) {
|
||||||
luaL_addlstring(b, news, p - news);
|
luaL_addlstring(b, news, ct_diff2sz(p - news));
|
||||||
p++; /* skip ESC */
|
p++; /* skip ESC */
|
||||||
if (*p == L_ESC) /* '%%' */
|
if (*p == L_ESC) /* '%%' */
|
||||||
luaL_addchar(b, *p);
|
luaL_addchar(b, *p);
|
||||||
else if (*p == '0') /* '%0' */
|
else if (*p == '0') /* '%0' */
|
||||||
luaL_addlstring(b, s, e - s);
|
luaL_addlstring(b, s, ct_diff2sz(e - s));
|
||||||
else if (isdigit(uchar(*p))) { /* '%n' */
|
else if (isdigit(cast_uchar(*p))) { /* '%n' */
|
||||||
const char *cap;
|
const char *cap;
|
||||||
ptrdiff_t resl = get_onecapture(ms, *p - '1', s, e, &cap);
|
ptrdiff_t resl = get_onecapture(ms, *p - '1', s, e, &cap);
|
||||||
if (resl == CAP_POSITION)
|
if (resl == CAP_POSITION)
|
||||||
luaL_addvalue(b); /* add position to accumulated result */
|
luaL_addvalue(b); /* add position to accumulated result */
|
||||||
else
|
else
|
||||||
luaL_addlstring(b, cap, resl);
|
luaL_addlstring(b, cap, cast_sizet(resl));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
luaL_error(L, "invalid use of '%c' in replacement string", L_ESC);
|
luaL_error(L, "invalid use of '%c' in replacement string", L_ESC);
|
||||||
l -= p + 1 - news;
|
l -= ct_diff2sz(p + 1 - news);
|
||||||
news = p + 1;
|
news = p + 1;
|
||||||
}
|
}
|
||||||
luaL_addlstring(b, news, l);
|
luaL_addlstring(b, news, l);
|
||||||
@@ -926,7 +929,7 @@ static int add_value (MatchState *ms, luaL_Buffer *b, const char *s,
|
|||||||
}
|
}
|
||||||
if (!lua_toboolean(L, -1)) { /* nil or false? */
|
if (!lua_toboolean(L, -1)) { /* nil or false? */
|
||||||
lua_pop(L, 1); /* remove value */
|
lua_pop(L, 1); /* remove value */
|
||||||
luaL_addlstring(b, s, e - s); /* keep original text */
|
luaL_addlstring(b, s, ct_diff2sz(e - s)); /* keep original text */
|
||||||
return 0; /* no changes */
|
return 0; /* no changes */
|
||||||
}
|
}
|
||||||
else if (l_unlikely(!lua_isstring(L, -1)))
|
else if (l_unlikely(!lua_isstring(L, -1)))
|
||||||
@@ -945,7 +948,8 @@ static int str_gsub (lua_State *L) {
|
|||||||
const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
|
const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
|
||||||
const char *lastmatch = NULL; /* end of last match */
|
const char *lastmatch = NULL; /* end of last match */
|
||||||
int tr = lua_type(L, 3); /* replacement type */
|
int tr = lua_type(L, 3); /* replacement type */
|
||||||
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */
|
/* max replacements */
|
||||||
|
lua_Integer max_s = luaL_optinteger(L, 4, cast_st2S(srcl) + 1);
|
||||||
int anchor = (*p == '^');
|
int anchor = (*p == '^');
|
||||||
lua_Integer n = 0; /* replacement count */
|
lua_Integer n = 0; /* replacement count */
|
||||||
int changed = 0; /* change flag */
|
int changed = 0; /* change flag */
|
||||||
@@ -975,7 +979,7 @@ static int str_gsub (lua_State *L) {
|
|||||||
if (!changed) /* no changes? */
|
if (!changed) /* no changes? */
|
||||||
lua_pushvalue(L, 1); /* return original string */
|
lua_pushvalue(L, 1); /* return original string */
|
||||||
else { /* something changed */
|
else { /* something changed */
|
||||||
luaL_addlstring(&b, src, ms.src_end-src);
|
luaL_addlstring(&b, src, ct_diff2sz(ms.src_end - src));
|
||||||
luaL_pushresult(&b); /* create and return new string */
|
luaL_pushresult(&b); /* create and return new string */
|
||||||
}
|
}
|
||||||
lua_pushinteger(L, n); /* number of substitutions */
|
lua_pushinteger(L, n); /* number of substitutions */
|
||||||
@@ -1013,15 +1017,15 @@ static int str_gsub (lua_State *L) {
|
|||||||
/*
|
/*
|
||||||
** Add integer part of 'x' to buffer and return new 'x'
|
** Add integer part of 'x' to buffer and return new 'x'
|
||||||
*/
|
*/
|
||||||
static lua_Number adddigit (char *buff, int n, lua_Number x) {
|
static lua_Number adddigit (char *buff, unsigned n, lua_Number x) {
|
||||||
lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */
|
lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */
|
||||||
int d = (int)dd;
|
int d = (int)dd;
|
||||||
buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */
|
buff[n] = cast_char(d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */
|
||||||
return x - dd; /* return what is left */
|
return x - dd; /* return what is left */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int num2straux (char *buff, int sz, lua_Number x) {
|
static int num2straux (char *buff, unsigned sz, lua_Number x) {
|
||||||
/* if 'inf' or 'NaN', format it like '%g' */
|
/* if 'inf' or 'NaN', format it like '%g' */
|
||||||
if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL)
|
if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL)
|
||||||
return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x);
|
return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x);
|
||||||
@@ -1032,7 +1036,7 @@ static int num2straux (char *buff, int sz, lua_Number x) {
|
|||||||
else {
|
else {
|
||||||
int e;
|
int e;
|
||||||
lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */
|
lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */
|
||||||
int n = 0; /* character count */
|
unsigned n = 0; /* character count */
|
||||||
if (m < 0) { /* is number negative? */
|
if (m < 0) { /* is number negative? */
|
||||||
buff[n++] = '-'; /* add sign */
|
buff[n++] = '-'; /* add sign */
|
||||||
m = -m; /* make it positive */
|
m = -m; /* make it positive */
|
||||||
@@ -1046,20 +1050,20 @@ static int num2straux (char *buff, int sz, lua_Number x) {
|
|||||||
m = adddigit(buff, n++, m * 16);
|
m = adddigit(buff, n++, m * 16);
|
||||||
} while (m > 0);
|
} while (m > 0);
|
||||||
}
|
}
|
||||||
n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */
|
n += cast_uint(l_sprintf(buff + n, sz - n, "p%+d", e)); /* add exponent */
|
||||||
lua_assert(n < sz);
|
lua_assert(n < sz);
|
||||||
return n;
|
return cast_int(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int lua_number2strx (lua_State *L, char *buff, int sz,
|
static int lua_number2strx (lua_State *L, char *buff, unsigned sz,
|
||||||
const char *fmt, lua_Number x) {
|
const char *fmt, lua_Number x) {
|
||||||
int n = num2straux(buff, sz, x);
|
int n = num2straux(buff, sz, x);
|
||||||
if (fmt[SIZELENMOD] == 'A') {
|
if (fmt[SIZELENMOD] == 'A') {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
buff[i] = toupper(uchar(buff[i]));
|
buff[i] = cast_char(toupper(cast_uchar(buff[i])));
|
||||||
}
|
}
|
||||||
else if (l_unlikely(fmt[SIZELENMOD] != 'a'))
|
else if (l_unlikely(fmt[SIZELENMOD] != 'a'))
|
||||||
return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
|
return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
|
||||||
@@ -1090,13 +1094,31 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
|
|||||||
|
|
||||||
|
|
||||||
/* valid flags in a format specification */
|
/* valid flags in a format specification */
|
||||||
#if !defined(L_FMTFLAGS)
|
#if !defined(L_FMTFLAGSF)
|
||||||
#define L_FMTFLAGS "-+ #0"
|
|
||||||
|
/* valid flags for a, A, e, E, f, F, g, and G conversions */
|
||||||
|
#define L_FMTFLAGSF "-+#0 "
|
||||||
|
|
||||||
|
/* valid flags for o, x, and X conversions */
|
||||||
|
#define L_FMTFLAGSX "-#0"
|
||||||
|
|
||||||
|
/* valid flags for d and i conversions */
|
||||||
|
#define L_FMTFLAGSI "-+0 "
|
||||||
|
|
||||||
|
/* valid flags for u conversions */
|
||||||
|
#define L_FMTFLAGSU "-0"
|
||||||
|
|
||||||
|
/* valid flags for c, p, and s conversions */
|
||||||
|
#define L_FMTFLAGSC "-"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** maximum size of each format specification (such as "%-099.99d")
|
** Maximum size of each format specification (such as "%-099.99d"):
|
||||||
|
** Initial '%', flags (up to 5), width (2), period, precision (2),
|
||||||
|
** length modifier (8), conversion specifier, and final '\0', plus some
|
||||||
|
** extra.
|
||||||
*/
|
*/
|
||||||
#define MAX_FORMAT 32
|
#define MAX_FORMAT 32
|
||||||
|
|
||||||
@@ -1108,12 +1130,12 @@ static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
|
|||||||
luaL_addchar(b, '\\');
|
luaL_addchar(b, '\\');
|
||||||
luaL_addchar(b, *s);
|
luaL_addchar(b, *s);
|
||||||
}
|
}
|
||||||
else if (iscntrl(uchar(*s))) {
|
else if (iscntrl(cast_uchar(*s))) {
|
||||||
char buff[10];
|
char buff[10];
|
||||||
if (!isdigit(uchar(*(s+1))))
|
if (!isdigit(cast_uchar(*(s+1))))
|
||||||
l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
|
l_sprintf(buff, sizeof(buff), "\\%d", (int)cast_uchar(*s));
|
||||||
else
|
else
|
||||||
l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s));
|
l_sprintf(buff, sizeof(buff), "\\%03d", (int)cast_uchar(*s));
|
||||||
luaL_addstring(b, buff);
|
luaL_addstring(b, buff);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1142,9 +1164,9 @@ static int quotefloat (lua_State *L, char *buff, lua_Number n) {
|
|||||||
int nb = lua_number2strx(L, buff, MAX_ITEM,
|
int nb = lua_number2strx(L, buff, MAX_ITEM,
|
||||||
"%" LUA_NUMBER_FRMLEN "a", n);
|
"%" LUA_NUMBER_FRMLEN "a", n);
|
||||||
/* ensures that 'buff' string uses a dot as the radix character */
|
/* ensures that 'buff' string uses a dot as the radix character */
|
||||||
if (memchr(buff, '.', nb) == NULL) { /* no dot? */
|
if (memchr(buff, '.', cast_uint(nb)) == NULL) { /* no dot? */
|
||||||
char point = lua_getlocaledecpoint(); /* try locale point */
|
char point = lua_getlocaledecpoint(); /* try locale point */
|
||||||
char *ppoint = (char *)memchr(buff, point, nb);
|
char *ppoint = (char *)memchr(buff, point, cast_uint(nb));
|
||||||
if (ppoint) *ppoint = '.'; /* change it to a dot */
|
if (ppoint) *ppoint = '.'; /* change it to a dot */
|
||||||
}
|
}
|
||||||
return nb;
|
return nb;
|
||||||
@@ -1174,7 +1196,7 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
|
|||||||
: LUA_INTEGER_FMT; /* else use default format */
|
: LUA_INTEGER_FMT; /* else use default format */
|
||||||
nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n);
|
nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n);
|
||||||
}
|
}
|
||||||
luaL_addsize(b, nb);
|
luaL_addsize(b, cast_uint(nb));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LUA_TNIL: case LUA_TBOOLEAN: {
|
case LUA_TNIL: case LUA_TBOOLEAN: {
|
||||||
@@ -1189,25 +1211,53 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
|
static const char *get2digits (const char *s) {
|
||||||
const char *p = strfrmt;
|
if (isdigit(cast_uchar(*s))) {
|
||||||
while (*p != '\0' && strchr(L_FMTFLAGS, *p) != NULL) p++; /* skip flags */
|
s++;
|
||||||
if ((size_t)(p - strfrmt) >= sizeof(L_FMTFLAGS)/sizeof(char))
|
if (isdigit(cast_uchar(*s))) s++; /* (2 digits at most) */
|
||||||
luaL_error(L, "invalid format (repeated flags)");
|
|
||||||
if (isdigit(uchar(*p))) p++; /* skip width */
|
|
||||||
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
|
|
||||||
if (*p == '.') {
|
|
||||||
p++;
|
|
||||||
if (isdigit(uchar(*p))) p++; /* skip precision */
|
|
||||||
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
|
|
||||||
}
|
}
|
||||||
if (isdigit(uchar(*p)))
|
return s;
|
||||||
luaL_error(L, "invalid format (width or precision too long)");
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Check whether a conversion specification is valid. When called,
|
||||||
|
** first character in 'form' must be '%' and last character must
|
||||||
|
** be a valid conversion specifier. 'flags' are the accepted flags;
|
||||||
|
** 'precision' signals whether to accept a precision.
|
||||||
|
*/
|
||||||
|
static void checkformat (lua_State *L, const char *form, const char *flags,
|
||||||
|
int precision) {
|
||||||
|
const char *spec = form + 1; /* skip '%' */
|
||||||
|
spec += strspn(spec, flags); /* skip flags */
|
||||||
|
if (*spec != '0') { /* a width cannot start with '0' */
|
||||||
|
spec = get2digits(spec); /* skip width */
|
||||||
|
if (*spec == '.' && precision) {
|
||||||
|
spec++;
|
||||||
|
spec = get2digits(spec); /* skip precision */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isalpha(cast_uchar(*spec))) /* did not go to the end? */
|
||||||
|
luaL_error(L, "invalid conversion specification: '%s'", form);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Get a conversion specification and copy it to 'form'.
|
||||||
|
** Return the address of its last character.
|
||||||
|
*/
|
||||||
|
static const char *getformat (lua_State *L, const char *strfrmt,
|
||||||
|
char *form) {
|
||||||
|
/* spans flags, width, and precision ('0' is included as a flag) */
|
||||||
|
size_t len = strspn(strfrmt, L_FMTFLAGSF "123456789.");
|
||||||
|
len++; /* adds following character (should be the specifier) */
|
||||||
|
/* still needs space for '%', '\0', plus a length modifier */
|
||||||
|
if (len >= MAX_FORMAT - 10)
|
||||||
|
luaL_error(L, "invalid format (too long)");
|
||||||
*(form++) = '%';
|
*(form++) = '%';
|
||||||
memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
|
memcpy(form, strfrmt, len * sizeof(char));
|
||||||
form += (p - strfrmt) + 1;
|
*(form + len) = '\0';
|
||||||
*form = '\0';
|
return strfrmt + len - 1;
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1230,6 +1280,7 @@ static int str_format (lua_State *L) {
|
|||||||
size_t sfl;
|
size_t sfl;
|
||||||
const char *strfrmt = luaL_checklstring(L, arg, &sfl);
|
const char *strfrmt = luaL_checklstring(L, arg, &sfl);
|
||||||
const char *strfrmt_end = strfrmt+sfl;
|
const char *strfrmt_end = strfrmt+sfl;
|
||||||
|
const char *flags;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
while (strfrmt < strfrmt_end) {
|
while (strfrmt < strfrmt_end) {
|
||||||
@@ -1239,25 +1290,35 @@ static int str_format (lua_State *L) {
|
|||||||
luaL_addchar(&b, *strfrmt++); /* %% */
|
luaL_addchar(&b, *strfrmt++); /* %% */
|
||||||
else { /* format item */
|
else { /* format item */
|
||||||
char form[MAX_FORMAT]; /* to store the format ('%...') */
|
char form[MAX_FORMAT]; /* to store the format ('%...') */
|
||||||
int maxitem = MAX_ITEM;
|
unsigned maxitem = MAX_ITEM; /* maximum length for the result */
|
||||||
char *buff = luaL_prepbuffsize(&b, maxitem); /* to put formatted item */
|
char *buff = luaL_prepbuffsize(&b, maxitem); /* to put result */
|
||||||
int nb = 0; /* number of bytes in added item */
|
int nb = 0; /* number of bytes in result */
|
||||||
if (++arg > top)
|
if (++arg > top)
|
||||||
return luaL_argerror(L, arg, "no value");
|
return luaL_argerror(L, arg, "no value");
|
||||||
strfrmt = scanformat(L, strfrmt, form);
|
strfrmt = getformat(L, strfrmt, form);
|
||||||
switch (*strfrmt++) {
|
switch (*strfrmt++) {
|
||||||
case 'c': {
|
case 'c': {
|
||||||
|
checkformat(L, form, L_FMTFLAGSC, 0);
|
||||||
nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg));
|
nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'd': case 'i':
|
case 'd': case 'i':
|
||||||
case 'o': case 'u': case 'x': case 'X': {
|
flags = L_FMTFLAGSI;
|
||||||
|
goto intcase;
|
||||||
|
case 'u':
|
||||||
|
flags = L_FMTFLAGSU;
|
||||||
|
goto intcase;
|
||||||
|
case 'o': case 'x': case 'X':
|
||||||
|
flags = L_FMTFLAGSX;
|
||||||
|
intcase: {
|
||||||
lua_Integer n = luaL_checkinteger(L, arg);
|
lua_Integer n = luaL_checkinteger(L, arg);
|
||||||
|
checkformat(L, form, flags, 1);
|
||||||
addlenmod(form, LUA_INTEGER_FRMLEN);
|
addlenmod(form, LUA_INTEGER_FRMLEN);
|
||||||
nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n);
|
nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'a': case 'A':
|
case 'a': case 'A':
|
||||||
|
checkformat(L, form, L_FMTFLAGSF, 1);
|
||||||
addlenmod(form, LUA_NUMBER_FRMLEN);
|
addlenmod(form, LUA_NUMBER_FRMLEN);
|
||||||
nb = lua_number2strx(L, buff, maxitem, form,
|
nb = lua_number2strx(L, buff, maxitem, form,
|
||||||
luaL_checknumber(L, arg));
|
luaL_checknumber(L, arg));
|
||||||
@@ -1268,12 +1329,14 @@ static int str_format (lua_State *L) {
|
|||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case 'e': case 'E': case 'g': case 'G': {
|
case 'e': case 'E': case 'g': case 'G': {
|
||||||
lua_Number n = luaL_checknumber(L, arg);
|
lua_Number n = luaL_checknumber(L, arg);
|
||||||
|
checkformat(L, form, L_FMTFLAGSF, 1);
|
||||||
addlenmod(form, LUA_NUMBER_FRMLEN);
|
addlenmod(form, LUA_NUMBER_FRMLEN);
|
||||||
nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
|
nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'p': {
|
case 'p': {
|
||||||
const void *p = lua_topointer(L, arg);
|
const void *p = lua_topointer(L, arg);
|
||||||
|
checkformat(L, form, L_FMTFLAGSC, 0);
|
||||||
if (p == NULL) { /* avoid calling 'printf' with argument NULL */
|
if (p == NULL) { /* avoid calling 'printf' with argument NULL */
|
||||||
p = "(null)"; /* result */
|
p = "(null)"; /* result */
|
||||||
form[strlen(form) - 1] = 's'; /* format it as a string */
|
form[strlen(form) - 1] = 's'; /* format it as a string */
|
||||||
@@ -1294,7 +1357,8 @@ static int str_format (lua_State *L) {
|
|||||||
luaL_addvalue(&b); /* keep entire string */
|
luaL_addvalue(&b); /* keep entire string */
|
||||||
else {
|
else {
|
||||||
luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
|
luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
|
||||||
if (!strchr(form, '.') && l >= 100) {
|
checkformat(L, form, L_FMTFLAGSC, 1);
|
||||||
|
if (strchr(form, '.') == NULL && l >= 100) {
|
||||||
/* no precision and string is too long to be formatted */
|
/* no precision and string is too long to be formatted */
|
||||||
luaL_addvalue(&b); /* keep entire string */
|
luaL_addvalue(&b); /* keep entire string */
|
||||||
}
|
}
|
||||||
@@ -1309,8 +1373,8 @@ static int str_format (lua_State *L) {
|
|||||||
return luaL_error(L, "invalid conversion '%s' to 'format'", form);
|
return luaL_error(L, "invalid conversion '%s' to 'format'", form);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lua_assert(nb < maxitem);
|
lua_assert(cast_uint(nb) < maxitem);
|
||||||
luaL_addsize(&b, nb);
|
luaL_addsize(&b, cast_uint(nb));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
@@ -1352,22 +1416,13 @@ static const union {
|
|||||||
} nativeendian = {1};
|
} nativeendian = {1};
|
||||||
|
|
||||||
|
|
||||||
/* dummy structure to get native alignment requirements */
|
|
||||||
struct cD {
|
|
||||||
char c;
|
|
||||||
union { double d; void *p; lua_Integer i; lua_Number n; } u;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAXALIGN (offsetof(struct cD, u))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** information to pack/unpack stuff
|
** information to pack/unpack stuff
|
||||||
*/
|
*/
|
||||||
typedef struct Header {
|
typedef struct Header {
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
int islittle;
|
int islittle;
|
||||||
int maxalign;
|
unsigned maxalign;
|
||||||
} Header;
|
} Header;
|
||||||
|
|
||||||
|
|
||||||
@@ -1395,14 +1450,14 @@ typedef enum KOption {
|
|||||||
*/
|
*/
|
||||||
static int digit (int c) { return '0' <= c && c <= '9'; }
|
static int digit (int c) { return '0' <= c && c <= '9'; }
|
||||||
|
|
||||||
static int getnum (const char **fmt, int df) {
|
static size_t getnum (const char **fmt, size_t df) {
|
||||||
if (!digit(**fmt)) /* no number? */
|
if (!digit(**fmt)) /* no number? */
|
||||||
return df; /* return default value */
|
return df; /* return default value */
|
||||||
else {
|
else {
|
||||||
int a = 0;
|
size_t a = 0;
|
||||||
do {
|
do {
|
||||||
a = a*10 + (*((*fmt)++) - '0');
|
a = a*10 + cast_uint(*((*fmt)++) - '0');
|
||||||
} while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10);
|
} while (digit(**fmt) && a <= (MAX_SIZE - 9)/10);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1410,14 +1465,14 @@ static int getnum (const char **fmt, int df) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Read an integer numeral and raises an error if it is larger
|
** Read an integer numeral and raises an error if it is larger
|
||||||
** than the maximum size for integers.
|
** than the maximum size of integers.
|
||||||
*/
|
*/
|
||||||
static int getnumlimit (Header *h, const char **fmt, int df) {
|
static unsigned getnumlimit (Header *h, const char **fmt, size_t df) {
|
||||||
int sz = getnum(fmt, df);
|
size_t sz = getnum(fmt, df);
|
||||||
if (l_unlikely(sz > MAXINTSIZE || sz <= 0))
|
if (l_unlikely((sz - 1u) >= MAXINTSIZE))
|
||||||
return luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
|
return cast_uint(luaL_error(h->L,
|
||||||
sz, MAXINTSIZE);
|
"integral size (%d) out of limits [1,%d]", sz, MAXINTSIZE));
|
||||||
return sz;
|
return cast_uint(sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1434,7 +1489,9 @@ static void initheader (lua_State *L, Header *h) {
|
|||||||
/*
|
/*
|
||||||
** Read and classify next option. 'size' is filled with option's size.
|
** Read and classify next option. 'size' is filled with option's size.
|
||||||
*/
|
*/
|
||||||
static KOption getoption (Header *h, const char **fmt, int *size) {
|
static KOption getoption (Header *h, const char **fmt, size_t *size) {
|
||||||
|
/* dummy structure to get native alignment requirements */
|
||||||
|
struct cD { char c; union { LUAI_MAXALIGN; } u; };
|
||||||
int opt = *((*fmt)++);
|
int opt = *((*fmt)++);
|
||||||
*size = 0; /* default */
|
*size = 0; /* default */
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
@@ -1454,8 +1511,8 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
|
|||||||
case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
|
case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
|
||||||
case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
|
case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
|
||||||
case 'c':
|
case 'c':
|
||||||
*size = getnum(fmt, -1);
|
*size = getnum(fmt, cast_sizet(-1));
|
||||||
if (l_unlikely(*size == -1))
|
if (l_unlikely(*size == cast_sizet(-1)))
|
||||||
luaL_error(h->L, "missing size for format option 'c'");
|
luaL_error(h->L, "missing size for format option 'c'");
|
||||||
return Kchar;
|
return Kchar;
|
||||||
case 'z': return Kzstr;
|
case 'z': return Kzstr;
|
||||||
@@ -1465,7 +1522,11 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
|
|||||||
case '<': h->islittle = 1; break;
|
case '<': h->islittle = 1; break;
|
||||||
case '>': h->islittle = 0; break;
|
case '>': h->islittle = 0; break;
|
||||||
case '=': h->islittle = nativeendian.little; break;
|
case '=': h->islittle = nativeendian.little; break;
|
||||||
case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break;
|
case '!': {
|
||||||
|
const size_t maxalign = offsetof(struct cD, u);
|
||||||
|
h->maxalign = getnumlimit(h, fmt, maxalign);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: luaL_error(h->L, "invalid format option '%c'", opt);
|
default: luaL_error(h->L, "invalid format option '%c'", opt);
|
||||||
}
|
}
|
||||||
return Knop;
|
return Knop;
|
||||||
@@ -1481,10 +1542,10 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
|
|||||||
** the maximum alignment ('maxalign'). Kchar option needs no alignment
|
** the maximum alignment ('maxalign'). Kchar option needs no alignment
|
||||||
** despite its size.
|
** despite its size.
|
||||||
*/
|
*/
|
||||||
static KOption getdetails (Header *h, size_t totalsize,
|
static KOption getdetails (Header *h, size_t totalsize, const char **fmt,
|
||||||
const char **fmt, int *psize, int *ntoalign) {
|
size_t *psize, unsigned *ntoalign) {
|
||||||
KOption opt = getoption(h, fmt, psize);
|
KOption opt = getoption(h, fmt, psize);
|
||||||
int align = *psize; /* usually, alignment follows size */
|
size_t align = *psize; /* usually, alignment follows size */
|
||||||
if (opt == Kpaddalign) { /* 'X' gets alignment from following option */
|
if (opt == Kpaddalign) { /* 'X' gets alignment from following option */
|
||||||
if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
|
if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0)
|
||||||
luaL_argerror(h->L, 1, "invalid next option for option 'X'");
|
luaL_argerror(h->L, 1, "invalid next option for option 'X'");
|
||||||
@@ -1494,9 +1555,15 @@ static KOption getdetails (Header *h, size_t totalsize,
|
|||||||
else {
|
else {
|
||||||
if (align > h->maxalign) /* enforce maximum alignment */
|
if (align > h->maxalign) /* enforce maximum alignment */
|
||||||
align = h->maxalign;
|
align = h->maxalign;
|
||||||
if (l_unlikely((align & (align - 1)) != 0)) /* not a power of 2? */
|
if (l_unlikely(!ispow2(align))) { /* not a power of 2? */
|
||||||
|
*ntoalign = 0; /* to avoid warnings */
|
||||||
luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
|
luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
|
||||||
*ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
|
}
|
||||||
|
else {
|
||||||
|
/* 'szmoda' = totalsize % align */
|
||||||
|
unsigned szmoda = cast_uint(totalsize & (align - 1));
|
||||||
|
*ntoalign = cast_uint((align - szmoda) & (align - 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return opt;
|
return opt;
|
||||||
}
|
}
|
||||||
@@ -1509,9 +1576,9 @@ static KOption getdetails (Header *h, size_t totalsize,
|
|||||||
** bytes if necessary (by default they would be zeros).
|
** bytes if necessary (by default they would be zeros).
|
||||||
*/
|
*/
|
||||||
static void packint (luaL_Buffer *b, lua_Unsigned n,
|
static void packint (luaL_Buffer *b, lua_Unsigned n,
|
||||||
int islittle, int size, int neg) {
|
int islittle, unsigned size, int neg) {
|
||||||
char *buff = luaL_prepbuffsize(b, size);
|
char *buff = luaL_prepbuffsize(b, size);
|
||||||
int i;
|
unsigned i;
|
||||||
buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */
|
buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */
|
||||||
for (i = 1; i < size; i++) {
|
for (i = 1; i < size; i++) {
|
||||||
n >>= NB;
|
n >>= NB;
|
||||||
@@ -1530,7 +1597,7 @@ static void packint (luaL_Buffer *b, lua_Unsigned n,
|
|||||||
** given 'islittle' is different from native endianness.
|
** given 'islittle' is different from native endianness.
|
||||||
*/
|
*/
|
||||||
static void copywithendian (char *dest, const char *src,
|
static void copywithendian (char *dest, const char *src,
|
||||||
int size, int islittle) {
|
unsigned size, int islittle) {
|
||||||
if (islittle == nativeendian.little)
|
if (islittle == nativeendian.little)
|
||||||
memcpy(dest, src, size);
|
memcpy(dest, src, size);
|
||||||
else {
|
else {
|
||||||
@@ -1551,8 +1618,11 @@ static int str_pack (lua_State *L) {
|
|||||||
lua_pushnil(L); /* mark to separate arguments from string buffer */
|
lua_pushnil(L); /* mark to separate arguments from string buffer */
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
while (*fmt != '\0') {
|
while (*fmt != '\0') {
|
||||||
int size, ntoalign;
|
unsigned ntoalign;
|
||||||
|
size_t size;
|
||||||
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
||||||
|
luaL_argcheck(L, size + ntoalign <= MAX_SIZE - totalsize, arg,
|
||||||
|
"result too long");
|
||||||
totalsize += ntoalign + size;
|
totalsize += ntoalign + size;
|
||||||
while (ntoalign-- > 0)
|
while (ntoalign-- > 0)
|
||||||
luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
|
luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
|
||||||
@@ -1564,7 +1634,7 @@ static int str_pack (lua_State *L) {
|
|||||||
lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);
|
lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);
|
||||||
luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow");
|
luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow");
|
||||||
}
|
}
|
||||||
packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0));
|
packint(&b, (lua_Unsigned)n, h.islittle, cast_uint(size), (n < 0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kuint: { /* unsigned integers */
|
case Kuint: { /* unsigned integers */
|
||||||
@@ -1572,7 +1642,7 @@ static int str_pack (lua_State *L) {
|
|||||||
if (size < SZINT) /* need overflow check? */
|
if (size < SZINT) /* need overflow check? */
|
||||||
luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)),
|
luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)),
|
||||||
arg, "unsigned overflow");
|
arg, "unsigned overflow");
|
||||||
packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
|
packint(&b, (lua_Unsigned)n, h.islittle, cast_uint(size), 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kfloat: { /* C float */
|
case Kfloat: { /* C float */
|
||||||
@@ -1602,20 +1672,24 @@ static int str_pack (lua_State *L) {
|
|||||||
case Kchar: { /* fixed-size string */
|
case Kchar: { /* fixed-size string */
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *s = luaL_checklstring(L, arg, &len);
|
const char *s = luaL_checklstring(L, arg, &len);
|
||||||
luaL_argcheck(L, len <= (size_t)size, arg,
|
luaL_argcheck(L, len <= size, arg, "string longer than given size");
|
||||||
"string longer than given size");
|
|
||||||
luaL_addlstring(&b, s, len); /* add string */
|
luaL_addlstring(&b, s, len); /* add string */
|
||||||
while (len++ < (size_t)size) /* pad extra space */
|
if (len < size) { /* does it need padding? */
|
||||||
luaL_addchar(&b, LUAL_PACKPADBYTE);
|
size_t psize = size - len; /* pad size */
|
||||||
|
char *buff = luaL_prepbuffsize(&b, psize);
|
||||||
|
memset(buff, LUAL_PACKPADBYTE, psize);
|
||||||
|
luaL_addsize(&b, psize);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kstring: { /* strings with length count */
|
case Kstring: { /* strings with length count */
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *s = luaL_checklstring(L, arg, &len);
|
const char *s = luaL_checklstring(L, arg, &len);
|
||||||
luaL_argcheck(L, size >= (int)sizeof(size_t) ||
|
luaL_argcheck(L, size >= sizeof(lua_Unsigned) ||
|
||||||
len < ((size_t)1 << (size * NB)),
|
len < ((lua_Unsigned)1 << (size * NB)),
|
||||||
arg, "string length does not fit in given size");
|
arg, "string length does not fit in given size");
|
||||||
packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */
|
/* pack length */
|
||||||
|
packint(&b, (lua_Unsigned)len, h.islittle, cast_uint(size), 0);
|
||||||
luaL_addlstring(&b, s, len);
|
luaL_addlstring(&b, s, len);
|
||||||
totalsize += len;
|
totalsize += len;
|
||||||
break;
|
break;
|
||||||
@@ -1646,16 +1720,17 @@ static int str_packsize (lua_State *L) {
|
|||||||
size_t totalsize = 0; /* accumulate total size of result */
|
size_t totalsize = 0; /* accumulate total size of result */
|
||||||
initheader(L, &h);
|
initheader(L, &h);
|
||||||
while (*fmt != '\0') {
|
while (*fmt != '\0') {
|
||||||
int size, ntoalign;
|
unsigned ntoalign;
|
||||||
|
size_t size;
|
||||||
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
|
||||||
luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1,
|
luaL_argcheck(L, opt != Kstring && opt != Kzstr, 1,
|
||||||
"variable-length format");
|
"variable-length format");
|
||||||
size += ntoalign; /* total space used by option */
|
size += ntoalign; /* total space used by option */
|
||||||
luaL_argcheck(L, totalsize <= MAXSIZE - size, 1,
|
luaL_argcheck(L, totalsize <= LUA_MAXINTEGER - size,
|
||||||
"format result too large");
|
1, "format result too large");
|
||||||
totalsize += size;
|
totalsize += size;
|
||||||
}
|
}
|
||||||
lua_pushinteger(L, (lua_Integer)totalsize);
|
lua_pushinteger(L, cast_st2S(totalsize));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1704,9 +1779,10 @@ static int str_unpack (lua_State *L) {
|
|||||||
luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
|
luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
|
||||||
initheader(L, &h);
|
initheader(L, &h);
|
||||||
while (*fmt != '\0') {
|
while (*fmt != '\0') {
|
||||||
int size, ntoalign;
|
unsigned ntoalign;
|
||||||
|
size_t size;
|
||||||
KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
|
KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign);
|
||||||
luaL_argcheck(L, (size_t)ntoalign + size <= ld - pos, 2,
|
luaL_argcheck(L, ntoalign + size <= ld - pos, 2,
|
||||||
"data string too short");
|
"data string too short");
|
||||||
pos += ntoalign; /* skip alignment */
|
pos += ntoalign; /* skip alignment */
|
||||||
/* stack space for item + next position */
|
/* stack space for item + next position */
|
||||||
@@ -1715,8 +1791,8 @@ static int str_unpack (lua_State *L) {
|
|||||||
switch (opt) {
|
switch (opt) {
|
||||||
case Kint:
|
case Kint:
|
||||||
case Kuint: {
|
case Kuint: {
|
||||||
lua_Integer res = unpackint(L, data + pos, h.islittle, size,
|
lua_Integer res = unpackint(L, data + pos, h.islittle,
|
||||||
(opt == Kint));
|
cast_int(size), (opt == Kint));
|
||||||
lua_pushinteger(L, res);
|
lua_pushinteger(L, res);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1743,10 +1819,11 @@ static int str_unpack (lua_State *L) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kstring: {
|
case Kstring: {
|
||||||
size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0);
|
lua_Unsigned len = (lua_Unsigned)unpackint(L, data + pos,
|
||||||
|
h.islittle, cast_int(size), 0);
|
||||||
luaL_argcheck(L, len <= ld - pos - size, 2, "data string too short");
|
luaL_argcheck(L, len <= ld - pos - size, 2, "data string too short");
|
||||||
lua_pushlstring(L, data + pos + size, len);
|
lua_pushlstring(L, data + pos + size, cast_sizet(len));
|
||||||
pos += len; /* skip string */
|
pos += cast_sizet(len); /* skip string */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Kzstr: {
|
case Kzstr: {
|
||||||
@@ -1763,7 +1840,7 @@ static int str_unpack (lua_State *L) {
|
|||||||
}
|
}
|
||||||
pos += size;
|
pos += size;
|
||||||
}
|
}
|
||||||
lua_pushinteger(L, pos + 1); /* next position */
|
lua_pushinteger(L, cast_st2S(pos) + 1); /* next position */
|
||||||
return n + 1;
|
return n + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vendored
+1355
File diff suppressed because it is too large
Load Diff
Vendored
+184
@@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
** $Id: ltable.h $
|
||||||
|
** Lua tables (hash)
|
||||||
|
** See Copyright Notice in lua.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ltable_h
|
||||||
|
#define ltable_h
|
||||||
|
|
||||||
|
#include "lobject.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define gnode(t,i) (&(t)->node[i])
|
||||||
|
#define gval(n) (&(n)->i_val)
|
||||||
|
#define gnext(n) ((n)->u.next)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Clear all bits of fast-access metamethods, which means that the table
|
||||||
|
** may have any of these metamethods. (First access that fails after the
|
||||||
|
** clearing will set the bit again.)
|
||||||
|
*/
|
||||||
|
#define invalidateTMcache(t) ((t)->flags &= cast_byte(~maskflags))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Bit BITDUMMY set in 'flags' means the table is using the dummy node
|
||||||
|
** for its hash part.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BITDUMMY (1 << 6)
|
||||||
|
#define NOTBITDUMMY cast_byte(~BITDUMMY)
|
||||||
|
#define isdummy(t) ((t)->flags & BITDUMMY)
|
||||||
|
|
||||||
|
#define setnodummy(t) ((t)->flags &= NOTBITDUMMY)
|
||||||
|
#define setdummy(t) ((t)->flags |= BITDUMMY)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* allocated size for hash nodes */
|
||||||
|
#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t))
|
||||||
|
|
||||||
|
|
||||||
|
/* returns the Node, given the value of a table entry */
|
||||||
|
#define nodefromval(v) cast(Node *, (v))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define luaH_fastgeti(t,k,res,tag) \
|
||||||
|
{ Table *h = t; lua_Unsigned u = l_castS2U(k) - 1u; \
|
||||||
|
if ((u < h->asize)) { \
|
||||||
|
tag = *getArrTag(h, u); \
|
||||||
|
if (!tagisempty(tag)) { farr2val(h, u, tag, res); }} \
|
||||||
|
else { tag = luaH_getint(h, (k), res); }}
|
||||||
|
|
||||||
|
|
||||||
|
#define luaH_fastseti(t,k,val,hres) \
|
||||||
|
{ Table *h = t; lua_Unsigned u = l_castS2U(k) - 1u; \
|
||||||
|
if ((u < h->asize)) { \
|
||||||
|
lu_byte *tag = getArrTag(h, u); \
|
||||||
|
if (checknoTM(h->metatable, TM_NEWINDEX) || !tagisempty(*tag)) \
|
||||||
|
{ fval2arr(h, u, tag, val); hres = HOK; } \
|
||||||
|
else hres = ~cast_int(u); } \
|
||||||
|
else { hres = luaH_psetint(h, k, val); }}
|
||||||
|
|
||||||
|
|
||||||
|
/* results from pset */
|
||||||
|
#define HOK 0
|
||||||
|
#define HNOTFOUND 1
|
||||||
|
#define HNOTATABLE 2
|
||||||
|
#define HFIRSTNODE 3
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 'luaH_get*' operations set 'res', unless the value is absent, and
|
||||||
|
** return the tag of the result.
|
||||||
|
** The 'luaH_pset*' (pre-set) operations set the given value and return
|
||||||
|
** HOK, unless the original value is absent. In that case, if the key
|
||||||
|
** is really absent, they return HNOTFOUND. Otherwise, if there is a
|
||||||
|
** slot with that key but with no value, 'luaH_pset*' return an encoding
|
||||||
|
** of where the key is (usually called 'hres'). (pset cannot set that
|
||||||
|
** value because there might be a metamethod.) If the slot is in the
|
||||||
|
** hash part, the encoding is (HFIRSTNODE + hash index); if the slot is
|
||||||
|
** in the array part, the encoding is (~array index), a negative value.
|
||||||
|
** The value HNOTATABLE is used by the fast macros to signal that the
|
||||||
|
** value being indexed is not a table.
|
||||||
|
** (The size for the array part is limited by the maximum power of two
|
||||||
|
** that fits in an unsigned integer; that is INT_MAX+1. So, the C-index
|
||||||
|
** ranges from 0, which encodes to -1, to INT_MAX, which encodes to
|
||||||
|
** INT_MIN. The size of the hash part is limited by the maximum power of
|
||||||
|
** two that fits in a signed integer; that is (INT_MAX+1)/2. So, it is
|
||||||
|
** safe to add HFIRSTNODE to any index there.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The array part of a table is represented by an inverted array of
|
||||||
|
** values followed by an array of tags, to avoid wasting space with
|
||||||
|
** padding. In between them there is an unsigned int, explained later.
|
||||||
|
** The 'array' pointer points between the two arrays, so that values are
|
||||||
|
** indexed with negative indices and tags with non-negative indices.
|
||||||
|
|
||||||
|
Values Tags
|
||||||
|
--------------------------------------------------------
|
||||||
|
... | Value 1 | Value 0 |unsigned|0|1|...
|
||||||
|
--------------------------------------------------------
|
||||||
|
^ t->array
|
||||||
|
|
||||||
|
** All accesses to 't->array' should be through the macros 'getArrTag'
|
||||||
|
** and 'getArrVal'.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Computes the address of the tag for the abstract C-index 'k' */
|
||||||
|
#define getArrTag(t,k) (cast(lu_byte*, (t)->array) + sizeof(unsigned) + (k))
|
||||||
|
|
||||||
|
/* Computes the address of the value for the abstract C-index 'k' */
|
||||||
|
#define getArrVal(t,k) ((t)->array - 1 - (k))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The unsigned between the two arrays is used as a hint for #t;
|
||||||
|
** see luaH_getn. It is stored there to avoid wasting space in
|
||||||
|
** the structure Table for tables with no array part.
|
||||||
|
*/
|
||||||
|
#define lenhint(t) cast(unsigned*, (t)->array)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Move TValues to/from arrays, using C indices
|
||||||
|
*/
|
||||||
|
#define arr2obj(h,k,val) \
|
||||||
|
((val)->tt_ = *getArrTag(h,(k)), (val)->value_ = *getArrVal(h,(k)))
|
||||||
|
|
||||||
|
#define obj2arr(h,k,val) \
|
||||||
|
(*getArrTag(h,(k)) = (val)->tt_, *getArrVal(h,(k)) = (val)->value_)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Often, we need to check the tag of a value before moving it. The
|
||||||
|
** following macros also move TValues to/from arrays, but receive the
|
||||||
|
** precomputed tag value or address as an extra argument.
|
||||||
|
*/
|
||||||
|
#define farr2val(h,k,tag,res) \
|
||||||
|
((res)->tt_ = tag, (res)->value_ = *getArrVal(h,(k)))
|
||||||
|
|
||||||
|
#define fval2arr(h,k,tag,val) \
|
||||||
|
(*tag = (val)->tt_, *getArrVal(h,(k)) = (val)->value_)
|
||||||
|
|
||||||
|
|
||||||
|
LUAI_FUNC lu_byte luaH_get (Table *t, const TValue *key, TValue *res);
|
||||||
|
LUAI_FUNC lu_byte luaH_getshortstr (Table *t, TString *key, TValue *res);
|
||||||
|
LUAI_FUNC lu_byte luaH_getstr (Table *t, TString *key, TValue *res);
|
||||||
|
LUAI_FUNC lu_byte luaH_getint (Table *t, lua_Integer key, TValue *res);
|
||||||
|
|
||||||
|
/* Special get for metamethods */
|
||||||
|
LUAI_FUNC const TValue *luaH_Hgetshortstr (Table *t, TString *key);
|
||||||
|
|
||||||
|
LUAI_FUNC int luaH_psetint (Table *t, lua_Integer key, TValue *val);
|
||||||
|
LUAI_FUNC int luaH_psetshortstr (Table *t, TString *key, TValue *val);
|
||||||
|
LUAI_FUNC int luaH_psetstr (Table *t, TString *key, TValue *val);
|
||||||
|
LUAI_FUNC int luaH_pset (Table *t, const TValue *key, TValue *val);
|
||||||
|
|
||||||
|
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
|
||||||
|
TValue *value);
|
||||||
|
LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
|
||||||
|
TValue *value);
|
||||||
|
|
||||||
|
LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
|
||||||
|
TValue *value, int hres);
|
||||||
|
LUAI_FUNC Table *luaH_new (lua_State *L);
|
||||||
|
LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned nasize,
|
||||||
|
unsigned nhsize);
|
||||||
|
LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned nasize);
|
||||||
|
LUAI_FUNC lu_mem luaH_size (Table *t);
|
||||||
|
LUAI_FUNC void luaH_free (lua_State *L, Table *t);
|
||||||
|
LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
|
||||||
|
LUAI_FUNC lua_Unsigned luaH_getn (lua_State *L, Table *t);
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(LUA_DEBUG)
|
||||||
|
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
+45
-48
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -58,9 +59,20 @@ static void checktab (lua_State *L, int arg, int what) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int tcreate (lua_State *L) {
|
||||||
|
lua_Unsigned sizeseq = (lua_Unsigned)luaL_checkinteger(L, 1);
|
||||||
|
lua_Unsigned sizerest = (lua_Unsigned)luaL_optinteger(L, 2, 0);
|
||||||
|
luaL_argcheck(L, sizeseq <= cast_uint(INT_MAX), 1, "out of range");
|
||||||
|
luaL_argcheck(L, sizerest <= cast_uint(INT_MAX), 2, "out of range");
|
||||||
|
lua_createtable(L, cast_int(sizeseq), cast_int(sizerest));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int tinsert (lua_State *L) {
|
static int tinsert (lua_State *L) {
|
||||||
lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
|
|
||||||
lua_Integer pos; /* where to insert new element */
|
lua_Integer pos; /* where to insert new element */
|
||||||
|
lua_Integer e = aux_getn(L, 1, TAB_RW);
|
||||||
|
e = luaL_intop(+, e, 1); /* first empty element */
|
||||||
switch (lua_gettop(L)) {
|
switch (lua_gettop(L)) {
|
||||||
case 2: { /* called with only 2 arguments */
|
case 2: { /* called with only 2 arguments */
|
||||||
pos = e; /* insert new element at the end */
|
pos = e; /* insert new element at the end */
|
||||||
@@ -92,7 +104,7 @@ static int tremove (lua_State *L) {
|
|||||||
lua_Integer pos = luaL_optinteger(L, 2, size);
|
lua_Integer pos = luaL_optinteger(L, 2, size);
|
||||||
if (pos != size) /* validate 'pos' if given */
|
if (pos != size) /* validate 'pos' if given */
|
||||||
/* check whether 'pos' is in [1, size + 1] */
|
/* check whether 'pos' is in [1, size + 1] */
|
||||||
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1,
|
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
|
||||||
"position out of bounds");
|
"position out of bounds");
|
||||||
lua_geti(L, 1, pos); /* result = t[pos] */
|
lua_geti(L, 1, pos); /* result = t[pos] */
|
||||||
for ( ; pos < size; pos++) {
|
for ( ; pos < size; pos++) {
|
||||||
@@ -147,7 +159,7 @@ static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
|
|||||||
lua_geti(L, 1, i);
|
lua_geti(L, 1, i);
|
||||||
if (l_unlikely(!lua_isstring(L, -1)))
|
if (l_unlikely(!lua_isstring(L, -1)))
|
||||||
luaL_error(L, "invalid value (%s) at index %I in table for 'concat'",
|
luaL_error(L, "invalid value (%s) at index %I in table for 'concat'",
|
||||||
luaL_typename(L, -1), i);
|
luaL_typename(L, -1), (LUAI_UACINT)i);
|
||||||
luaL_addvalue(b);
|
luaL_addvalue(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +207,7 @@ static int tunpack (lua_State *L) {
|
|||||||
lua_Integer i = luaL_optinteger(L, 2, 1);
|
lua_Integer i = luaL_optinteger(L, 2, 1);
|
||||||
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
|
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
|
||||||
if (i > e) return 0; /* empty range */
|
if (i > e) return 0; /* empty range */
|
||||||
n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
|
n = l_castS2U(e) - l_castS2U(i); /* number of elements minus 1 */
|
||||||
if (l_unlikely(n >= (unsigned int)INT_MAX ||
|
if (l_unlikely(n >= (unsigned int)INT_MAX ||
|
||||||
!lua_checkstack(L, (int)(++n))))
|
!lua_checkstack(L, (int)(++n))))
|
||||||
return luaL_error(L, "too many results to unpack");
|
return luaL_error(L, "too many results to unpack");
|
||||||
@@ -219,41 +231,26 @@ static int tunpack (lua_State *L) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* type for array indices */
|
/*
|
||||||
|
** Type for array indices. These indices are always limited by INT_MAX,
|
||||||
|
** so it is safe to cast them to lua_Integer even for Lua 32 bits.
|
||||||
|
*/
|
||||||
typedef unsigned int IdxT;
|
typedef unsigned int IdxT;
|
||||||
|
|
||||||
|
|
||||||
|
/* Versions of lua_seti/lua_geti specialized for IdxT */
|
||||||
|
#define geti(L,idt,idx) lua_geti(L, idt, l_castU2S(idx))
|
||||||
|
#define seti(L,idt,idx) lua_seti(L, idt, l_castU2S(idx))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Produce a "random" 'unsigned int' to randomize pivot choice. This
|
** Produce a "random" 'unsigned int' to randomize pivot choice. This
|
||||||
** macro is used only when 'sort' detects a big imbalance in the result
|
** macro is used only when 'sort' detects a big imbalance in the result
|
||||||
** of a partition. (If you don't want/need this "randomness", ~0 is a
|
** of a partition. (If you don't want/need this "randomness", ~0 is a
|
||||||
** good choice.)
|
** good choice.)
|
||||||
*/
|
*/
|
||||||
#if !defined(l_randomizePivot) /* { */
|
#if !defined(l_randomizePivot)
|
||||||
|
#define l_randomizePivot(L) luaL_makeseed(L)
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
/* size of 'e' measured in number of 'unsigned int's */
|
|
||||||
#define sof(e) (sizeof(e) / sizeof(unsigned int))
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Use 'time' and 'clock' as sources of "randomness". Because we don't
|
|
||||||
** know the types 'clock_t' and 'time_t', we cannot cast them to
|
|
||||||
** anything without risking overflows. A safe way to use their values
|
|
||||||
** is to copy them to an array of a known type and use the array values.
|
|
||||||
*/
|
|
||||||
static unsigned int l_randomizePivot (void) {
|
|
||||||
clock_t c = clock();
|
|
||||||
time_t t = time(NULL);
|
|
||||||
unsigned int buff[sof(c) + sof(t)];
|
|
||||||
unsigned int i, rnd = 0;
|
|
||||||
memcpy(buff, &c, sof(c) * sizeof(unsigned int));
|
|
||||||
memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int));
|
|
||||||
for (i = 0; i < sof(buff); i++)
|
|
||||||
rnd += buff[i];
|
|
||||||
return rnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* } */
|
#endif /* } */
|
||||||
|
|
||||||
|
|
||||||
@@ -262,8 +259,8 @@ static unsigned int l_randomizePivot (void) {
|
|||||||
|
|
||||||
|
|
||||||
static void set2 (lua_State *L, IdxT i, IdxT j) {
|
static void set2 (lua_State *L, IdxT i, IdxT j) {
|
||||||
lua_seti(L, 1, i);
|
seti(L, 1, i);
|
||||||
lua_seti(L, 1, j);
|
seti(L, 1, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -300,15 +297,15 @@ static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
|
|||||||
/* loop invariant: a[lo .. i] <= P <= a[j .. up] */
|
/* loop invariant: a[lo .. i] <= P <= a[j .. up] */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* next loop: repeat ++i while a[i] < P */
|
/* next loop: repeat ++i while a[i] < P */
|
||||||
while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
|
while ((void)geti(L, 1, ++i), sort_comp(L, -1, -2)) {
|
||||||
if (l_unlikely(i == up - 1)) /* a[i] < P but a[up - 1] == P ?? */
|
if (l_unlikely(i == up - 1)) /* a[up - 1] < P == a[up - 1] */
|
||||||
luaL_error(L, "invalid order function for sorting");
|
luaL_error(L, "invalid order function for sorting");
|
||||||
lua_pop(L, 1); /* remove a[i] */
|
lua_pop(L, 1); /* remove a[i] */
|
||||||
}
|
}
|
||||||
/* after the loop, a[i] >= P and a[lo .. i - 1] < P */
|
/* after the loop, a[i] >= P and a[lo .. i - 1] < P (a) */
|
||||||
/* next loop: repeat --j while P < a[j] */
|
/* next loop: repeat --j while P < a[j] */
|
||||||
while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
|
while ((void)geti(L, 1, --j), sort_comp(L, -3, -1)) {
|
||||||
if (l_unlikely(j < i)) /* j < i but a[j] > P ?? */
|
if (l_unlikely(j < i)) /* j <= i - 1 and a[j] > P, contradicts (a) */
|
||||||
luaL_error(L, "invalid order function for sorting");
|
luaL_error(L, "invalid order function for sorting");
|
||||||
lua_pop(L, 1); /* remove a[j] */
|
lua_pop(L, 1); /* remove a[j] */
|
||||||
}
|
}
|
||||||
@@ -332,7 +329,7 @@ static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
|
|||||||
*/
|
*/
|
||||||
static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
|
static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
|
||||||
IdxT r4 = (up - lo) / 4; /* range/4 */
|
IdxT r4 = (up - lo) / 4; /* range/4 */
|
||||||
IdxT p = rnd % (r4 * 2) + (lo + r4);
|
IdxT p = (rnd ^ lo ^ up) % (r4 * 2) + (lo + r4);
|
||||||
lua_assert(lo + r4 <= p && p <= up - r4);
|
lua_assert(lo + r4 <= p && p <= up - r4);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@@ -341,14 +338,13 @@ static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
|
|||||||
/*
|
/*
|
||||||
** Quicksort algorithm (recursive function)
|
** Quicksort algorithm (recursive function)
|
||||||
*/
|
*/
|
||||||
static void auxsort (lua_State *L, IdxT lo, IdxT up,
|
static void auxsort (lua_State *L, IdxT lo, IdxT up, unsigned rnd) {
|
||||||
unsigned int rnd) {
|
|
||||||
while (lo < up) { /* loop for tail recursion */
|
while (lo < up) { /* loop for tail recursion */
|
||||||
IdxT p; /* Pivot index */
|
IdxT p; /* Pivot index */
|
||||||
IdxT n; /* to be used later */
|
IdxT n; /* to be used later */
|
||||||
/* sort elements 'lo', 'p', and 'up' */
|
/* sort elements 'lo', 'p', and 'up' */
|
||||||
lua_geti(L, 1, lo);
|
geti(L, 1, lo);
|
||||||
lua_geti(L, 1, up);
|
geti(L, 1, up);
|
||||||
if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */
|
if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */
|
||||||
set2(L, lo, up); /* swap a[lo] - a[up] */
|
set2(L, lo, up); /* swap a[lo] - a[up] */
|
||||||
else
|
else
|
||||||
@@ -359,13 +355,13 @@ static void auxsort (lua_State *L, IdxT lo, IdxT up,
|
|||||||
p = (lo + up)/2; /* middle element is a good pivot */
|
p = (lo + up)/2; /* middle element is a good pivot */
|
||||||
else /* for larger intervals, it is worth a random pivot */
|
else /* for larger intervals, it is worth a random pivot */
|
||||||
p = choosePivot(lo, up, rnd);
|
p = choosePivot(lo, up, rnd);
|
||||||
lua_geti(L, 1, p);
|
geti(L, 1, p);
|
||||||
lua_geti(L, 1, lo);
|
geti(L, 1, lo);
|
||||||
if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */
|
if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */
|
||||||
set2(L, p, lo); /* swap a[p] - a[lo] */
|
set2(L, p, lo); /* swap a[p] - a[lo] */
|
||||||
else {
|
else {
|
||||||
lua_pop(L, 1); /* remove a[lo] */
|
lua_pop(L, 1); /* remove a[lo] */
|
||||||
lua_geti(L, 1, up);
|
geti(L, 1, up);
|
||||||
if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */
|
if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */
|
||||||
set2(L, p, up); /* swap a[up] - a[p] */
|
set2(L, p, up); /* swap a[up] - a[p] */
|
||||||
else
|
else
|
||||||
@@ -373,9 +369,9 @@ static void auxsort (lua_State *L, IdxT lo, IdxT up,
|
|||||||
}
|
}
|
||||||
if (up - lo == 2) /* only 3 elements? */
|
if (up - lo == 2) /* only 3 elements? */
|
||||||
return; /* already sorted */
|
return; /* already sorted */
|
||||||
lua_geti(L, 1, p); /* get middle element (Pivot) */
|
geti(L, 1, p); /* get middle element (Pivot) */
|
||||||
lua_pushvalue(L, -1); /* push Pivot */
|
lua_pushvalue(L, -1); /* push Pivot */
|
||||||
lua_geti(L, 1, up - 1); /* push a[up - 1] */
|
geti(L, 1, up - 1); /* push a[up - 1] */
|
||||||
set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */
|
set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */
|
||||||
p = partition(L, lo, up);
|
p = partition(L, lo, up);
|
||||||
/* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */
|
/* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */
|
||||||
@@ -390,7 +386,7 @@ static void auxsort (lua_State *L, IdxT lo, IdxT up,
|
|||||||
up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
|
up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
|
||||||
}
|
}
|
||||||
if ((up - lo) / 128 > n) /* partition too imbalanced? */
|
if ((up - lo) / 128 > n) /* partition too imbalanced? */
|
||||||
rnd = l_randomizePivot(); /* try a new randomization */
|
rnd = l_randomizePivot(L); /* try a new randomization */
|
||||||
} /* tail call auxsort(L, lo, up, rnd) */
|
} /* tail call auxsort(L, lo, up, rnd) */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,6 +408,7 @@ static int sort (lua_State *L) {
|
|||||||
|
|
||||||
static const luaL_Reg tab_funcs[] = {
|
static const luaL_Reg tab_funcs[] = {
|
||||||
{"concat", tconcat},
|
{"concat", tconcat},
|
||||||
|
{"create", tcreate},
|
||||||
{"insert", tinsert},
|
{"insert", tinsert},
|
||||||
{"pack", tpack},
|
{"pack", tpack},
|
||||||
{"unpack", tunpack},
|
{"unpack", tunpack},
|
||||||
Vendored
+364
@@ -0,0 +1,364 @@
|
|||||||
|
/*
|
||||||
|
** $Id: ltm.c $
|
||||||
|
** Tag methods
|
||||||
|
** See Copyright Notice in lua.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ltm_c
|
||||||
|
#define LUA_CORE
|
||||||
|
|
||||||
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "ldebug.h"
|
||||||
|
#include "ldo.h"
|
||||||
|
#include "lgc.h"
|
||||||
|
#include "lobject.h"
|
||||||
|
#include "lstate.h"
|
||||||
|
#include "lstring.h"
|
||||||
|
#include "ltable.h"
|
||||||
|
#include "ltm.h"
|
||||||
|
#include "lvm.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const char udatatypename[] = "userdata";
|
||||||
|
|
||||||
|
LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTYPES] = {
|
||||||
|
"no value",
|
||||||
|
"nil", "boolean", udatatypename, "number",
|
||||||
|
"string", "table", "function", udatatypename, "thread",
|
||||||
|
"upvalue", "proto" /* these last cases are used for tests only */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void luaT_init (lua_State *L) {
|
||||||
|
static const char *const luaT_eventname[] = { /* ORDER TM */
|
||||||
|
"__index", "__newindex",
|
||||||
|
"__gc", "__mode", "__len", "__eq",
|
||||||
|
"__add", "__sub", "__mul", "__mod", "__pow",
|
||||||
|
"__div", "__idiv",
|
||||||
|
"__band", "__bor", "__bxor", "__shl", "__shr",
|
||||||
|
"__unm", "__bnot", "__lt", "__le",
|
||||||
|
"__concat", "__call", "__close"
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
for (i=0; i<TM_N; i++) {
|
||||||
|
G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);
|
||||||
|
luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** function to be used with macro "fasttm": optimized for absence of
|
||||||
|
** tag methods
|
||||||
|
*/
|
||||||
|
const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
|
||||||
|
const TValue *tm = luaH_Hgetshortstr(events, ename);
|
||||||
|
lua_assert(event <= TM_EQ);
|
||||||
|
if (notm(tm)) { /* no tag method? */
|
||||||
|
events->flags |= cast_byte(1u<<event); /* cache this fact */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else return tm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
|
||||||
|
Table *mt;
|
||||||
|
switch (ttype(o)) {
|
||||||
|
case LUA_TTABLE:
|
||||||
|
mt = hvalue(o)->metatable;
|
||||||
|
break;
|
||||||
|
case LUA_TUSERDATA:
|
||||||
|
mt = uvalue(o)->metatable;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mt = G(L)->mt[ttype(o)];
|
||||||
|
}
|
||||||
|
return (mt ? luaH_Hgetshortstr(mt, G(L)->tmname[event]) : &G(L)->nilvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return the name of the type of an object. For tables and userdata
|
||||||
|
** with metatable, use their '__name' metafield, if present.
|
||||||
|
*/
|
||||||
|
const char *luaT_objtypename (lua_State *L, const TValue *o) {
|
||||||
|
Table *mt;
|
||||||
|
if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
|
||||||
|
(ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
|
||||||
|
const TValue *name = luaH_Hgetshortstr(mt, luaS_new(L, "__name"));
|
||||||
|
if (ttisstring(name)) /* is '__name' a string? */
|
||||||
|
return getstr(tsvalue(name)); /* use it as type name */
|
||||||
|
}
|
||||||
|
return ttypename(ttype(o)); /* else use standard type name */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
|
||||||
|
const TValue *p2, const TValue *p3) {
|
||||||
|
StkId func = L->top.p;
|
||||||
|
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
|
||||||
|
setobj2s(L, func + 1, p1); /* 1st argument */
|
||||||
|
setobj2s(L, func + 2, p2); /* 2nd argument */
|
||||||
|
setobj2s(L, func + 3, p3); /* 3rd argument */
|
||||||
|
L->top.p = func + 4;
|
||||||
|
/* metamethod may yield only when called from Lua code */
|
||||||
|
if (isLuacode(L->ci))
|
||||||
|
luaD_call(L, func, 0);
|
||||||
|
else
|
||||||
|
luaD_callnoyield(L, func, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lu_byte luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
|
||||||
|
const TValue *p2, StkId res) {
|
||||||
|
ptrdiff_t result = savestack(L, res);
|
||||||
|
StkId func = L->top.p;
|
||||||
|
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
|
||||||
|
setobj2s(L, func + 1, p1); /* 1st argument */
|
||||||
|
setobj2s(L, func + 2, p2); /* 2nd argument */
|
||||||
|
L->top.p += 3;
|
||||||
|
/* metamethod may yield only when called from Lua code */
|
||||||
|
if (isLuacode(L->ci))
|
||||||
|
luaD_call(L, func, 1);
|
||||||
|
else
|
||||||
|
luaD_callnoyield(L, func, 1);
|
||||||
|
res = restorestack(L, result);
|
||||||
|
setobjs2s(L, res, --L->top.p); /* move result to its place */
|
||||||
|
return ttypetag(s2v(res)); /* return tag of the result */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||||
|
StkId res, TMS event) {
|
||||||
|
const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */
|
||||||
|
if (notm(tm))
|
||||||
|
tm = luaT_gettmbyobj(L, p2, event); /* try second operand */
|
||||||
|
if (notm(tm))
|
||||||
|
return -1; /* tag method not found */
|
||||||
|
else /* call tag method and return the tag of the result */
|
||||||
|
return luaT_callTMres(L, tm, p1, p2, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||||
|
StkId res, TMS event) {
|
||||||
|
if (l_unlikely(callbinTM(L, p1, p2, res, event) < 0)) {
|
||||||
|
switch (event) {
|
||||||
|
case TM_BAND: case TM_BOR: case TM_BXOR:
|
||||||
|
case TM_SHL: case TM_SHR: case TM_BNOT: {
|
||||||
|
if (ttisnumber(p1) && ttisnumber(p2))
|
||||||
|
luaG_tointerror(L, p1, p2);
|
||||||
|
else
|
||||||
|
luaG_opinterror(L, p1, p2, "perform bitwise operation on");
|
||||||
|
}
|
||||||
|
/* calls never return, but to avoid warnings: *//* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
luaG_opinterror(L, p1, p2, "perform arithmetic on");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The use of 'p1' after 'callbinTM' is safe because, when a tag
|
||||||
|
** method is not found, 'callbinTM' cannot change the stack.
|
||||||
|
*/
|
||||||
|
void luaT_tryconcatTM (lua_State *L) {
|
||||||
|
StkId p1 = L->top.p - 2; /* first argument */
|
||||||
|
if (l_unlikely(callbinTM(L, s2v(p1), s2v(p1 + 1), p1, TM_CONCAT) < 0))
|
||||||
|
luaG_concaterror(L, s2v(p1), s2v(p1 + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaT_trybinassocTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||||
|
int flip, StkId res, TMS event) {
|
||||||
|
if (flip)
|
||||||
|
luaT_trybinTM(L, p2, p1, res, event);
|
||||||
|
else
|
||||||
|
luaT_trybinTM(L, p1, p2, res, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
|
||||||
|
int flip, StkId res, TMS event) {
|
||||||
|
TValue aux;
|
||||||
|
setivalue(&aux, i2);
|
||||||
|
luaT_trybinassocTM(L, p1, &aux, flip, res, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Calls an order tag method.
|
||||||
|
*/
|
||||||
|
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||||
|
TMS event) {
|
||||||
|
int tag = callbinTM(L, p1, p2, L->top.p, event); /* try original event */
|
||||||
|
if (tag >= 0) /* found tag method? */
|
||||||
|
return !tagisfalse(tag);
|
||||||
|
luaG_ordererror(L, p1, p2); /* no metamethod found */
|
||||||
|
return 0; /* to avoid warnings */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
||||||
|
int flip, int isfloat, TMS event) {
|
||||||
|
TValue aux; const TValue *p2;
|
||||||
|
if (isfloat) {
|
||||||
|
setfltvalue(&aux, cast_num(v2));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
setivalue(&aux, v2);
|
||||||
|
if (flip) { /* arguments were exchanged? */
|
||||||
|
p2 = p1; p1 = &aux; /* correct them */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p2 = &aux;
|
||||||
|
return luaT_callorderTM(L, p1, p2, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Create a vararg table at the top of the stack, with 'n' elements
|
||||||
|
** starting at 'f'.
|
||||||
|
*/
|
||||||
|
static void createvarargtab (lua_State *L, StkId f, int n) {
|
||||||
|
int i;
|
||||||
|
TValue key, value;
|
||||||
|
Table *t = luaH_new(L);
|
||||||
|
sethvalue(L, s2v(L->top.p), t);
|
||||||
|
L->top.p++;
|
||||||
|
luaH_resize(L, t, cast_uint(n), 1);
|
||||||
|
setsvalue(L, &key, luaS_new(L, "n")); /* key is "n" */
|
||||||
|
setivalue(&value, n); /* value is n */
|
||||||
|
/* No need to anchor the key: Due to the resize, the next operation
|
||||||
|
cannot trigger a garbage collection */
|
||||||
|
luaH_set(L, t, &key, &value); /* t.n = n */
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
luaH_setint(L, t, i + 1, s2v(f + i));
|
||||||
|
luaC_checkGC(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** initial stack: func arg1 ... argn extra1 ...
|
||||||
|
** ^ ci->func ^ L->top
|
||||||
|
** final stack: func nil ... nil extra1 ... func arg1 ... argn
|
||||||
|
** ^ ci->func
|
||||||
|
*/
|
||||||
|
static void buildhiddenargs (lua_State *L, CallInfo *ci, const Proto *p,
|
||||||
|
int totalargs, int nfixparams, int nextra) {
|
||||||
|
int i;
|
||||||
|
ci->u.l.nextraargs = nextra;
|
||||||
|
luaD_checkstack(L, p->maxstacksize + 1);
|
||||||
|
/* copy function to the top of the stack, after extra arguments */
|
||||||
|
setobjs2s(L, L->top.p++, ci->func.p);
|
||||||
|
/* move fixed parameters to after the copied function */
|
||||||
|
for (i = 1; i <= nfixparams; i++) {
|
||||||
|
setobjs2s(L, L->top.p++, ci->func.p + i);
|
||||||
|
setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
|
||||||
|
}
|
||||||
|
ci->func.p += totalargs + 1; /* 'func' now lives after hidden arguments */
|
||||||
|
ci->top.p += totalargs + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) {
|
||||||
|
int totalargs = cast_int(L->top.p - ci->func.p) - 1;
|
||||||
|
int nfixparams = p->numparams;
|
||||||
|
int nextra = totalargs - nfixparams; /* number of extra arguments */
|
||||||
|
if (p->flag & PF_VATAB) { /* does it need a vararg table? */
|
||||||
|
lua_assert(!(p->flag & PF_VAHID));
|
||||||
|
createvarargtab(L, ci->func.p + nfixparams + 1, nextra);
|
||||||
|
/* move table to proper place (last parameter) */
|
||||||
|
setobjs2s(L, ci->func.p + nfixparams + 1, L->top.p - 1);
|
||||||
|
}
|
||||||
|
else { /* no table */
|
||||||
|
lua_assert(p->flag & PF_VAHID);
|
||||||
|
buildhiddenargs(L, ci, p, totalargs, nfixparams, nextra);
|
||||||
|
/* set vararg parameter to nil */
|
||||||
|
setnilvalue(s2v(ci->func.p + nfixparams + 1));
|
||||||
|
lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaT_getvararg (CallInfo *ci, StkId ra, TValue *rc) {
|
||||||
|
int nextra = ci->u.l.nextraargs;
|
||||||
|
lua_Integer n;
|
||||||
|
if (tointegerns(rc, &n)) { /* integral value? */
|
||||||
|
if (l_castS2U(n) - 1 < cast_uint(nextra)) {
|
||||||
|
StkId slot = ci->func.p - nextra + cast_int(n) - 1;
|
||||||
|
setobjs2s(((lua_State*)NULL), ra, slot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ttisstring(rc)) { /* string value? */
|
||||||
|
size_t len;
|
||||||
|
const char *s = getlstr(tsvalue(rc), len);
|
||||||
|
if (len == 1 && s[0] == 'n') { /* key is "n"? */
|
||||||
|
setivalue(s2v(ra), nextra);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setnilvalue(s2v(ra)); /* else produce nil */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Get the number of extra arguments in a vararg function. If vararg
|
||||||
|
** table has been optimized away, that number is in the call info.
|
||||||
|
** Otherwise, get the field 'n' from the vararg table and check that it
|
||||||
|
** has a proper value (non-negative integer not larger than the stack
|
||||||
|
** limit).
|
||||||
|
*/
|
||||||
|
static int getnumargs (lua_State *L, CallInfo *ci, Table *h) {
|
||||||
|
if (h == NULL) /* no vararg table? */
|
||||||
|
return ci->u.l.nextraargs;
|
||||||
|
else {
|
||||||
|
TValue res;
|
||||||
|
if (luaH_getshortstr(h, luaS_new(L, "n"), &res) != LUA_VNUMINT ||
|
||||||
|
l_castS2U(ivalue(&res)) > cast_uint(INT_MAX/2))
|
||||||
|
luaG_runerror(L, "vararg table has no proper 'n'");
|
||||||
|
return cast_int(ivalue(&res));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Get 'wanted' vararg arguments and put them in 'where'. 'vatab' is
|
||||||
|
** the register of the vararg table or -1 if there is no vararg table.
|
||||||
|
*/
|
||||||
|
void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted,
|
||||||
|
int vatab) {
|
||||||
|
Table *h = (vatab < 0) ? NULL : hvalue(s2v(ci->func.p + vatab + 1));
|
||||||
|
int nargs = getnumargs(L, ci, h); /* number of available vararg args. */
|
||||||
|
int i, touse; /* 'touse' is minimum between 'wanted' and 'nargs' */
|
||||||
|
if (wanted < 0) {
|
||||||
|
touse = wanted = nargs; /* get all extra arguments available */
|
||||||
|
checkstackp(L, nargs, where); /* ensure stack space */
|
||||||
|
L->top.p = where + nargs; /* next instruction will need top */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
touse = (nargs > wanted) ? wanted : nargs;
|
||||||
|
if (h == NULL) { /* no vararg table? */
|
||||||
|
for (i = 0; i < touse; i++) /* get vararg values from the stack */
|
||||||
|
setobjs2s(L, where + i, ci->func.p - nargs + i);
|
||||||
|
}
|
||||||
|
else { /* get vararg values from vararg table */
|
||||||
|
for (i = 0; i < touse; i++) {
|
||||||
|
lu_byte tag = luaH_getint(h, i + 1, s2v(where + i));
|
||||||
|
if (tagisempty(tag))
|
||||||
|
setnilvalue(s2v(where + i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i < wanted; i++) /* complete required results with nil */
|
||||||
|
setnilvalue(s2v(where + i));
|
||||||
|
}
|
||||||
|
|
||||||
+14
-12
@@ -48,10 +48,10 @@ typedef enum {
|
|||||||
/*
|
/*
|
||||||
** Mask with 1 in all fast-access methods. A 1 in any of these bits
|
** Mask with 1 in all fast-access methods. A 1 in any of these bits
|
||||||
** in the flag of a (meta)table means the metatable does not have the
|
** in the flag of a (meta)table means the metatable does not have the
|
||||||
** corresponding metamethod field. (Bit 7 of the flag is used for
|
** corresponding metamethod field. (Bit 6 of the flag indicates that
|
||||||
** 'isrealasize'.)
|
** the table is using the dummy node; bit 7 is used for 'isrealasize'.)
|
||||||
*/
|
*/
|
||||||
#define maskflags (~(~0u << (TM_EQ + 1)))
|
#define maskflags cast_byte(~(~0u << (TM_EQ + 1)))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -60,11 +60,12 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
#define notm(tm) ttisnil(tm)
|
#define notm(tm) ttisnil(tm)
|
||||||
|
|
||||||
|
#define checknoTM(mt,e) ((mt) == NULL || (mt)->flags & (1u<<(e)))
|
||||||
|
|
||||||
#define gfasttm(g,et,e) ((et) == NULL ? NULL : \
|
#define gfasttm(g,mt,e) \
|
||||||
((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))
|
(checknoTM(mt, e) ? NULL : luaT_gettm(mt, e, (g)->tmname[e]))
|
||||||
|
|
||||||
#define fasttm(l,et,e) gfasttm(G(l), et, e)
|
#define fasttm(l,mt,e) gfasttm(G(l), mt, e)
|
||||||
|
|
||||||
#define ttypename(x) luaT_typenames_[(x) + 1]
|
#define ttypename(x) luaT_typenames_[(x) + 1]
|
||||||
|
|
||||||
@@ -80,8 +81,8 @@ LUAI_FUNC void luaT_init (lua_State *L);
|
|||||||
|
|
||||||
LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
|
LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
|
||||||
const TValue *p2, const TValue *p3);
|
const TValue *p2, const TValue *p3);
|
||||||
LUAI_FUNC void luaT_callTMres (lua_State *L, const TValue *f,
|
LUAI_FUNC lu_byte luaT_callTMres (lua_State *L, const TValue *f,
|
||||||
const TValue *p1, const TValue *p2, StkId p3);
|
const TValue *p1, const TValue *p2, StkId p3);
|
||||||
LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||||
StkId res, TMS event);
|
StkId res, TMS event);
|
||||||
LUAI_FUNC void luaT_tryconcatTM (lua_State *L);
|
LUAI_FUNC void luaT_tryconcatTM (lua_State *L);
|
||||||
@@ -94,10 +95,11 @@ LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
|
|||||||
LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
||||||
int inv, int isfloat, TMS event);
|
int inv, int isfloat, TMS event);
|
||||||
|
|
||||||
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
|
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, struct CallInfo *ci,
|
||||||
struct CallInfo *ci, const Proto *p);
|
const Proto *p);
|
||||||
LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
|
LUAI_FUNC void luaT_getvararg (CallInfo *ci, StkId ra, TValue *rc);
|
||||||
StkId where, int wanted);
|
LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, StkId where,
|
||||||
|
int wanted, int vatab);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+75
-46
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lua.h $
|
** $Id: lua.h $
|
||||||
** Lua - A Scripting Language
|
** Lua - A Scripting Language
|
||||||
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
|
** Lua.org, PUC-Rio, Brazil (www.lua.org)
|
||||||
** See Copyright Notice at the end of this file
|
** See Copyright Notice at the end of this file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -13,22 +13,21 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
#include "luaconf.h"
|
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2025 Lua.org, PUC-Rio"
|
||||||
|
|
||||||
|
|
||||||
#define LUA_VERSION_MAJOR "5"
|
|
||||||
#define LUA_VERSION_MINOR "4"
|
|
||||||
#define LUA_VERSION_RELEASE "3"
|
|
||||||
|
|
||||||
#define LUA_VERSION_NUM 504
|
|
||||||
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 0)
|
|
||||||
|
|
||||||
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
|
|
||||||
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
|
|
||||||
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2021 Lua.org, PUC-Rio"
|
|
||||||
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
|
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
|
||||||
|
|
||||||
|
|
||||||
|
#define LUA_VERSION_MAJOR_N 5
|
||||||
|
#define LUA_VERSION_MINOR_N 5
|
||||||
|
#define LUA_VERSION_RELEASE_N 0
|
||||||
|
|
||||||
|
#define LUA_VERSION_NUM (LUA_VERSION_MAJOR_N * 100 + LUA_VERSION_MINOR_N)
|
||||||
|
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + LUA_VERSION_RELEASE_N)
|
||||||
|
|
||||||
|
|
||||||
|
#include "luaconf.h"
|
||||||
|
|
||||||
|
|
||||||
/* mark for precompiled code ('<esc>Lua') */
|
/* mark for precompiled code ('<esc>Lua') */
|
||||||
#define LUA_SIGNATURE "\x1bLua"
|
#define LUA_SIGNATURE "\x1bLua"
|
||||||
|
|
||||||
@@ -38,10 +37,10 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Pseudo-indices
|
** Pseudo-indices
|
||||||
** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
|
** (The stack size is limited to INT_MAX/2; we keep some free empty
|
||||||
** space after that to help overflow detection)
|
** space after that to help overflow detection.)
|
||||||
*/
|
*/
|
||||||
#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
|
#define LUA_REGISTRYINDEX (-(INT_MAX/2 + 1000))
|
||||||
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
|
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
|
||||||
|
|
||||||
|
|
||||||
@@ -81,9 +80,10 @@ typedef struct lua_State lua_State;
|
|||||||
|
|
||||||
|
|
||||||
/* predefined values in the registry */
|
/* predefined values in the registry */
|
||||||
#define LUA_RIDX_MAINTHREAD 1
|
/* index 1 is reserved for the reference mechanism */
|
||||||
#define LUA_RIDX_GLOBALS 2
|
#define LUA_RIDX_GLOBALS 2
|
||||||
#define LUA_RIDX_LAST LUA_RIDX_GLOBALS
|
#define LUA_RIDX_MAINTHREAD 3
|
||||||
|
#define LUA_RIDX_LAST 3
|
||||||
|
|
||||||
|
|
||||||
/* type of numbers in Lua */
|
/* type of numbers in Lua */
|
||||||
@@ -131,6 +131,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
|
|||||||
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
|
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Type used by the debug API to collect debug information
|
||||||
|
*/
|
||||||
|
typedef struct lua_Debug lua_Debug;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Functions to be called by the debugger in specific events
|
||||||
|
*/
|
||||||
|
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -150,10 +160,10 @@ extern const char lua_ident[];
|
|||||||
/*
|
/*
|
||||||
** state manipulation
|
** state manipulation
|
||||||
*/
|
*/
|
||||||
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
|
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud, unsigned seed);
|
||||||
LUA_API void (lua_close) (lua_State *L);
|
LUA_API void (lua_close) (lua_State *L);
|
||||||
LUA_API lua_State *(lua_newthread) (lua_State *L);
|
LUA_API lua_State *(lua_newthread) (lua_State *L);
|
||||||
LUA_API int (lua_resetthread) (lua_State *L);
|
LUA_API int (lua_closethread) (lua_State *L, lua_State *from);
|
||||||
|
|
||||||
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
|
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
|
||||||
|
|
||||||
@@ -234,6 +244,8 @@ LUA_API void (lua_pushnil) (lua_State *L);
|
|||||||
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
|
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
|
||||||
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
|
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
|
||||||
LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
|
LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
|
||||||
|
LUA_API const char *(lua_pushexternalstring) (lua_State *L,
|
||||||
|
const char *s, size_t len, lua_Alloc falloc, void *ud);
|
||||||
LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
|
LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
|
||||||
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
|
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
|
||||||
va_list argp);
|
va_list argp);
|
||||||
@@ -313,7 +325,7 @@ LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont);
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** garbage-collection function and options
|
** garbage-collection options
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LUA_GCSTOP 0
|
#define LUA_GCSTOP 0
|
||||||
@@ -322,11 +334,28 @@ LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont);
|
|||||||
#define LUA_GCCOUNT 3
|
#define LUA_GCCOUNT 3
|
||||||
#define LUA_GCCOUNTB 4
|
#define LUA_GCCOUNTB 4
|
||||||
#define LUA_GCSTEP 5
|
#define LUA_GCSTEP 5
|
||||||
#define LUA_GCSETPAUSE 6
|
#define LUA_GCISRUNNING 6
|
||||||
#define LUA_GCSETSTEPMUL 7
|
#define LUA_GCGEN 7
|
||||||
#define LUA_GCISRUNNING 9
|
#define LUA_GCINC 8
|
||||||
#define LUA_GCGEN 10
|
#define LUA_GCPARAM 9
|
||||||
#define LUA_GCINC 11
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** garbage-collection parameters
|
||||||
|
*/
|
||||||
|
/* parameters for generational mode */
|
||||||
|
#define LUA_GCPMINORMUL 0 /* control minor collections */
|
||||||
|
#define LUA_GCPMAJORMINOR 1 /* control shift major->minor */
|
||||||
|
#define LUA_GCPMINORMAJOR 2 /* control shift minor->major */
|
||||||
|
|
||||||
|
/* parameters for incremental mode */
|
||||||
|
#define LUA_GCPPAUSE 3 /* size of pause between successive GCs */
|
||||||
|
#define LUA_GCPSTEPMUL 4 /* GC "speed" */
|
||||||
|
#define LUA_GCPSTEPSIZE 5 /* GC granularity */
|
||||||
|
|
||||||
|
/* number of parameters */
|
||||||
|
#define LUA_GCPN 6
|
||||||
|
|
||||||
|
|
||||||
LUA_API int (lua_gc) (lua_State *L, int what, ...);
|
LUA_API int (lua_gc) (lua_State *L, int what, ...);
|
||||||
|
|
||||||
@@ -342,7 +371,9 @@ LUA_API int (lua_next) (lua_State *L, int idx);
|
|||||||
LUA_API void (lua_concat) (lua_State *L, int n);
|
LUA_API void (lua_concat) (lua_State *L, int n);
|
||||||
LUA_API void (lua_len) (lua_State *L, int idx);
|
LUA_API void (lua_len) (lua_State *L, int idx);
|
||||||
|
|
||||||
LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
|
#define LUA_N2SBUFFSZ 64
|
||||||
|
LUA_API unsigned (lua_numbertocstring) (lua_State *L, int idx, char *buff);
|
||||||
|
LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
|
||||||
|
|
||||||
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
|
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
|
||||||
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
|
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
|
||||||
@@ -401,19 +432,12 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
|
|||||||
** compatibility macros
|
** compatibility macros
|
||||||
** ===============================================================
|
** ===============================================================
|
||||||
*/
|
*/
|
||||||
#if defined(LUA_COMPAT_APIINTCASTS)
|
|
||||||
|
|
||||||
#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
|
|
||||||
#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is))
|
|
||||||
#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1)
|
#define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1)
|
||||||
#define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1)
|
#define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1)
|
||||||
#define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1)
|
#define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1)
|
||||||
|
|
||||||
#define LUA_NUMTAGS LUA_NUMTYPES
|
#define lua_resetthread(L) lua_closethread(L,NULL)
|
||||||
|
|
||||||
/* }============================================================== */
|
/* }============================================================== */
|
||||||
|
|
||||||
@@ -442,12 +466,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
|
|||||||
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
|
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
|
||||||
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
|
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
|
||||||
|
|
||||||
typedef struct lua_Debug lua_Debug; /* activation record */
|
|
||||||
|
|
||||||
|
|
||||||
/* Functions to be called by the debugger in specific events */
|
|
||||||
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
|
|
||||||
|
|
||||||
|
|
||||||
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
|
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
|
||||||
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
|
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
|
||||||
@@ -465,7 +483,6 @@ LUA_API lua_Hook (lua_gethook) (lua_State *L);
|
|||||||
LUA_API int (lua_gethookmask) (lua_State *L);
|
LUA_API int (lua_gethookmask) (lua_State *L);
|
||||||
LUA_API int (lua_gethookcount) (lua_State *L);
|
LUA_API int (lua_gethookcount) (lua_State *L);
|
||||||
|
|
||||||
LUA_API int (lua_setcstacklimit) (lua_State *L, unsigned int limit);
|
|
||||||
|
|
||||||
struct lua_Debug {
|
struct lua_Debug {
|
||||||
int event;
|
int event;
|
||||||
@@ -480,9 +497,10 @@ struct lua_Debug {
|
|||||||
unsigned char nups; /* (u) number of upvalues */
|
unsigned char nups; /* (u) number of upvalues */
|
||||||
unsigned char nparams;/* (u) number of parameters */
|
unsigned char nparams;/* (u) number of parameters */
|
||||||
char isvararg; /* (u) */
|
char isvararg; /* (u) */
|
||||||
|
unsigned char extraargs; /* (t) number of extra arguments */
|
||||||
char istailcall; /* (t) */
|
char istailcall; /* (t) */
|
||||||
unsigned short ftransfer; /* (r) index of first value transferred */
|
int ftransfer; /* (r) index of first value transferred */
|
||||||
unsigned short ntransfer; /* (r) number of transferred values */
|
int ntransfer; /* (r) number of transferred values */
|
||||||
char short_src[LUA_IDSIZE]; /* (S) */
|
char short_src[LUA_IDSIZE]; /* (S) */
|
||||||
/* private part */
|
/* private part */
|
||||||
struct CallInfo *i_ci; /* active function */
|
struct CallInfo *i_ci; /* active function */
|
||||||
@@ -491,8 +509,19 @@ struct lua_Debug {
|
|||||||
/* }====================================================================== */
|
/* }====================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
#define LUAI_TOSTRAUX(x) #x
|
||||||
|
#define LUAI_TOSTR(x) LUAI_TOSTRAUX(x)
|
||||||
|
|
||||||
|
#define LUA_VERSION_MAJOR LUAI_TOSTR(LUA_VERSION_MAJOR_N)
|
||||||
|
#define LUA_VERSION_MINOR LUAI_TOSTR(LUA_VERSION_MINOR_N)
|
||||||
|
#define LUA_VERSION_RELEASE LUAI_TOSTR(LUA_VERSION_RELEASE_N)
|
||||||
|
|
||||||
|
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
|
||||||
|
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Copyright (C) 1994-2021 Lua.org, PUC-Rio.
|
* Copyright (C) 1994-2025 Lua.org, PUC-Rio.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
// lua.hpp
|
// lua.hpp
|
||||||
// Lua header files for C++
|
// Lua header files for C++
|
||||||
// <<extern "C">> not supplied automatically because Lua also compiles as C++
|
// 'extern "C" not supplied automatically in lua.h and other headers
|
||||||
|
// because Lua also compiles as C++
|
||||||
|
|
||||||
//extern "C" {
|
//extern "C" {
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
+60
-105
@@ -58,15 +58,37 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** When POSIX DLL ('LUA_USE_DLOPEN') is enabled, the Lua stand-alone
|
||||||
|
** application will try to dynamically link a 'readline' facility
|
||||||
|
** for its REPL. In that case, LUA_READLINELIB is the name of the
|
||||||
|
** library it will look for those facilities. If lua.c cannot open
|
||||||
|
** the specified library, it will generate a warning and then run
|
||||||
|
** without 'readline'. If that macro is not defined, lua.c will not
|
||||||
|
** use 'readline'.
|
||||||
|
*/
|
||||||
#if defined(LUA_USE_LINUX)
|
#if defined(LUA_USE_LINUX)
|
||||||
#define LUA_USE_POSIX
|
#define LUA_USE_POSIX
|
||||||
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
|
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
|
||||||
|
#define LUA_READLINELIB "libreadline.so"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_USE_MACOSX)
|
#if defined(LUA_USE_MACOSX)
|
||||||
#define LUA_USE_POSIX
|
#define LUA_USE_POSIX
|
||||||
#define LUA_USE_DLOPEN /* MacOS does not need -ldl */
|
#define LUA_USE_DLOPEN /* macOS does not need -ldl */
|
||||||
|
#define LUA_READLINELIB "libedit.dylib"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(LUA_USE_IOS)
|
||||||
|
#define LUA_USE_POSIX
|
||||||
|
#define LUA_USE_DLOPEN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(LUA_USE_C89) && defined(LUA_USE_POSIX)
|
||||||
|
#error "POSIX is not compatible with C89"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -116,7 +138,7 @@
|
|||||||
/*
|
/*
|
||||||
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
|
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
|
||||||
*/
|
*/
|
||||||
#define LUA_32BITS 0
|
/* #define LUA_32BITS */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -131,7 +153,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if LUA_32BITS /* { */
|
#if defined(LUA_32BITS) /* { */
|
||||||
/*
|
/*
|
||||||
** 32-bit integers and 'float'
|
** 32-bit integers and 'float'
|
||||||
*/
|
*/
|
||||||
@@ -251,6 +273,15 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** LUA_IGMARK is a mark to ignore all after it when building the
|
||||||
|
** module name (e.g., used to build the luaopen_ function name).
|
||||||
|
** Typically, the suffix after the mark is the module version,
|
||||||
|
** as in "mod-v1.2.so".
|
||||||
|
*/
|
||||||
|
#define LUA_IGMARK "-"
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
@@ -288,32 +319,13 @@
|
|||||||
** More often than not the libs go together with the core.
|
** More often than not the libs go together with the core.
|
||||||
*/
|
*/
|
||||||
#define LUALIB_API LUA_API
|
#define LUALIB_API LUA_API
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
/* Lua uses the "C name" when calling open functions */
|
||||||
|
#define LUAMOD_API extern "C"
|
||||||
|
#else
|
||||||
#define LUAMOD_API LUA_API
|
#define LUAMOD_API LUA_API
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
@@ LUAI_FUNC is a mark for all extern functions that are not to be
|
|
||||||
** exported to outside modules.
|
|
||||||
@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables,
|
|
||||||
** none of which to be exported to outside modules (LUAI_DDEF for
|
|
||||||
** definitions and LUAI_DDEC for declarations).
|
|
||||||
** CHANGE them if you need to mark them in some special way. Elf/gcc
|
|
||||||
** (versions 3.2 and later) mark them as "hidden" to optimize access
|
|
||||||
** when Lua is compiled as a shared library. Not all elf targets support
|
|
||||||
** this attribute. Unfortunately, gcc does not offer a way to check
|
|
||||||
** whether the target offers that support, and those without support
|
|
||||||
** give a warning about it. To avoid these warnings, change to the
|
|
||||||
** default definition.
|
|
||||||
*/
|
|
||||||
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
|
|
||||||
defined(__ELF__) /* { */
|
|
||||||
#define LUAI_FUNC __attribute__((visibility("internal"))) extern
|
|
||||||
#else /* }{ */
|
|
||||||
#define LUAI_FUNC extern
|
|
||||||
#endif /* } */
|
|
||||||
|
|
||||||
#define LUAI_DDEC(dec) LUAI_FUNC dec
|
|
||||||
#define LUAI_DDEF /* empty */
|
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
@@ -325,11 +337,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3.
|
@@ LUA_COMPAT_GLOBAL avoids 'global' being a reserved word
|
||||||
** You can define it to get all options, or change specific options
|
|
||||||
** to fit your specific needs.
|
|
||||||
*/
|
*/
|
||||||
#if defined(LUA_COMPAT_5_3) /* { */
|
#define LUA_COMPAT_GLOBAL
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
|
@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
|
||||||
@@ -337,23 +348,7 @@
|
|||||||
** (These functions were already officially removed in 5.3;
|
** (These functions were already officially removed in 5.3;
|
||||||
** nevertheless they are still available here.)
|
** nevertheless they are still available here.)
|
||||||
*/
|
*/
|
||||||
#define LUA_COMPAT_MATHLIB
|
/* #define LUA_COMPAT_MATHLIB */
|
||||||
|
|
||||||
/*
|
|
||||||
@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for
|
|
||||||
** manipulating other integer types (lua_pushunsigned, lua_tounsigned,
|
|
||||||
** luaL_checkint, luaL_checklong, etc.)
|
|
||||||
** (These macros were also officially removed in 5.3, but they are still
|
|
||||||
** available here.)
|
|
||||||
*/
|
|
||||||
#define LUA_COMPAT_APIINTCASTS
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ LUA_COMPAT_LT_LE controls the emulation of the '__le' metamethod
|
|
||||||
** using '__lt'.
|
|
||||||
*/
|
|
||||||
#define LUA_COMPAT_LT_LE
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -370,8 +365,6 @@
|
|||||||
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
|
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
|
||||||
#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
|
#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
|
||||||
|
|
||||||
#endif /* } */
|
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
|
|
||||||
@@ -390,35 +383,23 @@
|
|||||||
@@ l_floatatt(x) corrects float attribute 'x' to the proper float type
|
@@ l_floatatt(x) corrects float attribute 'x' to the proper float type
|
||||||
** by prefixing it with one of FLT/DBL/LDBL.
|
** by prefixing it with one of FLT/DBL/LDBL.
|
||||||
@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
|
@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
|
||||||
@@ LUA_NUMBER_FMT is the format for writing floats.
|
@@ LUA_NUMBER_FMT is the format for writing floats with the maximum
|
||||||
@@ lua_number2str converts a float to a string.
|
** number of digits that respects tostring(tonumber(numeral)) == numeral.
|
||||||
|
** (That would be floor(log10(2^n)), where n is the number of bits in
|
||||||
|
** the float mantissa.)
|
||||||
|
@@ LUA_NUMBER_FMT_N is the format for writing floats with the minimum
|
||||||
|
** number of digits that ensures tonumber(tostring(number)) == number.
|
||||||
|
** (That would be LUA_NUMBER_FMT+2.)
|
||||||
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
|
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
|
||||||
@@ l_floor takes the floor of a float.
|
@@ l_floor takes the floor of a float.
|
||||||
@@ lua_str2number converts a decimal numeral to a number.
|
@@ lua_str2number converts a decimal numeral to a number.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* The following definitions are good for most cases here */
|
/* The following definition is good for most cases here */
|
||||||
|
|
||||||
#define l_floor(x) (l_mathop(floor)(x))
|
#define l_floor(x) (l_mathop(floor)(x))
|
||||||
|
|
||||||
#define lua_number2str(s,sz,n) \
|
|
||||||
l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n))
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ lua_numbertointeger converts a float number with an integral value
|
|
||||||
** to an integer, or returns 0 if float is not within the range of
|
|
||||||
** a lua_Integer. (The range comparisons are tricky because of
|
|
||||||
** rounding. The tests here assume a two-complement representation,
|
|
||||||
** where MININTEGER always has an exact representation as a float;
|
|
||||||
** MAXINTEGER may not have one, and therefore its conversion to float
|
|
||||||
** may have an ill-defined value.)
|
|
||||||
*/
|
|
||||||
#define lua_numbertointeger(n,p) \
|
|
||||||
((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
|
|
||||||
(n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
|
|
||||||
(*(p) = (LUA_INTEGER)(n), 1))
|
|
||||||
|
|
||||||
|
|
||||||
/* now the variable definitions */
|
/* now the variable definitions */
|
||||||
|
|
||||||
@@ -432,6 +413,7 @@
|
|||||||
|
|
||||||
#define LUA_NUMBER_FRMLEN ""
|
#define LUA_NUMBER_FRMLEN ""
|
||||||
#define LUA_NUMBER_FMT "%.7g"
|
#define LUA_NUMBER_FMT "%.7g"
|
||||||
|
#define LUA_NUMBER_FMT_N "%.9g"
|
||||||
|
|
||||||
#define l_mathop(op) op##f
|
#define l_mathop(op) op##f
|
||||||
|
|
||||||
@@ -448,6 +430,7 @@
|
|||||||
|
|
||||||
#define LUA_NUMBER_FRMLEN "L"
|
#define LUA_NUMBER_FRMLEN "L"
|
||||||
#define LUA_NUMBER_FMT "%.19Lg"
|
#define LUA_NUMBER_FMT "%.19Lg"
|
||||||
|
#define LUA_NUMBER_FMT_N "%.21Lg"
|
||||||
|
|
||||||
#define l_mathop(op) op##l
|
#define l_mathop(op) op##l
|
||||||
|
|
||||||
@@ -462,7 +445,8 @@
|
|||||||
#define LUAI_UACNUMBER double
|
#define LUAI_UACNUMBER double
|
||||||
|
|
||||||
#define LUA_NUMBER_FRMLEN ""
|
#define LUA_NUMBER_FRMLEN ""
|
||||||
#define LUA_NUMBER_FMT "%.14g"
|
#define LUA_NUMBER_FMT "%.15g"
|
||||||
|
#define LUA_NUMBER_FMT_N "%.17g"
|
||||||
|
|
||||||
#define l_mathop(op) op
|
#define l_mathop(op) op
|
||||||
|
|
||||||
@@ -485,7 +469,6 @@
|
|||||||
@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
|
@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
|
||||||
@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
|
@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
|
||||||
@@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED.
|
@@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED.
|
||||||
@@ LUA_UNSIGNEDBITS is the number of bits in a LUA_UNSIGNED.
|
|
||||||
@@ lua_integer2str converts an integer to a string.
|
@@ lua_integer2str converts an integer to a string.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -506,9 +489,6 @@
|
|||||||
#define LUA_UNSIGNED unsigned LUAI_UACINT
|
#define LUA_UNSIGNED unsigned LUAI_UACINT
|
||||||
|
|
||||||
|
|
||||||
#define LUA_UNSIGNEDBITS (sizeof(LUA_UNSIGNED) * CHAR_BIT)
|
|
||||||
|
|
||||||
|
|
||||||
/* now the variable definitions */
|
/* now the variable definitions */
|
||||||
|
|
||||||
#if LUA_INT_TYPE == LUA_INT_INT /* { int */
|
#if LUA_INT_TYPE == LUA_INT_INT /* { int */
|
||||||
@@ -680,13 +660,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(LUA_CORE) || defined(LUA_LIB)
|
|
||||||
/* shorter names for Lua's own use */
|
|
||||||
#define l_likely(x) luai_likely(x)
|
|
||||||
#define l_unlikely(x) luai_unlikely(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
@@ -711,10 +684,7 @@
|
|||||||
@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
|
@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
|
||||||
** Define it as a help when debugging C code.
|
** Define it as a help when debugging C code.
|
||||||
*/
|
*/
|
||||||
#if defined(LUA_USE_APICHECK)
|
/* #define LUA_USE_APICHECK */
|
||||||
#include <assert.h>
|
|
||||||
#define luai_apicheck(l,e) assert(e)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* }================================================================== */
|
/* }================================================================== */
|
||||||
|
|
||||||
@@ -727,20 +697,6 @@
|
|||||||
** =====================================================================
|
** =====================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
@@ LUAI_MAXSTACK limits the size of the Lua stack.
|
|
||||||
** CHANGE it if you need a different limit. This limit is arbitrary;
|
|
||||||
** its only purpose is to stop Lua from consuming unlimited stack
|
|
||||||
** space (and to reserve some numbers for pseudo-indices).
|
|
||||||
** (It must fit into max(size_t)/32.)
|
|
||||||
*/
|
|
||||||
#if LUAI_IS32INT
|
|
||||||
#define LUAI_MAXSTACK 1000000
|
|
||||||
#else
|
|
||||||
#define LUAI_MAXSTACK 15000
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
|
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
|
||||||
** a Lua state with very fast access.
|
** a Lua state with very fast access.
|
||||||
@@ -751,14 +707,15 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUA_IDSIZE gives the maximum size for the description of the source
|
@@ LUA_IDSIZE gives the maximum size for the description of the source
|
||||||
@@ of a function in debug information.
|
** of a function in debug information.
|
||||||
** CHANGE it if you want a different size.
|
** CHANGE it if you want a different size.
|
||||||
*/
|
*/
|
||||||
#define LUA_IDSIZE 60
|
#define LUA_IDSIZE 60
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
|
@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
|
||||||
|
** buffer system.
|
||||||
*/
|
*/
|
||||||
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
|
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
|
||||||
|
|
||||||
@@ -784,7 +741,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
+40
-27
@@ -14,39 +14,52 @@
|
|||||||
/* version suffix for environment variable names */
|
/* version suffix for environment variable names */
|
||||||
#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
|
#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
|
||||||
|
|
||||||
|
#define LUA_GLIBK 1
|
||||||
LUAMOD_API int (luaopen_base) (lua_State *L);
|
LUAMOD_API int (luaopen_base) (lua_State *L);
|
||||||
|
|
||||||
#define LUA_COLIBNAME "coroutine"
|
|
||||||
LUAMOD_API int (luaopen_coroutine) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_TABLIBNAME "table"
|
|
||||||
LUAMOD_API int (luaopen_table) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_IOLIBNAME "io"
|
|
||||||
LUAMOD_API int (luaopen_io) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_OSLIBNAME "os"
|
|
||||||
LUAMOD_API int (luaopen_os) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_STRLIBNAME "string"
|
|
||||||
LUAMOD_API int (luaopen_string) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_UTF8LIBNAME "utf8"
|
|
||||||
LUAMOD_API int (luaopen_utf8) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_MATHLIBNAME "math"
|
|
||||||
LUAMOD_API int (luaopen_math) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_DBLIBNAME "debug"
|
|
||||||
LUAMOD_API int (luaopen_debug) (lua_State *L);
|
|
||||||
|
|
||||||
#define LUA_LOADLIBNAME "package"
|
#define LUA_LOADLIBNAME "package"
|
||||||
|
#define LUA_LOADLIBK (LUA_GLIBK << 1)
|
||||||
LUAMOD_API int (luaopen_package) (lua_State *L);
|
LUAMOD_API int (luaopen_package) (lua_State *L);
|
||||||
|
|
||||||
|
|
||||||
/* open all previous libraries */
|
#define LUA_COLIBNAME "coroutine"
|
||||||
LUALIB_API void (luaL_openlibs) (lua_State *L);
|
#define LUA_COLIBK (LUA_LOADLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_coroutine) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_DBLIBNAME "debug"
|
||||||
|
#define LUA_DBLIBK (LUA_COLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_debug) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_IOLIBNAME "io"
|
||||||
|
#define LUA_IOLIBK (LUA_DBLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_io) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_MATHLIBNAME "math"
|
||||||
|
#define LUA_MATHLIBK (LUA_IOLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_math) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_OSLIBNAME "os"
|
||||||
|
#define LUA_OSLIBK (LUA_MATHLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_os) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_STRLIBNAME "string"
|
||||||
|
#define LUA_STRLIBK (LUA_OSLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_string) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_TABLIBNAME "table"
|
||||||
|
#define LUA_TABLIBK (LUA_STRLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_table) (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_UTF8LIBNAME "utf8"
|
||||||
|
#define LUA_UTF8LIBK (LUA_TABLIBK << 1)
|
||||||
|
LUAMOD_API int (luaopen_utf8) (lua_State *L);
|
||||||
|
|
||||||
|
|
||||||
|
/* open selected libraries */
|
||||||
|
LUALIB_API void (luaL_openselectedlibs) (lua_State *L, int load, int preload);
|
||||||
|
|
||||||
|
/* open all libraries */
|
||||||
|
#define luaL_openlibs(L) luaL_openselectedlibs(L, ~0, 0)
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Vendored
+424
@@ -0,0 +1,424 @@
|
|||||||
|
/*
|
||||||
|
** $Id: lundump.c $
|
||||||
|
** load precompiled Lua chunks
|
||||||
|
** See Copyright Notice in lua.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define lundump_c
|
||||||
|
#define LUA_CORE
|
||||||
|
|
||||||
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "ldebug.h"
|
||||||
|
#include "ldo.h"
|
||||||
|
#include "lfunc.h"
|
||||||
|
#include "lmem.h"
|
||||||
|
#include "lobject.h"
|
||||||
|
#include "lstring.h"
|
||||||
|
#include "ltable.h"
|
||||||
|
#include "lundump.h"
|
||||||
|
#include "lzio.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(luai_verifycode)
|
||||||
|
#define luai_verifycode(L,f) /* empty */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
lua_State *L;
|
||||||
|
ZIO *Z;
|
||||||
|
const char *name;
|
||||||
|
Table *h; /* list for string reuse */
|
||||||
|
size_t offset; /* current position relative to beginning of dump */
|
||||||
|
lua_Unsigned nstr; /* number of strings in the list */
|
||||||
|
lu_byte fixed; /* dump is fixed in memory */
|
||||||
|
} LoadState;
|
||||||
|
|
||||||
|
|
||||||
|
static l_noret error (LoadState *S, const char *why) {
|
||||||
|
luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why);
|
||||||
|
luaD_throw(S->L, LUA_ERRSYNTAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** All high-level loads go through loadVector; you can change it to
|
||||||
|
** adapt to the endianness of the input
|
||||||
|
*/
|
||||||
|
#define loadVector(S,b,n) loadBlock(S,b,cast_sizet(n)*sizeof((b)[0]))
|
||||||
|
|
||||||
|
static void loadBlock (LoadState *S, void *b, size_t size) {
|
||||||
|
if (luaZ_read(S->Z, b, size) != 0)
|
||||||
|
error(S, "truncated chunk");
|
||||||
|
S->offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void loadAlign (LoadState *S, unsigned align) {
|
||||||
|
unsigned padding = align - cast_uint(S->offset % align);
|
||||||
|
if (padding < align) { /* (padding == align) means no padding */
|
||||||
|
lua_Integer paddingContent;
|
||||||
|
loadBlock(S, &paddingContent, padding);
|
||||||
|
lua_assert(S->offset % align == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define getaddr(S,n,t) cast(t *, getaddr_(S,cast_sizet(n) * sizeof(t)))
|
||||||
|
|
||||||
|
static const void *getaddr_ (LoadState *S, size_t size) {
|
||||||
|
const void *block = luaZ_getaddr(S->Z, size);
|
||||||
|
S->offset += size;
|
||||||
|
if (block == NULL)
|
||||||
|
error(S, "truncated fixed buffer");
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define loadVar(S,x) loadVector(S,&x,1)
|
||||||
|
|
||||||
|
|
||||||
|
static lu_byte loadByte (LoadState *S) {
|
||||||
|
int b = zgetc(S->Z);
|
||||||
|
if (b == EOZ)
|
||||||
|
error(S, "truncated chunk");
|
||||||
|
S->offset++;
|
||||||
|
return cast_byte(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static lua_Unsigned loadVarint (LoadState *S, lua_Unsigned limit) {
|
||||||
|
lua_Unsigned x = 0;
|
||||||
|
int b;
|
||||||
|
limit >>= 7;
|
||||||
|
do {
|
||||||
|
b = loadByte(S);
|
||||||
|
if (x > limit)
|
||||||
|
error(S, "integer overflow");
|
||||||
|
x = (x << 7) | (b & 0x7f);
|
||||||
|
} while ((b & 0x80) != 0);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static size_t loadSize (LoadState *S) {
|
||||||
|
return cast_sizet(loadVarint(S, MAX_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int loadInt (LoadState *S) {
|
||||||
|
return cast_int(loadVarint(S, cast_sizet(INT_MAX)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static lua_Number loadNumber (LoadState *S) {
|
||||||
|
lua_Number x;
|
||||||
|
loadVar(S, x);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static lua_Integer loadInteger (LoadState *S) {
|
||||||
|
lua_Unsigned cx = loadVarint(S, LUA_MAXUNSIGNED);
|
||||||
|
/* decode unsigned to signed */
|
||||||
|
if ((cx & 1) != 0)
|
||||||
|
return l_castU2S(~(cx >> 1));
|
||||||
|
else
|
||||||
|
return l_castU2S(cx >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Load a nullable string into slot 'sl' from prototype 'p'. The
|
||||||
|
** assignment to the slot and the barrier must be performed before any
|
||||||
|
** possible GC activity, to anchor the string. (Both 'loadVector' and
|
||||||
|
** 'luaH_setint' can call the GC.)
|
||||||
|
*/
|
||||||
|
static void loadString (LoadState *S, Proto *p, TString **sl) {
|
||||||
|
lua_State *L = S->L;
|
||||||
|
TString *ts;
|
||||||
|
TValue sv;
|
||||||
|
size_t size = loadSize(S);
|
||||||
|
if (size == 0) { /* previously saved string? */
|
||||||
|
lua_Unsigned idx = loadVarint(S, LUA_MAXUNSIGNED); /* get its index */
|
||||||
|
TValue stv;
|
||||||
|
if (idx == 0) { /* no string? */
|
||||||
|
lua_assert(*sl == NULL); /* must be prefilled */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (novariant(luaH_getint(S->h, l_castU2S(idx), &stv)) != LUA_TSTRING)
|
||||||
|
error(S, "invalid string index");
|
||||||
|
*sl = ts = tsvalue(&stv); /* get its value */
|
||||||
|
luaC_objbarrier(L, p, ts);
|
||||||
|
return; /* do not save it again */
|
||||||
|
}
|
||||||
|
else if ((size -= 1) <= LUAI_MAXSHORTLEN) { /* short string? */
|
||||||
|
char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */
|
||||||
|
loadVector(S, buff, size + 1); /* load string into buffer */
|
||||||
|
*sl = ts = luaS_newlstr(L, buff, size); /* create string */
|
||||||
|
luaC_objbarrier(L, p, ts);
|
||||||
|
}
|
||||||
|
else if (S->fixed) { /* for a fixed buffer, use a fixed string */
|
||||||
|
const char *s = getaddr(S, size + 1, char); /* get content address */
|
||||||
|
*sl = ts = luaS_newextlstr(L, s, size, NULL, NULL);
|
||||||
|
luaC_objbarrier(L, p, ts);
|
||||||
|
}
|
||||||
|
else { /* create internal copy */
|
||||||
|
*sl = ts = luaS_createlngstrobj(L, size); /* create string */
|
||||||
|
luaC_objbarrier(L, p, ts);
|
||||||
|
loadVector(S, getlngstr(ts), size + 1); /* load directly in final place */
|
||||||
|
}
|
||||||
|
/* add string to list of saved strings */
|
||||||
|
S->nstr++;
|
||||||
|
setsvalue(L, &sv, ts);
|
||||||
|
luaH_setint(L, S->h, l_castU2S(S->nstr), &sv);
|
||||||
|
luaC_objbarrierback(L, obj2gco(S->h), ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void loadCode (LoadState *S, Proto *f) {
|
||||||
|
int n = loadInt(S);
|
||||||
|
loadAlign(S, sizeof(f->code[0]));
|
||||||
|
if (S->fixed) {
|
||||||
|
f->code = getaddr(S, n, Instruction);
|
||||||
|
f->sizecode = n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f->code = luaM_newvectorchecked(S->L, n, Instruction);
|
||||||
|
f->sizecode = n;
|
||||||
|
loadVector(S, f->code, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void loadFunction(LoadState *S, Proto *f);
|
||||||
|
|
||||||
|
|
||||||
|
static void loadConstants (LoadState *S, Proto *f) {
|
||||||
|
int i;
|
||||||
|
int n = loadInt(S);
|
||||||
|
f->k = luaM_newvectorchecked(S->L, n, TValue);
|
||||||
|
f->sizek = n;
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
setnilvalue(&f->k[i]);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
TValue *o = &f->k[i];
|
||||||
|
int t = loadByte(S);
|
||||||
|
switch (t) {
|
||||||
|
case LUA_VNIL:
|
||||||
|
setnilvalue(o);
|
||||||
|
break;
|
||||||
|
case LUA_VFALSE:
|
||||||
|
setbfvalue(o);
|
||||||
|
break;
|
||||||
|
case LUA_VTRUE:
|
||||||
|
setbtvalue(o);
|
||||||
|
break;
|
||||||
|
case LUA_VNUMFLT:
|
||||||
|
setfltvalue(o, loadNumber(S));
|
||||||
|
break;
|
||||||
|
case LUA_VNUMINT:
|
||||||
|
setivalue(o, loadInteger(S));
|
||||||
|
break;
|
||||||
|
case LUA_VSHRSTR:
|
||||||
|
case LUA_VLNGSTR: {
|
||||||
|
lua_assert(f->source == NULL);
|
||||||
|
loadString(S, f, &f->source); /* use 'source' to anchor string */
|
||||||
|
if (f->source == NULL)
|
||||||
|
error(S, "bad format for constant string");
|
||||||
|
setsvalue2n(S->L, o, f->source); /* save it in the right place */
|
||||||
|
f->source = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: error(S, "invalid constant");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void loadProtos (LoadState *S, Proto *f) {
|
||||||
|
int i;
|
||||||
|
int n = loadInt(S);
|
||||||
|
f->p = luaM_newvectorchecked(S->L, n, Proto *);
|
||||||
|
f->sizep = n;
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
f->p[i] = NULL;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
f->p[i] = luaF_newproto(S->L);
|
||||||
|
luaC_objbarrier(S->L, f, f->p[i]);
|
||||||
|
loadFunction(S, f->p[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Load the upvalues for a function. The names must be filled first,
|
||||||
|
** because the filling of the other fields can raise read errors and
|
||||||
|
** the creation of the error message can call an emergency collection;
|
||||||
|
** in that case all prototypes must be consistent for the GC.
|
||||||
|
*/
|
||||||
|
static void loadUpvalues (LoadState *S, Proto *f) {
|
||||||
|
int i;
|
||||||
|
int n = loadInt(S);
|
||||||
|
f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
|
||||||
|
f->sizeupvalues = n;
|
||||||
|
for (i = 0; i < n; i++) /* make array valid for GC */
|
||||||
|
f->upvalues[i].name = NULL;
|
||||||
|
for (i = 0; i < n; i++) { /* following calls can raise errors */
|
||||||
|
f->upvalues[i].instack = loadByte(S);
|
||||||
|
f->upvalues[i].idx = loadByte(S);
|
||||||
|
f->upvalues[i].kind = loadByte(S);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void loadDebug (LoadState *S, Proto *f) {
|
||||||
|
int i;
|
||||||
|
int n = loadInt(S);
|
||||||
|
if (S->fixed) {
|
||||||
|
f->lineinfo = getaddr(S, n, ls_byte);
|
||||||
|
f->sizelineinfo = n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
|
||||||
|
f->sizelineinfo = n;
|
||||||
|
loadVector(S, f->lineinfo, n);
|
||||||
|
}
|
||||||
|
n = loadInt(S);
|
||||||
|
if (n > 0) {
|
||||||
|
loadAlign(S, sizeof(int));
|
||||||
|
if (S->fixed) {
|
||||||
|
f->abslineinfo = getaddr(S, n, AbsLineInfo);
|
||||||
|
f->sizeabslineinfo = n;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
|
||||||
|
f->sizeabslineinfo = n;
|
||||||
|
loadVector(S, f->abslineinfo, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n = loadInt(S);
|
||||||
|
f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
|
||||||
|
f->sizelocvars = n;
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
f->locvars[i].varname = NULL;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
loadString(S, f, &f->locvars[i].varname);
|
||||||
|
f->locvars[i].startpc = loadInt(S);
|
||||||
|
f->locvars[i].endpc = loadInt(S);
|
||||||
|
}
|
||||||
|
n = loadInt(S);
|
||||||
|
if (n != 0) /* does it have debug information? */
|
||||||
|
n = f->sizeupvalues; /* must be this many */
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
loadString(S, f, &f->upvalues[i].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void loadFunction (LoadState *S, Proto *f) {
|
||||||
|
f->linedefined = loadInt(S);
|
||||||
|
f->lastlinedefined = loadInt(S);
|
||||||
|
f->numparams = loadByte(S);
|
||||||
|
/* get only the meaningful flags */
|
||||||
|
f->flag = cast_byte(loadByte(S) & ~PF_FIXED);
|
||||||
|
if (S->fixed)
|
||||||
|
f->flag |= PF_FIXED; /* signal that code is fixed */
|
||||||
|
f->maxstacksize = loadByte(S);
|
||||||
|
loadCode(S, f);
|
||||||
|
loadConstants(S, f);
|
||||||
|
loadUpvalues(S, f);
|
||||||
|
loadProtos(S, f);
|
||||||
|
loadString(S, f, &f->source);
|
||||||
|
loadDebug(S, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void checkliteral (LoadState *S, const char *s, const char *msg) {
|
||||||
|
char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
|
||||||
|
size_t len = strlen(s);
|
||||||
|
loadVector(S, buff, len);
|
||||||
|
if (memcmp(s, buff, len) != 0)
|
||||||
|
error(S, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static l_noret numerror (LoadState *S, const char *what, const char *tname) {
|
||||||
|
const char *msg = luaO_pushfstring(S->L, "%s %s mismatch", tname, what);
|
||||||
|
error(S, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void checknumsize (LoadState *S, int size, const char *tname) {
|
||||||
|
if (size != loadByte(S))
|
||||||
|
numerror(S, "size", tname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void checknumformat (LoadState *S, int eq, const char *tname) {
|
||||||
|
if (!eq)
|
||||||
|
numerror(S, "format", tname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define checknum(S,tvar,value,tname) \
|
||||||
|
{ tvar i; checknumsize(S, sizeof(i), tname); \
|
||||||
|
loadVar(S, i); \
|
||||||
|
checknumformat(S, i == value, tname); }
|
||||||
|
|
||||||
|
|
||||||
|
static void checkHeader (LoadState *S) {
|
||||||
|
/* skip 1st char (already read and checked) */
|
||||||
|
checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
|
||||||
|
if (loadByte(S) != LUAC_VERSION)
|
||||||
|
error(S, "version mismatch");
|
||||||
|
if (loadByte(S) != LUAC_FORMAT)
|
||||||
|
error(S, "format mismatch");
|
||||||
|
checkliteral(S, LUAC_DATA, "corrupted chunk");
|
||||||
|
checknum(S, int, LUAC_INT, "int");
|
||||||
|
checknum(S, Instruction, LUAC_INST, "instruction");
|
||||||
|
checknum(S, lua_Integer, LUAC_INT, "Lua integer");
|
||||||
|
checknum(S, lua_Number, LUAC_NUM, "Lua number");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Load precompiled chunk.
|
||||||
|
*/
|
||||||
|
LClosure *luaU_undump (lua_State *L, ZIO *Z, const char *name, int fixed) {
|
||||||
|
LoadState S;
|
||||||
|
LClosure *cl;
|
||||||
|
if (*name == '@' || *name == '=')
|
||||||
|
name = name + 1;
|
||||||
|
else if (*name == LUA_SIGNATURE[0])
|
||||||
|
name = "binary string";
|
||||||
|
S.name = name;
|
||||||
|
S.L = L;
|
||||||
|
S.Z = Z;
|
||||||
|
S.fixed = cast_byte(fixed);
|
||||||
|
S.offset = 1; /* fist byte was already read */
|
||||||
|
checkHeader(&S);
|
||||||
|
cl = luaF_newLclosure(L, loadByte(&S));
|
||||||
|
setclLvalue2s(L, L->top.p, cl);
|
||||||
|
luaD_inctop(L);
|
||||||
|
S.h = luaH_new(L); /* create list of saved strings */
|
||||||
|
S.nstr = 0;
|
||||||
|
sethvalue2s(L, L->top.p, S.h); /* anchor it */
|
||||||
|
luaD_inctop(L);
|
||||||
|
cl->p = luaF_newproto(L);
|
||||||
|
luaC_objbarrier(L, cl, cl->p);
|
||||||
|
loadFunction(&S, cl->p);
|
||||||
|
if (cl->nupvalues != cl->p->sizeupvalues)
|
||||||
|
error(&S, "corrupted chunk");
|
||||||
|
luai_verifycode(L, cl->p);
|
||||||
|
L->top.p--; /* pop table */
|
||||||
|
return cl;
|
||||||
|
}
|
||||||
|
|
||||||
+9
-5
@@ -7,6 +7,8 @@
|
|||||||
#ifndef lundump_h
|
#ifndef lundump_h
|
||||||
#define lundump_h
|
#define lundump_h
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "llimits.h"
|
#include "llimits.h"
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lzio.h"
|
#include "lzio.h"
|
||||||
@@ -15,19 +17,21 @@
|
|||||||
/* data to catch conversion errors */
|
/* data to catch conversion errors */
|
||||||
#define LUAC_DATA "\x19\x93\r\n\x1a\n"
|
#define LUAC_DATA "\x19\x93\r\n\x1a\n"
|
||||||
|
|
||||||
#define LUAC_INT 0x5678
|
#define LUAC_INT -0x5678
|
||||||
#define LUAC_NUM cast_num(370.5)
|
#define LUAC_INST 0x12345678
|
||||||
|
#define LUAC_NUM cast_num(-370.5)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Encode major-minor version in one byte, one nibble for each
|
** Encode major-minor version in one byte, one nibble for each
|
||||||
*/
|
*/
|
||||||
#define MYINT(s) (s[0]-'0') /* assume one-digit numerals */
|
#define LUAC_VERSION (LUA_VERSION_MAJOR_N*16+LUA_VERSION_MINOR_N)
|
||||||
#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
|
|
||||||
|
|
||||||
#define LUAC_FORMAT 0 /* this is the official format */
|
#define LUAC_FORMAT 0 /* this is the official format */
|
||||||
|
|
||||||
|
|
||||||
/* load one chunk; from lundump.c */
|
/* load one chunk; from lundump.c */
|
||||||
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name);
|
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name,
|
||||||
|
int fixed);
|
||||||
|
|
||||||
/* dump one chunk; from ldump.c */
|
/* dump one chunk; from ldump.c */
|
||||||
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
|
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
|
||||||
+62
-60
@@ -10,7 +10,6 @@
|
|||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -19,23 +18,19 @@
|
|||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
#include "llimits.h"
|
||||||
|
|
||||||
|
|
||||||
#define MAXUNICODE 0x10FFFFu
|
#define MAXUNICODE 0x10FFFFu
|
||||||
|
|
||||||
#define MAXUTF 0x7FFFFFFFu
|
#define MAXUTF 0x7FFFFFFFu
|
||||||
|
|
||||||
/*
|
|
||||||
** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
|
#define MSGInvalid "invalid UTF-8 code"
|
||||||
*/
|
|
||||||
#if (UINT_MAX >> 30) >= 1
|
|
||||||
typedef unsigned int utfint;
|
|
||||||
#else
|
|
||||||
typedef unsigned long utfint;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define iscont(p) ((*(p) & 0xC0) == 0x80)
|
#define iscont(c) (((c) & 0xC0) == 0x80)
|
||||||
|
#define iscontp(p) iscont(*(p))
|
||||||
|
|
||||||
|
|
||||||
/* from strlib */
|
/* from strlib */
|
||||||
@@ -51,25 +46,25 @@ static lua_Integer u_posrelat (lua_Integer pos, size_t len) {
|
|||||||
** Decode one UTF-8 sequence, returning NULL if byte sequence is
|
** Decode one UTF-8 sequence, returning NULL if byte sequence is
|
||||||
** invalid. The array 'limits' stores the minimum value for each
|
** invalid. The array 'limits' stores the minimum value for each
|
||||||
** sequence length, to check for overlong representations. Its first
|
** sequence length, to check for overlong representations. Its first
|
||||||
** entry forces an error for non-ascii bytes with no continuation
|
** entry forces an error for non-ASCII bytes with no continuation
|
||||||
** bytes (count == 0).
|
** bytes (count == 0).
|
||||||
*/
|
*/
|
||||||
static const char *utf8_decode (const char *s, utfint *val, int strict) {
|
static const char *utf8_decode (const char *s, l_uint32 *val, int strict) {
|
||||||
static const utfint limits[] =
|
static const l_uint32 limits[] =
|
||||||
{~(utfint)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u};
|
{~(l_uint32)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u};
|
||||||
unsigned int c = (unsigned char)s[0];
|
unsigned int c = (unsigned char)s[0];
|
||||||
utfint res = 0; /* final result */
|
l_uint32 res = 0; /* final result */
|
||||||
if (c < 0x80) /* ascii? */
|
if (c < 0x80) /* ASCII? */
|
||||||
res = c;
|
res = c;
|
||||||
else {
|
else {
|
||||||
int count = 0; /* to count number of continuation bytes */
|
int count = 0; /* to count number of continuation bytes */
|
||||||
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
|
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
|
||||||
unsigned int cc = (unsigned char)s[++count]; /* read next byte */
|
unsigned int cc = (unsigned char)s[++count]; /* read next byte */
|
||||||
if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
|
if (!iscont(cc)) /* not a continuation byte? */
|
||||||
return NULL; /* invalid byte sequence */
|
return NULL; /* invalid byte sequence */
|
||||||
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
|
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
|
||||||
}
|
}
|
||||||
res |= ((utfint)(c & 0x7F) << (count * 5)); /* add first byte */
|
res |= ((l_uint32)(c & 0x7F) << (count * 5)); /* add first byte */
|
||||||
if (count > 5 || res > MAXUTF || res < limits[count])
|
if (count > 5 || res > MAXUTF || res < limits[count])
|
||||||
return NULL; /* invalid byte sequence */
|
return NULL; /* invalid byte sequence */
|
||||||
s += count; /* skip continuation bytes read */
|
s += count; /* skip continuation bytes read */
|
||||||
@@ -107,7 +102,7 @@ static int utflen (lua_State *L) {
|
|||||||
lua_pushinteger(L, posi + 1); /* ... and current position */
|
lua_pushinteger(L, posi + 1); /* ... and current position */
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
posi = s1 - s;
|
posi = ct_diff2S(s1 - s);
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
lua_pushinteger(L, n);
|
lua_pushinteger(L, n);
|
||||||
@@ -137,11 +132,11 @@ static int codepoint (lua_State *L) {
|
|||||||
n = 0; /* count the number of returns */
|
n = 0; /* count the number of returns */
|
||||||
se = s + pose; /* string end */
|
se = s + pose; /* string end */
|
||||||
for (s += posi - 1; s < se;) {
|
for (s += posi - 1; s < se;) {
|
||||||
utfint code;
|
l_uint32 code;
|
||||||
s = utf8_decode(s, &code, !lax);
|
s = utf8_decode(s, &code, !lax);
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
return luaL_error(L, "invalid UTF-8 code");
|
return luaL_error(L, MSGInvalid);
|
||||||
lua_pushinteger(L, code);
|
lua_pushinteger(L, l_castU2S(code));
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
@@ -177,69 +172,75 @@ static int utfchar (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** offset(s, n, [i]) -> index where n-th character counting from
|
** offset(s, n, [i]) -> indices where n-th character counting from
|
||||||
** position 'i' starts; 0 means character at 'i'.
|
** position 'i' starts and ends; 0 means character at 'i'.
|
||||||
*/
|
*/
|
||||||
static int byteoffset (lua_State *L) {
|
static int byteoffset (lua_State *L) {
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *s = luaL_checklstring(L, 1, &len);
|
const char *s = luaL_checklstring(L, 1, &len);
|
||||||
lua_Integer n = luaL_checkinteger(L, 2);
|
lua_Integer n = luaL_checkinteger(L, 2);
|
||||||
lua_Integer posi = (n >= 0) ? 1 : len + 1;
|
lua_Integer posi = (n >= 0) ? 1 : cast_st2S(len) + 1;
|
||||||
posi = u_posrelat(luaL_optinteger(L, 3, posi), len);
|
posi = u_posrelat(luaL_optinteger(L, 3, posi), len);
|
||||||
luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3,
|
luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3,
|
||||||
"position out of bounds");
|
"position out of bounds");
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
/* find beginning of current byte sequence */
|
/* find beginning of current byte sequence */
|
||||||
while (posi > 0 && iscont(s + posi)) posi--;
|
while (posi > 0 && iscontp(s + posi)) posi--;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (iscont(s + posi))
|
if (iscontp(s + posi))
|
||||||
return luaL_error(L, "initial position is a continuation byte");
|
return luaL_error(L, "initial position is a continuation byte");
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
while (n < 0 && posi > 0) { /* move back */
|
while (n < 0 && posi > 0) { /* move back */
|
||||||
do { /* find beginning of previous character */
|
do { /* find beginning of previous character */
|
||||||
posi--;
|
posi--;
|
||||||
} while (posi > 0 && iscont(s + posi));
|
} while (posi > 0 && iscontp(s + posi));
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
n--; /* do not move for 1st character */
|
n--; /* do not move for 1st character */
|
||||||
while (n > 0 && posi < (lua_Integer)len) {
|
while (n > 0 && posi < (lua_Integer)len) {
|
||||||
do { /* find beginning of next character */
|
do { /* find beginning of next character */
|
||||||
posi++;
|
posi++;
|
||||||
} while (iscont(s + posi)); /* (cannot pass final '\0') */
|
} while (iscontp(s + posi)); /* (cannot pass final '\0') */
|
||||||
n--;
|
n--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (n == 0) /* did it find given character? */
|
if (n != 0) { /* did not find given character? */
|
||||||
lua_pushinteger(L, posi + 1);
|
|
||||||
else /* no such character */
|
|
||||||
luaL_pushfail(L);
|
luaL_pushfail(L);
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
lua_pushinteger(L, posi + 1); /* initial position */
|
||||||
|
if ((s[posi] & 0x80) != 0) { /* multi-byte character? */
|
||||||
|
if (iscont(s[posi]))
|
||||||
|
return luaL_error(L, "initial position is a continuation byte");
|
||||||
|
while (iscontp(s + posi + 1))
|
||||||
|
posi++; /* skip to last continuation byte */
|
||||||
|
}
|
||||||
|
/* else one-byte character: final position is the initial one */
|
||||||
|
lua_pushinteger(L, posi + 1); /* 'posi' now is the final position */
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int iter_aux (lua_State *L, int strict) {
|
static int iter_aux (lua_State *L, int strict) {
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *s = luaL_checklstring(L, 1, &len);
|
const char *s = luaL_checklstring(L, 1, &len);
|
||||||
lua_Integer n = lua_tointeger(L, 2) - 1;
|
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
|
||||||
if (n < 0) /* first iteration? */
|
if (n < len) {
|
||||||
n = 0; /* start from here */
|
while (iscontp(s + n)) n++; /* go to next character */
|
||||||
else if (n < (lua_Integer)len) {
|
|
||||||
n++; /* skip current byte */
|
|
||||||
while (iscont(s + n)) n++; /* and its continuations */
|
|
||||||
}
|
}
|
||||||
if (n >= (lua_Integer)len)
|
if (n >= len) /* (also handles original 'n' being negative) */
|
||||||
return 0; /* no more codepoints */
|
return 0; /* no more codepoints */
|
||||||
else {
|
else {
|
||||||
utfint code;
|
l_uint32 code;
|
||||||
const char *next = utf8_decode(s + n, &code, strict);
|
const char *next = utf8_decode(s + n, &code, strict);
|
||||||
if (next == NULL)
|
if (next == NULL || iscontp(next))
|
||||||
return luaL_error(L, "invalid UTF-8 code");
|
return luaL_error(L, MSGInvalid);
|
||||||
lua_pushinteger(L, n + 1);
|
lua_pushinteger(L, l_castU2S(n + 1));
|
||||||
lua_pushinteger(L, code);
|
lua_pushinteger(L, l_castU2S(code));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,7 +257,8 @@ static int iter_auxlax (lua_State *L) {
|
|||||||
|
|
||||||
static int iter_codes (lua_State *L) {
|
static int iter_codes (lua_State *L) {
|
||||||
int lax = lua_toboolean(L, 2);
|
int lax = lua_toboolean(L, 2);
|
||||||
luaL_checkstring(L, 1);
|
const char *s = luaL_checkstring(L, 1);
|
||||||
|
luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
|
||||||
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
|
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
|
||||||
lua_pushvalue(L, 1);
|
lua_pushvalue(L, 1);
|
||||||
lua_pushinteger(L, 0);
|
lua_pushinteger(L, 0);
|
||||||
+492
-356
File diff suppressed because it is too large
Load Diff
+25
-25
@@ -43,7 +43,7 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
F2Ieq, /* no rounding; accepts only integral values */
|
F2Ieq, /* no rounding; accepts only integral values */
|
||||||
F2Ifloor, /* takes the floor of the number */
|
F2Ifloor, /* takes the floor of the number */
|
||||||
F2Iceil /* takes the ceil of the number */
|
F2Iceil /* takes the ceiling of the number */
|
||||||
} F2Imod;
|
} F2Imod;
|
||||||
|
|
||||||
|
|
||||||
@@ -76,40 +76,40 @@ typedef enum {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** fast track for 'gettable': if 't' is a table and 't[k]' is present,
|
** fast track for 'gettable'
|
||||||
** return 1 with 'slot' pointing to 't[k]' (position of final result).
|
|
||||||
** Otherwise, return 0 (meaning it will have to check metamethod)
|
|
||||||
** with 'slot' pointing to an empty 't[k]' (if 't' is a table) or NULL
|
|
||||||
** (otherwise). 'f' is the raw get function to use.
|
|
||||||
*/
|
*/
|
||||||
#define luaV_fastget(L,t,k,slot,f) \
|
#define luaV_fastget(t,k,res,f, tag) \
|
||||||
(!ttistable(t) \
|
(tag = (!ttistable(t) ? LUA_VNOTABLE : f(hvalue(t), k, res)))
|
||||||
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
|
|
||||||
: (slot = f(hvalue(t), k), /* else, do raw access */ \
|
|
||||||
!isempty(slot))) /* result not empty? */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Special case of 'luaV_fastget' for integers, inlining the fast case
|
** Special case of 'luaV_fastget' for integers, inlining the fast case
|
||||||
** of 'luaH_getint'.
|
** of 'luaH_getint'.
|
||||||
*/
|
*/
|
||||||
#define luaV_fastgeti(L,t,k,slot) \
|
#define luaV_fastgeti(t,k,res,tag) \
|
||||||
(!ttistable(t) \
|
if (!ttistable(t)) tag = LUA_VNOTABLE; \
|
||||||
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
|
else { luaH_fastgeti(hvalue(t), k, res, tag); }
|
||||||
: (slot = (l_castS2U(k) - 1u < hvalue(t)->alimit) \
|
|
||||||
? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \
|
|
||||||
!isempty(slot))) /* result not empty? */
|
#define luaV_fastset(t,k,val,hres,f) \
|
||||||
|
(hres = (!ttistable(t) ? HNOTATABLE : f(hvalue(t), k, val)))
|
||||||
|
|
||||||
|
#define luaV_fastseti(t,k,val,hres) \
|
||||||
|
if (!ttistable(t)) hres = HNOTATABLE; \
|
||||||
|
else { luaH_fastseti(hvalue(t), k, val, hres); }
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Finish a fast set operation (when fast get succeeds). In that case,
|
** Finish a fast set operation (when fast set succeeds).
|
||||||
** 'slot' points to the place to put the value.
|
|
||||||
*/
|
*/
|
||||||
#define luaV_finishfastset(L,t,slot,v) \
|
#define luaV_finishfastset(L,t,v) luaC_barrierback(L, gcvalue(t), v)
|
||||||
{ setobj2t(L, cast(TValue *,slot), v); \
|
|
||||||
luaC_barrierback(L, gcvalue(t), v); }
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Shift right is the same as shift left with a negative 'y'
|
||||||
|
*/
|
||||||
|
#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
|
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
|
||||||
@@ -120,10 +120,10 @@ LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode);
|
|||||||
LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p,
|
LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p,
|
||||||
F2Imod mode);
|
F2Imod mode);
|
||||||
LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode);
|
LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode);
|
||||||
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
|
LUAI_FUNC lu_byte luaV_finishget (lua_State *L, const TValue *t, TValue *key,
|
||||||
StkId val, const TValue *slot);
|
StkId val, lu_byte tag);
|
||||||
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
||||||
TValue *val, const TValue *slot);
|
TValue *val, int aux);
|
||||||
LUAI_FUNC void luaV_finishOp (lua_State *L);
|
LUAI_FUNC void luaV_finishOp (lua_State *L);
|
||||||
LUAI_FUNC void luaV_execute (lua_State *L, CallInfo *ci);
|
LUAI_FUNC void luaV_execute (lua_State *L, CallInfo *ci);
|
||||||
LUAI_FUNC void luaV_concat (lua_State *L, int total);
|
LUAI_FUNC void luaV_concat (lua_State *L, int total);
|
||||||
+29
-8
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "lapi.h"
|
||||||
#include "llimits.h"
|
#include "llimits.h"
|
||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
@@ -45,17 +46,25 @@ void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) {
|
|||||||
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------- read --- */
|
/* --------------------------------------------------------------- read --- */
|
||||||
|
|
||||||
|
static int checkbuffer (ZIO *z) {
|
||||||
|
if (z->n == 0) { /* no bytes in buffer? */
|
||||||
|
if (luaZ_fill(z) == EOZ) /* try to read more */
|
||||||
|
return 0; /* no more input */
|
||||||
|
else {
|
||||||
|
z->n++; /* luaZ_fill consumed first byte; put it back */
|
||||||
|
z->p--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1; /* now buffer has something */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t luaZ_read (ZIO *z, void *b, size_t n) {
|
size_t luaZ_read (ZIO *z, void *b, size_t n) {
|
||||||
while (n) {
|
while (n) {
|
||||||
size_t m;
|
size_t m;
|
||||||
if (z->n == 0) { /* no bytes in buffer? */
|
if (!checkbuffer(z))
|
||||||
if (luaZ_fill(z) == EOZ) /* try to read more */
|
return n; /* no more input; return number of missing bytes */
|
||||||
return n; /* no more input; return number of missing bytes */
|
|
||||||
else {
|
|
||||||
z->n++; /* luaZ_fill consumed first byte; put it back */
|
|
||||||
z->p--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m = (n <= z->n) ? n : z->n; /* min. between n and z->n */
|
m = (n <= z->n) ? n : z->n; /* min. between n and z->n */
|
||||||
memcpy(b, z->p, m);
|
memcpy(b, z->p, m);
|
||||||
z->n -= m;
|
z->n -= m;
|
||||||
@@ -66,3 +75,15 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const void *luaZ_getaddr (ZIO* z, size_t n) {
|
||||||
|
const void *res;
|
||||||
|
if (!checkbuffer(z))
|
||||||
|
return NULL; /* no more input */
|
||||||
|
if (z->n < n) /* not enough bytes? */
|
||||||
|
return NULL; /* block not whole; cannot give an address */
|
||||||
|
res = z->p; /* get block address */
|
||||||
|
z->n -= n; /* consume these bytes */
|
||||||
|
z->p += n;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
+2
-1
@@ -32,7 +32,7 @@ typedef struct Mbuffer {
|
|||||||
#define luaZ_sizebuffer(buff) ((buff)->buffsize)
|
#define luaZ_sizebuffer(buff) ((buff)->buffsize)
|
||||||
#define luaZ_bufflen(buff) ((buff)->n)
|
#define luaZ_bufflen(buff) ((buff)->n)
|
||||||
|
|
||||||
#define luaZ_buffremove(buff,i) ((buff)->n -= (i))
|
#define luaZ_buffremove(buff,i) ((buff)->n -= cast_sizet(i))
|
||||||
#define luaZ_resetbuffer(buff) ((buff)->n = 0)
|
#define luaZ_resetbuffer(buff) ((buff)->n = 0)
|
||||||
|
|
||||||
|
|
||||||
@@ -48,6 +48,7 @@ LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
|
|||||||
void *data);
|
void *data);
|
||||||
LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */
|
LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */
|
||||||
|
|
||||||
|
LUAI_FUNC const void *luaZ_getaddr (ZIO* z, size_t n);
|
||||||
|
|
||||||
|
|
||||||
/* --------- Private Part ------------------ */
|
/* --------- Private Part ------------------ */
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
#include "audio.h"
|
||||||
|
#include "jail_audio.h"
|
||||||
|
#include "mini/file/file.h"
|
||||||
|
|
||||||
|
namespace mini
|
||||||
|
{
|
||||||
|
namespace audio
|
||||||
|
{
|
||||||
|
int current_music = -1;
|
||||||
|
//#define MAX_SOUNDS 50
|
||||||
|
//JA_Sound_t *sounds[MAX_SOUNDS];
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
jail::audio::init();
|
||||||
|
//for (int i=0;i<MAX_SOUNDS;++i) sounds[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void quit() {
|
||||||
|
//if (current_music != NULL) JA_DeleteMusic(current_music);
|
||||||
|
//for (int i=0;i<MAX_SOUNDS;++i) if (sounds[i]!=NULL) JA_DeleteSound(sounds[i]);
|
||||||
|
jail::audio::quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace music
|
||||||
|
{
|
||||||
|
void play(const char *filename, const int loop) {
|
||||||
|
int size;
|
||||||
|
char *buffer = file::getfilebuffer(filename, size);
|
||||||
|
if (current_music != -1) jail::audio::music::destroy(current_music);
|
||||||
|
current_music = jail::audio::music::load((uint8_t*)buffer, size);
|
||||||
|
jail::audio::music::play(current_music, loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pause() {
|
||||||
|
jail::audio::music::pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
void resume() {
|
||||||
|
jail::audio::music::resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop(const int t) {
|
||||||
|
jail::audio::music::stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace pos {
|
||||||
|
void set(float value)
|
||||||
|
{
|
||||||
|
jail::audio::music::setPosition(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
float get()
|
||||||
|
{
|
||||||
|
return jail::audio::music::getPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace enable {
|
||||||
|
void set(const bool value)
|
||||||
|
{
|
||||||
|
jail::audio::music::enable(value);
|
||||||
|
file::setconfigvalue("music", value?"true":"false");
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool get()
|
||||||
|
{
|
||||||
|
return jail::audio::music::isEnabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace sound
|
||||||
|
{
|
||||||
|
int load(const char *filename) {
|
||||||
|
int size;
|
||||||
|
char *buffer = file::getfilebuffer(filename, size);
|
||||||
|
return jail::audio::sound::load((uint8_t*)buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(int soundfile) {
|
||||||
|
return jail::audio::sound::destroy(soundfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
int play(int soundfile, const int volume) {
|
||||||
|
// [TODO] Ficar el volumen
|
||||||
|
return jail::audio::sound::play(soundfile, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop(int soundchannel) {
|
||||||
|
return jail::audio::sound::channel::stop(soundchannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace enable {
|
||||||
|
void set(const bool value)
|
||||||
|
{
|
||||||
|
return jail::audio::sound::enable(value);
|
||||||
|
file::setconfigvalue("sound", value?"true":"false");
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool get()
|
||||||
|
{
|
||||||
|
return jail::audio::sound::isEnabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace mini
|
||||||
|
{
|
||||||
|
namespace audio
|
||||||
|
{
|
||||||
|
void init();
|
||||||
|
void quit();
|
||||||
|
|
||||||
|
namespace music
|
||||||
|
{
|
||||||
|
void play(const char *filename, const int loop=-1);
|
||||||
|
void pause();
|
||||||
|
void resume();
|
||||||
|
void stop(const int t=1000);
|
||||||
|
namespace pos {
|
||||||
|
void set(float value);
|
||||||
|
float get();
|
||||||
|
}
|
||||||
|
namespace enable {
|
||||||
|
void set(const bool value);
|
||||||
|
const bool get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace sound
|
||||||
|
{
|
||||||
|
int load(const char *filename);
|
||||||
|
void free(int soundfile);
|
||||||
|
int play(int soundfile, const int volume=-1);
|
||||||
|
void stop(int soundchannel);
|
||||||
|
namespace enable {
|
||||||
|
void set(const bool value);
|
||||||
|
const bool get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,642 @@
|
|||||||
|
#ifndef JA_USESDLMIXER
|
||||||
|
#include "jail_audio.h"
|
||||||
|
#include "external/stb_vorbis.h"
|
||||||
|
#include "other/log.h"
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// structs i variables
|
||||||
|
// =============================
|
||||||
|
namespace jail
|
||||||
|
{
|
||||||
|
namespace audio
|
||||||
|
{
|
||||||
|
static SDL_AudioSpec audioSpec { SDL_AUDIO_S16, 2, 48000 };
|
||||||
|
SDL_AudioDeviceID sdlAudioDevice { 0 };
|
||||||
|
SDL_TimerID timerID { 0 };
|
||||||
|
|
||||||
|
namespace music
|
||||||
|
{
|
||||||
|
struct music_t
|
||||||
|
{
|
||||||
|
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
|
||||||
|
Uint32 length { 0 };
|
||||||
|
Uint8 *buffer { nullptr };
|
||||||
|
|
||||||
|
int pos { 0 };
|
||||||
|
int times { 0 };
|
||||||
|
SDL_AudioStream *stream { nullptr };
|
||||||
|
music::state state { music::state::invalid };
|
||||||
|
};
|
||||||
|
|
||||||
|
static int current { -1 };
|
||||||
|
static std::vector<music_t> musics;
|
||||||
|
static float volume { 1.0f };
|
||||||
|
static bool enabled { true };
|
||||||
|
|
||||||
|
namespace fade
|
||||||
|
{
|
||||||
|
static bool fading = false;
|
||||||
|
static int start_time;
|
||||||
|
static int duration;
|
||||||
|
static int initial_volume;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace sound
|
||||||
|
{
|
||||||
|
struct sound_t
|
||||||
|
{
|
||||||
|
SDL_AudioSpec spec { SDL_AUDIO_S16, 2, 48000 };
|
||||||
|
Uint32 length { 0 };
|
||||||
|
Uint8 *buffer { NULL };
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<sound_t> sounds;
|
||||||
|
static float volume { 0.5f };
|
||||||
|
static bool enabled { true };
|
||||||
|
|
||||||
|
namespace channel
|
||||||
|
{
|
||||||
|
struct channel_t
|
||||||
|
{
|
||||||
|
int sound { -1 };
|
||||||
|
int pos { 0 };
|
||||||
|
int times { 0 };
|
||||||
|
SDL_AudioStream *stream { nullptr };
|
||||||
|
channel::state state { channel::state::free };
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<channel_t> channels;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Funcions
|
||||||
|
// ==================
|
||||||
|
namespace jail
|
||||||
|
{
|
||||||
|
namespace audio
|
||||||
|
{
|
||||||
|
static void updateMusic()
|
||||||
|
{
|
||||||
|
if (!music::enabled) return;
|
||||||
|
if (music::current < 0 || music::current > static_cast<int>(music::musics.size())) return;
|
||||||
|
auto &m = music::musics[music::current];
|
||||||
|
if (m.state != music::state::playing) return;
|
||||||
|
|
||||||
|
if (music::fade::fading) {
|
||||||
|
int time = SDL_GetTicks();
|
||||||
|
if (time > (music::fade::start_time + music::fade::duration)) {
|
||||||
|
music::fade::fading = false;
|
||||||
|
music::stop();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const int time_passed = time - music::fade::start_time;
|
||||||
|
const float percent = (float)time_passed / (float)music::fade::duration;
|
||||||
|
SDL_SetAudioStreamGain(m.stream, 1.0 - percent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m.times != 0)
|
||||||
|
{
|
||||||
|
if (SDL_GetAudioStreamAvailable(m.stream) < static_cast<int>(m.length/2)) {
|
||||||
|
SDL_PutAudioStreamData(m.stream, m.buffer, m.length);
|
||||||
|
}
|
||||||
|
if (m.times>0) m.times--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (SDL_GetAudioStreamAvailable(m.stream) == 0) music::stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateSound()
|
||||||
|
{
|
||||||
|
if (sound::enabled)
|
||||||
|
{
|
||||||
|
for (int i=0; i < static_cast<int>(sound::channel::channels.size()); ++i) {
|
||||||
|
auto &c = sound::channel::channels[i];
|
||||||
|
if (c.state == sound::channel::state::playing)
|
||||||
|
{
|
||||||
|
if (c.times != 0)
|
||||||
|
{
|
||||||
|
auto &s = sound::sounds[c.sound];
|
||||||
|
if (SDL_GetAudioStreamAvailable(c.stream) < static_cast<int>(s.length/2))
|
||||||
|
SDL_PutAudioStreamData(c.stream, s.buffer, s.length);
|
||||||
|
if (c.times>0) c.times--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (SDL_GetAudioStreamAvailable(c.stream) == 0) sound::channel::stop(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint32 updateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval)
|
||||||
|
{
|
||||||
|
updateMusic();
|
||||||
|
updateSound();
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
audioSpec = {SDL_AUDIO_S16, 1, 48000 };
|
||||||
|
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
|
||||||
|
sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audioSpec);
|
||||||
|
if (!sdlAudioDevice) {
|
||||||
|
log_msg(LOG_FAIL, "Failed to initialize SDL audio: %s\n", SDL_GetError());
|
||||||
|
} else {
|
||||||
|
log_msg(LOG_OK, "Audio subsytem initialized\n");
|
||||||
|
}
|
||||||
|
//SDL_PauseAudioDevice(sdlAudioDevice);
|
||||||
|
timerID = SDL_AddTimer(30, updateCallback, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void quit()
|
||||||
|
{
|
||||||
|
if (timerID) SDL_RemoveTimer(timerID);
|
||||||
|
|
||||||
|
for (int i=0; i<static_cast<int>(music::musics.size());++i) music::destroy(i);
|
||||||
|
music::musics.clear();
|
||||||
|
|
||||||
|
for (int i=0; i<static_cast<int>(sound::channel::channels.size());++i) sound::channel::stop(i);
|
||||||
|
sound::channel::channels.clear();
|
||||||
|
|
||||||
|
for (int i=0; i<static_cast<int>(sound::sounds.size());++i) sound::destroy(i);
|
||||||
|
sound::sounds.clear();
|
||||||
|
|
||||||
|
if (!sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice);
|
||||||
|
sdlAudioDevice = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float setVolume(float vol)
|
||||||
|
{
|
||||||
|
sound::setVolume(music::setVolume(vol) / 2.0f);
|
||||||
|
return music::volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace music
|
||||||
|
{
|
||||||
|
int load(const uint8_t* buffer, uint32_t length)
|
||||||
|
{
|
||||||
|
int music = 0;
|
||||||
|
while (music < static_cast<int>(musics.size()) && musics[music].state != state::invalid) { music++; }
|
||||||
|
if (music == static_cast<int>(musics.size())) musics.emplace_back();
|
||||||
|
|
||||||
|
auto &m = musics[music];
|
||||||
|
|
||||||
|
int chan, samplerate;
|
||||||
|
short *output;
|
||||||
|
m.length = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &output) * chan * 2;
|
||||||
|
|
||||||
|
m.spec.channels = chan;
|
||||||
|
m.spec.freq = samplerate;
|
||||||
|
m.spec.format = SDL_AUDIO_S16;
|
||||||
|
m.buffer = (uint8_t*)SDL_malloc(m.length);
|
||||||
|
SDL_memcpy(m.buffer, output, m.length);
|
||||||
|
free(output);
|
||||||
|
m.pos = 0;
|
||||||
|
m.state = state::stopped;
|
||||||
|
|
||||||
|
return music;
|
||||||
|
}
|
||||||
|
|
||||||
|
int load(const char* filename)
|
||||||
|
{
|
||||||
|
// [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid.
|
||||||
|
FILE *f = fopen(filename, "rb");
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long fsize = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
Uint8 *buffer = (Uint8*)malloc(fsize + 1);
|
||||||
|
if (fread(buffer, fsize, 1, f)!=1) return -1;
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
int music = load(buffer, fsize);
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
return music;
|
||||||
|
}
|
||||||
|
|
||||||
|
void play(int mus, int loop)
|
||||||
|
{
|
||||||
|
if (!music::enabled) return;
|
||||||
|
stop();
|
||||||
|
if (mus < 0 || mus >= static_cast<int>(musics.size())) {
|
||||||
|
log_msg(LOG_FAIL, "music::play: Illegal music handle: %i\n", mus);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = mus;
|
||||||
|
auto &m = musics[current];
|
||||||
|
m.pos = 0;
|
||||||
|
m.state = state::playing;
|
||||||
|
m.times = loop;
|
||||||
|
m.stream = SDL_CreateAudioStream(&m.spec, &audioSpec);
|
||||||
|
if (!SDL_PutAudioStreamData(m.stream, m.buffer, m.length)) log_msg(LOG_FAIL, "SDL_PutAudioStreamData failed!\n");
|
||||||
|
SDL_SetAudioStreamGain(m.stream, volume);
|
||||||
|
if (!SDL_BindAudioStream(sdlAudioDevice, m.stream)) log_msg(LOG_FAIL, "SDL_BindAudioStream failed!\n");
|
||||||
|
//SDL_ResumeAudioStreamDevice(current->stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pause()
|
||||||
|
{
|
||||||
|
if (!music::enabled) return;
|
||||||
|
if (current<0 || current>static_cast<int>(musics.size())) {
|
||||||
|
log_msg(LOG_FAIL, "music::pause: Illegal music handle: %i\n", current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &m = musics[current];
|
||||||
|
if (m.state == state::invalid) {
|
||||||
|
log_msg(LOG_FAIL, "music::pause: Invalidated music handle: %i\n", current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m.state = state::paused;
|
||||||
|
//SDL_PauseAudioStreamDevice(current->stream);
|
||||||
|
SDL_UnbindAudioStream(m.stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resume()
|
||||||
|
{
|
||||||
|
if (!music::enabled) return;
|
||||||
|
if (current<0 || current>static_cast<int>(musics.size())) {
|
||||||
|
log_msg(LOG_FAIL, "music::resume: Illegal music handle: %i\n", current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &m = musics[current];
|
||||||
|
if (m.state == state::invalid) {
|
||||||
|
log_msg(LOG_FAIL, "music::resume: Invalidated music handle: %i\n", current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m.state = state::playing;
|
||||||
|
//SDL_ResumeAudioStreamDevice(current->stream);
|
||||||
|
SDL_BindAudioStream(sdlAudioDevice, m.stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop()
|
||||||
|
{
|
||||||
|
if (!music::enabled) return;
|
||||||
|
if (current<0 || current>static_cast<int>(musics.size())) {
|
||||||
|
log_msg(LOG_FAIL, "music::stop: Illegal music handle: %i\n", current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &m = musics[current];
|
||||||
|
if (m.state == state::invalid) {
|
||||||
|
log_msg(LOG_FAIL, "music::stop: Invalidated music handle: %i\n", current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m.pos = 0;
|
||||||
|
m.state = state::stopped;
|
||||||
|
//SDL_PauseAudioStreamDevice(current->stream);
|
||||||
|
SDL_DestroyAudioStream(m.stream);
|
||||||
|
m.stream = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fadeOut(int milliseconds)
|
||||||
|
{
|
||||||
|
if (!music::enabled) return;
|
||||||
|
if (current<0 || current>static_cast<int>(musics.size())) {
|
||||||
|
log_msg(LOG_FAIL, "music::fadeOut: Illegal music handle: %i\n", current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &m = musics[current];
|
||||||
|
if (m.state == state::invalid) {
|
||||||
|
log_msg(LOG_FAIL, "music::fadeOut: Invalidated music handle: %i\n", current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fade::fading = true;
|
||||||
|
fade::start_time = SDL_GetTicks();
|
||||||
|
fade::duration = milliseconds;
|
||||||
|
fade::initial_volume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
music::state getState()
|
||||||
|
{
|
||||||
|
if (!music::enabled) return music::state::disabled;
|
||||||
|
if (current<0 || current>static_cast<int>(musics.size())) return state::invalid;
|
||||||
|
return musics[current].state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy(int mus)
|
||||||
|
{
|
||||||
|
if (current == mus) current = -1;
|
||||||
|
if (mus<0 || mus>static_cast<int>(musics.size())) {
|
||||||
|
log_msg(LOG_FAIL, "music::destroy: Illegal music handle: %i\n", mus);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &m = musics[mus];
|
||||||
|
SDL_free(m.buffer);
|
||||||
|
m.buffer = nullptr;
|
||||||
|
if (m.stream) SDL_DestroyAudioStream(m.stream);
|
||||||
|
m.stream = nullptr;
|
||||||
|
m.state = state::invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
float setVolume(float vol)
|
||||||
|
{
|
||||||
|
volume = SDL_clamp( vol, 0.0f, 1.0f );
|
||||||
|
|
||||||
|
if (current<0 || current>static_cast<int>(musics.size())) return vol;
|
||||||
|
auto &m = musics[current];
|
||||||
|
if (m.state == state::invalid) return vol;
|
||||||
|
|
||||||
|
SDL_SetAudioStreamGain(m.stream, volume);
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPosition(float value)
|
||||||
|
{
|
||||||
|
if (!music::enabled) return;
|
||||||
|
if (current<0 || current>static_cast<int>(musics.size())) {
|
||||||
|
log_msg(LOG_FAIL, "music::setPosition: Illegal music handle: %i\n", current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &m = musics[current];
|
||||||
|
if (m.state == state::invalid) {
|
||||||
|
log_msg(LOG_FAIL, "music::setPosition: Invalidated music handle: %i\n", current);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m.pos = value * m.spec.freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getPosition()
|
||||||
|
{
|
||||||
|
if (!music::enabled) return 0;
|
||||||
|
if (current<0 || current>static_cast<int>(musics.size())) {
|
||||||
|
log_msg(LOG_FAIL, "music::getPosition: Illegal music handle: %i\n", current);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto &m = musics[current];
|
||||||
|
if (m.state == state::invalid) {
|
||||||
|
log_msg(LOG_FAIL, "music::getPosition: Invalidated music handle: %i\n", current);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return float(m.pos)/float(m.spec.freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable(bool value)
|
||||||
|
{
|
||||||
|
if (!value && music::enabled && current>=0 && current<static_cast<int>(musics.size()) && musics[current].state==state::playing) stop();
|
||||||
|
music::enabled = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEnabled()
|
||||||
|
{
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace sound
|
||||||
|
{
|
||||||
|
int create(uint8_t* buffer, uint32_t length)
|
||||||
|
{
|
||||||
|
int snd = 0;
|
||||||
|
while (snd < static_cast<int>(sounds.size()) && sounds[snd].buffer) { snd++; }
|
||||||
|
if (snd == static_cast<int>(sounds.size())) sounds.emplace_back();
|
||||||
|
|
||||||
|
auto &s = sounds[snd];
|
||||||
|
s.buffer = buffer;
|
||||||
|
s.length = length;
|
||||||
|
return snd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int load(uint8_t* buffer, uint32_t size)
|
||||||
|
{
|
||||||
|
int snd = 0;
|
||||||
|
while (snd < static_cast<int>(sounds.size()) && sounds[snd].buffer) { snd++; }
|
||||||
|
if (snd == static_cast<int>(sounds.size())) sounds.emplace_back();
|
||||||
|
|
||||||
|
auto &s = sounds[snd];
|
||||||
|
SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size),1, &s.spec, &s.buffer, &s.length);
|
||||||
|
|
||||||
|
return snd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int load(const char* filename)
|
||||||
|
{
|
||||||
|
int snd = 0;
|
||||||
|
while (snd < static_cast<int>(sounds.size()) && sounds[snd].buffer) { snd++; }
|
||||||
|
if (snd == static_cast<int>(sounds.size())) sounds.emplace_back();
|
||||||
|
|
||||||
|
auto &s = sounds[snd];
|
||||||
|
SDL_LoadWAV(filename, &s.spec, &s.buffer, &s.length);
|
||||||
|
|
||||||
|
return snd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int play(int snd, int loop)
|
||||||
|
{
|
||||||
|
if (!sound::enabled) return -1;
|
||||||
|
|
||||||
|
if (snd<0 || snd>static_cast<int>(sounds.size())) {
|
||||||
|
log_msg(LOG_FAIL, "sound::play: Illegal sound handle: %i\n", snd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
auto &s = sounds[snd];
|
||||||
|
if (!s.buffer) {
|
||||||
|
log_msg(LOG_FAIL, "sound::play: Invalid sound: %i\n", snd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int chan = 0;
|
||||||
|
while (chan < static_cast<int>(channel::channels.size()) && channel::channels[chan].state != channel::state::free) { chan++; }
|
||||||
|
if (chan == static_cast<int>(channel::channels.size())) channel::channels.emplace_back();
|
||||||
|
channel::stop(chan);
|
||||||
|
auto &c = channel::channels[chan];
|
||||||
|
c.sound = snd;
|
||||||
|
c.times = loop;
|
||||||
|
c.pos = 0;
|
||||||
|
c.state = channel::state::playing;
|
||||||
|
c.stream = SDL_CreateAudioStream(&s.spec, &audioSpec);
|
||||||
|
SDL_PutAudioStreamData(c.stream, s.buffer, s.length);
|
||||||
|
SDL_SetAudioStreamGain(c.stream, volume);
|
||||||
|
SDL_BindAudioStream(sdlAudioDevice, c.stream);
|
||||||
|
|
||||||
|
return chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
int playOnChannel(int snd, int chan, int loop)
|
||||||
|
{
|
||||||
|
if (!sound::enabled) return -1;
|
||||||
|
|
||||||
|
if (snd<0 || snd>static_cast<int>(sounds.size())) {
|
||||||
|
log_msg(LOG_FAIL, "sound::playOnChannel: Illegal sound handle: %i\n", snd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
auto &s = sounds[snd];
|
||||||
|
if (!s.buffer) {
|
||||||
|
log_msg(LOG_FAIL, "sound::playOnChannel: Invalid sound: %i\n", snd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan<0 || chan>static_cast<int>(channel::channels.size())) {
|
||||||
|
log_msg(LOG_FAIL, "sound::playOnChannel: Illegal channel handle: %i\n", chan);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel::stop(chan);
|
||||||
|
|
||||||
|
auto &c = channel::channels[chan];
|
||||||
|
c.sound = snd;
|
||||||
|
c.times = loop;
|
||||||
|
c.pos = 0;
|
||||||
|
c.state = channel::state::playing;
|
||||||
|
c.stream = SDL_CreateAudioStream(&s.spec, &audioSpec);
|
||||||
|
SDL_PutAudioStreamData(c.stream, s.buffer, s.length);
|
||||||
|
SDL_SetAudioStreamGain(c.stream, volume);
|
||||||
|
SDL_BindAudioStream(sdlAudioDevice, c.stream);
|
||||||
|
|
||||||
|
return chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy(int snd)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < static_cast<int>(channel::channels.size()); i++) {
|
||||||
|
if (channel::channels[i].sound == snd) channel::stop(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snd<0 || snd>static_cast<int>(sounds.size())) {
|
||||||
|
log_msg(LOG_FAIL, "sound::destroy: Illegal sound handle: %i\n", snd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &s = sounds[snd];
|
||||||
|
SDL_free(s.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
float setVolume(float vol)
|
||||||
|
{
|
||||||
|
volume = SDL_clamp( vol, 0.0f, 1.0f );
|
||||||
|
|
||||||
|
for (int i = 0; i < static_cast<int>(channel::channels.size()); i++) {
|
||||||
|
auto &c = channel::channels[i];
|
||||||
|
if ( (c.state == channel::state::playing) || (c.state == channel::state::paused) )
|
||||||
|
SDL_SetAudioStreamGain(c.stream, volume);
|
||||||
|
}
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable(bool value)
|
||||||
|
{
|
||||||
|
if (!value && sound::enabled) {
|
||||||
|
for (int i = 0; i < static_cast<int>(channel::channels.size()); i++) {
|
||||||
|
if (channel::channels[i].state == channel::state::playing) channel::stop(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enabled = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEnabled()
|
||||||
|
{
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace channel
|
||||||
|
{
|
||||||
|
void pause(const int chan)
|
||||||
|
{
|
||||||
|
if (!sound::enabled) return;
|
||||||
|
|
||||||
|
if (chan == -1)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < static_cast<int>(channels.size()); i++)
|
||||||
|
if (channels[i].state == state::playing)
|
||||||
|
{
|
||||||
|
channels[i].state = state::paused;
|
||||||
|
//SDL_PauseAudioStreamDevice(channels[i].stream);
|
||||||
|
SDL_UnbindAudioStream(channels[i].stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (chan >= 0 && chan < static_cast<int>(channels.size()))
|
||||||
|
{
|
||||||
|
if (channels[chan].state == state::playing)
|
||||||
|
{
|
||||||
|
channels[chan].state = state::paused;
|
||||||
|
//SDL_PauseAudioStreamDevice(channels[channel].stream);
|
||||||
|
SDL_UnbindAudioStream(channels[chan].stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resume(int chan)
|
||||||
|
{
|
||||||
|
if (!sound::enabled) return;
|
||||||
|
|
||||||
|
if (chan == -1)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < static_cast<int>(channels.size()); i++)
|
||||||
|
if (channels[i].state == state::paused)
|
||||||
|
{
|
||||||
|
channels[i].state = state::playing;
|
||||||
|
//SDL_ResumeAudioStreamDevice(channels[i].stream);
|
||||||
|
SDL_BindAudioStream(sdlAudioDevice, channels[i].stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (chan >= 0 && chan < static_cast<int>(channels.size()))
|
||||||
|
{
|
||||||
|
if (channels[chan].state == state::paused)
|
||||||
|
{
|
||||||
|
channels[chan].state = state::playing;
|
||||||
|
//SDL_ResumeAudioStreamDevice(channels[channel].stream);
|
||||||
|
SDL_BindAudioStream(sdlAudioDevice, channels[chan].stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop(int chan)
|
||||||
|
{
|
||||||
|
if (!sound::enabled) return;
|
||||||
|
|
||||||
|
if (chan == -1)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < static_cast<int>(channels.size()); i++) {
|
||||||
|
if (channels[i].state != state::free) SDL_DestroyAudioStream(channels[i].stream);
|
||||||
|
channels[i].stream = nullptr;
|
||||||
|
channels[i].state = state::free;
|
||||||
|
channels[i].pos = 0;
|
||||||
|
channels[i].sound = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (chan >= 0 && chan < static_cast<int>(channels.size()))
|
||||||
|
{
|
||||||
|
if (channels[chan].state != state::free) SDL_DestroyAudioStream(channels[chan].stream);
|
||||||
|
channels[chan].stream = nullptr;
|
||||||
|
channels[chan].state = state::free;
|
||||||
|
channels[chan].pos = 0;
|
||||||
|
channels[chan].sound = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
channel::state getState(int chan)
|
||||||
|
{
|
||||||
|
if (!sound::enabled) return state::disabled;
|
||||||
|
if (chan < 0 || chan >= static_cast<int>(channels.size())) return state::invalid;
|
||||||
|
return channels[chan].state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace jail
|
||||||
|
{
|
||||||
|
namespace audio
|
||||||
|
{
|
||||||
|
void init(/*const int freq, const SDL_AudioFormat format, const int channels*/);
|
||||||
|
void quit();
|
||||||
|
|
||||||
|
namespace music
|
||||||
|
{
|
||||||
|
//struct JA_Music_t;
|
||||||
|
enum state { invalid, playing, paused, stopped, disabled };
|
||||||
|
|
||||||
|
int load(const char* filename);
|
||||||
|
int load(const uint8_t* buffer, uint32_t length);
|
||||||
|
void play(int mus, int loop = -1);
|
||||||
|
void pause();
|
||||||
|
void resume();
|
||||||
|
void stop();
|
||||||
|
void fadeOut(int milliseconds);
|
||||||
|
state getState();
|
||||||
|
void destroy(int mus);
|
||||||
|
float setVolume(float vol);
|
||||||
|
void setPosition(float value);
|
||||||
|
float getPosition();
|
||||||
|
void enable(bool value);
|
||||||
|
bool isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace sound
|
||||||
|
{
|
||||||
|
//struct JA_Sound_t;
|
||||||
|
int create(uint8_t* buffer, uint32_t length);
|
||||||
|
int load(uint8_t* buffer, uint32_t length);
|
||||||
|
int load(const char* filename);
|
||||||
|
int play(int snd, int loop = 0);
|
||||||
|
int playOnChannel(int snd, int chan, int loop = 0);
|
||||||
|
void destroy(int snd);
|
||||||
|
float setVolume(float vol);
|
||||||
|
void enable(bool value);
|
||||||
|
bool isEnabled();
|
||||||
|
|
||||||
|
namespace channel
|
||||||
|
{
|
||||||
|
enum state { invalid, free, playing, paused, disabled };
|
||||||
|
void pause(int chan);
|
||||||
|
void resume(int chan);
|
||||||
|
void stop(int chan);
|
||||||
|
state getState(int chan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#include "mini/file/file.h"
|
||||||
|
|
||||||
|
namespace mini
|
||||||
|
{
|
||||||
|
namespace config
|
||||||
|
{
|
||||||
|
namespace key {
|
||||||
|
void set(const char* key, const char* value) {
|
||||||
|
file::setconfigvalue(key, value);
|
||||||
|
}
|
||||||
|
const char* get(const char* key) {
|
||||||
|
return file::getconfigvalue(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *folder() {
|
||||||
|
return file::getconfigfolder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace mini
|
||||||
|
{
|
||||||
|
namespace config
|
||||||
|
{
|
||||||
|
namespace key {
|
||||||
|
void set(const char* key, const char* value);
|
||||||
|
const char *get(const char* key);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *folder();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,487 @@
|
|||||||
|
#include "draw.h"
|
||||||
|
#include "mini/surf/surf.h"
|
||||||
|
#include "mini/view/view.h"
|
||||||
|
#include "mini/font/font.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
namespace mini
|
||||||
|
{
|
||||||
|
namespace draw
|
||||||
|
{
|
||||||
|
state_t state;
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
state.mode = DRAWMODE_NORMAL;
|
||||||
|
state.fill_pattern = 0b1111111111111111;
|
||||||
|
}
|
||||||
|
|
||||||
|
void quit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace pixel {
|
||||||
|
static inline void pset_fast(int x, int y, uint8_t color) {
|
||||||
|
auto &s = surf::state.surfaces[surf::state.dest_surface];
|
||||||
|
uint8_t *p = s.p;
|
||||||
|
if (state.trans != color) p[x+y*s.w] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pset_bool(int x, int y, uint8_t color) {
|
||||||
|
if (state.trans != color) {
|
||||||
|
auto &s = surf::state.surfaces[surf::state.dest_surface];
|
||||||
|
uint8_t *p = s.p;
|
||||||
|
switch (state.mode) {
|
||||||
|
case DRAWMODE_AND:
|
||||||
|
p[x+y*s.w] &= color;
|
||||||
|
break;
|
||||||
|
case DRAWMODE_OR:
|
||||||
|
p[x+y*s.w] |= color;
|
||||||
|
break;
|
||||||
|
case DRAWMODE_XOR:
|
||||||
|
p[x+y*s.w] ^= color;
|
||||||
|
break;
|
||||||
|
case DRAWMODE_NOT:
|
||||||
|
p[x+y*s.w] = ~p[x+y*s.w];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pset_pattern(int x, int y, uint8_t color) {
|
||||||
|
int pbx = x % 4, pby = y % 4;
|
||||||
|
int pb = pbx+pby*4;
|
||||||
|
if (state.fill_pattern & (1 << pb))
|
||||||
|
if (state.trans != color) {
|
||||||
|
auto &s = surf::state.surfaces[surf::state.dest_surface];
|
||||||
|
uint8_t *p = s.p;
|
||||||
|
p[x+y*s.w] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Per a les funcions que pinten tot del mateix color
|
||||||
|
static inline void direct_pset(int x, int y, uint8_t color) {
|
||||||
|
auto &s = surf::state.surfaces[surf::state.dest_surface];
|
||||||
|
x += view::state.origin[0]; y += view::state.origin[1];
|
||||||
|
if (x < s.clip[0] || x > s.clip[2] || y < s.clip[1] || y > s.clip[3]) return;
|
||||||
|
switch (state.mode) {
|
||||||
|
case DRAWMODE_NORMAL: pset_fast(x,y,color); break;
|
||||||
|
case DRAWMODE_PATTERN: pset_pattern(x,y,color); break;
|
||||||
|
default: pset_bool(x,y,color); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Per a les funcions que van canviant de color (surf.pixel i draw.surf, bàsicament)
|
||||||
|
static inline void subst_pset(int x, int y, uint8_t color) {
|
||||||
|
direct_pset(x, y, state.draw_palette[color]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(int x, int y, uint8_t color) {
|
||||||
|
subst_pset(x,y,color);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t get(int x, int y) {
|
||||||
|
if (surf::state.source_surface==-1) return 0;
|
||||||
|
auto &s = surf::state.surfaces[surf::state.source_surface];
|
||||||
|
if (x < 0 || x > (s.w-1) || y < 0 || y > (s.h-1)) return 0;
|
||||||
|
return s.p[x+y*s.w];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bresenham Line Algorithm
|
||||||
|
void line(int x0, int y0, int x1, int y1, uint8_t color) {
|
||||||
|
int x, y;
|
||||||
|
int dx, dy;
|
||||||
|
int incx, incy;
|
||||||
|
int balance;
|
||||||
|
color = state.draw_palette[color];
|
||||||
|
|
||||||
|
if (x1 >= x0) { dx = x1 - x0; incx = 1; } else { dx = x0 - x1; incx = -1; }
|
||||||
|
if (y1 >= y0) { dy = y1 - y0; incy = 1; } else { dy = y0 - y1; incy = -1; }
|
||||||
|
|
||||||
|
x = x0; y = y0;
|
||||||
|
|
||||||
|
if (dx >= dy) {
|
||||||
|
dy <<= 1;
|
||||||
|
balance = dy - dx;
|
||||||
|
dx <<= 1;
|
||||||
|
|
||||||
|
while (x != x1) {
|
||||||
|
pixel::direct_pset(x, y, color);
|
||||||
|
if (balance >= 0) { y += incy; balance -= dx; }
|
||||||
|
balance += dy;
|
||||||
|
x += incx;
|
||||||
|
}
|
||||||
|
pixel::direct_pset(x, y, color);
|
||||||
|
} else {
|
||||||
|
dx <<= 1;
|
||||||
|
balance = dx - dy;
|
||||||
|
dy <<= 1;
|
||||||
|
|
||||||
|
while (y != y1) {
|
||||||
|
pixel::direct_pset(x, y, color);
|
||||||
|
if (balance >= 0) { x += incx; balance -= dy; }
|
||||||
|
balance += dx;
|
||||||
|
y += incy;
|
||||||
|
}
|
||||||
|
pixel::direct_pset(x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hline(int x0, int y, int x1, uint8_t color) {
|
||||||
|
color = state.draw_palette[color];
|
||||||
|
if (x0>x1) { const int tmp=x0;x0=x1;x1=tmp; }
|
||||||
|
for (int x=x0; x<=x1; ++x) pixel::direct_pset(x, y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vline(int x, int y0, int y1, uint8_t color) {
|
||||||
|
color = state.draw_palette[color];
|
||||||
|
if (y0>y1) { const int tmp=y0;y0=y1;y1=tmp; }
|
||||||
|
for (int y=y0; y<=y1; ++y) pixel::direct_pset(x, y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rect(int x, int y, int w, int h, uint8_t color) {
|
||||||
|
int x1 = w+x-1;
|
||||||
|
int y1 = h+y-1;
|
||||||
|
hline(x, y, x1, color);
|
||||||
|
hline(x, y1, x1, color);
|
||||||
|
vline(x, y, y1, color);
|
||||||
|
vline(x1, y, y1, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rectf(int x, int y, int w, int h, uint8_t color) {
|
||||||
|
int x1 = w+x-1;
|
||||||
|
int y1 = h+y-1;
|
||||||
|
for (int i=y; i<=y1; ++i) hline(x, i, x1, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void circ_scanline(int xc, int yc, int x, int y, uint8_t color) {
|
||||||
|
pixel::direct_pset(xc+x, yc+y, color);
|
||||||
|
pixel::direct_pset(xc-x, yc+y, color);
|
||||||
|
pixel::direct_pset(xc+x, yc-y, color);
|
||||||
|
pixel::direct_pset(xc-x, yc-y, color);
|
||||||
|
pixel::direct_pset(xc+y, yc+x, color);
|
||||||
|
pixel::direct_pset(xc-y, yc+x, color);
|
||||||
|
pixel::direct_pset(xc+y, yc-x, color);
|
||||||
|
pixel::direct_pset(xc-y, yc-x, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void circ(int x, int y, uint8_t r, uint8_t color) {
|
||||||
|
color = state.draw_palette[color];
|
||||||
|
int xi=0, yi=r;
|
||||||
|
int d=3-2*r;
|
||||||
|
circ_scanline(x, y, xi, yi, color);
|
||||||
|
while (yi>=xi++) {
|
||||||
|
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
|
||||||
|
circ_scanline(x, y, xi, yi, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void circf_scanline(int xc, int yc, int x, int y, uint8_t color) {
|
||||||
|
hline(xc-x, yc+y, xc+x, color);
|
||||||
|
hline(xc-x, yc-y, xc+x, color);
|
||||||
|
hline(xc-y, yc+x, xc+y, color);
|
||||||
|
hline(xc-y, yc-x, xc+y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void circf(int x, int y, uint8_t r, uint8_t color) {
|
||||||
|
int xi=0, yi=r;
|
||||||
|
int d=3-2*r;
|
||||||
|
circf_scanline(x, y, xi, yi, color);
|
||||||
|
while (yi>=xi++) {
|
||||||
|
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
|
||||||
|
circf_scanline(x, y, xi, yi, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void roundrect(int x, int y, int w, int h, uint8_t r, uint8_t color) {
|
||||||
|
int xi=0, yi=r;
|
||||||
|
int d=3-2*r;
|
||||||
|
|
||||||
|
int xf = w+x-1;
|
||||||
|
int yf = h+y-1;
|
||||||
|
int x1 = x+r, y1 = y+r;
|
||||||
|
int x2 = xf-r, y2 = yf-r;
|
||||||
|
hline(x1, y, x2, color);
|
||||||
|
hline(x1, yf, x2, color);
|
||||||
|
vline(x, y1, y2, color);
|
||||||
|
vline(xf, y1, y2, color);
|
||||||
|
|
||||||
|
color = state.draw_palette[color];
|
||||||
|
while (yi>=xi++) {
|
||||||
|
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
|
||||||
|
pixel::direct_pset(x2+xi, y2+yi, color);
|
||||||
|
pixel::direct_pset(x1-xi, y2+yi, color);
|
||||||
|
pixel::direct_pset(x2+xi, y1-yi, color);
|
||||||
|
pixel::direct_pset(x1-xi, y1-yi, color);
|
||||||
|
pixel::direct_pset(x2+yi, y2+xi, color);
|
||||||
|
pixel::direct_pset(x1-yi, y2+xi, color);
|
||||||
|
pixel::direct_pset(x2+yi, y1-xi, color);
|
||||||
|
pixel::direct_pset(x1-yi, y1-xi, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void roundrectf(int x, int y, int w, int h, uint8_t r, uint8_t color) {
|
||||||
|
int xi=0, yi=r;
|
||||||
|
int d=3-2*r;
|
||||||
|
|
||||||
|
int xf = w+x-1;
|
||||||
|
int yf = h+y-1;
|
||||||
|
int x1 = x+r, y1 = y+r;
|
||||||
|
int x2 = xf-r, y2 = yf-r;
|
||||||
|
for (int i=y1; i<=y2; ++i) hline(x, i, xf, color);
|
||||||
|
|
||||||
|
while (yi>=xi++) {
|
||||||
|
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
|
||||||
|
hline(x1-xi, y2+yi, x2+xi, color);
|
||||||
|
hline(x1-xi, y1-yi, x2+xi, color);
|
||||||
|
hline(x1-yi, y2+xi, x2+yi, color);
|
||||||
|
hline(x1-yi, y1-xi, x2+yi, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oval_scanline(int xc, int yc, int x, int y, float xf, float yf, uint8_t color) {
|
||||||
|
pixel::direct_pset((xc+x)*xf, (yc+y)*yf, color);
|
||||||
|
pixel::direct_pset((xc-x)*xf, (yc+y)*yf, color);
|
||||||
|
pixel::direct_pset((xc+x)*xf, (yc-y)*yf, color);
|
||||||
|
pixel::direct_pset((xc-x)*xf, (yc-y)*yf, color);
|
||||||
|
pixel::direct_pset((xc+y)*xf, (yc+x)*yf, color);
|
||||||
|
pixel::direct_pset((xc-y)*xf, (yc+x)*yf, color);
|
||||||
|
pixel::direct_pset((xc+y)*xf, (yc-x)*yf, color);
|
||||||
|
pixel::direct_pset((xc-y)*xf, (yc-x)*yf, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oval(int x0, int y0, int x1, int y1, uint8_t color) {
|
||||||
|
color = state.draw_palette[color];
|
||||||
|
int rx = (x1-x0)/2;
|
||||||
|
int ry = (y1-y0)/2;
|
||||||
|
int r = rx;
|
||||||
|
int x = x0 + rx;
|
||||||
|
int y = y0 + ry;
|
||||||
|
float xf = 1.0f, yf = 1.0f;
|
||||||
|
if (rx>=ry) {r=rx;yf=float(ry)/float(rx);} else {r=ry;xf=float(rx)/float(ry);}
|
||||||
|
int xi=0, yi=r;
|
||||||
|
int d=3-2*r;
|
||||||
|
oval_scanline(x, y, xi, yi, xf, yf, color);
|
||||||
|
while (yi>=xi++) {
|
||||||
|
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
|
||||||
|
oval_scanline(x, y, xi, yi, xf, yf, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ovalf_scanline(int xc, int yc, int x, int y, float xf, float yf, uint8_t color) {
|
||||||
|
hline((xc-x)*xf, (yc+y)*yf, (xc+x)*xf, color);
|
||||||
|
hline((xc-x)*xf, (yc-y)*yf, (xc+x)*xf, color);
|
||||||
|
hline((xc-y)*xf, (yc+x)*yf, (xc+y)*xf, color);
|
||||||
|
hline((xc-y)*xf, (yc-x)*yf, (xc+y)*xf, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ovalf(int x0, int y0, int x1, int y1, uint8_t color) {
|
||||||
|
int rx = (x1-x0)/2;
|
||||||
|
int ry = (y1-y0)/2;
|
||||||
|
int r = rx;
|
||||||
|
int x = x0 + rx;
|
||||||
|
int y = y0 + ry;
|
||||||
|
float xf = 1.0f, yf = 1.0f;
|
||||||
|
if (rx>=ry) {r=rx;yf=float(ry)/float(rx);} else {r=ry;xf=float(rx)/float(ry);}
|
||||||
|
int xi=0, yi=r;
|
||||||
|
int d=3-2*r;
|
||||||
|
ovalf_scanline(x, y, xi, yi, xf, yf, color);
|
||||||
|
while (yi>=xi++) {
|
||||||
|
d += d>0 ? 4*(xi-yi--)+10 : 4*xi+6;
|
||||||
|
ovalf_scanline(x, y, xi, yi, xf, yf, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace pattern {
|
||||||
|
void set(uint16_t pat, bool transparent) {
|
||||||
|
state.fill_pattern = pat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void surf(int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, bool flip_x, bool flip_y, bool invert) {
|
||||||
|
if (dw == 0) dw = sw;
|
||||||
|
if (dh == 0) dh = sh;
|
||||||
|
|
||||||
|
// 16.16 fixed point
|
||||||
|
int sdx = (sw << 16) / dw;
|
||||||
|
int sdy = (sh << 16) / dh;
|
||||||
|
|
||||||
|
if (flip_x) sdx = -sdx;
|
||||||
|
if (flip_y) sdy = -sdy;
|
||||||
|
|
||||||
|
int ssx = flip_x ? ((sx + sw - 1) << 16) : (sx << 16);
|
||||||
|
int ssy = flip_y ? ((sy + sh - 1) << 16) : (sy << 16);
|
||||||
|
|
||||||
|
int csy = ssy;
|
||||||
|
|
||||||
|
if (!invert) {
|
||||||
|
for (int y = dy; y < dy + dh; ++y) {
|
||||||
|
int csx = ssx;
|
||||||
|
for (int x = dx; x < dx + dw; ++x) {
|
||||||
|
uint8_t color = pixel::get(csx >> 16, csy >> 16);
|
||||||
|
pixel::subst_pset(x, y, color);
|
||||||
|
csx += sdx;
|
||||||
|
}
|
||||||
|
csy += sdy;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int y = dy; y < dy + dh; ++y) {
|
||||||
|
int csx = ssx;
|
||||||
|
for (int x = dx; x < dx + dw; ++x) {
|
||||||
|
uint8_t color = pixel::get(csy >> 16, csx >> 16);
|
||||||
|
pixel::subst_pset(x, y, color);
|
||||||
|
csx += sdx;
|
||||||
|
}
|
||||||
|
csy += sdy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void surfrot(int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, bool flip_x, bool flip_y, float angle_deg) {
|
||||||
|
if (dw == 0) dw = sw;
|
||||||
|
if (dh == 0) dh = sh;
|
||||||
|
|
||||||
|
// Centro del destino (rectángulo sin rotar)
|
||||||
|
float dcx = dx + dw * 0.5f;
|
||||||
|
float dcy = dy + dh * 0.5f;
|
||||||
|
|
||||||
|
// Centro del subrectángulo origen
|
||||||
|
float scx = sx + sw * 0.5f;
|
||||||
|
float scy = sy + sh * 0.5f;
|
||||||
|
|
||||||
|
// Escalado destino -> origen
|
||||||
|
float inv_scale_x = float(sw) / float(dw);
|
||||||
|
float inv_scale_y = float(sh) / float(dh);
|
||||||
|
|
||||||
|
// Flips integrados en la escala
|
||||||
|
if (flip_x) inv_scale_x = -inv_scale_x;
|
||||||
|
if (flip_y) inv_scale_y = -inv_scale_y;
|
||||||
|
|
||||||
|
// Ángulo en radianes
|
||||||
|
float a = angle_deg * 3.14159265f / 180.0f;
|
||||||
|
float ca = cosf(a);
|
||||||
|
float sa = sinf(a);
|
||||||
|
|
||||||
|
// --- 1. Bounding box rotado del rectángulo destino ---
|
||||||
|
|
||||||
|
float hx = dw * 0.5f;
|
||||||
|
float hy = dh * 0.5f;
|
||||||
|
|
||||||
|
float vx[4] = { -hx, hx, -hx, hx };
|
||||||
|
float vy[4] = { -hy, -hy, hy, hy };
|
||||||
|
|
||||||
|
float min_x = 1e9f, max_x = -1e9f;
|
||||||
|
float min_y = 1e9f, max_y = -1e9f;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
float rr_x = vx[i] * ca - vy[i] * sa;
|
||||||
|
float rr_y = vx[i] * sa + vy[i] * ca;
|
||||||
|
|
||||||
|
float dxp = dcx + rr_x;
|
||||||
|
float dyp = dcy + rr_y;
|
||||||
|
|
||||||
|
if (dxp < min_x) min_x = dxp;
|
||||||
|
if (dxp > max_x) max_x = dxp;
|
||||||
|
if (dyp < min_y) min_y = dyp;
|
||||||
|
if (dyp > max_y) max_y = dyp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bb_x0 = (int)floorf(min_x);
|
||||||
|
int bb_x1 = (int)ceilf (max_x);
|
||||||
|
int bb_y0 = (int)floorf(min_y);
|
||||||
|
int bb_y1 = (int)ceilf (max_y);
|
||||||
|
|
||||||
|
// --- 2. Rotación inversa + escalado + clipping estricto ---
|
||||||
|
|
||||||
|
for (int y = bb_y0; y <= bb_y1; ++y) {
|
||||||
|
for (int x = bb_x0; x <= bb_x1; ++x) {
|
||||||
|
|
||||||
|
// Coordenadas relativas al centro destino
|
||||||
|
float rx = x - dcx;
|
||||||
|
float ry = y - dcy;
|
||||||
|
|
||||||
|
// Rotación inversa
|
||||||
|
float ux = rx * ca + ry * sa;
|
||||||
|
float uy = -rx * sa + ry * ca;
|
||||||
|
|
||||||
|
// Escalado destino -> origen (con flips)
|
||||||
|
float sxp = scx + ux * inv_scale_x;
|
||||||
|
float syp = scy + uy * inv_scale_y;
|
||||||
|
|
||||||
|
// Clipping estricto al subrectángulo origen
|
||||||
|
if (sxp < sx || sxp >= sx + sw ||
|
||||||
|
syp < sy || syp >= sy + sh)
|
||||||
|
continue; // no pintamos nada
|
||||||
|
|
||||||
|
uint8_t color = pixel::get((int)sxp, (int)syp);
|
||||||
|
pixel::subst_pset(x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tileblit(uint8_t n, int x, int y, int tw, int th) {
|
||||||
|
//const int tw = tile_width;
|
||||||
|
//const int th = tile_height;
|
||||||
|
|
||||||
|
const int tiles_per_row = mini::surf::state.surfaces[mini::surf::state.source_surface].w / tw;
|
||||||
|
|
||||||
|
// Coordenadas del tile dentro del spritesheet
|
||||||
|
int tx = (n % tiles_per_row) * tw;
|
||||||
|
int ty = (n / tiles_per_row) * th;
|
||||||
|
|
||||||
|
int src_y = ty;
|
||||||
|
|
||||||
|
for (int yi = 0; yi < th; ++yi) {
|
||||||
|
int src_x = tx;
|
||||||
|
|
||||||
|
for (int xi = 0; xi < tw; ++xi) {
|
||||||
|
uint8_t c = mini::draw::pixel::get(src_x, src_y);
|
||||||
|
mini::draw::pixel::subst_pset(x + xi, y + yi, c);
|
||||||
|
src_x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
src_y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t printchar(uint8_t c, int x, int y) {
|
||||||
|
font::char_t &chr = font::current_font->chars[c];
|
||||||
|
draw::surf(chr.x, chr.y, chr.w, chr.h, x, y-chr.base);
|
||||||
|
return chr.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
void text(const char* str, int x, int y, uint8_t color) {
|
||||||
|
|
||||||
|
const unsigned char* p = (const unsigned char*)str;
|
||||||
|
int xpos = x;
|
||||||
|
|
||||||
|
uint8_t old_source = surf::source::get();
|
||||||
|
surf::source::set(font::current_font->surface);
|
||||||
|
uint8_t old_color = state.draw_palette[1];
|
||||||
|
state.draw_palette[1] = color;
|
||||||
|
uint8_t old_trans = state.trans;
|
||||||
|
state.trans = 0;
|
||||||
|
while (p[0]!=0) {
|
||||||
|
uint8_t cp = p[0];
|
||||||
|
if (p[0] < 0x80) {
|
||||||
|
p+=1;
|
||||||
|
} else if ((p[0] & 0xE0) == 0xC0) {
|
||||||
|
cp = (p[0] << 6) | (p[1] & 0x3F);
|
||||||
|
p+=2;
|
||||||
|
}
|
||||||
|
xpos += printchar(cp, xpos, y) + font::current_font->spacing;
|
||||||
|
}
|
||||||
|
state.trans = old_trans;
|
||||||
|
state.draw_palette[1] = old_color;
|
||||||
|
surf::source::set(old_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace mode {
|
||||||
|
void set(uint8_t mode) {
|
||||||
|
state.mode = mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user