diff --git a/config.d/ac_config_files.m4 b/config.d/ac_config_files.m4 index 499c93099..df307effd 100644 --- a/config.d/ac_config_files.m4 +++ b/config.d/ac_config_files.m4 @@ -75,8 +75,6 @@ tools/qfvis/Makefile tools/qfvis/include/Makefile tools/qfvis/source/Makefile - tools/qwaq/Makefile - tools/qwaq/progs.src tools/wad/Makefile tools/wav/Makefile @@ -88,6 +86,7 @@ ruamoko/gui/Makefile ruamoko/cl_menu/Makefile ruamoko/scheme/Makefile + ruamoko/qwaq/Makefile pkg-config/Makefile pkg-config/qfcc.pc diff --git a/config.d/build_control.m4 b/config.d/build_control.m4 index a4df4a3a4..f88c12ca2 100644 --- a/config.d/build_control.m4 +++ b/config.d/build_control.m4 @@ -235,7 +235,11 @@ if test "x$ENABLE_tools_qfvis" = xyes; then QF_NEED(libs,[util]) fi if test "x$ENABLE_tools_qwaq" = xyes; then - QF_NEED(tools,[qwaq]) + if test "x$HAVE_PANEL" = xyes -a "x$HAVE_PTHREAD" = xyes; then + QWAQ_TARGETS="$QWAQ_TARGETS qwaq-curses\$(EXEEXT)" + fi + QF_NEED(tools,[qfcc]) + QF_NEED(ruamoko,[qwaq]) QF_NEED(libs,[ruamoko gamecode util]) fi if test "x$ENABLE_tools_wad" = xyes; then @@ -249,14 +253,24 @@ fi QF_NEED(top, [libs hw nq qtv qw]) -QF_PROCESS_NEED_DIRS(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis qwaq wad wav]) -QF_PROCESS_NEED_FUNC(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis qwaq wad wav], QF_NEED(top,tools)) +QF_PROCESS_NEED_DIRS(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis wad wav]) +QF_PROCESS_NEED_FUNC(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis wad wav], QF_NEED(top,tools)) QF_PROCESS_NEED_DIRS(libs,[util gamecode ruamoko gib audio image models video console net qw client]) +QF_PROCESS_NEED_DIRS(ruamoko,[qwaq]) + if test "$ENABLE_tools_qfcc" = "yes" -a "$ENABLE_tools_pak" = "yes"; then QF_NEED(top, [ruamoko]) + qfcc_include_qf="\$(qfcc_include_qf)" fi +QF_SUBST(qfcc_include_qf) + +if test x"${top_need_libs}" = xyes; then + include_qf="\$(include_qf)" +fi +QF_SUBST(include_qf) + progs_gz= if test "$HAVE_ZLIB" = "yes"; then progs_gz=".gz" @@ -380,6 +394,7 @@ QF_DEPS(QFCC, QF_DEPS(QFCC_TEST, [], [$(top_builddir)/libs/ruamoko/libQFruamoko.la + $(top_builddir)/libs/gamecode/libQFgamecode.la $(top_builddir)/libs/util/libQFutil.la], [$(WIN32_LIBS)], ) @@ -414,6 +429,7 @@ QF_DEPS(QFVIS, QF_DEPS(QWAQ, [], [$(top_builddir)/libs/ruamoko/libQFruamoko.la + $(top_builddir)/libs/gamecode/libQFgamecode.la $(top_builddir)/libs/util/libQFutil.la], [$(WIN32_LIBS)], ) @@ -421,6 +437,7 @@ QF_DEPS(CARNE, [], [$(top_builddir)/libs/gib/libQFgib.la $(top_builddir)/libs/ruamoko/libQFruamoko.la + $(top_builddir)/libs/gamecode/libQFgamecode.la $(top_builddir)/libs/util/libQFutil.la], [$(WIN32_LIBS)], ) diff --git a/config.d/curses.m4 b/config.d/curses.m4 index 80a2b0415..073e98217 100644 --- a/config.d/curses.m4 +++ b/config.d/curses.m4 @@ -2,7 +2,7 @@ AC_ARG_ENABLE(curses, [ --disable-curses disable curses support] ) if test "x$enable_curses" != "xno"; then - AC_CHECK_HEADERS(curses.h) + AC_CHECK_HEADER(curses.h) AC_CHECK_LIB(ncurses, initscr, CURSES_LIBS=-lncurses, AC_CHECK_LIB(pdcurses, initscr, @@ -13,7 +13,32 @@ if test "x$enable_curses" != "xno"; then ) ) ) + if test "x$CURSES_LIBS" != "x"; then + AC_DEFINE(HAVE_CURSES, 1, [Define if you have the ncurses library]) + HAVE_CURSES=yes + else + HAVE_CURSES=no + fi else + HAVE_CURSES=no CURSES_LIBS= fi AC_SUBST(CURSES_LIBS) + +if test "x$HAVE_CURSES" == "xyes"; then + AC_CHECK_HEADER(panel.h, + [AC_CHECK_LIB(panel, new_panel, + [AC_DEFINE(HAVE_PANEL, 1, + [Define if you have the ncurses panel library]) + PANEL_LIBS=-lpanel + HAVE_PANEL=yes], + [HAVE_PANEL=no], + $CURSES_LIBS + )], + HAVE_PANEL=no, + [] + ) +else + PANEL_LIBS= +fi +AC_SUBST(PANEL_LIBS) diff --git a/doc/progs/vm-exec.c b/doc/progs/vm-exec.c index 0234c2158..1f9ae4b8e 100644 --- a/doc/progs/vm-exec.c +++ b/doc/progs/vm-exec.c @@ -23,6 +23,7 @@ call_progs_main (progs_t *pr, int argc, const char **argv) PR_RESET_PARAMS (pr); P_INT (pr, 0) = argc; P_POINTER (pr, 1) = PR_SetPointer (pr, pr_argv); + pr->pr_argc = 2; PR_ExecuteProgram (pr, progs_main); PR_PopFrame (pr); PR_Zone_Free (pr, pr_argv); diff --git a/doc/quakeforge.dox.conf.in b/doc/quakeforge.dox.conf.in index 3781f222a..a235a895d 100644 --- a/doc/quakeforge.dox.conf.in +++ b/doc/quakeforge.dox.conf.in @@ -1566,7 +1566,7 @@ FORMULA_TRANSPARENT = YES # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -USE_MATHJAX = NO +USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: diff --git a/include/QF/Makefile.am b/include/QF/Makefile.am index aa9eaf1f8..bb6b0d2da 100644 --- a/include/QF/Makefile.am +++ b/include/QF/Makefile.am @@ -1,15 +1,19 @@ AUTOMAKE_OPTIONS = foreign pkgincludedir = $(includedir)/QF -nobase_pkginclude_HEADERS = \ +#for header files that qfcc (ruamoko) will use +pkgdatadir = $(datarootdir)/qfcc/include/QF + +include_qf= \ alloc.h bspfile.h cbuf.h cdaudio.h checksum.h clip_hull.h cmd.h \ - console.h crc.h csqc.h cvar.h darray.h dstring.h draw.h gib.h hash.h hl.h \ + console.h crc.h csqc.h cvar.h darray.h dstring.h draw.h gib.h hash.h \ idparse.h image.h in_event.h info.h input.h iqm.h joystick.h keys.h \ link.h llist.h locs.h mathlib.h mdfour.h mersenne.h model.h modelgen.h \ msg.h object.h pak.h pakfile.h pcx.h png.h plugin.h pr_comp.h pr_debug.h \ pr_obj.h pr_type.h progs.h qargs.h qdefs.h qendian.h qfplist.h qtypes.h \ quakefs.h \ - quakeio.h render.h riff.h ruamoko.h screen.h script.h segtext.h set.h \ - sizebuf.h skin.h sound.h spritegn.h sys.h teamplay.h tga.h uint32.h va.h \ + quakeio.h render.h riff.h ringbuffer.h ruamoko.h \ + screen.h script.h segtext.h set.h \ + sizebuf.h skin.h sound.h spritegn.h sys.h teamplay.h tga.h va.h \ ver_check.h vid.h vrect.h view.h wad.h wadfile.h winding.h zone.h \ \ GL/ati.h GL/defines.h GL/extensions.h GL/funcs.h GL/qf_draw.h \ @@ -26,3 +30,9 @@ nobase_pkginclude_HEADERS = \ \ plugin/cd.h plugin/console.h plugin/general.h plugin/input.h \ plugin/snd_output.h plugin/snd_render.h plugin/vid_render.h + +qfcc_include_qf=keys.h +nobase_pkginclude_HEADERS = @include_qf@ +pkgdata_DATA=@qfcc_include_qf@ + +EXTRA_HEADERS = $(include_qf) $(qfcc_include_qf) diff --git a/include/QF/bspfile.h b/include/QF/bspfile.h index b7683849f..0d32c09e8 100644 --- a/include/QF/bspfile.h +++ b/include/QF/bspfile.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __bspfile_h_ -#define __bspfile_h_ +#ifndef __QF_bspfile_h +#define __QF_bspfile_h #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -310,4 +310,4 @@ void BSP_AddVisibility (bsp_t *bsp, const byte *visdata, size_t visdatasize); void BSP_AddEntities (bsp_t *bsp, const char *entdata, size_t entdatasize); void BSP_AddTextures (bsp_t *bsp, const byte *texdata, size_t texdatasize); -#endif//__bspfile_h_ +#endif//__QF_bspfile_h diff --git a/include/QF/cdaudio.h b/include/QF/cdaudio.h index 12d3aa2a9..e265231db 100644 --- a/include/QF/cdaudio.h +++ b/include/QF/cdaudio.h @@ -25,8 +25,8 @@ */ -#ifndef _CDAUDIO_H -#define _CDAUDIO_H +#ifndef __QF_cdaudio_h +#define __QF_cdaudio_h #include "QF/qtypes.h" @@ -37,4 +37,4 @@ void CDAudio_Pause(void); void CDAudio_Resume(void); void CDAudio_Update(void); -#endif // _CDAUDIO_H +#endif//__QF_cdaudio_h diff --git a/include/QF/checksum.h b/include/QF/checksum.h index ed6f035b1..12fcaf477 100644 --- a/include/QF/checksum.h +++ b/include/QF/checksum.h @@ -25,8 +25,8 @@ */ -#ifndef __checksum_h -#define __checksum_h +#ifndef __QF_checksum_h +#define __QF_checksum_h /** \addtogroup crc */ @@ -40,4 +40,4 @@ byte COM_BlockSequenceCRCByte (const byte *base, int length, int sequence); ///@} -#endif // __checksum_h +#endif//__QF_checksum_h diff --git a/include/QF/console.h b/include/QF/console.h index b18e66401..f885404fa 100644 --- a/include/QF/console.h +++ b/include/QF/console.h @@ -25,8 +25,8 @@ */ -#ifndef __console_h -#define __console_h +#ifndef __QF_console_h +#define __QF_console_h #include @@ -150,4 +150,4 @@ void Menu_Leave_f (void); void Menu_Prev_f (void); void Menu_Next_f (void); -#endif // __console_h +#endif//__QF_console_h diff --git a/include/QF/crc.h b/include/QF/crc.h index cc635e7b9..ad26bacb8 100644 --- a/include/QF/crc.h +++ b/include/QF/crc.h @@ -25,8 +25,8 @@ */ -#ifndef __crc_h -#define __crc_h +#ifndef __QF_crc_h +#define __QF_crc_h /** \defgroup crc Checksum generation. \ingroup utils @@ -43,4 +43,4 @@ unsigned short CRC_Block (const byte *start, int count) __attribute__((pure)); ///@} -#endif // __crc_h +#endif//__QF_crc_h diff --git a/include/QF/cvar.h b/include/QF/cvar.h index 3d81a3b1c..946a20f13 100644 --- a/include/QF/cvar.h +++ b/include/QF/cvar.h @@ -25,8 +25,8 @@ */ -#ifndef __cvar_h -#define __cvar_h +#ifndef __QF_cvar_h +#define __QF_cvar_h /** \defgroup cvar Configuration variables \ingroup utils @@ -140,4 +140,4 @@ extern cvar_t *cvar_vars; ///@} -#endif // __cvar_h +#endif//__QF_cvar_h diff --git a/include/QF/draw.h b/include/QF/draw.h index 529f3e892..8f6b78889 100644 --- a/include/QF/draw.h +++ b/include/QF/draw.h @@ -25,8 +25,8 @@ */ -#ifndef _DRAW_H -#define _DRAW_H +#ifndef __QF_draw_h +#define __QF_draw_h /** \defgroup video Video Sub-sytem */ @@ -234,4 +234,4 @@ void Draw_Picf (float x, float y, qpic_t *pic); void Draw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height); ///@} -#endif // _DRAW_H +#endif//__QF_draw_h diff --git a/include/QF/dstring.h b/include/QF/dstring.h index 638d9e340..937e9be54 100644 --- a/include/QF/dstring.h +++ b/include/QF/dstring.h @@ -25,8 +25,8 @@ */ -#ifndef __dstring_h -#define __dstring_h +#ifndef __QF_dstring_h +#define __QF_dstring_h /** \defgroup dstring Dynamic Strings \ingroup utils @@ -164,17 +164,17 @@ void dstring_clearstr (dstring_t *dstr); /** Formatted printing to dstrings. Existing data is replaced by the formatted string. */ -int dvsprintf (dstring_t *dstr, const char *fmt, va_list args) __attribute__((format(printf,2,0))); -int dsprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); +char *dvsprintf (dstring_t *dstr, const char *fmt, va_list args) __attribute__((format(printf,2,0))); +char *dsprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); ///@} ///@{ /** Formatted printing to dstrings. Formatted string is appened to the dstring. Embedded nulls in the dstring are ignored. */ -int davsprintf (dstring_t *dstr, const char *fmt, va_list args) __attribute__((format(printf,2,0))); -int dasprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); +char *davsprintf (dstring_t *dstr, const char *fmt, va_list args) __attribute__((format(printf,2,0))); +char *dasprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); ///@} ///@} -#endif // __dstring_h +#endif//__QF_dstring_h diff --git a/include/QF/gib.h b/include/QF/gib.h index 34c187ac7..09bcf01ad 100644 --- a/include/QF/gib.h +++ b/include/QF/gib.h @@ -28,8 +28,8 @@ */ -#ifndef __gib_h -#define __gib_h +#ifndef __QF_gib_h +#define __QF_gib_h // Dependencies @@ -216,4 +216,4 @@ unsigned long int GIB_Handle_New (gib_object_t *data); void GIB_Handle_Free (unsigned long int num); gib_object_t *GIB_Handle_Get (unsigned long int num) __attribute__((pure)); -#endif +#endif//__QF_gib_h diff --git a/include/QF/hash.h b/include/QF/hash.h index ae040cfa9..7a31a06db 100644 --- a/include/QF/hash.h +++ b/include/QF/hash.h @@ -25,8 +25,8 @@ */ -#ifndef __hash_h -#define __hash_h +#ifndef __QF_hash_h +#define __QF_hash_h #include #include @@ -211,4 +211,4 @@ void Hash_Stats (hashtab_t *tab); ///@} -#endif // __hash_h +#endif//__QF_hash_h diff --git a/include/QF/hl.h b/include/QF/hl.h deleted file mode 100644 index 286768cc0..000000000 --- a/include/QF/hl.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - hl_bsp.h - - Half Life file definitions - - Copyright (C) 1996-1997 Id Software, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ - - -#ifndef _HL_BSP_H -#define _HL_BSP_H - -#include "QF/qtypes.h" - -extern void CL_ParseEntityLump(const char *entdata); -extern void HL_Mod_LoadLighting (lump_t *l); -extern void HL_Mod_LoadTextures (lump_t *l); -extern byte *W_GetTexture(const char *name, int matchwidth, int matchheight); -extern void W_LoadTextureWadFile (const char *filename, int complain); - -#endif // _HL_BSP_H diff --git a/include/QF/image.h b/include/QF/image.h index 33c69c120..106379bb7 100644 --- a/include/QF/image.h +++ b/include/QF/image.h @@ -49,4 +49,4 @@ typedef struct tex_s { tex_t *LoadImage (const char *imageFile); -#endif //__QF_image_h +#endif//__QF_image_h diff --git a/include/QF/info.h b/include/QF/info.h index 4e34f6fa2..7bf16b0ab 100644 --- a/include/QF/info.h +++ b/include/QF/info.h @@ -25,8 +25,8 @@ */ -#ifndef _INFO_H -#define _INFO_H +#ifndef __QF_info_h +#define __QF_info_h /** \defgroup info Info Keys \ingroup utils @@ -65,4 +65,4 @@ void Info_AddKeys (info_t *info, info_t *keys); ///@} -#endif // _INFO_H +#endif//__QF_info_h diff --git a/include/QF/input.h b/include/QF/input.h index ab808386f..7644af8cf 100644 --- a/include/QF/input.h +++ b/include/QF/input.h @@ -25,8 +25,8 @@ */ -#ifndef __QF_input_h_ -#define __QF_input_h_ +#ifndef __QF_input_h +#define __QF_input_h #include "QF/keys.h" @@ -73,4 +73,4 @@ void IN_LL_Grab_Input (int grab); extern kbutton_t in_strafe, in_klook, in_speed, in_mlook; -#endif // __QF_input_h_ +#endif//__QF_input_h diff --git a/include/QF/iqm.h b/include/QF/iqm.h index fb6517c76..adc5a3313 100644 --- a/include/QF/iqm.h +++ b/include/QF/iqm.h @@ -1,5 +1,5 @@ -#ifndef __QF_iqm_h__ -#define __QF_iqm_h__ +#ifndef __QF_iqm_h +#define __QF_iqm_h #include "QF/qtypes.h" @@ -149,4 +149,4 @@ typedef struct { void *extra_data; } iqm_t; -#endif//__QF_iqm_h__ +#endif//__QF_iqm_h diff --git a/include/QF/joystick.h b/include/QF/joystick.h index 1eeba5d49..4b8163f7e 100644 --- a/include/QF/joystick.h +++ b/include/QF/joystick.h @@ -25,8 +25,8 @@ */ -#ifndef __QF_joystick_h_ -#define __QF_joystick_h_ +#ifndef __QF_joystick_h +#define __QF_joystick_h #include #include "QF/quakeio.h" @@ -154,4 +154,4 @@ int JOY_GetAxis_i (int dest, const char *c); void Joy_WriteBindings (QFile *f); -#endif // __QF_joystick_h_ +#endif//__QF_joystick_h diff --git a/include/QF/keys.h b/include/QF/keys.h index 66ef8d99e..7c9c959fd 100644 --- a/include/QF/keys.h +++ b/include/QF/keys.h @@ -26,8 +26,8 @@ */ -#ifndef _KEYS_H -#define _KEYS_H +#ifndef __QF_keys_h +#define __QF_keys_h #ifndef __QFCC__ # include "QF/qtypes.h" @@ -661,4 +661,4 @@ void Key_Progs_Init (struct progs_s *pr); ///@} -#endif // _KEYS_H +#endif//__QF_keys_h diff --git a/include/QF/link.h b/include/QF/link.h index de29bb454..5b6fdcf8c 100644 --- a/include/QF/link.h +++ b/include/QF/link.h @@ -25,8 +25,8 @@ */ -#ifndef _LINK_H -#define _LINK_H +#ifndef __QF_link_h +#define __QF_link_h // (type *)STRUCT_FROM_LINK(link_t *link, type, member) // ent = STRUCT_FROM_LINK(link,entity_t,order) @@ -43,4 +43,4 @@ void RemoveLink (link_t *l); void InsertLinkBefore (link_t *l, link_t *before); void InsertLinkAfter (link_t *l, link_t *after); -#endif // _LINK_H +#endif//__QF_link_h diff --git a/include/QF/llist.h b/include/QF/llist.h index b9a3a0140..e555c6bd6 100644 --- a/include/QF/llist.h +++ b/include/QF/llist.h @@ -25,8 +25,8 @@ */ -#ifndef _LLIST_H -#define _LLIST_H +#ifndef __QF_llist_h +#define __QF_llist_h #include "QF/qtypes.h" @@ -112,4 +112,4 @@ void *llist_createarray (llist_t *list, size_t esize); //@} -#endif +#endif//__QF_llist_h diff --git a/include/QF/locs.h b/include/QF/locs.h index 425e8980d..4f7dc9b5c 100644 --- a/include/QF/locs.h +++ b/include/QF/locs.h @@ -25,8 +25,8 @@ */ -#ifndef __locs_h -#define __locs_h +#ifndef __QF_locs_h +#define __QF_locs_h #include "QF/qtypes.h" @@ -47,4 +47,4 @@ void locs_reset (void); void locs_save (const char *filename, qboolean gz); void map_to_loc (const char *mapname, char *filename); -#endif // __locs_h +#endif//__QF_locs_h diff --git a/include/QF/mathlib.h b/include/QF/mathlib.h index 5c9b854fe..851b841eb 100644 --- a/include/QF/mathlib.h +++ b/include/QF/mathlib.h @@ -25,8 +25,8 @@ */ -#ifndef __mathlib_h -#define __mathlib_h +#ifndef __QF_mathlib_h +#define __QF_mathlib_h /** \defgroup mathlib Vector and matrix functions \ingroup utils @@ -220,4 +220,4 @@ void BarycentricCoords (const vec_t **points, int num_points, const vec3_t p, ///@} -#endif // __mathlib_h +#endif//__QF_mathlib_h diff --git a/include/QF/mdfour.h b/include/QF/mdfour.h index 19360e838..ec8648cd2 100644 --- a/include/QF/mdfour.h +++ b/include/QF/mdfour.h @@ -26,20 +26,20 @@ */ -#ifndef __mdfour_h -#define __mdfour_h +#ifndef __QF_mdfour_h +#define __QF_mdfour_h + +#include "QF/qtypes.h" /** \addtogroup crc */ ///@{ -#include "QF/uint32.h" - #define MDFOUR_DIGEST_BYTES 16 struct mdfour { - uint32 A, B, C, D; - uint32 totalN; + uint32_t A, B, C, D; + uint32_t totalN; }; void mdfour_begin(struct mdfour *md); // old: MD4Init @@ -49,4 +49,4 @@ void mdfour(unsigned char *out, const unsigned char *in, int n); ///@} -#endif // __mdfour_h +#endif//__QF_mdfour_h diff --git a/include/QF/model.h b/include/QF/model.h index 6b3fbc3b5..d4b243241 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -25,8 +25,8 @@ */ -#ifndef _MODEL_H -#define _MODEL_H +#ifndef __QF_model_h +#define __QF_model_h #include "QF/qtypes.h" #include "QF/bspfile.h" @@ -468,4 +468,4 @@ extern byte *mod_base; extern byte mod_novis[MAX_MAP_LEAFS / 8]; extern int mod_lightmap_bytes; -#endif // _MODEL_H +#endif//__QF_model_h diff --git a/include/QF/modelgen.h b/include/QF/modelgen.h index 447a8c864..66cdd1308 100644 --- a/include/QF/modelgen.h +++ b/include/QF/modelgen.h @@ -31,8 +31,8 @@ // * pass data from one to the other via model files. * // ********************************************************* -#ifndef _MODELGEN_H -#define _MODELGEN_H +#ifndef __QF_modelgen_h +#define __QF_modelgen_h #include "QF/mathlib.h" @@ -142,4 +142,4 @@ typedef struct { // little-endian "IDP2" #define IDHEADER_MD2 (('2'<<24)+('P'<<16)+('D'<<8)+'I') -#endif // _MODELGEN_H +#endif//__QF_modelgen_h diff --git a/include/QF/msg.h b/include/QF/msg.h index 6a92e2d54..4f696f896 100644 --- a/include/QF/msg.h +++ b/include/QF/msg.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef _MSG_H -#define _MSG_H +#ifndef __QF_msg_h +#define __QF_msg_h /** \defgroup msg Message reading and writing \ingroup utils @@ -251,4 +251,4 @@ int MSG_ReadUTF8 (qmsg_t *msg); ///@} -#endif +#endif//__QF_msg_h diff --git a/include/QF/object.h b/include/QF/object.h index 39f06210b..f5c4f97f8 100644 --- a/include/QF/object.h +++ b/include/QF/object.h @@ -32,8 +32,8 @@ */ -#ifndef __object_h -#define __object_h +#ifndef __QF_object_h +#define __QF_object_h #include "QF/qtypes.h" @@ -115,4 +115,4 @@ void Object_Garbage_Collect (void); #include "QF/classes/String.h" -#endif +#endif//__QF_object_h diff --git a/include/QF/pak.h b/include/QF/pak.h index ea86ffd14..e331fca6e 100644 --- a/include/QF/pak.h +++ b/include/QF/pak.h @@ -28,8 +28,8 @@ */ -#ifndef __qf_pak_h -#define __qf_pak_h +#ifndef __QF_pak_h +#define __QF_pak_h /** \addtogroup pak */ @@ -53,4 +53,4 @@ typedef struct { ///@} -#endif//__qf_pak_h +#endif//__QF_pak_h diff --git a/include/QF/pcx.h b/include/QF/pcx.h index 6bfeb03e5..8536b9f69 100644 --- a/include/QF/pcx.h +++ b/include/QF/pcx.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __pcx_h -#define __pcx_h +#ifndef __QF_pcx_h +#define __QF_pcx_h #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -77,4 +77,4 @@ pcx_t *EncodePCX (byte *data, int width, int height, int rowbytes, */ struct tex_s *LoadPCX (QFile *f, qboolean convert, byte *pal); -#endif // __pcx_h +#endif//__QF_pcx_h diff --git a/include/QF/plugin.h b/include/QF/plugin.h index 0a06f73f2..f1ff974a3 100644 --- a/include/QF/plugin.h +++ b/include/QF/plugin.h @@ -25,8 +25,8 @@ */ -#ifndef __QF_plugin_h_ -#define __QF_plugin_h_ +#ifndef __QF_plugin_h +#define __QF_plugin_h /** \defgroup plugin Plugins \ingroup utils @@ -113,4 +113,4 @@ void PI_Shutdown (void); ///@} -#endif // __QF_plugin_h_ +#endif//__QF_plugin_h diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 185a802ad..3c6ccc8fe 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -18,8 +18,8 @@ */ // this file is shared by QuakeForge and qfcc -#ifndef __pr_comp_h -#define __pr_comp_h +#ifndef __QF_pr_comp_h +#define __QF_pr_comp_h #include "QF/qtypes.h" @@ -27,7 +27,7 @@ typedef int16_t pr_short_t; typedef uint16_t pr_ushort_t; typedef int32_t pr_int_t; typedef uint32_t pr_uint_t; -typedef pr_int_t func_t; +typedef pr_uint_t func_t; typedef pr_int_t string_t; typedef pr_uint_t pointer_t; @@ -50,8 +50,8 @@ typedef enum { ev_type_count // not a type, gives number of types } etype_t; -extern int pr_type_size[ev_type_count]; -extern const char *pr_type_name[ev_type_count]; +extern const pr_ushort_t pr_type_size[ev_type_count]; +extern const char * const pr_type_name[ev_type_count]; #define OFS_NULL 0 #define OFS_RETURN 1 @@ -395,7 +395,12 @@ typedef enum { OP_MOD_I, OP_MOD_F, OP_MOD_D, + + OP_MEMSETI, + OP_MEMSETP, + OP_MEMSETPI, } pr_opcode_e; +#define OP_BREAK 0x8000 typedef struct opcode_s { const char *name; @@ -407,9 +412,9 @@ typedef struct opcode_s { const char *fmt; } opcode_t; -extern opcode_t pr_opcodes[]; +extern const opcode_t pr_opcodes[]; opcode_t *PR_Opcode (pr_short_t opcode); -void PR_Opcode_Init (void); +void PR_Opcode_Init (void); // idempotent typedef struct dstatement_s { pr_opcode_e op:16; @@ -417,12 +422,30 @@ typedef struct dstatement_s { } GCC_STRUCT dstatement_t; typedef struct ddef_s { - pr_ushort_t type; // if DEF_SAVEGLOBGAL bit is set + pr_ushort_t type; // if DEF_SAVEGLOBAL bit is set // the variable needs to be saved in savegames pr_ushort_t ofs; - pr_int_t s_name; + string_t s_name; } ddef_t; +typedef struct xdef_s { + pointer_t type; ///< pointer to type definition + pointer_t ofs; ///< 32-bit version of ddef_t.ofs +} xdef_t; + +typedef struct pr_xdefs_s { + pointer_t xdefs; + pr_int_t num_xdefs; +} pr_xdefs_t; + +typedef struct pr_def_s { + pr_ushort_t type; + pr_ushort_t size; ///< may not be correct + pointer_t ofs; + string_t name; + pointer_t type_encoding; +} pr_def_t; + typedef struct dparmsize_s { uint8_t size:5; uint8_t alignment:3; @@ -435,11 +458,11 @@ typedef struct dparmsize_s { typedef struct dfunction_s { pr_int_t first_statement; // negative numbers are builtins pr_int_t parm_start; - pr_int_t locals; // total ints of parms + locals + pr_uint_t locals; // total ints of parms + locals - pr_int_t profile; // runtime + pr_uint_t profile; // runtime - pr_int_t s_name; + string_t s_name; pr_int_t s_file; // source file defined in pr_int_t numparms; @@ -484,10 +507,10 @@ typedef struct dprograms_s { pr_uint_t numfielddefs; pr_uint_t ofs_functions; - pr_int_t numfunctions; // function 0 is an empty + pr_uint_t numfunctions; // function 0 is an empty pr_uint_t ofs_strings; - pr_int_t numstrings; // first string is a null string + pr_uint_t numstrings; // first string is a null string pr_uint_t ofs_globals; pr_uint_t numglobals; @@ -495,4 +518,4 @@ typedef struct dprograms_s { pr_uint_t entityfields; } dprograms_t; -#endif // __pr_comp_h +#endif//__QF_pr_comp_h diff --git a/include/QF/pr_debug.h b/include/QF/pr_debug.h index 65b953381..be398f056 100644 --- a/include/QF/pr_debug.h +++ b/include/QF/pr_debug.h @@ -28,8 +28,8 @@ */ -#ifndef __pr_debug_h -#define __pr_debug_h +#ifndef __QF_pr_debug_h +#define __QF_pr_debug_h #include "QF/pr_comp.h" @@ -39,8 +39,7 @@ typedef struct pr_auxfunction_s { pr_uint_t line_info; // index to first lineno entry pr_uint_t local_defs; // index to the first local def pr_uint_t num_locals; // number of local defs - pr_short_t return_type; // return type of this function - pr_short_t reserved; + pr_uint_t return_type; // return type of this function } pr_auxfunction_t; typedef struct pr_lineno_s { @@ -51,7 +50,7 @@ typedef struct pr_lineno_s { pr_uint_t line; } pr_lineno_t; -#define PROG_DEBUG_VERSION 0x00001002 // MMmmmRRR 0.001.002 (hex) +#define PROG_DEBUG_VERSION 0x00001003 // MMmmmRRR 0.001.002 (hex) typedef struct pr_debug_header_s { pr_int_t version; @@ -65,4 +64,4 @@ typedef struct pr_debug_header_s { pr_uint_t num_locals; } pr_debug_header_t; -#endif//__pr_debug_h +#endif//__QF_pr_debug_h diff --git a/include/QF/pr_obj.h b/include/QF/pr_obj.h index 5e4f8463c..52f05aa16 100644 --- a/include/QF/pr_obj.h +++ b/include/QF/pr_obj.h @@ -28,8 +28,8 @@ */ -#ifndef __pr_obj_h -#define __pr_obj_h +#ifndef __QF_pr_obj_h +#define __QF_pr_obj_h #include "QF/pr_comp.h" @@ -94,7 +94,7 @@ typedef struct pr_class_s { pr_int_t instance_size; pointer_t ivars; // pr_ivar_list_t pointer_t methods; // pr_method_list_t - pointer_t dtable; + pointer_t dtable; // resource index pointer_t subclass_list; // pr_class_t pointer_t sibling_class; // pr_class_t pointer_t protocols; // pr_protocol_list_t @@ -185,4 +185,4 @@ typedef struct pr_super_s { pointer_t class; } pr_super_t; -#endif//__pr_obj_h +#endif//__QF_pr_obj_h diff --git a/include/QF/pr_type.h b/include/QF/pr_type.h index 0c8b37664..c9e45185c 100644 --- a/include/QF/pr_type.h +++ b/include/QF/pr_type.h @@ -28,8 +28,8 @@ */ -#ifndef __pr_type_h -#define __pr_type_h +#ifndef __QF_pr_type_h +#define __QF_pr_type_h /** \defgroup qfcc_qfo_type Object file type encoding \ingroup progs @@ -40,6 +40,16 @@ #include "QF/pr_comp.h" +typedef enum { + ty_basic, ///< VM type (float, int, pointer, field, etc) + ty_struct, + ty_union, + ty_enum, + ty_array, + ty_class, +} ty_meta_e; + + typedef struct qfot_fldptr_s { pr_int_t type; ///< ev_field or ev_pointer pointer_t aux_type; ///< referenced type @@ -88,20 +98,20 @@ typedef struct qfot_type_s { pr_int_t size; ///< total word size of this encoding string_t encoding; ///< Objective-QC encoding union { - pr_int_t type; ///< basic type: etype_t - qfot_fldptr_t fldptr; ///< ty_none, ev_pointer/ev_field - qfot_func_t func; ///< ty_none, ev_func + pr_int_t type; ///< ty_basic: etype_t + qfot_fldptr_t fldptr; ///< ty_basic, ev_pointer/ev_field + qfot_func_t func; ///< ty_basic, ev_func qfot_struct_t strct; ///< ty_struct/ty_union/ty_enum qfot_array_t array; ///< ty_array - pointer_t class; ///< ty_class + string_t class; ///< ty_class } t; } qfot_type_t; typedef struct qfot_type_encodings_s { pointer_t types; - pr_int_t size; + pr_uint_t size; } qfot_type_encodings_t; ///@} -#endif//__pr_type_h +#endif//__QF_pr_type_h diff --git a/include/QF/progs.h b/include/QF/progs.h index e7953883e..c615e6d14 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -53,8 +53,12 @@ typedef struct edict_s edict_t; ///@{ /** Initialize the progs engine. + + The first call will initialize subsystems common to all progs instances. + + \param pr The progs engine instance to initialize. */ -void PR_Init (void); +void PR_Init (progs_t *pr); /** Initialize the Cvars for the progs engine. Call before calling PR_Init(). */ @@ -87,15 +91,63 @@ void PR_RunError (progs_t *pr, const char *error, ...) __attribute__((format(pri (pr)->pr_params[1] = (pr)->pr_real_params[1]; \ } while (0) -/** Save the current parameters. - \param pr pointer to ::progs_t VM struct +/** \name Detouring Function Calls + + These functions allow a builtin function that uses PR_CallFunction() to + safely insert a call to another VM function. The +initialize diversion + required by Objective-QuakeC uses this. + + PR_PushFrame (pr); + __auto_type params = PR_SaveParams (pr); + ... set up parameters to detour_function + PR_ExecuteProgram (pr, detour_function) + PR_RestoreParams (pr, params); + PR_PopFrame (pr); + */ -void PR_SaveParams (progs_t *pr); +///@{ +typedef struct pr_stashed_params_s { + pr_type_t *param_ptrs[2]; + int argc; + pr_type_t params[1]; +} pr_stashed_params_t; + +/** Save the current parameters to the provided stash. + + \warning The memory for the parameter stash is allocated using + alloca(). + + \param pr pointer to ::progs_t VM struct + \return Pointer to a newly allocated and initialized parameter + stash that has the current parameters saved to it. + \hideinitializer +*/ +#define PR_SaveParams(pr) \ + _PR_SaveParams((pr), \ + alloca (field_offset (pr_stashed_params_t, \ + params[(pr)->pr_argc \ + * (pr)->pr_param_size]))) + +/** [INTERNAL] Save the current parameters to the provided stash. + + \warning Requires \a params to be correctly allocated. Use + PR_SaveParams instead as it will create a suitable stash for + saving the parameters. + + \param pr pointer to ::progs_t VM struct + \param params location to save the parameters, must be of adequade size + to hold \a pr_argc * \a pr_param_size words in \a params + \return \a params Allows the likes of: + __auto_type params = PR_SaveParams (pr); +*/ +pr_stashed_params_t *_PR_SaveParams (progs_t *pr, pr_stashed_params_t *params); /** Restore the parameters saved by PR_SaveParams(). \param pr pointer to ::progs_t VM struct + \param params pointer to stash created by PR_SaveParams() */ -void PR_RestoreParams (progs_t *pr); +void PR_RestoreParams (progs_t *pr, pr_stashed_params_t *params); +///@} /** Push an execution frame onto the VM stack. Saves current execution state. \param pr pointer to ::progs_t VM struct @@ -236,7 +288,7 @@ void ED_PrintNum (progs_t *pr, pr_int_t ent); // pr_parse.c struct script_s; struct plitem_s; -qboolean ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key, +qboolean ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s); struct plitem_s *ED_EntityDict (progs_t *pr, edict_t *ed); struct plitem_s *ED_GlobalsDict (progs_t *pr); @@ -269,11 +321,13 @@ void ED_EntityParseFunction (progs_t *pr); */ ///@{ -ddef_t *PR_FieldAtOfs (progs_t *pr, pr_int_t ofs) __attribute__((pure)); -ddef_t *PR_GlobalAtOfs (progs_t *pr, pr_int_t ofs) __attribute__((pure)); +pr_def_t *PR_SearchDefs (pr_def_t *defs, unsigned num_defs, pointer_t offset) + __attribute__((pure)); +pr_def_t *PR_FieldAtOfs (progs_t *pr, pointer_t ofs) __attribute__((pure)); +pr_def_t *PR_GlobalAtOfs (progs_t *pr, pointer_t ofs) __attribute__((pure)); -ddef_t *PR_FindField (progs_t *pr, const char *name); -ddef_t *PR_FindGlobal (progs_t *pr, const char *name); +pr_def_t *PR_FindField (progs_t *pr, const char *name); +pr_def_t *PR_FindGlobal (progs_t *pr, const char *name); dfunction_t *PR_FindFunction (progs_t *pr, const char *name); int PR_ResolveGlobals (progs_t *pr); @@ -510,6 +564,20 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define P_var(p,n,t) ((p)->pr_params[n]->t##_var) +/** Access a parameter as an arbitray type. + + \par QC type: + \c struct etc small enough to fit in a single parameter + \param p pointer to ::progs_t VM struct + \param t C type of the structure + \param n parameter number (0-7) + \return structure lvalue. use & to make a pointer of the + appropriate type. + + \hideinitializer +*/ +#define P_PACKED(p,t,n) (*(t *) (p)->pr_params[n]) + /** Access a float parameter. Can be assigned to. \par QC type: @@ -532,7 +600,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define P_DOUBLE(p,n) (*(double *) ((p)->pr_params[n])) +#define P_DOUBLE(p,n) P_PACKED(p, double, n) /** Access an integer parameter. Can be assigned to. @@ -618,7 +686,6 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define P_POINTER(p,n) P_var (p, n, pointer) - /** Access an entity parameter. \par QC type: @@ -715,6 +782,19 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define R_var(p,t) ((p)->pr_return->t##_var) +/** Access the VM function return value parameter as an arbitray type. + + \par QC type: + \c struct etc small enough to fit in the return slot + \param p pointer to ::progs_t VM struct + \param t C type of the structure + \return structure lvalue. use & to make a pointer of the + appropriate type. + + \hideinitializer +*/ +#define R_PACKED(p,t) (*(t *) (p)->pr_return) + /** Access the VM function return value as a \c float \par QC type: @@ -735,7 +815,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define R_DOUBLE(p) (*(double *) ((p)->pr_return)) +#define R_DOUBLE(p) R_PACKED (p, double) /** Access the VM function return value as a \c ::pr_int_t (AKA int32_t) @@ -1142,12 +1222,12 @@ int PR_RelocateBuiltins (progs_t *pr); */ ///@{ -/** Initialize the string tables using the strings supplied by the progs. - Called automatically during progs load. - \param pr pointer to ::progs_t VM struct - \return true for success, false for failure +/** Initialize the string management subsystem. + + \param pr The VM of which the string management subsystem will be + initialized; */ -int PR_LoadStrings (progs_t *pr); +void PR_Strings_Init (progs_t *pr); /** Check the validity of a string index. \param pr pointer to ::progs_t VM struct @@ -1196,6 +1276,29 @@ string_t PR_SetReturnString(progs_t *pr, const char *s); */ string_t PR_SetTempString(progs_t *pr, const char *s); +/** Make a temporary memory block that will be freed when the current progs + stack frame is exited. The contents may be anything and a new block is + returned every time, and the block is in VM addressible space. To access + the contents of the block (for reading, writing, etc), use PR_GetString() + and cast the pointer as necessary. + + \param pr pointer to ::progs_t VM struct + \param size size of block in bytes + \return string index of the block +*/ +string_t PR_AllocTempBlock (progs_t *pr, size_t size); + +/** Push a temporary string to the callee stack frame + + This is for when the temp string needs to be freed when the called function + returns rather than the calling function. It is an error to push a non-temp + string. + + \param pr pointer to ::progs_t VM struct + \param num string index of the temp string +*/ +void PR_PushTempString (progs_t *pr, string_t num); + /** Make a temporary progs string that is the concatenation of two C strings. \param pr pointer to ::progs_t VM struct \param a C string @@ -1226,11 +1329,6 @@ string_t PR_NewMutableString (progs_t *pr); */ string_t PR_SetDynamicString (progs_t *pr, const char *s); -/** Clear all of the return string slots. Called at progs load. - \param pr pointer to ::progs_t VM struct -*/ -void PR_ClearReturnStrings (progs_t *pr); - /** Destroy a mutable, dynamic or temporary string. \param pr pointer to ::progs_t VM struct \param str string index of the string to be destroyed @@ -1418,6 +1516,8 @@ void *PR_Resources_Find (progs_t *pr, const char *name); Any memory allocated to the resource must be freed before freeing the resource. + A reset resource map is guaranteed to allocate elements sequentially. + \param type The type of the resource. Must match the \c type parameter used for PR_RESMAP. \param map The resource map. @@ -1432,6 +1532,8 @@ void *PR_Resources_Find (progs_t *pr, const char *name); *(type **) &map._free[j] = &map._free[j + 1]; \ if (i < map._size - 1) \ *(type **) &map._free[j] = &map._map[i + 1][0]; \ + else \ + *(type **) &map._free[j] = 0; \ } \ map._free = map._map[0]; @@ -1488,19 +1590,66 @@ void *PR_Zone_Realloc (progs_t *pr, void *ptr, pr_int_t size); /// \addtogroup debug ///@{ -void PR_Debug_Init (void); +struct qfot_type_s; + +/** Callback for viewing progs data + + \param type C pointer to the type definition by which to view the + data. + \param value C pointer to the data to be viewed. + \param data User data. +*/ +typedef void (*type_view_func) (struct qfot_type_s *type, pr_type_t *value, + void *data); + +/** Set of callbacks for viewing progs data + + Each possible type has its own callback. Basic types (those for which the + VM has specific instructions) all have separate callbacks, one for each + type, but the callbacks for compound types are expected to some + interpretation on their own, such as displaying a simple identifier or + the entire contents of the data. +*/ +typedef struct type_view_s { + type_view_func void_view; + type_view_func string_view; + type_view_func float_view; + type_view_func vector_view; + type_view_func entity_view; + type_view_func field_view; + type_view_func func_view; + type_view_func pointer_view; + type_view_func quat_view; + type_view_func integer_view; + type_view_func uinteger_view; + type_view_func short_view; + type_view_func double_view; + + type_view_func struct_view; + type_view_func union_view; + type_view_func enum_view; + type_view_func array_view; + type_view_func class_view; +} type_view_t; + +void PR_Debug_Init (progs_t *pr); void PR_Debug_Init_Cvars (void); int PR_LoadDebug (progs_t *pr); void PR_Debug_Watch (progs_t *pr, const char *expr); void PR_Debug_Print (progs_t *pr, const char *expr); +pr_auxfunction_t *PR_Debug_AuxFunction (progs_t *pr, pr_uint_t func) __attribute__((pure)); +pr_auxfunction_t *PR_Debug_MappedAuxFunction (progs_t *pr, pr_uint_t func) __attribute__((pure)); +pr_def_t *PR_Debug_LocalDefs (progs_t *pr, pr_auxfunction_t *aux_function) __attribute__((pure)); +pr_lineno_t *PR_Debug_Linenos (progs_t *pr, pr_auxfunction_t *aux_function, + pr_uint_t *num_linenos); pr_auxfunction_t *PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); pr_uint_t PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); pr_uint_t PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); pr_lineno_t *PR_Find_Lineno (progs_t *pr, pr_uint_t addr) __attribute__((pure)); const char *PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); const char *PR_Get_Source_Line (progs_t *pr, pr_uint_t addr); -ddef_t *PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) __attribute__((pure)); -ddef_t *PR_Get_Local_Def (progs_t *pr, pr_int_t offs) __attribute__((pure)); +pr_def_t *PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) __attribute__((pure)); +pr_def_t *PR_Get_Local_Def (progs_t *pr, pointer_t *offs) __attribute__((pure)); void PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents); void PR_DumpState (progs_t *pr); void PR_StackTrace (progs_t *pr); @@ -1541,8 +1690,6 @@ typedef struct { strref_t *tstr; ///< Linked list of temporary strings. } prstack_t; -struct obj_list_s; - struct progs_s { int (*parse_field) (progs_t *pr, const char *key, const char *value); @@ -1550,7 +1697,7 @@ struct progs_s { int no_exec_limit; void (*file_error) (progs_t *pr, const char *path); - void *(*load_file) (progs_t *pr, const char *path); + void *(*load_file) (progs_t *pr, const char *path, off_t *size); void *(*allocate_progs_mem) (progs_t *pr, int size); void (*free_progs_mem) (progs_t *pr, void *mem); @@ -1597,16 +1744,9 @@ struct progs_s { /// \name string management ///@{ - struct dstring_mem_s *ds_mem; - strref_t *free_string_refs; - strref_t *static_strings; - strref_t **string_map; - strref_t *return_strings[PR_RS_SLOTS]; - int rs_slot; - unsigned dyn_str_size; - struct hashtab_s *strref_hash; - int num_strings; + struct prstr_resources_s *pr_string_resources; strref_t *pr_xtstr; + strref_t *pr_pushtstr; int float_promoted; ///< for PR_Sprintf ///@} @@ -1616,8 +1756,8 @@ struct progs_s { bfunction_t *function_table; char *pr_strings; int pr_stringsize; - ddef_t *pr_globaldefs; - ddef_t *pr_fielddefs; + pr_def_t *pr_globaldefs; + pr_def_t *pr_fielddefs; dstatement_t *pr_statements; pr_type_t *pr_globals; unsigned globals_size; @@ -1628,14 +1768,12 @@ struct progs_s { pr_type_t *pr_return; pr_type_t *pr_params[MAX_PARMS]; pr_type_t *pr_real_params[MAX_PARMS]; - pr_type_t *pr_param_ptrs[2]; - pr_type_t *pr_saved_params; - int pr_saved_argc; int pr_param_size; ///< covers both params and return int pr_param_alignment; ///< covers both params and return ///@} /// \name edicts + /// \todo FIXME should this be outside the VM? ///@{ edict_t **edicts; int max_edicts; ///< set by user @@ -1652,7 +1790,7 @@ struct progs_s { /// \name execution state ///@{ - int pr_argc; + int pr_argc; //FIXME need a good way to ensure it is correct qboolean pr_trace; int pr_trace_depth; @@ -1687,28 +1825,13 @@ struct progs_s { /// \name obj info ///@{ - unsigned selector_index; - unsigned selector_index_max; - struct obj_list_s **selector_sels; - string_t *selector_names; - struct hashtab_s *selector_hash; - struct hashtab_s *classes; - struct hashtab_s *load_methods; - struct obj_list_s *unresolved_classes; - struct obj_list_s *unclaimed_categories; - struct obj_list_s *unclaimed_proto_list; - struct obj_list_s *module_list; - struct obj_list_s *class_tree_list; + struct probj_resources_s *pr_objective_resources; ///@} - /// \name debug info + /// \name debugging ///@{ - const char *debugfile; - struct pr_debug_header_s *debug; - struct pr_auxfunction_s *auxfunctions; - struct pr_auxfunction_s **auxfunction_map; - struct pr_lineno_s *linenos; - ddef_t *local_defs; + struct prdeb_resources_s *pr_debug_resources; + void (*breakpoint_handler) (progs_t *pr); pr_type_t *watch; int wp_conditional; pr_type_t wp_val; @@ -1740,7 +1863,7 @@ struct progs_s { \return C pointer represented by the parameter. 0 offset -> NULL */ static inline pr_type_t * -PR_GetPointer (progs_t *pr, pointer_t o) +PR_GetPointer (const progs_t *pr, pointer_t o) { return o ? pr->pr_globals + o : 0; } @@ -1751,9 +1874,9 @@ PR_GetPointer (progs_t *pr, pointer_t o) \return Progs offset/pointer represented by \c p. NULL -> 0 offset */ static inline pointer_t -PR_SetPointer (progs_t *pr, void *p) +PR_SetPointer (const progs_t *pr, const void *p) { - return p ? (pr_type_t *) p - pr->pr_globals : 0; + return p ? (const pr_type_t *) p - pr->pr_globals : 0; } ///@} diff --git a/include/QF/qargs.h b/include/QF/qargs.h index 50dfbd35a..bf49495a4 100644 --- a/include/QF/qargs.h +++ b/include/QF/qargs.h @@ -27,8 +27,8 @@ */ -#ifndef __qargs_h -#define __qargs_h +#ifndef __QF_qargs_h +#define __QF_qargs_h /** \addtogroup misc */ @@ -52,4 +52,4 @@ void COM_ParseConfig (void); ///@} -#endif // __qargs_h +#endif//__QF_qargs_h diff --git a/include/QF/qdefs.h b/include/QF/qdefs.h index 1d00abee0..a0dbbfe5c 100644 --- a/include/QF/qdefs.h +++ b/include/QF/qdefs.h @@ -27,8 +27,8 @@ */ -#ifndef __qdefs_h -#define __qdefs_h +#ifndef __QF_qdefs_h +#define __QF_qdefs_h #define MAX_QPATH 64 #define MAX_CL_STATS 32 @@ -40,4 +40,4 @@ #define clc_stringcmd 4 -#endif // __qdefs_h +#endif//__QF_qdefs_h diff --git a/include/QF/qendian.h b/include/QF/qendian.h index a42bd749f..7c418be53 100644 --- a/include/QF/qendian.h +++ b/include/QF/qendian.h @@ -27,8 +27,8 @@ */ -#ifndef __qendian_h -#define __qendian_h +#ifndef __QF_qendian_h +#define __QF_qendian_h /** \defgroup qendian Endian handling functions \ingroup utils @@ -120,4 +120,4 @@ unsigned int ReadLong (struct QFile_s *file); ///@} -#endif // __qendian_h +#endif//__QF_qendian_h diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index e0c2557ca..7a12b7c4c 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -25,8 +25,8 @@ */ -#ifndef __QF_qfplist_h_ -#define __QF_qfplist_h_ +#ifndef __QF_qfplist_h +#define __QF_qfplist_h /** \defgroup qfplist Property lists \ingroup utils @@ -228,4 +228,4 @@ void PL_Free (plitem_t *item); ///@} -#endif // __QF_qfplist_h_ +#endif//__QF_qfplist_h diff --git a/include/QF/qtypes.h b/include/QF/qtypes.h index e328ff2fc..ea3a4df6c 100644 --- a/include/QF/qtypes.h +++ b/include/QF/qtypes.h @@ -27,8 +27,8 @@ */ -#ifndef __qtypes_h -#define __qtypes_h +#ifndef __QF_qtypes_h +#define __QF_qtypes_h #include #include @@ -115,4 +115,4 @@ typedef struct sphere_s { vec_t radius; } sphere_t; -#endif // __qtypes_h +#endif//__QF_qtypes_h diff --git a/include/QF/quakefs.h b/include/QF/quakefs.h index 364718db0..761997eea 100644 --- a/include/QF/quakefs.h +++ b/include/QF/quakefs.h @@ -27,8 +27,8 @@ */ -#ifndef __quakefs_h -#define __quakefs_h +#ifndef __QF_quakefs_h +#define __QF_quakefs_h /** \defgroup quakefs Quake Filesystem \ingroup utils @@ -420,4 +420,4 @@ void QFS_FilelistFree (filelist_t *list); ///@} -#endif // __quakefs_h +#endif//__QF_quakefs_h diff --git a/include/QF/quakeio.h b/include/QF/quakeio.h index 08b14af69..1fd7205a0 100644 --- a/include/QF/quakeio.h +++ b/include/QF/quakeio.h @@ -26,8 +26,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __quakeio_h -#define __quakeio_h +#ifndef __QF_quakeio_h +#define __QF_quakeio_h #include @@ -62,4 +62,4 @@ const char *Qgetline(QFile *file); ///@} -#endif /*__quakeio_h*/ +#endif//__QF_quakeio_h diff --git a/include/QF/render.h b/include/QF/render.h index 03cebfa1c..7f02672e2 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -25,8 +25,8 @@ */ -#ifndef __render_h -#define __render_h +#ifndef __QF_render_h +#define __QF_render_h #include "QF/mathlib.h" #include "QF/model.h" @@ -177,4 +177,4 @@ void R_LoadModule (struct vid_internal_s *vid_internal); struct progs_s; void R_Progs_Init (struct progs_s *pr); -#endif // __render_h +#endif//__QF_render_h diff --git a/include/QF/ringbuffer.h b/include/QF/ringbuffer.h new file mode 100644 index 000000000..cc289640e --- /dev/null +++ b/include/QF/ringbuffer.h @@ -0,0 +1,103 @@ +/* + ringbuffer.h + + ring buffer + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_ringbuffer_h +#define __QF_ringbuffer_h + +#define RING_BUFFER(type, size) \ + struct { \ + type buffer[size]; \ + unsigned head; \ + unsigned tail; \ + } + +#define RB_buffer_size(ring_buffer) \ + ({ __auto_type rb = (ring_buffer); \ + sizeof (rb->buffer) / sizeof (rb->buffer[0]); \ + }) + +#define RB_SPACE_AVAILABLE(ring_buffer) \ + ({ __auto_type rb = &(ring_buffer); \ + (rb->tail + RB_buffer_size(rb) - rb->head - 1) % RB_buffer_size(rb);\ + }) + +#define RB_DATA_AVAILABLE(ring_buffer) \ + ({ __auto_type rb = &(ring_buffer); \ + (rb->head + RB_buffer_size (rb) - rb->tail) % RB_buffer_size (rb); \ + }) + +#define RB_WRITE_DATA(ring_buffer, data, count) \ + ({ __auto_type rb = &(ring_buffer); \ + const typeof (rb->buffer[0]) *d = (data); \ + unsigned c = (count); \ + unsigned h = rb->head; \ + rb->head = (h + c) % RB_buffer_size (rb); \ + if (c > RB_buffer_size (rb) - h) { \ + memcpy (rb->buffer + h, d, \ + (RB_buffer_size (rb) - h) * sizeof (rb->buffer[0])); \ + c -= RB_buffer_size (rb) - h; \ + d += RB_buffer_size (rb) - h; \ + h = 0; \ + } \ + memcpy (rb->buffer + h, d, c * sizeof (rb->buffer[0])); \ + }) + +#define RB_READ_DATA(ring_buffer, data, count) \ + ({ __auto_type rb = &(ring_buffer); \ + typeof (&rb->buffer[0]) d = (data); \ + unsigned c = (count); \ + unsigned oc = c; \ + unsigned t = rb->tail; \ + if (c > RB_buffer_size (rb) - t) { \ + memcpy (d, rb->buffer + t, \ + (RB_buffer_size (rb) - t) * sizeof (rb->buffer[0])); \ + c -= RB_buffer_size (rb) - t; \ + d += RB_buffer_size (rb) - t; \ + t = 0; \ + } \ + memcpy (d, rb->buffer + t, c * sizeof (rb->buffer[0])); \ + rb->tail = (t + oc) % RB_buffer_size (rb); \ + }) + +#define RB_DROP_DATA(ring_buffer, count) \ + ({ __auto_type rb = &(ring_buffer); \ + unsigned c = (count); \ + unsigned t = rb->tail; \ + rb->tail = (t + c) % RB_buffer_size (rb); \ + }) + +#define RB_PEEK_DATA(ring_buffer, ahead) \ + ({ __auto_type rb = &(ring_buffer); \ + rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)]; \ + }) + +#define RB_POKE_DATA(ring_buffer, ahead, data) \ + ({ __auto_type rb = &(ring_buffer); \ + rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)] = (data); \ + }) + +#endif//__QF_ringbuffer_h diff --git a/include/QF/screen.h b/include/QF/screen.h index 9586e20a1..8dda2deb4 100644 --- a/include/QF/screen.h +++ b/include/QF/screen.h @@ -26,8 +26,8 @@ */ // screen.h -#ifndef __screen_h -#define __screen_h +#ifndef __QF_screen_h +#define __QF_screen_h #include "QF/qtypes.h" @@ -67,4 +67,4 @@ extern struct qpic_s *scr_turtle; extern struct cvar_s *hud_fps, *hud_time; -#endif // __screen_h +#endif//__QF_screen_h diff --git a/include/QF/script.h b/include/QF/script.h index 357e5100b..34e6f269a 100644 --- a/include/QF/script.h +++ b/include/QF/script.h @@ -41,8 +41,9 @@ typedef struct script_s { /// line number of the file being processed. used only for error reporting /// but updated internally. int line; - /// if set, will be called instead of the internal error handler - void (*error)(struct script_s *script, const char *msg); + /// contains last error message or null if no error + /// if set, no tokens will be parsed. + const char *error; /// if set, multi line quoted tokens will be treated as errors int no_quote_lines; /// if set, characters in this string will always be lexed as single @@ -65,6 +66,7 @@ void Script_Delete (script_t *script); /** Prepare a script_t object for parsing. The caller is responsible for freeing the memory associated with file and data when parsing is complete. + Resets \a script->error \param script The script_t object being parsed \param file Name of the file being parsed. used only for error reporting \param data The script to be parsed diff --git a/include/QF/sizebuf.h b/include/QF/sizebuf.h index 7f6fc4ac3..08436b1b8 100644 --- a/include/QF/sizebuf.h +++ b/include/QF/sizebuf.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __sizebuf_h -#define __sizebuf_h +#ifndef __QF_sizebuf_h +#define __QF_sizebuf_h /** \defgroup sizebuf Fixed Size Buffers \ingroup utils @@ -53,4 +53,4 @@ void SZ_Print (sizebuf_t *buf, const char *data); // strcats onto the sizebuf ///@} -#endif // __sizebuf_h +#endif//__QF_sizebuf_h diff --git a/include/QF/skin.h b/include/QF/skin.h index b9c8a3dcb..7f520e1d6 100644 --- a/include/QF/skin.h +++ b/include/QF/skin.h @@ -25,8 +25,8 @@ */ -#ifndef _SKIN_H -#define _SKIN_H +#ifndef __QF_skin_h +#define __QF_skin_h #include "QF/qtypes.h" #include "QF/vid.h" @@ -57,4 +57,4 @@ typedef struct skin_s { int auxtex; } skin_t; -#endif +#endif//__QF_skin_h diff --git a/include/QF/sound.h b/include/QF/sound.h index 3382d4b91..9fba9b158 100644 --- a/include/QF/sound.h +++ b/include/QF/sound.h @@ -26,8 +26,8 @@ */ // sound.h -- client sound i/o functions -#ifndef _SOUND_H -#define _SOUND_H +#ifndef __QF_sound_h +#define __QF_sound_h /** \defgroup sound QuakeForge sound engine */ @@ -195,4 +195,4 @@ void S_Progs_Init (struct progs_s *pr); ///@} -#endif // _SOUND_H +#endif//__QF_sound_h diff --git a/include/QF/spritegn.h b/include/QF/spritegn.h index 4505ad59f..de490f28d 100644 --- a/include/QF/spritegn.h +++ b/include/QF/spritegn.h @@ -45,8 +45,8 @@ // //------------------------------------------------------- -#ifndef _SPRITEGN_H -#define _SPRITEGN_H +#ifndef __QF_sprintgn_h +#define __QF_sprintgn_h #define SPR_VERSION 1 #define SP2_VERSION 2 @@ -102,4 +102,4 @@ typedef struct { // little-endian "IDS2" #define IDHEADER_SP2 (('2'<<24)+('S'<<16)+('D'<<8)+'I') -#endif // _SPRITEGN_H +#endif//__QF_sprintgn_h diff --git a/include/QF/sys.h b/include/QF/sys.h index 10c1c902e..98cb7e540 100644 --- a/include/QF/sys.h +++ b/include/QF/sys.h @@ -25,10 +25,10 @@ */ -#ifndef __sys_h -#define __sys_h +#ifndef __QF_sys_h +#define __QF_sys_h -/** \defgroup sys Portability +/** \defgroup sys System Portability \ingroup utils Non-portable functions */ @@ -65,8 +65,8 @@ int Sys_mkdir (const char *path); typedef void (*sys_printf_t) (const char *fmt, va_list args) __attribute__((format(printf, 1, 0))); typedef void (*sys_error_t) (void *data); -void Sys_SetStdPrintf (sys_printf_t func); -void Sys_SetErrPrintf (sys_printf_t func); +sys_printf_t Sys_SetStdPrintf (sys_printf_t func); +sys_printf_t Sys_SetErrPrintf (sys_printf_t func); void Sys_PushErrorHandler (sys_error_t func, void *data); void Sys_PopErrorHandler (void); @@ -161,4 +161,4 @@ char *Sys_ExpandSquiggle (const char *path); ///@} -#endif // __sys_h +#endif//__QF_sys_h diff --git a/include/QF/teamplay.h b/include/QF/teamplay.h index bf4ae9445..91b2a6f65 100644 --- a/include/QF/teamplay.h +++ b/include/QF/teamplay.h @@ -25,8 +25,8 @@ */ -#ifndef __teamplay_h -#define __teamplay_h +#ifndef __QF_teamplay_h +#define __QF_teamplay_h extern struct cvar_s *cl_parsesay; extern struct cvar_s *cl_nofake; @@ -47,4 +47,4 @@ const char *Team_ParseSay (struct dstring_s *buf, const char *); void Locs_Init (void); void Team_ParseChat (const char *string); void Team_ResetTimers (void); -#endif // __teamplay_h +#endif//__QF_teamplay_h diff --git a/include/QF/tga.h b/include/QF/tga.h index 1d0bc8c25..365f5d366 100644 --- a/include/QF/tga.h +++ b/include/QF/tga.h @@ -25,8 +25,8 @@ */ -#ifndef __tga_h -#define __tga_h +#ifndef __QF_tga_h +#define __QF_tga_h #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -70,4 +70,4 @@ typedef struct _TargaHeader { struct tex_s *LoadTGA (QFile *fin); void WriteTGAfile (const char *tganame, byte *data, int width, int height); -#endif // __tga_h +#endif//__QF_tga_h diff --git a/include/QF/txtbuffer.h b/include/QF/txtbuffer.h new file mode 100644 index 000000000..e73c7257a --- /dev/null +++ b/include/QF/txtbuffer.h @@ -0,0 +1,98 @@ +/* + txtbuffer.h + + Text buffer for edit or scrollback + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_txtbuffer_h +#define __QF_txtbuffer_h + +#include +#include + +/** \defgroup txtbuffer Text buffers + \ingroup utils +*/ +///@{ + +/// must be a power of 2 +#define TXTBUFFER_GROW 0x4000 + +/** Text buffer implementing efficient editing. +*/ +typedef struct txtbuffer_s { + struct txtbuffer_s *next; + char *text; + size_t textSize; ///< amount of text in the buffer + size_t bufferSize; ///< current capacity of the buffer + size_t gapOffset; ///< beginning of the gap + size_t gapSize; ///< size of gap. gapSize + textSize == bufferSize +} txtbuffer_t; + +/** Create a new, empty buffer. +*/ +txtbuffer_t *TextBuffer_Create (void); + +/** Destroy a buffer, freeing all resources connected to it. + \param buffer The buffer to destroy. +*/ +void TextBuffer_Destroy (txtbuffer_t *buffer); + +/** Insert a block of text at the specified offset. + + Text after the offset is moved to be after the inserted block of text. + The buffer is resized as necessary. + nul characters are not significant in that they do not mark the end of + the text to be inserted. + + \param buffer The buffer to be updated + \param offset The offset in the buffer at which to insert the text block + \param text The text block to be inserted. May contain nul ('\0') + characters. + \param text_len The number of characters to insert. + \return 1 for success, 0 for failure (offset not valid or out + of memory) +*/ +int TextBuffer_InsertAt (txtbuffer_t *buffer, size_t offset, + const char *text, size_t text_len); + +/** Delete a block of text from the buffer. + + The buffer is not resized. Rather, its capacity before resizing is require + is increased. + + \param buffer The buffer to be updated + \param offset The offset of the beginning of the text block to be deleted + \param len The amount of characters to be deleted. Values larger than + the amount of text in the buffer beyond the beginning of + block are truncated to the amount of remaining text. Thus + using excessivly large values sets the offset to be the + end of the buffer. + \return 1 for success, 0 for failure (offset not valid) +*/ +int TextBuffer_DeleteAt (txtbuffer_t *buffer, size_t offset, size_t len); + +///@} + +#endif//__QF_txtbuffer_h diff --git a/include/QF/uint32.h b/include/QF/uint32.h deleted file mode 100644 index 513117d01..000000000 --- a/include/QF/uint32.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - uint32.h - - Definitions for portable (?) unsigned int - - Copyright (C) 2000 Jeff Teunissen - - Author: Jeff Teunissen - Date: 01 Jan 2000 - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ - -#ifndef __uint32_h -#define __uint32_h - -#ifndef int32 -# if (SIZEOF_INT == 4) -# define int32 int -# elif (SIZEOF_LONG == 4) -# define int32 long -# elif (SIZEOF_SHORT == 4) -# define int32 short -# else -/* I hope this works */ -# define int32 int -# define LARGE_INT32 -# endif -#endif - -#ifndef uint32 -# define uint32 unsigned int32 -#endif - -#endif // __uint32_h diff --git a/include/QF/va.h b/include/QF/va.h index 40c794712..1bf0eadaf 100644 --- a/include/QF/va.h +++ b/include/QF/va.h @@ -26,8 +26,8 @@ */ -#ifndef __va_h -#define __va_h +#ifndef __QF_va_h +#define __QF_va_h /** \addtogroup misc Formatted printing. @@ -41,4 +41,4 @@ char *nva(const char *format, ...) __attribute__((format(printf,1,2))); ///@} -#endif // __va_h +#endif//__QF_va_h diff --git a/include/QF/ver_check.h b/include/QF/ver_check.h index 8ac943796..eaa4d9391 100644 --- a/include/QF/ver_check.h +++ b/include/QF/ver_check.h @@ -25,8 +25,8 @@ */ -#ifndef __ver_check_h_ -#define __ver_check_h_ +#ifndef __QF_ver_check_h +#define __QF_ver_check_h /** \defgroup utils Utils */ @@ -47,4 +47,4 @@ int ver_compare (const char *, const char *); ///@} -#endif // __ver_check_h_ +#endif//__QF_ver_check_h diff --git a/include/QF/vid.h b/include/QF/vid.h index e1228fcd7..19618f66c 100644 --- a/include/QF/vid.h +++ b/include/QF/vid.h @@ -25,8 +25,8 @@ */ -#ifndef __vid_h_ -#define __vid_h_ +#ifndef __QF_vid_h +#define __QF_vid_h #include "QF/qtypes.h" #include "QF/vrect.h" @@ -79,4 +79,4 @@ void VID_Init (byte *palette, byte *colormap); void VID_SetCaption (const char *text); void VID_ClearMemory (void); -#endif // __vid_h_ +#endif//__QF_vid_h diff --git a/include/QF/view.h b/include/QF/view.h index 570935ae8..5a6ae339f 100644 --- a/include/QF/view.h +++ b/include/QF/view.h @@ -28,8 +28,8 @@ */ -#ifndef __qf_view_h -#define __qf_view_h +#ifndef __QF_view_h +#define __QF_view_h /** \defgroup console_view Console View Objects \ingroup console @@ -217,4 +217,4 @@ void view_move (view_t *view, int xp, int yp); ///@} -#endif//__qf_view_h +#endif//__QF_view_h diff --git a/include/QF/wad.h b/include/QF/wad.h index 82e836dc9..2e6bb9c67 100644 --- a/include/QF/wad.h +++ b/include/QF/wad.h @@ -26,8 +26,8 @@ */ // wad.h -#ifndef _WAD_H -#define _WAD_H +#ifndef __QF_wad_h +#define __QF_wad_h /** \addtogroup wad Wad Files @@ -48,4 +48,4 @@ void SwapPic (qpic_t *pic); ///@} -#endif // _WAD_H +#endif//__QF_wad_h diff --git a/include/QF/zone.h b/include/QF/zone.h index 1f968737f..10063b2cc 100644 --- a/include/QF/zone.h +++ b/include/QF/zone.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __zone_h -#define __zone_h +#ifndef __QF_zone_h +#define __QF_zone_h /** \defgroup zone Memory Management \ingroup utils @@ -142,4 +142,4 @@ int Cache_ReadLock (cache_user_t *c) __attribute__((pure)); ///@} -#endif // __zone_h +#endif//__QF_zone_h diff --git a/include/rua_internal.h b/include/rua_internal.h index 0b6b34801..158d6e477 100644 --- a/include/rua_internal.h +++ b/include/rua_internal.h @@ -39,8 +39,6 @@ void RUA_Cmd_Init (struct progs_s *pr, int secure); void RUA_Cvar_Init (struct progs_s *pr, int secure); -void RUA_File_Init (struct progs_s *pr, int secure); - void RUA_Hash_Init (struct progs_s *pr, int secure); void RUA_Math_Init (struct progs_s *pr, int secure); diff --git a/libs/console/bi_inputline.c b/libs/console/bi_inputline.c index e4a936d6f..f48a4551e 100644 --- a/libs/console/bi_inputline.c +++ b/libs/console/bi_inputline.c @@ -130,9 +130,11 @@ bi_inputline_enter (inputline_t *il) P_POINTER (pr, 0) = data->data[0]; P_POINTER (pr, 1) = data->data[1]; P_STRING (pr, 2) = PR_SetTempString (pr, line); + pr->pr_argc = 3; } else { P_STRING (pr, 0) = PR_SetTempString (pr, line); P_POINTER (pr, 1) = data->data[0]; + pr->pr_argc = 2; } PR_ExecuteProgram (pr, data->enter); PR_PopFrame (pr); diff --git a/libs/console/buffer.c b/libs/console/buffer.c index d494c0655..2aa477abc 100644 --- a/libs/console/buffer.c +++ b/libs/console/buffer.c @@ -92,7 +92,7 @@ Con_BufferAddText (con_buffer_t *buf, const char *text) } while (len--) { byte c = *pos++ = *text++; - if ((size_t) (pos - buf->buffer) >= buf->buffer_size) + if (pos >= buf->buffer + buf->buffer_size) pos = buf->buffer; cur_line->len++; if (pos == tail_line->text) { diff --git a/libs/console/menu.c b/libs/console/menu.c index e65fff1cb..ec9fc3355 100644 --- a/libs/console/menu.c +++ b/libs/console/menu.c @@ -117,7 +117,7 @@ static int menu_resolve_globals (progs_t *pr) { const char *sym; - ddef_t *def; + pr_def_t *def; dfunction_t *f; size_t i; @@ -439,6 +439,7 @@ bi_Menu_Enter (progs_t *pr) P_STRING (&menu_pr_state, 0) = PR_SetTempString (&menu_pr_state, item->text); P_INT (&menu_pr_state, 1) = 0; + pr->pr_argc = 2; PR_ExecuteProgram (&menu_pr_state, item->func); PR_PopFrame (&menu_pr_state); run_menu_post (); @@ -510,9 +511,11 @@ menu_free_progs_mem (progs_t *pr, void *mem) } static void * -menu_load_file (progs_t *pr, const char *path) +menu_load_file (progs_t *pr, const char *path, off_t *size) { - return QFS_LoadFile (QFS_FOpenFile (path), 0); + void *data = QFS_LoadFile (QFS_FOpenFile (path), 0); + *size = qfs_filesize; + return data; } static builtin_t builtins[] = { @@ -581,6 +584,8 @@ Menu_Init (void) menu_pr_state.max_edicts = 0; menu_pr_state.zone_size = 1024 * 1024; + PR_Init (&menu_pr_state); + menu_hash = Hash_NewTable (61, menu_get_key, menu_free, 0); PR_RegisterBuiltins (&menu_pr_state, builtins); @@ -668,6 +673,7 @@ Menu_Draw (view_t *view) PR_RESET_PARAMS (&menu_pr_state); P_INT (&menu_pr_state, 0) = x; P_INT (&menu_pr_state, 1) = y; + menu_pr_state.pr_argc = 2; PR_ExecuteProgram (&menu_pr_state, menu->draw); ret = R_INT (&menu_pr_state); run_menu_post (); @@ -702,6 +708,7 @@ Menu_Draw (view_t *view) PR_RESET_PARAMS (&menu_pr_state); P_INT (&menu_pr_state, 0) = x + item->x; P_INT (&menu_pr_state, 1) = y + item->y; + menu_pr_state.pr_argc = 2; PR_ExecuteProgram (&menu_pr_state, menu->cursor); run_menu_post (); } else { @@ -734,6 +741,7 @@ Menu_KeyEvent (knum_t key, short unicode, qboolean down) P_INT (&menu_pr_state, 0) = key; P_INT (&menu_pr_state, 1) = unicode; P_INT (&menu_pr_state, 2) = down; + menu_pr_state.pr_argc = 3; PR_ExecuteProgram (&menu_pr_state, menu->keyevent); ret = R_INT (&menu_pr_state); run_menu_post (); @@ -748,6 +756,7 @@ Menu_KeyEvent (knum_t key, short unicode, qboolean down) P_STRING (&menu_pr_state, 0) = PR_SetTempString (&menu_pr_state, item->text); P_INT (&menu_pr_state, 1) = key; + menu_pr_state.pr_argc = 2; PR_ExecuteProgram (&menu_pr_state, item->func); PR_PopFrame (&menu_pr_state); ret = R_INT (&menu_pr_state); diff --git a/libs/gamecode/pr_builtins.c b/libs/gamecode/pr_builtins.c index a3ab8c9d9..7e4bb4431 100644 --- a/libs/gamecode/pr_builtins.c +++ b/libs/gamecode/pr_builtins.c @@ -47,7 +47,6 @@ #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/zone.h" -#include "QF/va.h" #include "compat.h" @@ -158,7 +157,8 @@ bi_no_function (progs_t *pr) VISIBLE int PR_RelocateBuiltins (progs_t *pr) { - pr_int_t i, ind; + pr_uint_t i; + pr_int_t ind; int bad = 0; dfunction_t *desc; bfunction_t *func; diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 174987135..d2ed5e7f1 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -52,7 +52,6 @@ #include "QF/quakefs.h" #include "QF/script.h" #include "QF/sys.h" -#include "QF/va.h" #include "QF/zone.h" #include "compat.h" @@ -65,17 +64,97 @@ typedef struct { typedef struct { char *name; char *text; + off_t size; line_t *lines; pr_uint_t num_lines; progs_t *pr; } file_t; +typedef struct prdeb_resources_s { + progs_t *pr; + dstring_t *string; + dstring_t *dva; + dstring_t *line; + dstring_t *dstr; + const char *debugfile; + struct pr_debug_header_s *debug; + struct pr_auxfunction_s *auxfunctions; + struct pr_auxfunction_s **auxfunction_map; + struct pr_lineno_s *linenos; + pr_def_t *local_defs; + pr_def_t *type_encodings_def; + qfot_type_t void_type; + qfot_type_t *type_encodings[ev_type_count]; +} prdeb_resources_t; + +typedef struct { + progs_t *pr; + dstring_t *dstr; +} pr_debug_data_t; + cvar_t *pr_debug; cvar_t *pr_source_path; static hashtab_t *file_hash; static char *source_path_string; static char **source_paths; +static void pr_debug_void_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_string_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_float_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_vector_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_entity_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_field_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_func_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_pointer_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_quat_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_integer_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_uinteger_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_short_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_double_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_struct_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_union_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_enum_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_array_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_class_view (qfot_type_t *type, pr_type_t *value, + void *_data); + +static type_view_t raw_type_view = { + pr_debug_void_view, + pr_debug_string_view, + pr_debug_float_view, + pr_debug_vector_view, + pr_debug_entity_view, + pr_debug_field_view, + pr_debug_func_view, + pr_debug_pointer_view, + pr_debug_quat_view, + pr_debug_integer_view, + pr_debug_uinteger_view, + pr_debug_short_view, + pr_debug_double_view, + pr_debug_struct_view, + pr_debug_union_view, + pr_debug_enum_view, + pr_debug_array_view, + pr_debug_class_view, +}; static const char * file_get_key (const void *_f, void *unused) @@ -101,50 +180,100 @@ source_path_f (cvar_t *var) int i; char *s; - if (source_path_string) + if (source_path_string) { free (source_path_string); + } source_path_string = strdup (var->string); - if (source_paths) + if (source_paths) { free (source_paths); - for (i = 2, s = source_path_string; *s; s++) - if (*s == ';') + } + // i starts at 2 because an empty path is equivalent to "." and the + // list is null terminated + for (i = 2, s = source_path_string; *s; s++) { + if (*s == ';') { i++; + } + } source_paths = malloc (i * sizeof (char *)); source_paths[0] = source_path_string; - for (i = 1, s = source_path_string; *s; s++) + // i starts at one because the first path is in 0 and any additional + // paths come after, then the null terminator + for (i = 1, s = source_path_string; *s; s++) { if (*s == ';') { - *s++ = 0; - source_paths[i++] = s; + *s = 0; + source_paths[i++] = s + 1; } + } source_paths[i] = 0; } -static void -pr_debug_expression_error (script_t *script, const char *msg) +#define RUP(x,a) (((x) + ((a) - 1)) & ~((a) - 1)) +static pr_short_t __attribute__((pure)) +pr_debug_type_size (const progs_t *pr, const qfot_type_t *type) { - Sys_Printf ("%s\n", msg); + pr_short_t size; + qfot_type_t *aux_type; + switch (type->meta) { + case ty_basic: + return pr_type_size[type->t.type]; + case ty_struct: + case ty_union: + size = 0; + for (pr_int_t i = 0; i < type->t.strct.num_fields; i++) { + const qfot_var_t *field = &type->t.strct.fields[i]; + aux_type = &G_STRUCT (pr, qfot_type_t, field->type); + size = max (size, + field->offset + pr_debug_type_size (pr, aux_type)); + } + return size; + case ty_enum: + return pr_type_size[ev_integer]; + case ty_array: + aux_type = &G_STRUCT (pr, qfot_type_t, type->t.array.type); + size = pr_debug_type_size (pr, aux_type); + return type->t.array.size * size; + case ty_class: + return 1; //FIXME or should it return sizeof class struct? + } + return 0; } -static ddef_t +static qfot_type_t * +get_def_type (progs_t *pr, pr_def_t *def, qfot_type_t *type) +{ + if (!def->type_encoding) { + // no type encoding, so use basic type data to fill in and return + // the dummy encoding + memset (type, 0, sizeof (*type)); + type->t.type = def->type; + } else { + type = &G_STRUCT (pr, qfot_type_t, def->type_encoding); + if (!def->size) { + def->size = pr_debug_type_size (pr, type); + } + } + return type; +} + +static pr_def_t parse_expression (progs_t *pr, const char *expr, int conditional) { script_t *es; char *e; pr_type_t *expr_ptr; - ddef_t d; + pr_def_t d; d.ofs = 0; d.type = ev_invalid; - d.s_name = 0; + d.name = 0; es = Script_New (); - es->error = pr_debug_expression_error; Script_Start (es, "", expr); expr_ptr = 0; es->single = "{}()':[]."; if (Script_GetToken (es, 1)) { if (strequal (es->token->str, "[")) { edict_t *ent; - ddef_t *field; + pr_def_t *field; if (!Script_GetToken (es, 1)) goto error; @@ -168,7 +297,7 @@ parse_expression (progs_t *pr, const char *expr, int conditional) d.type = ev_void; d.ofs = PR_SetPointer (pr, expr_ptr); } else { - ddef_t *global = PR_FindGlobal (pr, es->token->str); + pr_def_t *global = PR_FindGlobal (pr, es->token->str); if (!global) goto error; d = *global; @@ -194,29 +323,47 @@ parse_expression (progs_t *pr, const char *expr, int conditional) Sys_Printf ("ignoring tail\n"); } error: + if (es->error) { + Sys_Printf (es->error); + } Script_Delete (es); return d; } -void -PR_Debug_Init (void) +static void +pr_debug_clear (progs_t *pr, void *data) { - file_hash = Hash_NewTable (1024, file_get_key, file_free, 0); -} + __auto_type res = (prdeb_resources_t *) data; -void -PR_Debug_Init_Cvars (void) -{ - pr_debug = Cvar_Get ("pr_debug", "0", CVAR_NONE, NULL, - "enable progs debugging"); - pr_source_path = Cvar_Get ("pr_source_path", ".", CVAR_NONE, source_path_f, - "where to look (within gamedir) for source " - "files"); + dstring_clearstr (res->string); + dstring_clearstr (res->dva); + dstring_clearstr (res->line); + dstring_clearstr (res->dstr); + + if (res->debug) + pr->free_progs_mem (pr, res->debug); + res->debug = 0; + res->auxfunctions = 0; + if (res->auxfunction_map) + pr->free_progs_mem (pr, res->auxfunction_map); + res->auxfunction_map = 0; + res->linenos = 0; + res->local_defs = 0; + + pr->pr_debug_resources = res; + pr->watch = 0; + pr->wp_conditional = 0; + pr->wp_val.integer_var = 0; + + for (int i = 0; i < ev_type_count; i++ ) { + res->type_encodings[i] = &res->void_type; + } } static file_t * PR_Load_Source_File (progs_t *pr, const char *fname) { + prdeb_resources_t *res = pr->pr_debug_resources; char *l, *p, **dir; file_t *f = Hash_Find (file_hash, fname); @@ -226,8 +373,9 @@ PR_Load_Source_File (progs_t *pr, const char *fname) if (!f) return 0; for (dir = source_paths; *dir && !f->text; dir++) { - f->text = pr->load_file (pr, va ("%s%s%s", *dir, **dir ? "/" : "", - fname)); + f->text = pr->load_file (pr, dsprintf (res->dva, "%s%s%s", *dir, + **dir ? "/" : "", fname), + &f->size); } if (!f->text) { pr->file_error (pr, fname); @@ -271,21 +419,17 @@ PR_Load_Source_File (progs_t *pr, const char *fname) VISIBLE int PR_LoadDebug (progs_t *pr) { + prdeb_resources_t *res = PR_Resources_Find (pr, "PR_Debug"); char *sym_path; const char *path_end, *sym_file; + off_t debug_size; pr_uint_t i; - ddef_t *def; + pr_def_t *def; pr_type_t *str = 0; - - if (pr->debug) - pr->free_progs_mem (pr, pr->debug); - pr->debug = 0; - pr->auxfunctions = 0; - if (pr->auxfunction_map) - pr->free_progs_mem (pr, pr->auxfunction_map); - pr->auxfunction_map = 0; - pr->linenos = 0; - pr->local_defs = 0; + qfot_type_encodings_t *encodings = 0; + pointer_t type_encodings = 0; + pointer_t type_ptr; + qfot_type_t *type; if (!pr_debug->int_val) return 1; @@ -297,107 +441,194 @@ PR_LoadDebug (progs_t *pr) Hash_FlushTable (file_hash); if (!str) return 1; - pr->debugfile = PR_GetString (pr, str->string_var); - sym_file = QFS_SkipPath (pr->debugfile); + res->debugfile = PR_GetString (pr, str->string_var); + sym_file = QFS_SkipPath (res->debugfile); path_end = QFS_SkipPath (pr->progs_name); sym_path = malloc (strlen (sym_file) + (path_end - pr->progs_name) + 1); strncpy (sym_path, pr->progs_name, path_end - pr->progs_name); strcpy (sym_path + (path_end - pr->progs_name), sym_file); - pr->debug = pr->load_file (pr, sym_path); - if (!pr->debug) { + res->debug = pr->load_file (pr, sym_path, &debug_size); + if (!res->debug) { Sys_Printf ("can't load %s for debug info\n", sym_path); free (sym_path); return 1; } - pr->debug->version = LittleLong (pr->debug->version); - if (pr->debug->version != PROG_DEBUG_VERSION) { + res->debug->version = LittleLong (res->debug->version); + if (res->debug->version != PROG_DEBUG_VERSION) { Sys_Printf ("ignoring %s with unsupported version %x.%03x.%03x\n", sym_path, - (pr->debug->version >> 24) & 0xff, - (pr->debug->version >> 12) & 0xfff, - pr->debug->version & 0xfff); - pr->debug = 0; + (res->debug->version >> 24) & 0xff, + (res->debug->version >> 12) & 0xfff, + res->debug->version & 0xfff); + res->debug = 0; free (sym_path); return 1; } - pr->debug->crc = LittleShort (pr->debug->crc); - if (pr->debug->crc != pr->crc) { + res->debug->crc = LittleShort (res->debug->crc); + if (res->debug->crc != pr->crc) { Sys_Printf ("ignoring %s that doesn't match %s. (CRCs: " "sym:%d dat:%d)\n", sym_path, pr->progs_name, - pr->debug->crc, + res->debug->crc, pr->crc); - pr->debug = 0; + res->debug = 0; free (sym_path); return 1; } free (sym_path); - pr->debug->you_tell_me_and_we_will_both_know = LittleShort - (pr->debug->you_tell_me_and_we_will_both_know); - pr->debug->auxfunctions = LittleLong (pr->debug->auxfunctions); - pr->debug->num_auxfunctions = LittleLong (pr->debug->num_auxfunctions); - pr->debug->linenos = LittleLong (pr->debug->linenos); - pr->debug->num_linenos = LittleLong (pr->debug->num_linenos); - pr->debug->locals = LittleLong (pr->debug->locals); - pr->debug->num_locals = LittleLong (pr->debug->num_locals); + res->debug->you_tell_me_and_we_will_both_know = LittleShort + (res->debug->you_tell_me_and_we_will_both_know); + res->debug->auxfunctions = LittleLong (res->debug->auxfunctions); + res->debug->num_auxfunctions = LittleLong (res->debug->num_auxfunctions); + res->debug->linenos = LittleLong (res->debug->linenos); + res->debug->num_linenos = LittleLong (res->debug->num_linenos); + res->debug->locals = LittleLong (res->debug->locals); + res->debug->num_locals = LittleLong (res->debug->num_locals); - pr->auxfunctions = (pr_auxfunction_t*)((char*)pr->debug + - pr->debug->auxfunctions); - pr->linenos = (pr_lineno_t*)((char*)pr->debug + pr->debug->linenos); - pr->local_defs = (ddef_t*)((char*)pr->debug + pr->debug->locals); + res->auxfunctions = (pr_auxfunction_t*)((char*)res->debug + + res->debug->auxfunctions); + res->linenos = (pr_lineno_t*)((char*)res->debug + res->debug->linenos); + res->local_defs = (pr_def_t*)((char*)res->debug + res->debug->locals); i = pr->progs->numfunctions * sizeof (pr_auxfunction_t *); - pr->auxfunction_map = pr->allocate_progs_mem (pr, i); - for (i = 0; (int) i < pr->progs->numfunctions; i++) //FIXME (cast) - pr->auxfunction_map[i] = 0; + res->auxfunction_map = pr->allocate_progs_mem (pr, i); + for (i = 0; i < pr->progs->numfunctions; i++) + res->auxfunction_map[i] = 0; - for (i = 0; i < pr->debug->num_auxfunctions; i++) { - pr->auxfunctions[i].function = LittleLong - (pr->auxfunctions[i].function); - pr->auxfunctions[i].source_line = LittleLong - (pr->auxfunctions[i].source_line); - pr->auxfunctions[i].line_info = LittleLong - (pr->auxfunctions[i].line_info); - pr->auxfunctions[i].local_defs = LittleLong - (pr->auxfunctions[i].local_defs); - pr->auxfunctions[i].num_locals = LittleLong - (pr->auxfunctions[i].num_locals); + res->type_encodings_def = PR_FindGlobal (pr, ".type_encodings"); + if (res->type_encodings_def) { + encodings = &G_STRUCT (pr, qfot_type_encodings_t, + res->type_encodings_def->ofs); + type_encodings = encodings->types; + } + for (i = 0; i < res->debug->num_auxfunctions; i++) { + res->auxfunctions[i].function = LittleLong + (res->auxfunctions[i].function); + res->auxfunctions[i].source_line = LittleLong + (res->auxfunctions[i].source_line); + res->auxfunctions[i].line_info = LittleLong + (res->auxfunctions[i].line_info); + res->auxfunctions[i].local_defs = LittleLong + (res->auxfunctions[i].local_defs); + res->auxfunctions[i].num_locals = LittleLong + (res->auxfunctions[i].num_locals); - pr->auxfunction_map[pr->auxfunctions[i].function] = - &pr->auxfunctions[i]; + if (type_encodings) { + res->auxfunctions[i].return_type += type_encodings; + } + res->auxfunction_map[res->auxfunctions[i].function] = + &res->auxfunctions[i]; } - for (i = 0; i < pr->debug->num_linenos; i++) { - pr->linenos[i].fa.func = LittleLong (pr->linenos[i].fa.func); - pr->linenos[i].line = LittleLong (pr->linenos[i].line); + for (i = 0; i < res->debug->num_linenos; i++) { + res->linenos[i].fa.func = LittleLong (res->linenos[i].fa.func); + res->linenos[i].line = LittleLong (res->linenos[i].line); } - for (i = 0; i < pr->debug->num_locals; i++) { - pr->local_defs[i].type = LittleShort (pr->local_defs[i].type); - pr->local_defs[i].ofs = LittleShort (pr->local_defs[i].ofs); - pr->local_defs[i].s_name = LittleLong (pr->local_defs[i].s_name); + for (i = 0; i < res->debug->num_locals; i++) { + res->local_defs[i].type = LittleShort (res->local_defs[i].type); + res->local_defs[i].size = LittleShort (res->local_defs[i].size); + res->local_defs[i].ofs = LittleLong (res->local_defs[i].ofs); + res->local_defs[i].name = LittleLong (res->local_defs[i].name); + res->local_defs[i].type_encoding + = LittleLong (res->local_defs[i].type_encoding); + if (type_encodings) { + res->local_defs[i].type_encoding += type_encodings; + } + } + if (encodings) { + for (type_ptr = 4; type_ptr < encodings->size; + type_ptr += type->size) { + type = &G_STRUCT (pr, qfot_type_t, type_encodings + type_ptr); + if (type->meta == ty_basic + && type->t.type >= 0 && type->t.type < ev_type_count) { + res->type_encodings[type->t.type] = type; + } + } } return 1; } +VISIBLE pr_auxfunction_t * +PR_Debug_AuxFunction (progs_t *pr, pr_uint_t func) +{ + prdeb_resources_t *res = pr->pr_debug_resources; + if (!res->debug || func >= res->debug->num_auxfunctions) { + return 0; + } + return &res->auxfunctions[func]; +} + +VISIBLE pr_auxfunction_t * +PR_Debug_MappedAuxFunction (progs_t *pr, pr_uint_t func) +{ + prdeb_resources_t *res = pr->pr_debug_resources; + if (!res->debug || func >= pr->progs->numfunctions) { + return 0; + } + return res->auxfunction_map[func]; +} + +VISIBLE pr_def_t * +PR_Debug_LocalDefs (progs_t *pr, pr_auxfunction_t *aux_function) +{ + prdeb_resources_t *res = pr->pr_debug_resources; + if (!res->debug || !aux_function) { + return 0; + } + if (aux_function->local_defs > res->debug->num_locals) { + return 0; + } + return res->local_defs + aux_function->local_defs; +} + +VISIBLE pr_lineno_t * +PR_Debug_Linenos (progs_t *pr, pr_auxfunction_t *aux_function, + pr_uint_t *num_linenos) +{ + pr_uint_t i, count; + prdeb_resources_t *res = pr->pr_debug_resources; + if (!res->debug) { + return 0; + } + if (!aux_function) { + *num_linenos = res->debug->num_linenos; + return res->linenos; + } + if (aux_function->line_info > res->debug->num_linenos) { + return 0; + } + //FIXME put lineno count in sym file + for (count = 1, i = aux_function->line_info + 1; + i < res->debug->num_linenos; i++, count++) { + if (!res->linenos[i].line) { + break; + } + } + *num_linenos = count; + return res->linenos + aux_function->line_info; +} + pr_auxfunction_t * PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno) { - while (lineno > pr->linenos && lineno->line) + prdeb_resources_t *res = pr->pr_debug_resources; + while (lineno > res->linenos && lineno->line) lineno--; if (lineno->line) return 0; - return &pr->auxfunctions[lineno->fa.func]; + return &res->auxfunctions[lineno->fa.func]; } pr_uint_t PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno) { + prdeb_resources_t *res = pr->pr_debug_resources; pr_auxfunction_t *f; if (lineno->line) return lineno->fa.addr; - if (lineno->fa.func < pr->debug->num_auxfunctions) { - f = &pr->auxfunctions[lineno->fa.func]; + if (lineno->fa.func < res->debug->num_auxfunctions) { + f = &res->auxfunctions[lineno->fa.func]; return pr->pr_functions[f->function].first_statement; } // take a wild guess that only the line number is bogus and return @@ -416,16 +647,17 @@ PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno) pr_lineno_t * PR_Find_Lineno (progs_t *pr, pr_uint_t addr) { + prdeb_resources_t *res = pr->pr_debug_resources; pr_uint_t i; pr_lineno_t *lineno = 0; - if (!pr->debug) + if (!res->debug) return 0; - if (!pr->debug->num_linenos) + if (!res->debug->num_linenos) return 0; - for (i = pr->debug->num_linenos; i > 0; i--) { - if (PR_Get_Lineno_Addr (pr, &pr->linenos[i - 1]) <= addr) { - lineno = &pr->linenos[i - 1]; + for (i = res->debug->num_linenos; i > 0; i--) { + if (PR_Get_Lineno_Addr (pr, &res->linenos[i - 1]) <= addr) { + lineno = &res->linenos[i - 1]; break; } } @@ -446,6 +678,7 @@ PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno) const char * PR_Get_Source_Line (progs_t *pr, pr_uint_t addr) { + prdeb_resources_t *res = pr->pr_debug_resources; const char *fname; pr_uint_t line; file_t *file; @@ -465,22 +698,24 @@ PR_Get_Source_Line (progs_t *pr, pr_uint_t addr) file = PR_Load_Source_File (pr, fname); if (!file || !file->lines || !line || line > file->num_lines) - return va ("%s:%u", fname, line); + return dsprintf (res->dva, "%s:%u", fname, line); - return va ("%s:%u:%.*s", fname, line, (int)file->lines[line - 1].len, - file->lines[line - 1].text); + return dsprintf (res->dva, "%s:%u:%.*s", fname, line, + (int)file->lines[line - 1].len, + file->lines[line - 1].text); } -ddef_t * +pr_def_t * PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) { + prdeb_resources_t *res = pr->pr_debug_resources; pr_uint_t i; pr_auxfunction_t *aux_func; - ddef_t *ddef = 0; + pr_def_t *ddef = 0; int num_params; int param_offs = 0; - if (!pr->debug) + if (!res->debug) return 0; if (!func) return 0; @@ -493,12 +728,12 @@ PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) if (parm >= (unsigned) num_params) return 0; - aux_func = pr->auxfunction_map[func - pr->pr_functions]; + aux_func = res->auxfunction_map[func - pr->pr_functions]; if (!aux_func) return 0; for (i = 0; i < aux_func->num_locals; i++) { - ddef = &pr->local_defs[aux_func->local_defs + param_offs + i]; + ddef = &res->local_defs[aux_func->local_defs + param_offs + i]; if (!parm--) break; } @@ -508,62 +743,58 @@ PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) static pr_auxfunction_t * get_aux_function (progs_t *pr) { + prdeb_resources_t *res = pr->pr_debug_resources; dfunction_t *func; - if (!pr->pr_xfunction || !pr->auxfunction_map) + if (!pr->pr_xfunction || !res->auxfunction_map) return 0; func = pr->pr_xfunction->descriptor; - return pr->auxfunction_map[func - pr->pr_functions]; + return res->auxfunction_map[func - pr->pr_functions]; } -static etype_t -get_etype (progs_t *pr, int typeptr) +static qfot_type_t * +get_type (prdeb_resources_t *res, int typeptr) { - //FIXME cache .type_encodings def - ddef_t *te_def = PR_FindGlobal (pr, ".type_encodings"); - qfot_type_encodings_t *encodings; - qfot_type_t *type; + progs_t *pr = res->pr; - if (!te_def) { - // can't decode the type, so make no assumptions about it - return typeptr; + if (!typeptr) { + return &res->void_type; } - encodings = &G_STRUCT (pr, qfot_type_encodings_t, te_def->ofs); - type = &G_STRUCT (pr, qfot_type_t, encodings->types + typeptr); - if (type->meta == 0) { - return type->t.type; - } - return ev_void; + return &G_STRUCT (pr, qfot_type_t, typeptr); } -ddef_t * -PR_Get_Local_Def (progs_t *pr, pr_int_t offs) +pr_def_t * +PR_Get_Local_Def (progs_t *pr, pointer_t *offset) { - pr_uint_t i; + prdeb_resources_t *res = pr->pr_debug_resources; dfunction_t *func; pr_auxfunction_t *aux_func; + pointer_t offs = *offset; + pr_def_t *def; if (!pr->pr_xfunction) return 0; func = pr->pr_xfunction->descriptor; if (!func) return 0; - aux_func = pr->auxfunction_map[func - pr->pr_functions]; + aux_func = res->auxfunction_map[func - pr->pr_functions]; if (!aux_func) return 0; offs -= func->parm_start; - if (offs < 0 || offs >= func->locals) + if (offs >= func->locals) return 0; - for (i = 0; i < aux_func->num_locals; i++) - if (pr->local_defs[aux_func->local_defs + i].ofs == offs) - return &pr->local_defs[aux_func->local_defs + i]; - return 0; + if ((def = PR_SearchDefs (res->local_defs + aux_func->local_defs, + aux_func->num_locals, offs))) { + *offset = offs - def->ofs; + } + return def; } VISIBLE void PR_DumpState (progs_t *pr) { + prdeb_resources_t *res = pr->pr_debug_resources; if (pr->pr_xfunction) { - if (pr_debug->int_val && pr->debug) { + if (pr_debug->int_val && res->debug) { pr_lineno_t *lineno; pr_auxfunction_t *func = 0; dfunction_t *descriptor = pr->pr_xfunction->descriptor; @@ -588,187 +819,416 @@ PR_DumpState (progs_t *pr) #define ISDENORM(x) ((x) && !((x) & 0x7f800000)) static const char * -value_string (progs_t *pr, etype_t type, pr_type_t *val) +value_string (pr_debug_data_t *data, qfot_type_t *type, pr_type_t *value) { - static dstring_t *line; - ddef_t *def; - pr_int_t ofs; - edict_t *edict; - dfunction_t *f; - const char *str; - - if (!line) - line = dstring_new (); - - type &= ~DEF_SAVEGLOBAL; - - switch (type) { - case ev_string: - if (!PR_StringValid (pr, val->string_var)) - return "*** invalid ***"; - str = PR_GetString (pr, val->string_var); - dstring_copystr (line, "\""); - while (*str) { - const char *s; - - for (s = str; *s && !strchr ("\"\n\t", *s); s++) - ; - if (s != str) - dstring_appendsubstr (line, str, s - str); - if (*s) { - switch (*s) { - case '\"': - dstring_appendstr (line, "\\\""); - break; - case '\n': - dstring_appendstr (line, "\\n"); - break; - case '\t': - dstring_appendstr (line, "\\t"); - break; - default: - dasprintf (line, "\\x%02x", *s & 0xff); - } - s++; - } - str = s; - } - dstring_appendstr (line, "\""); - break; - case ev_entity: - edict = PROG_TO_EDICT (pr, val->entity_var); - dsprintf (line, "entity %d", NUM_FOR_BAD_EDICT (pr, edict)); - break; - case ev_func: - if (val->func_var < 0 || val->func_var >= pr->progs->numfunctions) - dsprintf (line, "INVALID:%d", val->func_var); - else if (!val->func_var) - return "NULL"; - else { - f = pr->pr_functions + val->func_var; - dsprintf (line, "%s()", PR_GetString (pr, f->s_name)); + switch (type->meta) { + case ty_basic: + switch (type->t.type) { + case ev_void: + raw_type_view.void_view (type, value, data); + break; + case ev_string: + raw_type_view.string_view (type, value, data); + break; + case ev_float: + raw_type_view.float_view (type, value, data); + break; + case ev_vector: + raw_type_view.vector_view (type, value, data); + break; + case ev_entity: + raw_type_view.entity_view (type, value, data); + break; + case ev_field: + raw_type_view.field_view (type, value, data); + break; + case ev_func: + raw_type_view.func_view (type, value, data); + break; + case ev_pointer: + raw_type_view.pointer_view (type, value, data); + break; + case ev_quat: + raw_type_view.quat_view (type, value, data); + break; + case ev_integer: + raw_type_view.integer_view (type, value, data); + break; + case ev_uinteger: + raw_type_view.uinteger_view (type, value, data); + break; + case ev_short: + raw_type_view.short_view (type, value, data); + break; + case ev_double: + raw_type_view.double_view (type, value, data); + break; + case ev_invalid: + case ev_type_count: + dstring_appendstr (data->dstr, ""); } break; - case ev_field: - def = PR_FieldAtOfs (pr, val->integer_var); - if (def) - dsprintf (line, ".%s", PR_GetString (pr, def->s_name)); - else - dsprintf (line, ".<$%04x>", val->integer_var); + case ty_struct: + raw_type_view.struct_view (type, value, data); break; - case ev_void: - return "void"; - case ev_float: - if (ISDENORM (val->integer_var) && val->uinteger_var != 0x80000000) - dsprintf (line, "<%08x>", val->integer_var); - else - dsprintf (line, "%g", val->float_var); + case ty_union: + raw_type_view.union_view (type, value, data); break; - case ev_vector: - dsprintf (line, "'%g %g %g'", - val->vector_var[0], val->vector_var[1], - val->vector_var[2]); + case ty_enum: + raw_type_view.enum_view (type, value, data); break; - case ev_pointer: - def = 0; - ofs = val->integer_var; - if (pr_debug->int_val && pr->debug) - def = PR_Get_Local_Def (pr, ofs); - if (!def) - def = PR_GlobalAtOfs (pr, ofs); - if (def && def->s_name) - dsprintf (line, "&%s", PR_GetString (pr, def->s_name)); - else - dsprintf (line, "[$%x]", ofs); + case ty_array: + raw_type_view.array_view (type, value, data); break; - case ev_quat: - dsprintf (line, "'%g %g %g %g'", - val->vector_var[0], val->vector_var[1], - val->vector_var[2], val->vector_var[3]); - break; - case ev_integer: - dsprintf (line, "%d", val->integer_var); - break; - case ev_uinteger: - dsprintf (line, "$%08x", val->uinteger_var); - break; - case ev_double: - dsprintf (line, "%g", *(double *)val); - break; - case ev_short: - case ev_invalid: - case ev_type_count: - //dsprintf (line, "bad type %i", type); - dsprintf (line, "<%x %x %x %x>", - val[0].integer_var, val[1].integer_var, - val[2].integer_var, val[3].integer_var); + case ty_class: + raw_type_view.class_view (type, value, data); break; } - - return line->str; + return data->dstr->str; } -static ddef_t * -def_string (progs_t *pr, pr_int_t ofs, dstring_t *dstr) +static pr_def_t * +pr_debug_find_def (progs_t *pr, pointer_t *ofs) { - ddef_t *def = 0; - const char *name; + prdeb_resources_t *res = pr->pr_debug_resources; + pr_def_t *def = 0; - if (pr_debug->int_val && pr->debug) + if (*ofs >= pr->progs->numglobals) { + return 0; + } + if (pr_debug->int_val && res->debug) { def = PR_Get_Local_Def (pr, ofs); - if (!def) - def = PR_GlobalAtOfs (pr, ofs); - if (!def || !*(name = PR_GetString (pr, def->s_name))) - dsprintf (dstr, "[$%x]", ofs); - else - dsprintf (dstr, "%s", name); + } + if (!def) { + def = PR_GlobalAtOfs (pr, *ofs); + if (def) { + *ofs -= def->ofs; + } + } return def; } static const char * -global_string (progs_t *pr, pointer_t ofs, etype_t type, int contents) +global_string (pr_debug_data_t *data, pointer_t offset, qfot_type_t *type, + int contents) { - static dstring_t *line = NULL; - ddef_t *def = NULL; - const char *s; + progs_t *pr = data->pr; + prdeb_resources_t *res = pr->pr_debug_resources; + dstring_t *dstr = data->dstr; + pr_def_t *def = NULL; + qfot_type_t dummy_type = { }; + const char *name = 0; + pointer_t offs = offset; - if (!line) - line = dstring_newstr(); + dstring_clearstr (dstr); - if (type == ev_short) { - dsprintf (line, "%04x", (short) ofs); - return line->str; + if (type && type->meta == ty_basic && type->t.type == ev_short) { + dsprintf (dstr, "%04x", (short) offset); + return dstr->str; } - def = def_string (pr, ofs, line); + if (offset > pr->globals_size) { + dsprintf (dstr, "%08x out of bounds", offset); + return dstr->str; + } - if (contents && (def || type != ev_void)) { - const char *oi = ""; - if (def) { - if (type == ev_void) - type = def->type; - if (type != (etype_t) (def->type & ~DEF_SAVEGLOBAL)) - oi = "?"; - } - - if (ofs > pr->globals_size) - s = "Out of bounds"; - else - s = value_string (pr, type, &pr->pr_globals[ofs]); - - if (strequal(line->str, "IMMEDIATE") || strequal(line->str, ".imm")) { - dsprintf (line, "%s", s); + def = pr_debug_find_def (pr, &offs); + if (!def || !PR_StringValid (pr, def->name) + || !*(name = PR_GetString (pr, def->name))) { + dsprintf (dstr, "[$%x]", offset); + } + if (name) { + if (strequal (name, "IMMEDIATE") || strequal (name, ".imm")) { + contents = 1; } else { - dasprintf (line, "%s(%s)", oi, s); + if (offs) { + dsprintf (dstr, "{%s + %u}", name, offs); + } else { + dsprintf (dstr, "%s", name); + } } } - return line->str; + if (contents) { + if (name) { + dstring_appendstr (dstr, "("); + } + if (!type) { + if (def) { + if (!def->type_encoding) { + dummy_type.t.type = def->type; + type = &dummy_type; + } else { + type = &G_STRUCT (pr, qfot_type_t, def->type_encoding); + } + } else { + type = &res->void_type; + } + } + value_string (data, type, pr->pr_globals + offset); + if (name) { + dstring_appendstr (dstr, ")"); + } + } + return dstr->str; +} + +static void +pr_debug_void_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dasprintf (data->dstr, ""); +} + +static void +pr_debug_string_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + string_t string = value->string_var; + if (PR_StringValid (data->pr, string)) { + const char *str = PR_GetString (data->pr, string); + + dstring_appendstr (dstr, "\""); + while (*str) { + const char *s; + + for (s = str; *s && !strchr ("\"\n\t", *s); s++) { + } + if (s != str) { + dstring_appendsubstr (dstr, str, s - str); + } + if (*s) { + switch (*s) { + case '\"': + dstring_appendstr (dstr, "\\\""); + break; + case '\n': + dstring_appendstr (dstr, "\\n"); + break; + case '\t': + dstring_appendstr (dstr, "\\t"); + break; + default: + dasprintf (dstr, "\\x%02x", *s & 0xff); + } + s++; + } + str = s; + } + dstring_appendstr (dstr, "\""); + } else { + dstring_appendstr (dstr, "*** invalid string offset ***"); + } +} + +static void +pr_debug_float_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + if (data->pr->progs->version == PROG_ID_VERSION + && ISDENORM (value->integer_var) + && value->uinteger_var != 0x80000000) { + dasprintf (dstr, "<%08x>", value->integer_var); + } else { + dasprintf (dstr, "%.9g", value->float_var); + } +} + +static void +pr_debug_vector_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "'%.9g %.9g %.9g'", + value->vector_var[0], value->vector_var[1], + value->vector_var[2]); +} + +static void +pr_debug_entity_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + + if (pr->edicts) { + edict_t *edict = PROG_TO_EDICT (pr, value->entity_var); + dasprintf (dstr, "entity %d", NUM_FOR_BAD_EDICT (pr, edict)); + } else { + dasprintf (dstr, "entity [%x]",value->entity_var); + } +} + +static void +pr_debug_field_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + pr_def_t *def = PR_FieldAtOfs (pr, value->integer_var); + + if (def) { + dasprintf (dstr, ".%s", PR_GetString (pr, def->name)); + } else { + dasprintf (dstr, ".<$%04x>", value->integer_var); + } +} + +static void +pr_debug_func_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + + if (value->func_var >= pr->progs->numfunctions) { + dasprintf (dstr, "INVALID:%d", value->func_var); + } else if (!value->func_var) { + dstring_appendstr (dstr, "NULL"); + } else { + dfunction_t *f = pr->pr_functions + value->func_var; + dasprintf (dstr, "%s()", PR_GetString (pr, f->s_name)); + } +} + +static void +pr_debug_pointer_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + pointer_t offset = value->integer_var; + pointer_t offs = offset; + pr_def_t *def = 0; + + def = pr_debug_find_def (pr, &offs); + if (def && def->name) { + if (offs) { + dasprintf (dstr, "&%s + %u", PR_GetString (pr, def->name), offs); + } else { + dasprintf (dstr, "&%s", PR_GetString (pr, def->name)); + } + } else { + dasprintf (dstr, "[$%x]", offset); + } +} + +static void +pr_debug_quat_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "'%.9g %.9g %.9g %.9g'", + value->vector_var[0], value->vector_var[1], + value->vector_var[2], value->vector_var[3]); +} + +static void +pr_debug_integer_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "%d", value->integer_var); +} + +static void +pr_debug_uinteger_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "$%08x", value->uinteger_var); +} + +static void +pr_debug_short_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "%04x", (short)value->integer_var); +} + +static void +pr_debug_double_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "%.17g", *(double *)value); +} + +static void +pr_dump_struct (qfot_type_t *type, pr_type_t *value, void *_data, + const char *struct_type) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + qfot_struct_t *strct = &type->t.strct; + + dstring_appendstr (dstr, "{"); + for (int i = 0; i < strct->num_fields; i++) { + qfot_var_t *field = strct->fields + i; + qfot_type_t *val_type = &G_STRUCT (pr, qfot_type_t, field->type); + pr_type_t *val = value + field->offset; + dasprintf (dstr, "%s=", PR_GetString (pr, field->name)); + value_string (data, val_type, val); + if (i < strct->num_fields - 1) { + dstring_appendstr (dstr, ", "); + } + } + dstring_appendstr (dstr, "}"); + //dasprintf (dstr, "<%s>", struct_type); +} +static void +pr_debug_struct_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + pr_dump_struct (type, value, _data, "struct"); +} + +static void +pr_debug_union_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + pr_dump_struct (type, value, _data, "union"); +} + +static void +pr_debug_enum_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dstring_appendstr (dstr, ""); +} + +static void +pr_debug_array_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dstring_appendstr (dstr, ""); +} + +static void +pr_debug_class_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dstring_appendstr (dstr, ""); } VISIBLE void PR_Debug_Watch (progs_t *pr, const char *expr) { - ddef_t watch; + pr_def_t watch; if (!expr) { Sys_Printf ("watch \n"); if (pr->watch) { @@ -777,8 +1237,7 @@ PR_Debug_Watch (progs_t *pr, const char *expr) if (pr->wp_conditional) Sys_Printf (" if new val == %d\n", pr->wp_val.integer_var); - } else { - Sys_Printf (" none active\n"); + } else { Sys_Printf (" none active\n"); } return; } @@ -799,7 +1258,9 @@ PR_Debug_Watch (progs_t *pr, const char *expr) VISIBLE void PR_Debug_Print (progs_t *pr, const char *expr) { - ddef_t print; + prdeb_resources_t *res = pr->pr_debug_resources; + pr_def_t print; + pr_debug_data_t data = {pr, res->dstr}; if (!expr) { Sys_Printf ("print \n"); @@ -807,8 +1268,9 @@ PR_Debug_Print (progs_t *pr, const char *expr) } print = parse_expression (pr, expr, 0); - if (print.type != ev_invalid) { - const char *s = global_string (pr, print.ofs, print.type, 1); + if (print.type_encoding) { + qfot_type_t *type = get_type (res, print.type_encoding); + const char *s = global_string (&data, print.ofs, type, 1); Sys_Printf ("[%d] = %s\n", print.ofs, s); } } @@ -816,28 +1278,29 @@ PR_Debug_Print (progs_t *pr, const char *expr) VISIBLE void PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) { + prdeb_resources_t *res = pr->pr_debug_resources; int addr = s - pr->pr_statements; int dump_code = contents & 2; const char *fmt; opcode_t *op; - static dstring_t *line; dfunction_t *call_func = 0; - ddef_t *parm_def = 0; + pr_def_t *parm_def = 0; pr_auxfunction_t *aux_func = 0; + pr_debug_data_t data; - if (!line) - line = dstring_new (); + dstring_clearstr (res->line); - dstring_clearstr (line); + data.pr = pr; + data.dstr = res->dstr; if (pr_debug->int_val > 1) dump_code = 1; - if (pr_debug->int_val && pr->debug) { + if (pr_debug->int_val && res->debug) { const char *source_line = PR_Get_Source_Line (pr, addr); if (source_line) { - dasprintf (line, "%s%s", source_line, dump_code ? "\n" : ""); + dasprintf (res->line, "%s%s", source_line, dump_code ? "\n" : ""); if (!dump_code) goto do_print; } @@ -847,34 +1310,35 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) op = PR_Opcode (s->op); if (!op) { - Sys_Printf ("%sUnknown instruction %d\n", line->str, s->op); + Sys_Printf ("%sUnknown instruction %d\n", res->line->str, s->op); return; } if (!(fmt = op->fmt)) fmt = "%Ga, %Gb, %gc"; - dasprintf (line, "%04x ", addr); + dasprintf (res->line, "%04x ", addr); if (pr_debug->int_val > 2) - dasprintf (line, "%02x %04x(%8s) %04x(%8s) %04x(%8s)\t", + dasprintf (res->line, "%02x %04x(%8s) %04x(%8s) %04x(%8s)\t", s->op, s->a, pr_type_name[op->type_a], s->b, pr_type_name[op->type_b], s->c, pr_type_name[op->type_c]); - dasprintf (line, "%s ", op->opname); + dasprintf (res->line, "%s ", op->opname); while (*fmt) { if (*fmt == '%') { if (fmt[1] == '%') { - dstring_appendsubstr (line, fmt + 1, 1); + dstring_appendsubstr (res->line, fmt + 1, 1); fmt += 2; } else { const char *str; char mode = fmt[1], opchar = fmt[2]; unsigned parm_ind = 0; pr_int_t opval; - etype_t optype = ev_void; + qfot_type_t *optype = &res->void_type; + func_t func; if (mode == 'P') { opchar = fmt[3]; @@ -887,15 +1351,15 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) switch (opchar) { case 'a': opval = s->a; - optype = op->type_a; + optype = res->type_encodings[op->type_a]; break; case 'b': opval = s->b; - optype = op->type_b; + optype = res->type_encodings[op->type_b]; break; case 'c': opval = s->c; - optype = op->type_c; + optype = res->type_encodings[op->type_c]; break; case 'x': if (mode == 'P') { @@ -908,40 +1372,48 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) } switch (mode) { case 'R': - optype = ev_void; + optype = &res->void_type; aux_func = get_aux_function (pr); - if (aux_func) - optype = get_etype (pr, aux_func->return_type); - str = global_string (pr, opval, optype, contents & 1); + if (aux_func) { + optype = get_type (res, aux_func->return_type); + } + str = global_string (&data, opval, optype, + contents & 1); break; case 'F': - str = global_string (pr, opval, optype, contents & 1); - if (G_FUNCTION (pr, opval) >= 0 - && G_FUNCTION (pr, opval) - < pr->progs->numfunctions) - call_func = pr->pr_functions + G_FUNCTION (pr, opval); + str = global_string (&data, opval, optype, + contents & 1); + func = G_FUNCTION (pr, opval); + if (func < pr->progs->numfunctions) { + call_func = pr->pr_functions + func; + } break; case 'P': parm_def = PR_Get_Param_Def (pr, call_func, parm_ind); - optype = ev_void; - if (parm_def) - optype = parm_def->type; - str = global_string (pr, opval, optype, contents & 1); + optype = &res->void_type; + if (parm_def) { + optype = get_type (res, parm_def->type_encoding); + } + str = global_string (&data, opval, optype, + contents & 1); break; case 'V': - str = global_string (pr, opval, ev_void, contents & 1); + str = global_string (&data, opval, ev_void, + contents & 1); break; case 'G': - str = global_string (pr, opval, optype, contents & 1); + str = global_string (&data, opval, optype, + contents & 1); break; case 'g': - str = global_string (pr, opval, optype, 0); + str = global_string (&data, opval, optype, 0); break; case 's': - str = va ("%d", (short) opval); + str = dsprintf (res->dva, "%d", (short) opval); break; case 'O': - str = va ("%04x", addr + (short) opval); + str = dsprintf (res->dva, "%04x", + addr + (short) opval); break; case 'E': { @@ -958,39 +1430,41 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) str = "bad entity.field"; break; } - str = global_string (pr, opval, optype, + str = global_string (&data, opval, optype, contents & 1); - str = va ("$%x $%x %s", s->a, s->b, str); + str = dsprintf (res->dva, "$%x $%x %s", + s->a, s->b, str); } break; default: goto err; } - dstring_appendstr (line, str); + dstring_appendstr (res->line, str); fmt += 3; continue; err: - dstring_appendstr (line, fmt); + dstring_appendstr (res->line, fmt); break; } } else { - dstring_appendsubstr (line, fmt++, 1); + dstring_appendsubstr (res->line, fmt++, 1); } } do_print: - Sys_Printf ("%s\n", line->str); + Sys_Printf ("%s\n", res->line->str); } static void dump_frame (progs_t *pr, prstack_t *frame) { + prdeb_resources_t *res = pr->pr_debug_resources; dfunction_t *f = frame->f ? frame->f->descriptor : 0; if (!f) { Sys_Printf ("\n"); return; } - if (pr_debug->int_val && pr->debug) { + if (pr_debug->int_val && res->debug) { pr_lineno_t *lineno = PR_Find_Lineno (pr, frame->s); pr_auxfunction_t *func = PR_Get_Lineno_Func (pr, lineno); pr_uint_t line = PR_Get_Lineno_Line (pr, lineno); @@ -1037,7 +1511,7 @@ PR_StackTrace (progs_t *pr) VISIBLE void PR_Profile (progs_t * pr) { - pr_int_t max, num, i; + pr_uint_t max, num, i; dfunction_t *best, *f; num = 0; @@ -1069,11 +1543,15 @@ PR_Profile (progs_t * pr) VISIBLE void ED_Print (progs_t *pr, edict_t *ed) { - int type, l; - pr_uint_t i; + prdeb_resources_t *res = pr->pr_debug_resources; + int l; + pr_uint_t i, j; const char *name; - ddef_t *d; + pr_def_t *d; pr_type_t *v; + qfot_type_t dummy_type = { }; + qfot_type_t *type; + pr_debug_data_t data = {pr, res->dstr}; if (ed->free) { Sys_Printf ("FREE\n"); @@ -1083,50 +1561,66 @@ ED_Print (progs_t *pr, edict_t *ed) Sys_Printf ("\nEDICT %d:\n", NUM_FOR_BAD_EDICT (pr, ed)); for (i = 0; i < pr->progs->numfielddefs; i++) { d = &pr->pr_fielddefs[i]; - if (!d->s_name) // null field def (probably 1st) + if (!d->name) // null field def (probably 1st) continue; - name = PR_GetString (pr, d->s_name); + type = get_def_type (pr, d, &dummy_type); + name = PR_GetString (pr, d->name); if (name[strlen (name) - 2] == '_' && strchr ("xyz", name[strlen (name) -1])) continue; // skip _x, _y, _z vars - v = ed->v + d->ofs; - - // if the value is still all 0, skip the field - type = d->type & ~DEF_SAVEGLOBAL; - - switch (type) { - case ev_entity: - case ev_integer: - case ev_uinteger: - case ev_pointer: - case ev_func: - case ev_field: - if (!v->integer_var) - continue; + for (j = 0; j < d->size; j++) { + if (E_INT (ed, d->ofs + j)) { break; - case ev_string: - if (PR_StringValid (pr, v->string_var)) - if (!PR_GetString (pr, v->string_var)[0]) - continue; - break; - case ev_float: - if (!v->float_var) - continue; - break; - case ev_vector: - if (!v[0].float_var && !v[1].float_var && !v[2].float_var) - continue; - break; - case ev_void: - break; - default: - PR_Error (pr, "ED_Print: Unhandled type %d", type); + } } + if (j == d->size) { + continue; + } + + v = ed->v + d->ofs; l = 15 - strlen (name); if (l < 1) l = 1; - Sys_Printf ("%s%*s%s\n", name, l, "", value_string (pr, d->type, v)); + + dstring_clearstr (res->dstr); + value_string (&data, type, v); + Sys_Printf ("%s%*s%s\n", name, l, "", res->dstr->str); } } + +void +PR_Debug_Init (progs_t *pr) +{ + prdeb_resources_t *res = calloc (1, sizeof (*res)); + res->pr = pr; + res->string = dstring_newstr (); + res->dva = dstring_newstr (); + res->line = dstring_newstr (); + res->dstr = dstring_newstr (); + + res->void_type.meta = ty_basic; + res->void_type.size = 4; + res->void_type.encoding = 0; + res->void_type.t.type = ev_void; + for (int i = 0; i < ev_type_count; i++ ) { + res->type_encodings[i] = &res->void_type; + } + + PR_Resources_Register (pr, "PR_Debug", res, pr_debug_clear); + if (!file_hash) { + file_hash = Hash_NewTable (1024, file_get_key, file_free, 0); + } + PR_AddLoadFunc (pr, PR_LoadDebug); +} + +void +PR_Debug_Init_Cvars (void) +{ + pr_debug = Cvar_Get ("pr_debug", "0", CVAR_NONE, NULL, + "enable progs debugging"); + pr_source_path = Cvar_Get ("pr_source_path", ".", CVAR_NONE, source_path_f, + "where to look (within gamedir) for source " + "files"); +} diff --git a/libs/gamecode/pr_edict.c b/libs/gamecode/pr_edict.c index 2241e3e9f..e3bfc778b 100644 --- a/libs/gamecode/pr_edict.c +++ b/libs/gamecode/pr_edict.c @@ -34,22 +34,10 @@ #ifdef HAVE_STRINGS_H # include #endif -#include -#include -#include "QF/cbuf.h" -#include "QF/crc.h" #include "QF/cvar.h" -#include "QF/dstring.h" -#include "QF/hash.h" -#include "QF/idparse.h" #include "QF/progs.h" -#include "QF/qdefs.h" -#include "QF/qendian.h" -#include "QF/quakefs.h" #include "QF/sys.h" -#include "QF/zone.h" -#include "QF/va.h" #include "compat.h" @@ -63,7 +51,7 @@ ED_ClearEdict (progs_t *pr, edict_t *e, int val) { pr_uint_t i; - if (NUM_FOR_EDICT (pr, e) < *pr->reserved_edicts) + if (pr->reserved_edicts && NUM_FOR_EDICT (pr, e) < *pr->reserved_edicts) Sys_Printf ("clearing reserved edict %d\n", NUM_FOR_EDICT (pr, e)); for (i=0; i < pr->progs->entityfields; i++) e->v[i].integer_var = val; @@ -86,6 +74,9 @@ ED_Alloc (progs_t *pr) edict_t *e; int start = pr->reserved_edicts ? *pr->reserved_edicts : 0; + if (!pr->num_edicts) { + PR_RunError (pr, "Edicts not supported in this VM\n"); + } for (i = start + 1; i < *pr->num_edicts; i++) { e = EDICT_NUM (pr, i); // the first couple seconds of server time can involve a lot of @@ -145,6 +136,10 @@ ED_Free (progs_t *pr, edict_t *ed) VISIBLE void ED_PrintNum (progs_t *pr, pr_int_t ent) { + if (!pr->num_edicts) { + Sys_Printf ("Edicts not supported in this VM\n"); + return; + } ED_Print (pr, EDICT_NUM (pr, ent)); } @@ -158,13 +153,17 @@ ED_PrintEdicts (progs_t *pr, const char *fieldval) { pr_int_t i; int count; - ddef_t *def; + pr_def_t *def; def = PR_FindField(pr, "classname"); + if (!pr->num_edicts) { + Sys_Printf ("Edicts not supported in this VM\n"); + return; + } if (fieldval && fieldval[0] && def) { count = 0; - for (i = 0; i < *(pr)->num_edicts; i++) + for (i = 0; i < *pr->num_edicts; i++) if (strequal(fieldval, E_GSTRING (pr, EDICT_NUM(pr, i), def->ofs))) { ED_PrintNum (pr, i); @@ -172,9 +171,9 @@ ED_PrintEdicts (progs_t *pr, const char *fieldval) } Sys_Printf ("%i entities\n", count); } else { - for (i = 0; i < *(pr)->num_edicts; i++) + for (i = 0; i < *pr->num_edicts; i++) ED_PrintNum (pr, i); - Sys_Printf ("%i entities\n", *(pr)->num_edicts); + Sys_Printf ("%i entities\n", *pr->num_edicts); } } @@ -188,14 +187,18 @@ ED_Count (progs_t *pr) { pr_int_t i; int active, models, solid, step, zombie; - ddef_t *solid_def; - ddef_t *model_def; + pr_def_t *solid_def; + pr_def_t *model_def; edict_t *ent; + if (!pr->num_edicts) { + Sys_Printf ("Edicts not supported in this VM\n"); + return; + } solid_def = PR_FindField (pr, "solid"); model_def = PR_FindField (pr, "model"); active = models = solid = step = zombie = 0; - for (i = 0; i < *(pr)->num_edicts; i++) { + for (i = 0; i < *pr->num_edicts; i++) { ent = EDICT_NUM (pr, i); if (ent->free) { if (pr->globals.time && *pr->globals.time - ent->freetime <= 0.5) @@ -209,7 +212,7 @@ ED_Count (progs_t *pr) models++; } - Sys_Printf ("num_edicts:%3i\n", *(pr)->num_edicts); + Sys_Printf ("num_edicts:%3i\n", *pr->num_edicts); Sys_Printf ("active :%3i\n", active); Sys_Printf ("view :%3i\n", models); Sys_Printf ("touch :%3i\n", solid); @@ -234,7 +237,7 @@ ED_NumForEdict (progs_t *pr, edict_t *e) b = NUM_FOR_BAD_EDICT (pr, e); - if (b && (b < 0 || b >= *(pr)->num_edicts)) + if (b && (b < 0 || b >= *pr->num_edicts)) PR_RunError (pr, "NUM_FOR_EDICT: bad pointer %d %p %p", b, e, *(pr)->edicts); @@ -244,6 +247,9 @@ ED_NumForEdict (progs_t *pr, edict_t *e) qboolean PR_EdictValid (progs_t *pr, pr_int_t e) { + if (!pr->num_edicts) { + return false; + } if (e < 0 || e >= pr->pr_edictareasize) return false; if (e % pr->pr_edict_size) diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index f7becdfa5..a73e5a474 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -68,41 +68,45 @@ PR_RunError (progs_t * pr, const char *error, ...) // dump the stack so PR_Error can shutdown functions pr->pr_depth = 0; + pr->localstack_used = 0; PR_Error (pr, "Program error: %s", string->str); } -VISIBLE void -PR_SaveParams (progs_t *pr) +VISIBLE pr_stashed_params_t * +_PR_SaveParams (progs_t *pr, pr_stashed_params_t *params) { int i; int size = pr->pr_param_size * sizeof (pr_type_t); - pr->pr_param_ptrs[0] = pr->pr_params[0]; - pr->pr_param_ptrs[1] = pr->pr_params[1]; + params->param_ptrs[0] = pr->pr_params[0]; + params->param_ptrs[1] = pr->pr_params[1]; pr->pr_params[0] = pr->pr_real_params[0]; pr->pr_params[1] = pr->pr_real_params[1]; for (i = 0; i < pr->pr_argc; i++) { - memcpy (pr->pr_saved_params + i * pr->pr_param_size, + memcpy (params->params + i * pr->pr_param_size, pr->pr_real_params[i], size); - if (i < 2) - memcpy (pr->pr_real_params[i], pr->pr_param_ptrs[0], size); + if (i < 2) { //XXX FIXME what the what?!? + memcpy (pr->pr_real_params[i], params->param_ptrs[0], size); + } } - pr->pr_saved_argc = pr->pr_argc; + params->argc = pr->pr_argc; + return params; } VISIBLE void -PR_RestoreParams (progs_t *pr) +PR_RestoreParams (progs_t *pr, pr_stashed_params_t *params) { int i; int size = pr->pr_param_size * sizeof (pr_type_t); - pr->pr_params[0] = pr->pr_param_ptrs[0]; - pr->pr_params[1] = pr->pr_param_ptrs[1]; - pr->pr_argc = pr->pr_saved_argc; - for (i = 0; i < pr->pr_argc; i++) + pr->pr_params[0] = params->param_ptrs[0]; + pr->pr_params[1] = params->param_ptrs[1]; + pr->pr_argc = params->argc; + for (i = 0; i < pr->pr_argc; i++) { memcpy (pr->pr_real_params[i], - pr->pr_saved_params + i * pr->pr_param_size, size); + params->params + i * pr->pr_param_size, size); + } } VISIBLE inline void @@ -119,7 +123,8 @@ PR_PushFrame (progs_t *pr) frame->f = pr->pr_xfunction; frame->tstr = pr->pr_xtstr; - pr->pr_xtstr = 0; + pr->pr_xtstr = pr->pr_pushtstr; + pr->pr_pushtstr = 0; pr->pr_xfunction = 0; } @@ -133,6 +138,17 @@ PR_PopFrame (progs_t *pr) if (pr->pr_xtstr) PR_FreeTempStrings (pr); + // normally, this won't happen, but if a builtin pushed a temp string + // when calling a function and the callee was another builtin that + // did not call a progs function, then the push strings will still be + // valid because PR_EnterFunction was never called + // however, not if a temp string survived: better to hold on to the push + // strings a little longer than lose one erroneously + if (!pr->pr_xtstr && pr->pr_pushtstr) { + pr->pr_xtstr = pr->pr_pushtstr; + pr->pr_pushtstr = 0; + PR_FreeTempStrings (pr); + } // up stack frame = pr->pr_stack + --pr->pr_depth; @@ -183,6 +199,7 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f) if (pr->pr_params[i] != pr->pr_real_params[i]) { copy_param (pr->pr_real_params[i], pr->pr_params[i], f->parm_size[i].size); + pr->pr_params[i] = pr->pr_real_params[i]; } } } else if (f->numparms < 0) { @@ -194,6 +211,7 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f) if (pr->pr_params[i] != pr->pr_real_params[i]) { copy_param (pr->pr_real_params[i], pr->pr_params[i], f->parm_size[i].size); + pr->pr_params[i] = pr->pr_real_params[i]; } } dparmsize_t parmsize = { pr->pr_param_size, pr->pr_param_alignment }; @@ -205,6 +223,7 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f) if (pr->pr_params[i] != pr->pr_real_params[i]) { copy_param (pr->pr_real_params[i], pr->pr_params[i], parmsize.size); + pr->pr_params[i] = pr->pr_real_params[i]; } } } @@ -385,6 +404,14 @@ check_stack_pointer (progs_t *pr, pointer_t stack, int size) } } +static inline void +pr_memset (pr_type_t *dst, int val, int count) +{ + while (count-- > 0) { + (*dst++).integer_var = val; + } +} + /* PR_ExecuteProgram @@ -436,7 +463,16 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) if (pr->pr_trace) PR_PrintStatement (pr, st, 1); - switch (st->op) { + if (st->op & OP_BREAK) { + if (pr->breakpoint_handler) { + pr->breakpoint_handler (pr); + } else { + PR_RunError (pr, "breakpoint hit"); + } + } + + pr_opcode_e op = st->op & ~OP_BREAK; + switch (op) { case OP_ADD_D: OPC_double_var = OPA_double_var + OPB_double_var; break; @@ -1580,7 +1616,23 @@ op_call: pr->pr_globals + OPA.integer_var, st->b * 4); break; - + case OP_MEMSETI: + pr_memset (&OPC, OPA.integer_var, st->b); + break; + case OP_MEMSETP: + if (pr_boundscheck->int_val) { + PR_BoundsCheckSize (pr, OPC.pointer_var, OPB.integer_var); + } + pr_memset (pr->pr_globals + OPC.pointer_var, OPA.integer_var, + OPB.integer_var); + break; + case OP_MEMSETPI: + if (pr_boundscheck->int_val) { + PR_BoundsCheckSize (pr, OPC.pointer_var, st->b); + } + pr_memset (pr->pr_globals + OPC.pointer_var, OPA.integer_var, + st->b); + break; case OP_GE_D: OPC.float_var = OPA_double_var >= OPB_double_var; break; @@ -1636,6 +1688,7 @@ op_call: watch->integer_var); } exit_program: + pr->pr_argc = 0; Sys_PopErrorHandler (); Sys_PopSignalHook (); } diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index 8bc554296..d385dff12 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -34,22 +34,17 @@ #ifdef HAVE_STRINGS_H # include #endif -#include -#include -#include "QF/cmd.h" #include "QF/crc.h" #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/hash.h" #include "QF/mathlib.h" #include "QF/progs.h" -#include "QF/qdefs.h" #include "QF/qendian.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/zone.h" -#include "QF/va.h" #include "compat.h" @@ -70,8 +65,8 @@ static const char * var_get_key (const void *d, void *_pr) { progs_t *pr = (progs_t*)_pr; - ddef_t *def = (ddef_t*)d; - return PR_GetString (pr, def->s_name); + pr_def_t *def = (pr_def_t*)d; + return PR_GetString (pr, def->name); } static void @@ -81,9 +76,11 @@ file_error (progs_t *pr, const char *path) } static void * -load_file (progs_t *pr, const char *path) +load_file (progs_t *pr, const char *path, off_t *size) { - return QFS_LoadHunkFile (QFS_FOpenFile (path)); + void *data = QFS_LoadHunkFile (QFS_FOpenFile (path)); + *size = qfs_filesize; + return data; } static void * @@ -117,6 +114,9 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) dprograms_t progs; byte *base; byte *heap; + pr_def_t *xdefs_def = 0; + ddef_t *global_ddefs; + ddef_t *field_ddefs; if (!pr->file_error) pr->file_error = file_error; @@ -128,7 +128,6 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) pr->free_progs_mem = free_progs_mem; PR_Resources_Clear (pr); - PR_ClearReturnStrings (pr); if (pr->progs) pr->free_progs_mem (pr, pr->progs); pr->progs = 0; @@ -184,6 +183,7 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) pr->pr_edict_size = align_size (pr->pr_edict_size); pr->pr_edictareasize = pr->max_edicts * pr->pr_edict_size; + pr->edict_parse = 0; mem_size = pr->progs_size + pr->zone_size + pr->pr_edictareasize + pr->stack_size; @@ -202,12 +202,11 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) base -= sizeof (progs); // offsets are from file start heap = ((byte *) pr->progs + pr->progs_size + pr->pr_edictareasize); - pr->float_promoted = progs.version == PROG_VERSION; - if (pr->edicts) { *pr->edicts = (edict_t *)((byte *) pr->progs + pr->progs_size); } + pr->zone = 0; if (pr->zone_size) { //FIXME zone_size needs to be at least as big as memzone_t, but //memzone_t is opaque so its size is unknown @@ -218,8 +217,8 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) (dfunction_t *) (base + pr->progs->ofs_functions); pr->pr_strings = (char *) base + pr->progs->ofs_strings; pr->pr_stringsize = (char *) heap + pr->zone_size - (char *) base; - pr->pr_globaldefs = (ddef_t *) (base + pr->progs->ofs_globaldefs); - pr->pr_fielddefs = (ddef_t *) (base + pr->progs->ofs_fielddefs); + global_ddefs = (ddef_t *) (base + pr->progs->ofs_globaldefs); + field_ddefs = (ddef_t *) (base + pr->progs->ofs_fielddefs); pr->pr_statements = (dstatement_t *) (base + pr->progs->ofs_statements); pr->pr_globals = (pr_type_t *) (base + pr->progs->ofs_globals); @@ -270,24 +269,67 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) Hash_Add (pr->function_hash, &pr->pr_functions[i]); } + if (pr->pr_globaldefs) { + free (pr->pr_globaldefs); + } + pr->pr_globaldefs = calloc (pr->progs->numglobaldefs, sizeof (pr_def_t)); + for (i = 0; i < pr->progs->numglobaldefs; i++) { - pr->pr_globaldefs[i].type = LittleShort (pr->pr_globaldefs[i].type); - pr->pr_globaldefs[i].ofs = LittleShort (pr->pr_globaldefs[i].ofs); - pr->pr_globaldefs[i].s_name = LittleLong (pr->pr_globaldefs[i].s_name); + pr_ushort_t safe_type = global_ddefs[i].type & ~DEF_SAVEGLOBAL; + global_ddefs[i].type = LittleShort (global_ddefs[i].type); + global_ddefs[i].ofs = LittleShort (global_ddefs[i].ofs); + global_ddefs[i].s_name = LittleLong (global_ddefs[i].s_name); + + pr->pr_globaldefs[i].type = global_ddefs[i].type; + pr->pr_globaldefs[i].size = pr_type_size[safe_type]; + pr->pr_globaldefs[i].ofs = global_ddefs[i].ofs; + pr->pr_globaldefs[i].name = global_ddefs[i].s_name; Hash_Add (pr->global_hash, &pr->pr_globaldefs[i]); } + if (pr->pr_fielddefs) { + free (pr->pr_fielddefs); + } + pr->pr_fielddefs = calloc (pr->progs->numfielddefs, sizeof (pr_def_t)); for (i = 0; i < pr->progs->numfielddefs; i++) { - pr->pr_fielddefs[i].type = LittleShort (pr->pr_fielddefs[i].type); - if (pr->pr_fielddefs[i].type & DEF_SAVEGLOBAL) - PR_Error (pr, "PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); - pr->pr_fielddefs[i].ofs = LittleShort (pr->pr_fielddefs[i].ofs); - pr->pr_fielddefs[i].s_name = LittleLong (pr->pr_fielddefs[i].s_name); + field_ddefs[i].type = LittleShort (field_ddefs[i].type); + if (field_ddefs[i].type & DEF_SAVEGLOBAL) + PR_Error (pr, "PR_LoadProgs: DEF_SAVEGLOBAL on field def %zd", i); + field_ddefs[i].ofs = LittleShort (field_ddefs[i].ofs); + field_ddefs[i].s_name = LittleLong (field_ddefs[i].s_name); + + pr->pr_fielddefs[i].type = field_ddefs[i].type; + pr->pr_fielddefs[i].ofs = field_ddefs[i].ofs; + pr->pr_fielddefs[i].name = field_ddefs[i].s_name; Hash_Add (pr->field_hash, &pr->pr_fielddefs[i]); } for (i = 0; i < pr->progs->numglobals; i++) ((int *) pr->pr_globals)[i] = LittleLong (((int *) pr->pr_globals)[i]); + + xdefs_def = PR_FindGlobal (pr, ".xdefs"); + if (xdefs_def) { + pr_xdefs_t *xdefs = &G_STRUCT (pr, pr_xdefs_t, xdefs_def->ofs); + xdef_t *xdef = &G_STRUCT (pr, xdef_t, xdefs->xdefs); + pr_def_t *def; + for (def = pr->pr_globaldefs, i = 0; i < pr->progs->numglobaldefs; + i++, xdef++, def++) { + def->ofs = xdef->ofs; + def->type_encoding = xdef->type; + } + for (def = pr->pr_fielddefs, i = 0; i < pr->progs->numfielddefs; + i++, xdef++, def++) { + def->ofs = xdef->ofs; + def->type_encoding = xdef->type; + } + } + pr->pr_trace = 0; + pr->pr_trace_depth = 0; + pr->pr_xfunction = 0; + pr->pr_xstatement = 0; + pr->pr_depth = 0; + pr->localstack_used = 0; + pr->pr_argc = 0; } VISIBLE void @@ -321,7 +363,7 @@ PR_AddLoadFinishFunc (progs_t *pr, int (*func)(progs_t *)) static int pr_run_ctors (progs_t *pr) { - pr_int_t fnum; + pr_uint_t fnum; dfunction_t *func; for (fnum = 0; fnum < pr->progs->numfunctions; fnum++) { @@ -333,9 +375,7 @@ pr_run_ctors (progs_t *pr) } static int (*load_funcs_1[])(progs_t *) = { - PR_LoadStrings, PR_RelocateBuiltins, - PR_LoadDebug, 0, }; @@ -427,10 +467,12 @@ PR_Init_Cvars (void) } VISIBLE void -PR_Init (void) +PR_Init (progs_t *pr) { - PR_Opcode_Init (); - PR_Debug_Init (); + PR_Opcode_Init (); // idempotent + PR_Resources_Init (pr); + PR_Strings_Init (pr); + PR_Debug_Init (pr); } VISIBLE void diff --git a/libs/gamecode/pr_opcode.c b/libs/gamecode/pr_opcode.c index 15185b37d..30ad8b06e 100644 --- a/libs/gamecode/pr_opcode.c +++ b/libs/gamecode/pr_opcode.c @@ -46,9 +46,9 @@ #include "compat.h" -hashtab_t *opcode_table; +static hashtab_t *opcode_table; -VISIBLE int pr_type_size[ev_type_count] = { +VISIBLE const pr_ushort_t pr_type_size[ev_type_count] = { 1, // ev_void 1, // ev_string 1, // ev_float @@ -62,9 +62,10 @@ VISIBLE int pr_type_size[ev_type_count] = { 1, // ev_uinteger 0, // ev_short value in opcode 2, // ev_double + 0, // ev_invalid not a valid/simple type }; -VISIBLE const char *pr_type_name[ev_type_count] = { +VISIBLE const char * const pr_type_name[ev_type_count] = { "void", "string", "float", @@ -97,7 +98,7 @@ VISIBLE const char *pr_type_name[ev_type_count] = { // c operand c // x place holder for P (padding) // 0-7 parameter index (for P) -VISIBLE opcode_t pr_opcodes[] = { +VISIBLE const opcode_t pr_opcodes[] = { {"", "done", OP_DONE, false, // OP_DONE is actually the same as ev_entity, ev_field, ev_void, // OP_RETURN, the types are bogus PROG_ID_VERSION, @@ -543,12 +544,12 @@ VISIBLE opcode_t pr_opcodes[] = { {"&", "lea", OP_LEA, false, ev_pointer, ev_integer, ev_pointer, PROG_VERSION, - "%Ga, %Gb, %gc", + "(%Ga + %Gb), %gc", }, {"&", "leai", OP_LEAI, false, ev_pointer, ev_short, ev_pointer, PROG_VERSION, - "%Ga, %sb, %gc", + "(%Ga + %sb), %gc", }, {"", "conv.if", OP_CONV_IF, false, @@ -1180,8 +1181,23 @@ VISIBLE opcode_t pr_opcodes[] = { {"", "movepi", OP_MOVEPI, true, ev_pointer, ev_short, ev_pointer, PROG_VERSION, + "%Ga, %sb, %Gc", + }, + {"", "memseti", OP_MEMSETI, true, + ev_integer, ev_short, ev_void, + PROG_VERSION, + "%Ga, %sb, %gc", + }, + {"", "memsetp", OP_MEMSETP, true, + ev_integer, ev_integer, ev_pointer, + PROG_VERSION, "%Ga, %Gb, %Gc", }, + {"", "memsetpi", OP_MEMSETPI, true, + ev_integer, ev_short, ev_pointer, + PROG_VERSION, + "%Ga, %sb, %Gc", + }, {"", "push.s", OP_PUSH_S, false, ev_string, ev_invalid, ev_invalid, @@ -1491,13 +1507,17 @@ PR_Opcode (pr_short_t opcode) VISIBLE void PR_Opcode_Init (void) { - opcode_t *op; + const opcode_t *op; + if (opcode_table) { + // already initialized + return; + } opcode_table = Hash_NewTable (1021, 0, 0, 0); Hash_SetHashCompare (opcode_table, opcode_get_hash, opcode_compare); for (op = pr_opcodes; op->name; op++) { - Hash_AddElement (opcode_table, op); + Hash_AddElement (opcode_table, (void *) op); } } @@ -1535,7 +1555,7 @@ check_global (progs_t *pr, dstatement_t *st, opcode_t *op, etype_t type, unsigned short operand, int check_denorm) { const char *msg; - ddef_t *def; + pr_def_t *def; switch (type) { case ev_short: @@ -1695,6 +1715,9 @@ PR_Check_Opcodes (progs_t *pr) check_global_size (pr, st, op, st->b, st->a); check_global_size (pr, st, op, st->b, st->c); break; + case OP_MEMSETI: + check_global_size (pr, st, op, st->b, st->c); + break; case OP_PUSHB_F: case OP_PUSHB_S: case OP_PUSHB_ENT: diff --git a/libs/gamecode/pr_parse.c b/libs/gamecode/pr_parse.c index a8259ee78..2652694e8 100644 --- a/libs/gamecode/pr_parse.c +++ b/libs/gamecode/pr_parse.c @@ -43,21 +43,12 @@ #include #endif -#include "QF/cbuf.h" -#include "QF/crc.h" -#include "QF/cvar.h" #include "QF/dstring.h" -#include "QF/hash.h" #include "QF/mathlib.h" #include "QF/progs.h" -#include "QF/qdefs.h" #include "QF/qfplist.h" -#include "QF/qendian.h" -#include "QF/quakefs.h" #include "QF/script.h" #include "QF/sys.h" -#include "QF/zone.h" -#include "QF/va.h" #include "compat.h" @@ -68,15 +59,11 @@ Easier to parse than PR_ValueString */ static const char * -PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val) +PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val, dstring_t *line) { - static dstring_t *line = 0; - ddef_t *def; + pr_def_t *def; dfunction_t *f; - if (!line) - line = dstring_new (); - type &= ~DEF_SAVEGLOBAL; switch (type) { @@ -93,7 +80,7 @@ PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val) break; case ev_field: def = PR_FieldAtOfs (pr, val->integer_var); - dsprintf (line, "%s", PR_GetString (pr, def->s_name)); + dsprintf (line, "%s", PR_GetString (pr, def->name)); break; case ev_void: dstring_copystr (line, "void"); @@ -121,6 +108,7 @@ PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val) VISIBLE plitem_t * ED_EntityDict (progs_t *pr, edict_t *ed) { + dstring_t *dstr = dstring_newstr (); plitem_t *entity = PL_NewDictionary (); pr_uint_t i; int j; @@ -131,9 +119,9 @@ ED_EntityDict (progs_t *pr, edict_t *ed) if (!ed->free) { for (i = 0; i < pr->progs->numfielddefs; i++) { - ddef_t *d = &pr->pr_fielddefs[i]; + pr_def_t *d = &pr->pr_fielddefs[i]; - name = PR_GetString (pr, d->s_name); + name = PR_GetString (pr, d->name); if (!name[0]) continue; // skip unnamed fields if (name[strlen (name) - 2] == '_') @@ -149,10 +137,11 @@ ED_EntityDict (progs_t *pr, edict_t *ed) if (j == pr_type_size[type]) continue; - value = PR_UglyValueString (pr, type, v); + value = PR_UglyValueString (pr, type, v, dstr); PL_D_AddObject (entity, name, PL_NewString (value)); } } + dstring_delete (dstr); return entity; } @@ -165,11 +154,12 @@ ED_EntityDict (progs_t *pr, edict_t *ed) VISIBLE plitem_t * ED_GlobalsDict (progs_t *pr) { + dstring_t *dstr = dstring_newstr (); plitem_t *globals = PL_NewDictionary (); pr_uint_t i; const char *name; const char *value; - ddef_t *def; + pr_def_t *def; int type; for (i = 0; i < pr->progs->numglobaldefs; i++) { @@ -182,10 +172,11 @@ ED_GlobalsDict (progs_t *pr) if (type != ev_string && type != ev_float && type != ev_entity) continue; - name = PR_GetString (pr, def->s_name); - value = PR_UglyValueString (pr, type, &pr->pr_globals[def->ofs]); + name = PR_GetString (pr, def->name); + value = PR_UglyValueString (pr, type, &pr->pr_globals[def->ofs], dstr); PL_D_AddObject (globals, name, PL_NewString (value)); } + dstring_delete (dstr); return globals; } @@ -222,11 +213,11 @@ ED_NewString (progs_t *pr, const char *string) returns false if error */ VISIBLE qboolean -ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key, const char *s) +ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s) { int i; char *string; - ddef_t *def; + pr_def_t *def; char *v, *w; pr_type_t *d; dfunction_t *func; @@ -301,6 +292,7 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key, const char *s) VISIBLE plitem_t * ED_ConvertToPlist (script_t *script, int nohack) { + dstring_t *dstr = dstring_newstr (); plitem_t *plist = PL_NewArray (); plitem_t *ent; plitem_t *key; @@ -341,15 +333,18 @@ ED_ConvertToPlist (script_t *script, int nohack) token = script->token->str; if (strequal (token, "}")) Sys_Error ("ED_ConvertToPlist: closing brace without data"); - if (anglehack) - value = PL_NewString (va ("0 %s 0", token)); - else + if (anglehack) { + dsprintf (dstr, "0 %s 0", token); + value = PL_NewString (dstr->str); + } else { value = PL_NewString (token); + } PL_D_AddObject (ent, PL_String (key), value); PL_Free (key); } PL_A_AddObject (plist, ent); } + dstring_delete (dstr); return plist; } @@ -357,8 +352,8 @@ ED_ConvertToPlist (script_t *script, int nohack) VISIBLE void ED_InitGlobals (progs_t *pr, plitem_t *globals) { - ddef_t vector_def; - ddef_t *global; + pr_def_t vector_def; + pr_def_t *global; plitem_t *keys; int count; const char *global_name; @@ -405,7 +400,7 @@ ED_InitGlobals (progs_t *pr, plitem_t *globals) VISIBLE void ED_InitEntity (progs_t *pr, plitem_t *entity, edict_t *ent) { - ddef_t *field; + pr_def_t *field; plitem_t *keys; const char *field_name; const char *value; @@ -524,6 +519,7 @@ ED_LoadFromFile (progs_t *pr, const char *data) PR_PushFrame (pr); PR_RESET_PARAMS (pr); P_INT (pr, 0) = PR_SetTempString (pr, data); + pr->pr_argc = 1; PR_ExecuteProgram (pr, pr->edict_parse); PR_PopFrame (pr); return; diff --git a/libs/gamecode/pr_resolve.c b/libs/gamecode/pr_resolve.c index 3238e774e..6270653d2 100644 --- a/libs/gamecode/pr_resolve.c +++ b/libs/gamecode/pr_resolve.c @@ -34,59 +34,59 @@ #ifdef HAVE_STRINGS_H # include #endif -#include -#include -#include "QF/cmd.h" -#include "QF/crc.h" -#include "QF/cvar.h" #include "QF/hash.h" #include "QF/progs.h" -#include "QF/qdefs.h" -#include "QF/qendian.h" -#include "QF/quakefs.h" #include "QF/sys.h" -#include "QF/zone.h" -#include "QF/va.h" #include "compat.h" +static const char param_str[] = ".param_0"; -ddef_t * -PR_GlobalAtOfs (progs_t * pr, pr_int_t ofs) +pr_def_t * +PR_SearchDefs (pr_def_t *defs, unsigned num_defs, pointer_t offset) { - ddef_t *def; - pr_uint_t i; + // fuzzy bsearh + unsigned left = 0; + unsigned right = num_defs - 1; + unsigned mid; - for (i = 0; i < pr->progs->numglobaldefs; i++) { - def = &pr->pr_globaldefs[i]; - if (def->ofs == ofs) - return def; + if (!num_defs) { + return 0; } - return NULL; + while (left != right) { + mid = (left + right + 1) / 2; + if (defs[mid].ofs > offset) { + right = mid - 1; + } else { + left = mid; + } + } + if (defs[left].ofs <= offset) { + return defs + left; + } + return 0; } -VISIBLE ddef_t * -PR_FieldAtOfs (progs_t * pr, pr_int_t ofs) +pr_def_t * +PR_GlobalAtOfs (progs_t * pr, pointer_t ofs) { - ddef_t *def; - pr_uint_t i; - - for (i = 0; i < pr->progs->numfielddefs; i++) { - def = &pr->pr_fielddefs[i]; - if (def->ofs == ofs) - return def; - } - return NULL; + return PR_SearchDefs (pr->pr_globaldefs, pr->progs->numglobaldefs, ofs); } -VISIBLE ddef_t * +VISIBLE pr_def_t * +PR_FieldAtOfs (progs_t * pr, pointer_t ofs) +{ + return PR_SearchDefs (pr->pr_fielddefs, pr->progs->numfielddefs, ofs); +} + +VISIBLE pr_def_t * PR_FindField (progs_t * pr, const char *name) { return Hash_Find (pr->field_hash, name); } -VISIBLE ddef_t * +VISIBLE pr_def_t * PR_FindGlobal (progs_t * pr, const char *name) { return Hash_Find (pr->global_hash, name); @@ -108,7 +108,7 @@ VISIBLE int PR_ResolveGlobals (progs_t *pr) { const char *sym; - ddef_t *def; + pr_def_t *def; int i; if (pr->progs->version == PROG_ID_VERSION) { @@ -124,11 +124,14 @@ PR_ResolveGlobals (progs_t *pr) pr->pr_param_size = OFS_PARM1 - OFS_PARM0; pr->pr_param_alignment = 0; // log2 } else { + char *param_n = alloca (sizeof (param_str)); + strcpy (param_n, param_str); if (!(def = PR_FindGlobal (pr, sym = ".return"))) goto error; pr->pr_return = &pr->pr_globals[def->ofs]; for (i = 0; i < MAX_PARMS; i++) { - if (!(def = PR_FindGlobal (pr, sym = va(".param_%d", i)))) + param_n[sizeof (param_str) - 2] = i + '0'; + if (!(def = PR_FindGlobal (pr, sym = param_n))) goto error; pr->pr_params[i] = &pr->pr_globals[def->ofs]; } @@ -139,10 +142,6 @@ PR_ResolveGlobals (progs_t *pr) goto error; pr->pr_param_alignment = G_INT (pr, def->ofs); } - if (pr->pr_saved_params) - free (pr->pr_saved_params); - pr->pr_saved_params = calloc (pr->pr_param_size * MAX_PARMS, - sizeof (pr_type_t)); memcpy (pr->pr_real_params, pr->pr_params, sizeof (pr->pr_params)); if (!pr->globals.time) { if ((def = PR_FindGlobal (pr, "time"))) @@ -180,7 +179,7 @@ int PR_AccessField (progs_t *pr, const char *name, etype_t type, const char *file, int line) { - ddef_t *def = PR_FindField (pr, name); + pr_def_t *def = PR_FindField (pr, name); if (!def) PR_Error (pr, "undefined field %s accessed at %s:%d", name, file, line); diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index 85602e3d2..00bb16e4f 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -42,26 +42,6 @@ #include "QF/dstring.h" #include "QF/hash.h" #include "QF/progs.h" -#include "QF/va.h" - -typedef enum { - str_free, - str_static, - str_dynamic, - str_mutable, - str_temp, - str_return, -} str_e; - -struct strref_s { - strref_t *next; - strref_t **prev; - str_e type; - union { - char *string; - dstring_t *dstring; - } s; -}; // format adjustments #define FMT_ALTFORM (1<<0) @@ -87,7 +67,45 @@ typedef struct fmt_item_s { struct fmt_item_s *next; } fmt_item_t; -static fmt_item_t *free_fmt_items; +typedef struct strref_slot_s { + struct strref_slot_s *next; + struct strref_slot_s **prev; + strref_t *strref; +} strref_slot_t; + +typedef struct prstr_resources_s { + progs_t *pr; + dstring_mem_t ds_mem; + strref_t *free_string_refs; + strref_t *static_strings; + strref_t **string_map; + strref_slot_t return_strings[PR_RS_SLOTS]; + strref_slot_t *rs_slot; + unsigned dyn_str_size; + struct hashtab_s *strref_hash; + int num_strings; + fmt_item_t *free_fmt_items; + dstring_t *print_str; +} prstr_resources_t; + +typedef enum { + str_free, + str_static, + str_dynamic, + str_mutable, + str_temp, + str_return, +} str_e; + +struct strref_s { + strref_t *next; + strref_slot_t *rs_slot; + str_e type; + union { + char *string; + dstring_t *dstring; + } s; +}; static void * pr_strings_alloc (void *_pr, size_t size) @@ -111,51 +129,50 @@ pr_strings_realloc (void *_pr, void *ptr, size_t size) } static strref_t * -new_string_ref (progs_t *pr) +new_string_ref (prstr_resources_t *res) { strref_t *sr; - if (!pr->free_string_refs) { + if (!res->free_string_refs) { int i; size_t size; - pr->dyn_str_size++; - size = pr->dyn_str_size * sizeof (strref_t *); - pr->string_map = realloc (pr->string_map, size); - if (!pr->string_map) - PR_Error (pr, "out of memory"); - if (!(pr->free_string_refs = calloc (1024, sizeof (strref_t)))) - PR_Error (pr, "out of memory"); - pr->string_map[pr->dyn_str_size - 1] = pr->free_string_refs; - for (i = 0, sr = pr->free_string_refs; i < 1023; i++, sr++) + res->dyn_str_size++; + size = res->dyn_str_size * sizeof (strref_t *); + res->string_map = realloc (res->string_map, size); + if (!res->string_map) + PR_Error (res->pr, "out of memory"); + if (!(res->free_string_refs = calloc (1024, sizeof (strref_t)))) + PR_Error (res->pr, "out of memory"); + res->string_map[res->dyn_str_size - 1] = res->free_string_refs; + for (i = 0, sr = res->free_string_refs; i < 1023; i++, sr++) sr->next = sr + 1; sr->next = 0; } - sr = pr->free_string_refs; - pr->free_string_refs = sr->next; + sr = res->free_string_refs; + res->free_string_refs = sr->next; sr->next = 0; + sr->rs_slot = 0; return sr; } static void -free_string_ref (progs_t *pr, strref_t *sr) +free_string_ref (prstr_resources_t *res, strref_t *sr) { sr->type = str_free; - if (sr->prev) - *sr->prev = sr->next; - sr->next = pr->free_string_refs; - pr->free_string_refs = sr; + sr->next = res->free_string_refs; + res->free_string_refs = sr; } static __attribute__((pure)) string_t -string_index (progs_t *pr, strref_t *sr) +string_index (prstr_resources_t *res, strref_t *sr) { - long o = (long) (sr - pr->static_strings); + long o = (long) (sr - res->static_strings); unsigned i; - if (o >= 0 && o < pr->num_strings) - return sr->s.string - pr->pr_strings; - for (i = 0; i < pr->dyn_str_size; i++) { - int d = sr - pr->string_map[i]; + if (o >= 0 && o < res->num_strings) + return sr->s.string - res->pr->pr_strings; + for (i = 0; i < res->dyn_str_size; i++) { + int d = sr - res->string_map[i]; if (d >= 0 && d < 1024) return ~(i * 1024 + d); } @@ -172,70 +189,124 @@ strref_get_key (const void *_sr, void *notused) } static void -strref_free (void *_sr, void *_pr) +strref_free (void *_sr, void *_res) { - progs_t *pr = (progs_t*)_pr; - strref_t *sr = (strref_t*)_sr; + __auto_type res = (prstr_resources_t *) _res; + __auto_type sr = (strref_t *) _sr; // Since this is called only by Hash_FlushTable, the memory pointed // to by sr->string or sr->dstring has already been lost in the progs // load/reload and thus there's no need to free it. // free the string and ref only if it's not a static string - if (sr < pr->static_strings || sr >= pr->static_strings + pr->num_strings) { - free_string_ref (pr, sr); + if (sr < res->static_strings + || sr >= res->static_strings + res->num_strings) { + free_string_ref (res, sr); } } -VISIBLE int +static void +pr_strings_clear (progs_t *pr, void *data) +{ + __auto_type res = (prstr_resources_t *) data; + int i; + + for (i = 0; i < PR_RS_SLOTS; i++) { + if (res->return_strings[i].strref) + free_string_ref (res, res->return_strings[i].strref); + res->return_strings[i].strref = 0; + } + if (!res->rs_slot) { + strref_slot_t * const rs = res->return_strings; + for (i = 0; i < PR_RS_SLOTS; i++) { + rs[i].next = &rs[(i + 1) % PR_RS_SLOTS]; + rs[i].prev = &rs[(i - 1 + PR_RS_SLOTS) % PR_RS_SLOTS].next; + } + res->rs_slot = rs; + } + + pr->pr_string_resources = res; + pr->pr_xtstr = 0; +} + +static int PR_LoadStrings (progs_t *pr) { + prstr_resources_t *res = PR_Resources_Find (pr, "Strings"); + char *end = pr->pr_strings + pr->progs->numstrings; char *str = pr->pr_strings; int count = 0; + pr->float_promoted = 0; + while (str < end) { count++; + if (*str == '@' && pr->progs->version == PROG_VERSION) { + if (!strcmp (str, "@float_promoted@")) { + pr->float_promoted = 1; + } + } str += strlen (str) + 1; } - if (!pr->ds_mem) { - pr->ds_mem = malloc (sizeof (dstring_mem_t)); - pr->ds_mem->alloc = pr_strings_alloc; - pr->ds_mem->free = pr_strings_free; - pr->ds_mem->realloc = pr_strings_realloc; - pr->ds_mem->data = pr; - } - if (pr->strref_hash) { - Hash_FlushTable (pr->strref_hash); + res->ds_mem.alloc = pr_strings_alloc; + res->ds_mem.free = pr_strings_free; + res->ds_mem.realloc = pr_strings_realloc; + res->ds_mem.data = pr; + + if (res->strref_hash) { + Hash_FlushTable (res->strref_hash); } else { - pr->strref_hash = Hash_NewTable (1021, strref_get_key, strref_free, - pr); - pr->string_map = 0; - pr->free_string_refs = 0; - pr->dyn_str_size = 0; + res->strref_hash = Hash_NewTable (1021, strref_get_key, strref_free, + res); + res->string_map = 0; + res->free_string_refs = 0; + res->dyn_str_size = 0; } - if (pr->static_strings) - free (pr->static_strings); - pr->static_strings = malloc (count * sizeof (strref_t)); + if (res->static_strings) + free (res->static_strings); + res->static_strings = calloc (count, sizeof (strref_t)); count = 0; str = pr->pr_strings; while (str < end) { - if (!Hash_Find (pr->strref_hash, str)) { - pr->static_strings[count].type = str_static; - pr->static_strings[count].s.string = str; - Hash_Add (pr->strref_hash, &pr->static_strings[count]); + if (!Hash_Find (res->strref_hash, str)) { + res->static_strings[count].type = str_static; + res->static_strings[count].s.string = str; + Hash_Add (res->strref_hash, &res->static_strings[count]); count++; } str += strlen (str) + 1; } - pr->num_strings = count; + res->num_strings = count; return 1; } +static void +requeue_strref (prstr_resources_t *res, strref_t *sr) +{ + strref_slot_t *rs_slot = sr->rs_slot; + if (rs_slot->next != res->rs_slot) { + // this is the oldest slot, so advance res->rs_slot to the + // next oldest slot so this slot does not get reused just yet + if (res->rs_slot == rs_slot) { + res->rs_slot = rs_slot->next; + } + // unlink this slot from the chain + rs_slot->next->prev = rs_slot->prev; + *rs_slot->prev = rs_slot->next; + // link this slot just before the oldest slot: all the slots + // form a doubly linked circular list + rs_slot->prev = res->rs_slot->prev; + rs_slot->next = res->rs_slot; + *res->rs_slot->prev = rs_slot; + res->rs_slot->prev = &rs_slot->next; + } +} + static inline strref_t * -get_strref (progs_t *pr, string_t num) +get_strref (prstr_resources_t *res, string_t num) { if (num < 0) { strref_t *ref; @@ -243,9 +314,9 @@ get_strref (progs_t *pr, string_t num) num = ~num % 1024; - if (row >= pr->dyn_str_size) + if (row >= res->dyn_str_size) return 0; - ref = &pr->string_map[row][num]; + ref = &res->string_map[row][num]; if (ref->type == str_free) return 0; return ref; @@ -256,22 +327,24 @@ get_strref (progs_t *pr, string_t num) static inline __attribute__((pure)) const char * get_string (progs_t *pr, string_t num) { + __auto_type res = pr->pr_string_resources; if (num < 0) { - strref_t *ref = get_strref (pr, num); + strref_t *ref = get_strref (res, num); if (!ref) return 0; switch (ref->type) { + case str_return: + requeue_strref (res, ref); case str_static: case str_temp: case str_dynamic: - case str_return: return ref->s.string; case str_mutable: return ref->s.dstring->str; case str_free: break; } - PR_Error (pr, "internal string error"); + PR_Error (pr, "internal string error: %d", __LINE__); } else { if (num >= pr->pr_stringsize) return 0; @@ -282,7 +355,10 @@ get_string (progs_t *pr, string_t num) VISIBLE qboolean PR_StringValid (progs_t *pr, string_t num) { - return get_string (pr, num) != 0; + if (num >= 0) { + return num < pr->pr_stringsize; + } + return get_strref (pr->pr_string_resources, num) != 0; } VISIBLE const char * @@ -299,7 +375,7 @@ PR_GetString (progs_t *pr, string_t num) VISIBLE dstring_t * PR_GetMutableString (progs_t *pr, string_t num) { - strref_t *ref = get_strref (pr, num); + strref_t *ref = get_strref (pr->pr_string_resources, num); if (ref) { if (ref->type == str_mutable) return ref->s.dstring; @@ -308,10 +384,16 @@ PR_GetMutableString (progs_t *pr, string_t num) PR_RunError (pr, "Invalid string offset: %d", num); } +static inline void * +pr_strmalloc (progs_t *pr, size_t size) +{ + return PR_Zone_Malloc (pr, size); +} + static inline char * pr_stralloc (progs_t *pr, size_t len) { - return PR_Zone_Malloc (pr, len + 1); + return pr_strmalloc (pr, len + 1); } static inline void @@ -331,70 +413,72 @@ pr_strdup (progs_t *pr, const char *s) VISIBLE string_t PR_SetString (progs_t *pr, const char *s) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr; if (!s) s = ""; - sr = Hash_Find (pr->strref_hash, s); + sr = Hash_Find (res->strref_hash, s); if (__builtin_expect (!sr, 1)) { - sr = new_string_ref (pr); + sr = new_string_ref (res); sr->type = str_static; sr->s.string = pr_strdup(pr, s); - Hash_Add (pr->strref_hash, sr); - } - return string_index (pr, sr); -} - -void -PR_ClearReturnStrings (progs_t *pr) -{ - int i; - - for (i = 0; i < PR_RS_SLOTS; i++) { - if (pr->return_strings[i]) - free_string_ref (pr, pr->return_strings[i]); - pr->return_strings[i] = 0; + Hash_Add (res->strref_hash, sr); } + return string_index (res, sr); } VISIBLE string_t PR_SetReturnString (progs_t *pr, const char *s) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr; if (!s) s = ""; - if ((sr = Hash_Find (pr->strref_hash, s))) { - return string_index (pr, sr); + if ((sr = Hash_Find (res->strref_hash, s))) { + if (sr->type == str_return && sr->rs_slot) { + requeue_strref (res, sr); + } else if ((sr->type == str_return && !sr->rs_slot) + || (sr->type != str_return && sr->rs_slot)) { + PR_Error (pr, "internal string error: %d %d %p", __LINE__, + sr->type, sr->rs_slot); + } + return string_index (res, sr); } - if ((sr = pr->return_strings[pr->rs_slot])) { - if (sr->type != str_return) - PR_Error (pr, "internal string error"); + // grab the string ref from the oldest slot, or make a new one if the + // slot is empty + if ((sr = res->rs_slot->strref)) { + if (sr->type != str_return || sr->rs_slot != res->rs_slot) { + PR_Error (pr, "internal string error: %d", __LINE__); + } pr_strfree (pr, sr->s.string); } else { - sr = new_string_ref (pr); + sr = new_string_ref (res); } sr->type = str_return; + sr->rs_slot = res->rs_slot; sr->s.string = pr_strdup(pr, s); - pr->return_strings[pr->rs_slot++] = sr; - pr->rs_slot %= PR_RS_SLOTS; - return string_index (pr, sr); + // the oldest slot just became the newest, so advance to the next oldest + res->rs_slot = res->rs_slot->next; + + return string_index (res, sr); } static inline string_t -pr_settempstring (progs_t *pr, char *s) +pr_settempstring (progs_t *pr, prstr_resources_t *res, char *s) { strref_t *sr; - sr = new_string_ref (pr); + sr = new_string_ref (res); sr->type = str_temp; sr->s.string = s; sr->next = pr->pr_xtstr; pr->pr_xtstr = sr; - return string_index (pr, sr); + return string_index (res, sr); } VISIBLE string_t @@ -410,46 +494,77 @@ PR_CatStrings (progs_t *pr, const char *a, const char *b) strcpy (c, a); strcpy (c + lena, b); - return pr_settempstring (pr, c); + return pr_settempstring (pr, pr->pr_string_resources, c); } VISIBLE string_t PR_SetTempString (progs_t *pr, const char *s) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr; if (!s) return PR_SetString (pr, ""); - if ((sr = Hash_Find (pr->strref_hash, s))) { - return string_index (pr, sr); + if ((sr = Hash_Find (res->strref_hash, s))) { + return string_index (res, sr); } - return pr_settempstring (pr, pr_strdup (pr, s)); + return pr_settempstring (pr, res, pr_strdup (pr, s)); +} + +VISIBLE string_t +PR_AllocTempBlock (progs_t *pr, size_t size) +{ + prstr_resources_t *res = pr->pr_string_resources; + return pr_settempstring (pr, res, pr_strmalloc (pr, size)); +} + +VISIBLE void +PR_PushTempString (progs_t *pr, string_t num) +{ + prstr_resources_t *res = pr->pr_string_resources; + strref_t *ref = get_strref (res, num); + strref_t **temp_ref; + + if (!ref || ref->type != str_temp) { + PR_Error (pr, "attempt to push a non-temp string"); + } + for (temp_ref = &pr->pr_xtstr; *temp_ref; temp_ref = &(*temp_ref)->next) { + if (*temp_ref == ref) { + *temp_ref = ref->next; + ref->next = pr->pr_pushtstr; + pr->pr_pushtstr = ref; + return; + } + } + PR_Error (pr, "attempt to push stale temp string"); } VISIBLE string_t PR_SetDynamicString (progs_t *pr, const char *s) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr; if (!s) return PR_SetString (pr, ""); - if ((sr = Hash_Find (pr->strref_hash, s))) { - return string_index (pr, sr); + if ((sr = Hash_Find (res->strref_hash, s))) { + return string_index (res, sr); } - sr = new_string_ref (pr); + sr = new_string_ref (res); sr->type = str_dynamic; sr->s.string = pr_strdup (pr, s); - return string_index (pr, sr); + return string_index (res, sr); } void PR_MakeTempString (progs_t *pr, string_t str) { - strref_t *sr = get_strref (pr, str); + prstr_resources_t *res = pr->pr_string_resources; + strref_t *sr = get_strref (res, str); if (!sr) PR_RunError (pr, "invalid string %d", str); @@ -470,16 +585,18 @@ PR_MakeTempString (progs_t *pr, string_t str) VISIBLE string_t PR_NewMutableString (progs_t *pr) { - strref_t *sr = new_string_ref (pr); + prstr_resources_t *res = pr->pr_string_resources; + strref_t *sr = new_string_ref (res); sr->type = str_mutable; - sr->s.dstring = _dstring_newstr (pr->ds_mem); - return string_index (pr, sr); + sr->s.dstring = _dstring_newstr (&res->ds_mem); + return string_index (res, sr); } VISIBLE void PR_FreeString (progs_t *pr, string_t str) { - strref_t *sr = get_strref (pr, str); + prstr_resources_t *res = pr->pr_string_resources; + strref_t *sr = get_strref (res, str); if (sr) { switch (sr->type) { @@ -494,32 +611,32 @@ PR_FreeString (progs_t *pr, string_t str) break; case str_return: default: - PR_Error (pr, "internal string error"); + PR_Error (pr, "internal string error: %d", __LINE__); } - free_string_ref (pr, sr); + free_string_ref (res, sr); return; } - if (!get_string (pr, str)) - PR_RunError (pr, "attempt to free invalid string %d", str); + PR_RunError (pr, "attempt to free invalid string %d", str); } void PR_FreeTempStrings (progs_t *pr) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr, *t; for (sr = pr->pr_xtstr; sr; sr = t) { t = sr->next; if (sr->type != str_temp) - PR_Error (pr, "internal string error"); - if (R_STRING (pr) < 0 && string_index (pr, sr) == R_STRING (pr) + PR_Error (pr, "internal string error: %d", __LINE__); + if (R_STRING (pr) < 0 && string_index (res, sr) == R_STRING (pr) && pr->pr_depth) { prstack_t *frame = pr->pr_stack + pr->pr_depth - 1; sr->next = frame->tstr; frame->tstr = sr; } else { pr_strfree (pr, sr->s.string); - free_string_ref (pr, sr); + free_string_ref (res, sr); } } pr->pr_xtstr = 0; @@ -551,10 +668,9 @@ PR_FreeTempStrings (progs_t *pr) list item. */ static void -I_DoPrint (dstring_t *result, fmt_item_t *formatting) +I_DoPrint (dstring_t *tmp, dstring_t *result, fmt_item_t *formatting) { fmt_item_t *current = formatting; - dstring_t *tmp = dstring_new (); while (current) { qboolean doPrecision, doWidth; @@ -617,34 +733,33 @@ I_DoPrint (dstring_t *result, fmt_item_t *formatting) } current = current->next; } - dstring_delete (tmp); } static fmt_item_t * -new_fmt_item (void) +new_fmt_item (prstr_resources_t *res) { int i; fmt_item_t *fi; - if (!free_fmt_items) { - free_fmt_items = malloc (16 * sizeof (fmt_item_t)); + if (!res->free_fmt_items) { + res->free_fmt_items = malloc (16 * sizeof (fmt_item_t)); for (i = 0; i < 15; i++) - free_fmt_items[i].next = free_fmt_items + i + 1; - free_fmt_items[i].next = 0; + res->free_fmt_items[i].next = res->free_fmt_items + i + 1; + res->free_fmt_items[i].next = 0; } - fi = free_fmt_items; - free_fmt_items = fi->next; + fi = res->free_fmt_items; + res->free_fmt_items = fi->next; memset (fi, 0, sizeof (*fi)); fi->precision = -1; return fi; } static void -free_fmt_item (fmt_item_t *fi) +free_fmt_item (prstr_resources_t *res, fmt_item_t *fi) { - fi->next = free_fmt_items; - free_fmt_items = fi; + fi->next = res->free_fmt_items; + res->free_fmt_items = fi; } #undef P_var @@ -655,6 +770,7 @@ VISIBLE void PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, const char *format, int count, pr_type_t **args) { + prstr_resources_t *res = pr->pr_string_resources; const char *c, *l; const char *msg = ""; fmt_item_t *fmt_items = 0; @@ -664,7 +780,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, if (!name) name = "PR_Sprintf"; - *fi = new_fmt_item (); + *fi = new_fmt_item (res); c = l = format; while (*c) { if (*c++ == '%') { @@ -674,14 +790,14 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->type = 's'; (*fi)->data.string_var = l; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; } if (*c == '%') { (*fi)->type = 's'; (*fi)->data.string_var = "%"; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; } else { do { @@ -729,7 +845,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, case '@': // object fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 'e': @@ -739,7 +855,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, P_EDICTNUM (pr, fmt_count); fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 'i': @@ -750,7 +866,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->data.integer_var = P_INT (pr, fmt_count); fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 'f': @@ -769,7 +885,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, } fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 'p': @@ -779,7 +895,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->data.uinteger_var = P_UINT (pr, fmt_count); fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 's': @@ -788,7 +904,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->data.string_var = P_GSTRING (pr, fmt_count); fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 'v': @@ -815,7 +931,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->type = 's'; (*fi)->data.string_var = " "; } - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; (*fi)->flags = flags; @@ -825,7 +941,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->data.float_var = P_VECTOR (pr, fmt_count)[i]; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; } } @@ -834,7 +950,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->data.string_var = "'"; fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 'x': @@ -843,7 +959,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->data.uinteger_var = P_UINT (pr, fmt_count); fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; } @@ -859,7 +975,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->type = 's'; (*fi)->data.string_var = l; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); } if (fmt_count != count) { @@ -867,17 +983,30 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, msg = "Not enough arguments for format string."; else msg = "Too many arguments for format string."; - msg = va ("%s: %d %d", msg, fmt_count, count); + dsprintf (res->print_str, "%s: %d %d", msg, fmt_count, count); + msg = res->print_str->str; goto error; } - I_DoPrint (result, fmt_items); + dstring_clear (res->print_str); + I_DoPrint (res->print_str, result, fmt_items); while (fmt_items) { fmt_item_t *t = fmt_items->next; - free_fmt_item (fmt_items); + free_fmt_item (res, fmt_items); fmt_items = t; } return; error: PR_RunError (pr, "%s: %s", name, msg); } + +void +PR_Strings_Init (progs_t *pr) +{ + prstr_resources_t *res = calloc (1, sizeof (*res)); + res->pr = pr; + res->print_str = dstring_new (); + + PR_Resources_Register (pr, "Strings", res, pr_strings_clear); + PR_AddLoadFunc (pr, PR_LoadStrings); +} diff --git a/libs/gib/bi_gib.c b/libs/gib/bi_gib.c index b1482c030..3c462712c 100644 --- a/libs/gib/bi_gib.c +++ b/libs/gib/bi_gib.c @@ -91,6 +91,7 @@ bi_gib_builtin_f (void) PR_RESET_PARAMS (builtin->pr); P_INT (builtin->pr, 0) = GIB_Argc(); P_INT (builtin->pr, 1) = PR_SetPointer (builtin->pr, pr_list); + builtin->pr->pr_argc = 2; PR_ExecuteProgram (builtin->pr, builtin->func); PR_PopFrame (builtin->pr); PR_Zone_Free (builtin->pr, pr_list); diff --git a/libs/ruamoko/Makefile.am b/libs/ruamoko/Makefile.am index 64c65e972..15d4c4360 100644 --- a/libs/ruamoko/Makefile.am +++ b/libs/ruamoko/Makefile.am @@ -16,6 +16,6 @@ libQFruamoko_la_LIBADD= $(rua_libs) libQFruamoko_la_DEPENDENCIES= $(rua_libs) libQFruamoko_la_SOURCES= \ pr_cmds.c \ - rua_cbuf.c rua_cmd.c rua_cvar.c rua_file.c rua_hash.c rua_init.c \ + rua_cbuf.c rua_cmd.c rua_cvar.c rua_hash.c rua_init.c \ rua_math.c rua_msgbuf.c rua_obj.c rua_plist.c rua_qfile.c rua_qfs.c \ rua_script.c rua_set.c rua_string.c diff --git a/libs/ruamoko/pr_cmds.c b/libs/ruamoko/pr_cmds.c index 8352228d4..9a531fb14 100644 --- a/libs/ruamoko/pr_cmds.c +++ b/libs/ruamoko/pr_cmds.c @@ -255,7 +255,7 @@ PF_Find (progs_t *pr) int i; // ev_vector int e, f; etype_t type; - ddef_t *field_def; + pr_def_t *field_def; edict_t *ed; e = P_EDICTNUM (pr, 0); @@ -583,6 +583,25 @@ PF_sprintf (progs_t *pr) dstring_delete (dstr); } +static void +PF_vsprintf (progs_t *pr) +{ + const char *fmt = P_GSTRING (pr, 0); + __auto_type args = &P_PACKED (pr, pr_va_list_t, 1); + pr_type_t *list_start = PR_GetPointer (pr, args->list); + pr_type_t **list = alloca (args->count * sizeof (*list)); + dstring_t *dstr; + + for (int i = 0; i < args->count; i++) { + list[i] = list_start + i * pr->pr_param_size; + } + + dstr = dstring_newstr (); + PR_Sprintf (pr, dstr, "PF_vsprintf", fmt, args->count, list); + RETURN_STRING (pr, dstr->str); + dstring_delete (dstr); +} + /* string () gametype */ @@ -596,7 +615,7 @@ static void PF_PR_SetField (progs_t *pr) { edict_t *ent = P_EDICT (pr, 0); - ddef_t *field = PR_FindField (pr, P_GSTRING (pr, 1)); + pr_def_t *field = PR_FindField (pr, P_GSTRING (pr, 1)); const char *value = P_GSTRING (pr, 2); R_INT (pr) = 0; @@ -643,6 +662,7 @@ static builtin_t builtins[] = { {"strlen", PF_strlen, QF 100}, {"charcount", PF_charcount, QF 101}, {"sprintf", PF_sprintf, QF 109}, + {"vsprintf", PF_vsprintf, -1}, {"ftoi", PF_ftoi, QF 110}, {"itof", PF_itof, QF 111}, {"itos", PF_itos, QF 112}, diff --git a/libs/ruamoko/rua_file.c b/libs/ruamoko/rua_file.c deleted file mode 100644 index 61def0a3f..000000000 --- a/libs/ruamoko/rua_file.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - bi_file.c - - CSQC file builtins - - Copyright (C) 1996-1997 Id Software, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif - -#ifdef HAVE_FNMATCH_H -# define model_t sunmodel_t -# include -# undef model_t -#else -# ifdef _WIN32 -# include "fnmatch.h" -# endif -#endif - -#ifndef HAVE_FNMATCH_PROTO -int fnmatch (const char *__pattern, const char *__string, int __flags); -#endif - -#include "QF/cvar.h" -#include "QF/progs.h" -#include "QF/quakefs.h" -#include "QF/va.h" -#include "QF/zone.h" - -#include "rua_internal.h" - -static const char *file_ban_list[] = { - "default.cfg{,.gz}", - "demo1.dem{,.gz}", - "demo2.dem{,.gz}", - "demo3.dem{,.gz}", - "end1.bin{,.gz}", - "end2.bin{,.gz}", - "gfx.wad{,.gz}", - "progs.dat{,.gz}", - "quake.rc{,.gz}", - 0, -}; - -static const char *dir_ban_list[] = { - "gfx", - "maps", - "progs", - "skins", - "sound", - 0, -}; - -static int -file_readable (char *path) -{ - char t; - char *p = strchr (path, '/'); - const char **match; - - if (p) { - t = *p; - *p = 0; - for (match = dir_ban_list; *match; match++) { - if (fnmatch (*match, path, FNM_PATHNAME) == 0) { - *p = t; - return 0; - } - } - } else { - for (match = file_ban_list; *match; match++) { - if (fnmatch (*match, path, FNM_PATHNAME) == 0) { - return 0; - } - } - } - return 1; -} - -static int -file_writeable (char *path) -{ - return file_readable (path); -} - -static void -bi_File_Open (progs_t *pr) -{ - QFile *file; - const char *pth = P_GSTRING (pr, 0); - const char *mode = P_GSTRING (pr, 1); - char *path; - char *p; - int do_write = 0; - int do_read = 0; - - p = strchr (mode, 'r'); - if (p) { - do_read |= 1; - if (p[1] == '+') - do_write |= 1; - } - - p = strchr (mode, 'w'); - if (p) { - do_write |= 1; - if (p[1] == '+') - do_read |= 1; - } - - p = strchr (mode, 'a'); - if (p) { - do_write |= 1; - if (p[1] == '+') - do_read |= 1; - } - - path = QFS_CompressPath (pth); - //printf ("'%s' '%s'\n", P_GSTRING (pr, 0), path); - if (!path[0]) - goto error; - if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || path [2] == 0)) - goto error; - if (path[strlen (path) - 1] =='/') - goto error; - if (!do_read && !do_write) - goto error; - if (do_read && !file_readable (path)) - goto error; - if (do_write && !file_writeable (path)) - goto error; - - file = QFS_Open (va ("%s/%s", qfs_gamedir->dir.def, path), mode); - if (!file) - goto error; - free (path); - if ((R_INT (pr) = QFile_AllocHandle (pr, file))) - return; - Qclose (file); - return; -error: - free (path); - R_INT (pr) = 0; -} - -static builtin_t builtins[] = { - {"File_Open", bi_File_Open, -1}, - {0} -}; - -void -RUA_File_Init (progs_t *pr, int secure) -{ - PR_RegisterBuiltins (pr, builtins); -} diff --git a/libs/ruamoko/rua_hash.c b/libs/ruamoko/rua_hash.c index cc6d2b8c6..fedb8c288 100644 --- a/libs/ruamoko/rua_hash.c +++ b/libs/ruamoko/rua_hash.c @@ -98,6 +98,7 @@ bi_get_key (const void *key, void *_ht) PR_RESET_PARAMS (ht->pr); P_INT (ht->pr, 0) = (intptr_t) (key); P_INT (ht->pr, 1) = ht->ud; + ht->pr->pr_argc = 2; PR_ExecuteProgram (ht->pr, ht->gk); return PR_GetString (ht->pr, R_STRING (ht->pr)); } @@ -109,6 +110,7 @@ bi_get_hash (const void *key, void *_ht) PR_RESET_PARAMS (ht->pr); P_INT (ht->pr, 0) = (intptr_t) (key); P_INT (ht->pr, 1) = ht->ud; + ht->pr->pr_argc = 2; PR_ExecuteProgram (ht->pr, ht->gh); return R_INT (ht->pr); } @@ -121,6 +123,7 @@ bi_compare (const void *key1, const void *key2, void *_ht) P_INT (ht->pr, 0) = (intptr_t) (key1); P_INT (ht->pr, 1) = (intptr_t) (key2); P_INT (ht->pr, 2) = ht->ud; + ht->pr->pr_argc = 3; PR_ExecuteProgram (ht->pr, ht->cmp); return R_INT (ht->pr); } @@ -132,6 +135,7 @@ bi_free (void *key, void *_ht) PR_RESET_PARAMS (ht->pr); P_INT (ht->pr, 0) = (intptr_t) (key); P_INT (ht->pr, 1) = ht->ud; + ht->pr->pr_argc = 2; PR_ExecuteProgram (ht->pr, ht->f); } diff --git a/libs/ruamoko/rua_init.c b/libs/ruamoko/rua_init.c index ab973b569..7741405a5 100644 --- a/libs/ruamoko/rua_init.c +++ b/libs/ruamoko/rua_init.c @@ -39,7 +39,6 @@ static void (*init_funcs[])(progs_t *, int) = { RUA_Cbuf_Init, RUA_Cmd_Init, RUA_Cvar_Init, - RUA_File_Init, RUA_Hash_Init, RUA_Math_Init, RUA_MsgBuf_Init, @@ -56,7 +55,6 @@ RUA_Init (progs_t *pr, int secure) { size_t i; - PR_Resources_Init (pr); for (i = 0; i < sizeof (init_funcs) / sizeof (init_funcs[0]); i++) init_funcs[i] (pr, secure); } diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index ed3a1d78b..854341b56 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -56,11 +56,75 @@ #include "compat.h" #include "rua_internal.h" +#define always_inline inline __attribute__((__always_inline__)) + typedef struct obj_list_s { struct obj_list_s *next; void *data; } obj_list; +typedef struct dtable_s { + size_t size; + func_t *imp; +} dtable_t; + +typedef struct probj_resources_s { + progs_t *pr; + unsigned selector_index; + unsigned selector_index_max; + obj_list **selector_sels; + string_t *selector_names; + PR_RESMAP (dtable_t) dtables; + func_t obj_forward; + pr_sel_t *forward_selector; + dstring_t *msg; + hashtab_t *selector_hash; + hashtab_t *classes; + hashtab_t *protocols; + hashtab_t *load_methods; + obj_list *unresolved_classes; + obj_list *unclaimed_categories; + obj_list *uninitialized_statics; + obj_list *unclaimed_proto_list; + obj_list *module_list; + obj_list *class_tree_list; +} probj_t; + +static dtable_t * +dtable_new (probj_t *probj) +{ + PR_RESNEW (dtable_t, probj->dtables); +} + +static void +dtable_reset (probj_t *probj) +{ + PR_RESRESET (dtable_t, probj->dtables); +} + +static inline dtable_t * +dtable_get (probj_t *probj, int index) +{ + PR_RESGET (probj->dtables, index); +} + +static inline int +dtable_index (probj_t *probj, dtable_t *dtable) +{ + PR_RESINDEX (probj->dtables, dtable); +} + +static always_inline dtable_t * __attribute__((pure)) +get_dtable (probj_t *probj, const char *name, int index) +{ + dtable_t *dtable = dtable_get (probj, index); + + if (!dtable) { + PR_RunError (probj->pr, "invalid dtable index in %s", name); + } + return dtable; +} + static obj_list *obj_list_free_list; static obj_list * @@ -144,7 +208,7 @@ class_tree_new (void) } static int -class_is_subclass_of_class (progs_t *pr, pr_class_t *class, +class_is_subclass_of_class (probj_t *probj, pr_class_t *class, pr_class_t *superclass) { while (class) { @@ -152,20 +216,22 @@ class_is_subclass_of_class (progs_t *pr, pr_class_t *class, return 1; if (!class->super_class) break; - class = Hash_Find (pr->classes, PR_GetString (pr, class->super_class)); + class = Hash_Find (probj->classes, + PR_GetString (probj->pr, class->super_class)); } return 0; } static class_tree * -create_tree_of_subclasses_inherited_from (progs_t *pr, pr_class_t *bottom, +create_tree_of_subclasses_inherited_from (probj_t *probj, pr_class_t *bottom, pr_class_t *upper) { + progs_t *pr = probj->pr; const char *super_class = PR_GetString (pr, bottom->super_class); pr_class_t *superclass; class_tree *tree, *prev; - superclass = bottom->super_class ? Hash_Find (pr->classes, super_class) + superclass = bottom->super_class ? Hash_Find (probj->classes, super_class) : 0; tree = prev = class_tree_new (); prev->class = bottom; @@ -174,7 +240,7 @@ create_tree_of_subclasses_inherited_from (progs_t *pr, pr_class_t *bottom, tree->class = superclass; tree->subclasses = list_cons (prev, tree->subclasses); super_class = PR_GetString (pr, superclass->super_class); - superclass = (superclass->super_class ? Hash_Find (pr->classes, + superclass = (superclass->super_class ? Hash_Find (probj->classes, super_class) : 0); prev = tree; @@ -183,16 +249,17 @@ create_tree_of_subclasses_inherited_from (progs_t *pr, pr_class_t *bottom, } static class_tree * -_obj_tree_insert_class (progs_t *pr, class_tree *tree, pr_class_t *class) +_obj_tree_insert_class (probj_t *probj, class_tree *tree, pr_class_t *class) { + progs_t *pr = probj->pr; obj_list *subclasses; class_tree *new_tree; if (!tree) - return create_tree_of_subclasses_inherited_from (pr, class, 0); + return create_tree_of_subclasses_inherited_from (probj, class, 0); if (class == tree->class) return tree; - if ((class->super_class ? Hash_Find (pr->classes, + if ((class->super_class ? Hash_Find (probj->classes, PR_GetString (pr, class->super_class)) : 0) == tree->class) { @@ -209,32 +276,32 @@ _obj_tree_insert_class (progs_t *pr, class_tree *tree, pr_class_t *class) tree->subclasses = list_cons (node, tree->subclasses); return tree; } - if (!class_is_subclass_of_class (pr, class, tree->class)) + if (!class_is_subclass_of_class (probj, class, tree->class)) return 0; for (subclasses = tree->subclasses; subclasses; subclasses = subclasses->next) { pr_class_t *aclass = ((class_tree *)subclasses->data)->class; - if (class_is_subclass_of_class (pr, class, aclass)) { - subclasses->data = _obj_tree_insert_class (pr, subclasses->data, + if (class_is_subclass_of_class (probj, class, aclass)) { + subclasses->data = _obj_tree_insert_class (probj, subclasses->data, class); return tree; } } - new_tree = create_tree_of_subclasses_inherited_from (pr, class, + new_tree = create_tree_of_subclasses_inherited_from (probj, class, tree->class); tree->subclasses = list_cons (new_tree, tree->subclasses); return tree; } static void -obj_tree_insert_class (progs_t *pr, pr_class_t *class) +obj_tree_insert_class (probj_t *probj, pr_class_t *class) { obj_list *list_node; class_tree *tree; - list_node = pr->class_tree_list; + list_node = probj->class_tree_list; while (list_node) { - tree = _obj_tree_insert_class (pr, list_node->data, class); + tree = _obj_tree_insert_class (probj, list_node->data, class); if (tree) { list_node->data = tree; break; @@ -243,73 +310,82 @@ obj_tree_insert_class (progs_t *pr, pr_class_t *class) } } if (!list_node) { - tree = _obj_tree_insert_class (pr, 0, class); - pr->class_tree_list = list_cons (tree, pr->class_tree_list); + tree = _obj_tree_insert_class (probj, 0, class); + probj->class_tree_list = list_cons (tree, probj->class_tree_list); } } static void -obj_create_classes_tree (progs_t *pr, pr_module_t *module) +obj_create_classes_tree (probj_t *probj, pr_module_t *module) { + progs_t *pr = probj->pr; pr_symtab_t *symtab = &G_STRUCT (pr, pr_symtab_t, module->symtab); int i; for (i = 0; i < symtab->cls_def_cnt; i++) { pr_class_t *class = &G_STRUCT (pr, pr_class_t, symtab->defs[i]); - obj_tree_insert_class (pr, class); + obj_tree_insert_class (probj, class); } } static void -obj_destroy_class_tree_node (progs_t *pr, class_tree *tree, int level) +obj_destroy_class_tree_node (probj_t *probj, class_tree *tree, int level) { tree->subclasses = (obj_list *) class_tree_free_list; class_tree_free_list = tree; } static void -obj_preorder_traverse (progs_t *pr, class_tree *tree, int level, - void (*func) (progs_t *, class_tree *, int)) +obj_preorder_traverse (probj_t *probj, class_tree *tree, int level, + void (*func) (probj_t *, class_tree *, int)) { obj_list *node; - func (pr, tree, level); + func (probj, tree, level); for (node = tree->subclasses; node; node = node->next) - obj_preorder_traverse (pr, node->data, level + 1, func); + obj_preorder_traverse (probj, node->data, level + 1, func); } static void -obj_postorder_traverse (progs_t *pr, class_tree *tree, int level, - void (*func) (progs_t *, class_tree *, int)) +obj_postorder_traverse (probj_t *probj, class_tree *tree, int level, + void (*func) (probj_t *, class_tree *, int)) { obj_list *node; for (node = tree->subclasses; node; node = node->next) - obj_postorder_traverse (pr, node->data, level + 1, func); - func (pr, tree, level); + obj_postorder_traverse (probj, node->data, level + 1, func); + func (probj, tree, level); } static const char * -selector_get_key (const void *s, void *_pr) +selector_get_key (const void *s, void *_probj) { - progs_t *pr = (progs_t *) _pr; - return PR_GetString (pr, pr->selector_names[(intptr_t) s]); + __auto_type probj = (probj_t *) _probj; + return PR_GetString (probj->pr, probj->selector_names[(intptr_t) s]); } static const char * -class_get_key (const void *c, void *pr) +class_get_key (const void *c, void *_probj) { - return PR_GetString ((progs_t *)pr, ((pr_class_t *)c)->name); + __auto_type probj = (probj_t *) _probj; + return PR_GetString (probj->pr, ((pr_class_t *)c)->name); +} + +static const char * +protocol_get_key (const void *p, void *_probj) +{ + __auto_type probj = (probj_t *) _probj; + return PR_GetString (probj->pr, ((pr_protocol_t *)p)->protocol_name); } static uintptr_t -load_methods_get_hash (const void *m, void *pr) +load_methods_get_hash (const void *m, void *_probj) { return (uintptr_t) m; } static int -load_methods_compare (const void *m1, const void *m2, void *pr) +load_methods_compare (const void *m1, const void *m2, void *_probj) { return m1 == m2; } @@ -323,8 +399,9 @@ sel_eq (pr_sel_t *s1, pr_sel_t *s2) } static int -object_is_instance (progs_t *pr, pr_id_t *object) +object_is_instance (probj_t *probj, pr_id_t *object) { + progs_t *pr = probj->pr; pr_class_t *class; if (object) { @@ -335,8 +412,9 @@ object_is_instance (progs_t *pr, pr_id_t *object) } static string_t -object_get_class_name (progs_t *pr, pr_id_t *object) +object_get_class_name (probj_t *probj, pr_id_t *object) { + progs_t *pr = probj->pr; pr_class_t *class; if (object) { @@ -356,8 +434,9 @@ object_get_class_name (progs_t *pr, pr_id_t *object) //==================================================================== static void -finish_class (progs_t *pr, pr_class_t *class, pointer_t object_ptr) +finish_class (probj_t *probj, pr_class_t *class, pointer_t object_ptr) { + progs_t *pr = probj->pr; pr_class_t *meta = &G_STRUCT (pr, pr_class_t, class->class_pointer); pr_class_t *val; @@ -365,7 +444,7 @@ finish_class (progs_t *pr, pr_class_t *class, pointer_t object_ptr) if (class->super_class) { const char *super_class = PR_GetString (pr, class->super_class); const char *class_name = PR_GetString (pr, class->name); - val = Hash_Find (pr->classes, super_class); + val = Hash_Find (probj->classes, super_class); if (!val) PR_Error (pr, "broken class %s: super class %s not found", class_name, super_class); @@ -384,39 +463,39 @@ finish_class (progs_t *pr, pr_class_t *class, pointer_t object_ptr) //==================================================================== static int -add_sel_name (progs_t *pr, const char *name) +add_sel_name (probj_t *probj, const char *name) { - int ind = ++pr->selector_index; + int ind = ++probj->selector_index; int size, i; - if (pr->selector_index >= pr->selector_index_max) { - size = pr->selector_index_max + 128; - pr->selector_sels = realloc (pr->selector_sels, - size * sizeof (obj_list *)); - pr->selector_names = realloc (pr->selector_names, - size * sizeof (string_t)); - for (i = pr->selector_index_max; i < size; i++) { - pr->selector_sels[i] = 0; - pr->selector_names[i] = 0; + if (probj->selector_index >= probj->selector_index_max) { + size = probj->selector_index_max + 128; + probj->selector_sels = realloc (probj->selector_sels, + size * sizeof (obj_list *)); + probj->selector_names = realloc (probj->selector_names, + size * sizeof (string_t)); + for (i = probj->selector_index_max; i < size; i++) { + probj->selector_sels[i] = 0; + probj->selector_names[i] = 0; } - pr->selector_index_max = size; + probj->selector_index_max = size; } - pr->selector_names[ind] = PR_SetString (pr, name); + probj->selector_names[ind] = PR_SetString (probj->pr, name); return ind; } static pr_sel_t * -sel_register_typed_name (progs_t *pr, const char *name, const char *types, +sel_register_typed_name (probj_t *probj, const char *name, const char *types, pr_sel_t *sel) { + progs_t *pr = probj->pr; intptr_t index; int is_new = 0; obj_list *l; - Sys_MaskPrintf (SYS_RUA_OBJ, " Registering SEL %s %s\n", name, types); - index = (intptr_t) Hash_Find (pr->selector_hash, name); + index = (intptr_t) Hash_Find (probj->selector_hash, name); if (index) { - for (l = pr->selector_sels[index]; l; l = l->next) { + for (l = probj->selector_sels[index]; l; l = l->next) { pr_sel_t *s = l->data; if (!types || !s->sel_types) { if (!s->sel_types && !types) { @@ -435,7 +514,9 @@ sel_register_typed_name (progs_t *pr, const char *name, const char *types, } } } else { - index = add_sel_name (pr, name); + Sys_MaskPrintf (SYS_RUA_OBJ, " Registering SEL %s %s\n", + name, types); + index = add_sel_name (probj, name); is_new = 1; } if (!sel) @@ -446,11 +527,11 @@ sel_register_typed_name (progs_t *pr, const char *name, const char *types, l = obj_list_new (); l->data = sel; - l->next = pr->selector_sels[index]; - pr->selector_sels[index] = l; + l->next = probj->selector_sels[index]; + probj->selector_sels[index] = l; if (is_new) - Hash_Add (pr->selector_hash, (void *) index); + Hash_Add (probj->selector_hash, (void *) index); done: Sys_MaskPrintf (SYS_RUA_OBJ, " %d @ %x\n", sel->sel_id, PR_SetPointer (pr, sel)); @@ -458,40 +539,91 @@ done: } static pr_sel_t * -sel_register_name (progs_t *pr, const char *name) +sel_register_name (probj_t *probj, const char *name) { - return sel_register_typed_name (pr, name, "", 0); + return sel_register_typed_name (probj, name, "", 0); } static void -register_selectors_from_list (progs_t *pr, pr_method_list_t *method_list) +obj_register_selectors_from_description_list (probj_t *probj, + pr_method_description_list_t *method_list) { + progs_t *pr = probj->pr; + int i; + + if (!method_list) { + return; + } + for (i = 0; i < method_list->count; i++) { + pr_method_description_t *method = &method_list->list[i]; + const char *name = PR_GetString (pr, method->name); + const char *types = PR_GetString (pr, method->types); + pr_sel_t *sel = sel_register_typed_name (probj, name, types, 0); + method->name = PR_SetPointer (pr, sel); + } +} + +static void +obj_register_selectors_from_list (probj_t *probj, + pr_method_list_t *method_list) +{ + progs_t *pr = probj->pr; int i; for (i = 0; i < method_list->method_count; i++) { pr_method_t *method = &method_list->method_list[i]; const char *name = PR_GetString (pr, method->method_name); const char *types = PR_GetString (pr, method->method_types); - pr_sel_t *sel = sel_register_typed_name (pr, name, types, 0); + pr_sel_t *sel = sel_register_typed_name (probj, name, types, 0); method->method_name = PR_SetPointer (pr, sel); } } static void -obj_register_selectors_from_class (progs_t *pr, pr_class_t *class) +obj_register_selectors_from_class (probj_t *probj, pr_class_t *class) { + progs_t *pr = probj->pr; pr_method_list_t *method_list = &G_STRUCT (pr, pr_method_list_t, class->methods); while (method_list) { - register_selectors_from_list (pr, method_list); + obj_register_selectors_from_list (probj, method_list); method_list = &G_STRUCT (pr, pr_method_list_t, method_list->method_next); } } +static void obj_init_protocols (probj_t *probj, pr_protocol_list_t *protos); + static void -obj_init_protocols (progs_t *pr, pr_protocol_list_t *protos) +obj_init_protocol (probj_t *probj, pr_class_t *proto_class, + pr_protocol_t *proto) { + progs_t *pr = probj->pr; + + if (!proto->class_pointer) { + const char *protocol_name = PR_GetString (pr, proto->protocol_name); + proto->class_pointer = PR_SetPointer (pr, proto_class); + obj_register_selectors_from_description_list (probj, + &G_STRUCT (pr, pr_method_description_list_t, + proto->instance_methods)); + obj_register_selectors_from_description_list (probj, + &G_STRUCT (pr, pr_method_description_list_t, + proto->class_methods)); + if (!Hash_Find (probj->protocols, protocol_name)) { + Hash_Add (probj->protocols, proto); + } + obj_init_protocols (probj, &G_STRUCT (pr, pr_protocol_list_t, + proto->protocol_list)); + } else { + if (proto->class_pointer != PR_SetPointer (pr, proto_class)) + PR_RunError (pr, "protocol broken"); + } +} + +static void +obj_init_protocols (probj_t *probj, pr_protocol_list_t *protos) +{ + progs_t *pr = probj->pr; pr_class_t *proto_class; pr_protocol_t *proto; int i; @@ -499,28 +631,23 @@ obj_init_protocols (progs_t *pr, pr_protocol_list_t *protos) if (!protos) return; - if (!(proto_class = Hash_Find (pr->classes, "Protocol"))) { - pr->unclaimed_proto_list = list_cons (protos, - pr->unclaimed_proto_list); + if (!(proto_class = Hash_Find (probj->classes, "Protocol"))) { + probj->unclaimed_proto_list = list_cons (protos, + probj->unclaimed_proto_list); return; } for (i = 0; i < protos->count; i++) { proto = &G_STRUCT (pr, pr_protocol_t, protos->list[i]); - if (!proto->class_pointer) { - proto->class_pointer = PR_SetPointer (pr, proto_class); - obj_init_protocols (pr, &G_STRUCT (pr, pr_protocol_list_t, - proto->protocol_list)); - } else { - if (proto->class_pointer != PR_SetPointer (pr, proto_class)) - PR_RunError (pr, "protocol broken"); - } + obj_init_protocol (probj, proto_class, proto); } } static void -class_add_method_list (progs_t *pr, pr_class_t *class, pr_method_list_t *list) +class_add_method_list (probj_t *probj, pr_class_t *class, + pr_method_list_t *list) { + progs_t *pr = probj->pr; int i; for (i = 0; i < list->method_count; i++) { @@ -528,7 +655,7 @@ class_add_method_list (progs_t *pr, pr_class_t *class, pr_method_list_t *list) if (method->method_name) { const char *name = PR_GetString (pr, method->method_name); const char *types = PR_GetString (pr, method->method_types); - pr_sel_t *sel = sel_register_typed_name (pr, name, types, 0); + pr_sel_t *sel = sel_register_typed_name (probj, name, types, 0); method->method_name = PR_SetPointer (pr, sel); } } @@ -538,7 +665,7 @@ class_add_method_list (progs_t *pr, pr_class_t *class, pr_method_list_t *list) } static void -obj_class_add_protocols (progs_t *pr, pr_class_t *class, +obj_class_add_protocols (probj_t *probj, pr_class_t *class, pr_protocol_list_t *protos) { if (!protos) @@ -549,50 +676,54 @@ obj_class_add_protocols (progs_t *pr, pr_class_t *class, } static void -finish_category (progs_t *pr, pr_category_t *category, pr_class_t *class) +finish_category (probj_t *probj, pr_category_t *category, pr_class_t *class) { + progs_t *pr = probj->pr; pr_method_list_t *method_list; pr_protocol_list_t *protocol_list; if (category->instance_methods) { method_list = &G_STRUCT (pr, pr_method_list_t, category->instance_methods); - class_add_method_list (pr, class, method_list); + class_add_method_list (probj, class, method_list); } if (category->class_methods) { pr_class_t *meta = &G_STRUCT (pr, pr_class_t, class->class_pointer); method_list = &G_STRUCT (pr, pr_method_list_t, category->class_methods); - class_add_method_list (pr, meta, method_list); + class_add_method_list (probj, meta, method_list); } if (category->protocols) { protocol_list = &G_STRUCT (pr, pr_protocol_list_t, category->protocols); - obj_init_protocols (pr, protocol_list); - obj_class_add_protocols (pr, class, protocol_list); + obj_init_protocols (probj, protocol_list); + obj_class_add_protocols (probj, class, protocol_list); } } static void -obj_send_message_in_list (progs_t *pr, pr_method_list_t *method_list, +obj_send_message_in_list (probj_t *probj, pr_method_list_t *method_list, pr_class_t *class, pr_sel_t *op) { + progs_t *pr = probj->pr; int i; if (!method_list) return; - obj_send_message_in_list (pr, &G_STRUCT (pr, pr_method_list_t, - method_list->method_next), + obj_send_message_in_list (probj, &G_STRUCT (pr, pr_method_list_t, + method_list->method_next), class, op); for (i = 0; i < method_list->method_count; i++) { pr_method_t *mth = &method_list->method_list[i]; if (mth->method_name && sel_eq (&G_STRUCT (pr, pr_sel_t, mth->method_name), op) - && !Hash_FindElement (pr->load_methods, (void *) (intptr_t) mth->method_imp)) { - Hash_AddElement (pr->load_methods, (void *) (intptr_t) mth->method_imp); - + && !Hash_FindElement (probj->load_methods, + (void *) (intptr_t) mth->method_imp)) { + Hash_AddElement (probj->load_methods, + (void *) (intptr_t) mth->method_imp); + //FIXME need to wrap in save/restore params? PR_ExecuteProgram (pr, mth->method_imp); break; } @@ -600,58 +731,62 @@ obj_send_message_in_list (progs_t *pr, pr_method_list_t *method_list, } static void -send_load (progs_t *pr, class_tree *tree, int level) +send_load (probj_t *probj, class_tree *tree, int level) { - pr_sel_t *load_sel = sel_register_name (pr, "load"); + progs_t *pr = probj->pr; + pr_sel_t *load_sel = sel_register_name (probj, "load"); pr_class_t *class = tree->class; pr_class_t *meta = &G_STRUCT (pr, pr_class_t, class->class_pointer); pr_method_list_t *method_list = &G_STRUCT (pr, pr_method_list_t, meta->methods); - obj_send_message_in_list (pr, method_list, class, load_sel); + obj_send_message_in_list (probj, method_list, class, load_sel); } static void -obj_send_load (progs_t *pr) +obj_send_load (probj_t *probj) { + progs_t *pr = probj->pr; obj_list *m; - if (pr->unresolved_classes) { - pr_class_t *class = pr->unresolved_classes->data; + if (probj->unresolved_classes) { + pr_class_t *class = probj->unresolved_classes->data; const char *super_class = PR_GetString (pr, class->super_class); - while (Hash_Find (pr->classes, super_class)) { - list_remove (&pr->unresolved_classes); - if (pr->unresolved_classes) { - class = pr->unresolved_classes->data; + while (Hash_Find (probj->classes, super_class)) { + list_remove (&probj->unresolved_classes); + if (probj->unresolved_classes) { + class = probj->unresolved_classes->data; super_class = PR_GetString (pr, class->super_class); } else { break; } } - if (pr->unresolved_classes) + if (probj->unresolved_classes) return; } //XXX constant string stuff here (see init.c in libobjc source) - for (m = pr->module_list; m; m = m->next) - obj_create_classes_tree (pr, m->data); - while (pr->class_tree_list) { - obj_preorder_traverse (pr, pr->class_tree_list->data, 0, send_load); - obj_postorder_traverse (pr, pr->class_tree_list->data, 0, + for (m = probj->module_list; m; m = m->next) + obj_create_classes_tree (probj, m->data); + while (probj->class_tree_list) { + obj_preorder_traverse (probj, probj->class_tree_list->data, 0, + send_load); + obj_postorder_traverse (probj, probj->class_tree_list->data, 0, obj_destroy_class_tree_node); - list_remove (&pr->class_tree_list); + list_remove (&probj->class_tree_list); } //XXX callback - //for (m = pr->module_list; m; m = m->next) - // obj_create_classes_tree (pr, m->data); - obj_list_free (pr->module_list); - pr->module_list = 0; + //for (m = probj->module_list; m; m = m->next) + // obj_create_classes_tree (probj, m->data); + obj_list_free (probj->module_list); + probj->module_list = 0; } static pr_method_t * -obj_find_message (progs_t *pr, pr_class_t *class, pr_sel_t *selector) +obj_find_message (probj_t *probj, pr_class_t *class, pr_sel_t *selector) { + progs_t *pr = probj->pr; pr_class_t *c = class; pr_method_list_t *method_list; pr_method_t *method; @@ -661,7 +796,7 @@ obj_find_message (progs_t *pr, pr_class_t *class, pr_sel_t *selector) string_t *names; if (dev & SYS_RUA_MSG) { - names = pr->selector_names; + names = probj->selector_names; Sys_Printf ("Searching for %s\n", PR_GetString (pr, names[selector->sel_id])); } @@ -680,13 +815,13 @@ obj_find_message (progs_t *pr, pr_class_t *class, pr_sel_t *selector) i < method_list->method_count; i++, method++) { sel = &G_STRUCT (pr, pr_sel_t, method->method_name); if (developer->int_val & SYS_RUA_MSG) { - names = pr->selector_names; + names = probj->selector_names; Sys_Printf (" %s\n", PR_GetString (pr, names[sel->sel_id])); } if (sel->sel_id == selector->sel_id) { if (dev & SYS_RUA_MSG) { - names = pr->selector_names; + names = probj->selector_names; Sys_Printf ("found %s: %x\n", PR_GetString (pr, names[selector->sel_id]), method->method_imp); @@ -703,13 +838,14 @@ obj_find_message (progs_t *pr, pr_class_t *class, pr_sel_t *selector) } static void -obj_send_initialize (progs_t *pr, pr_class_t *class) +obj_send_initialize (probj_t *probj, pr_class_t *class) { + progs_t *pr = probj->pr; pr_method_list_t *method_list; pr_method_t *method; pr_sel_t *sel; pr_class_t *class_pointer; - pr_sel_t *selector = sel_register_name (pr, "initialize"); + pr_sel_t *selector = sel_register_name (probj, "initialize"); int i; if (PR_CLS_ISINITIALIZED (class)) @@ -718,8 +854,8 @@ obj_send_initialize (progs_t *pr, pr_class_t *class) PR_CLS_SETINITIALIZED (class); PR_CLS_SETINITIALIZED (class_pointer); if (class->super_class) - obj_send_initialize (pr, &G_STRUCT (pr, pr_class_t, - class->super_class)); + obj_send_initialize (probj, &G_STRUCT (pr, pr_class_t, + class->super_class)); method_list = &G_STRUCT (pr, pr_method_list_t, class_pointer->methods); while (method_list) { @@ -728,12 +864,12 @@ obj_send_initialize (progs_t *pr, pr_class_t *class) sel = &G_STRUCT (pr, pr_sel_t, method->method_name); if (sel->sel_id == selector->sel_id) { PR_PushFrame (pr); - PR_SaveParams (pr); + __auto_type params = PR_SaveParams (pr); // param 0 is known to be the class pointer P_POINTER (pr, 1) = method->method_name; // pr->pr_argc is known to be 2 PR_ExecuteProgram (pr, method->method_imp); - PR_RestoreParams (pr); + PR_RestoreParams (pr, params); PR_PopFrame (pr); return; } @@ -743,48 +879,148 @@ obj_send_initialize (progs_t *pr, pr_class_t *class) } } -static func_t -get_imp (progs_t *pr, pr_class_t *class, pr_sel_t *sel) +static void +obj_install_methods_in_dtable (probj_t *probj, pr_class_t *class, + pr_method_list_t *method_list) { - pr_method_t *method = obj_find_message (pr, class, sel); + progs_t *pr = probj->pr; + dtable_t *dtable; - return method ? method->method_imp : 0; + if (!method_list) { + return; + } + if (method_list->method_next) { + obj_install_methods_in_dtable (probj, class, + &G_STRUCT (pr, pr_method_list_t, + method_list->method_next)); + } + + dtable = get_dtable (probj, __FUNCTION__, class->dtable); + for (int i = 0; i < method_list->method_count; i++) { + pr_method_t *method = &method_list->method_list[i]; + pr_sel_t *sel = &G_STRUCT (pr, pr_sel_t, method->method_name); + if (sel->sel_id < dtable->size) { + dtable->imp[sel->sel_id] = method->method_imp; + } + } +} + +static void +obj_install_dispatch_table_for_class (probj_t *probj, pr_class_t *class) +{ + progs_t *pr = probj->pr; + pr_class_t *super = &G_STRUCT (pr, pr_class_t, class->super_class); + dtable_t *dtable; + + Sys_MaskPrintf (SYS_RUA_OBJ, " install dispatch for class %s %x %d\n", + PR_GetString (pr, class->name), + class->methods, + PR_CLS_ISMETA(class)); + + if (super && !super->dtable) { + obj_install_dispatch_table_for_class (probj, super); + } + + dtable = dtable_new (probj); + class->dtable = dtable_index (probj, dtable); + dtable->size = probj->selector_index + 1; + dtable->imp = calloc (dtable->size, sizeof (func_t)); + if (super) { + dtable_t *super_dtable = get_dtable (probj, __FUNCTION__, + super->dtable); + memcpy (dtable->imp, super_dtable->imp, + super_dtable->size * sizeof (*dtable->imp)); + } + obj_install_methods_in_dtable (probj, class, + &G_STRUCT (pr, pr_method_list_t, + class->methods)); +} + +static inline dtable_t * +obj_check_dtable_installed (probj_t *probj, pr_class_t *class) +{ + if (!class->dtable) { + obj_install_dispatch_table_for_class (probj, class); + } + return get_dtable (probj, __FUNCTION__, class->dtable); } static func_t -obj_msg_lookup (progs_t *pr, pr_id_t *receiver, pr_sel_t *op) +get_imp (probj_t *probj, pr_class_t *class, pr_sel_t *sel) { + func_t imp = 0; + + if (class->dtable) { + dtable_t *dtable = get_dtable (probj, __FUNCTION__, class->dtable); + if (sel->sel_id < dtable->size) { + imp = dtable->imp[sel->sel_id]; + } + } + if (!imp) { + if (!class->dtable) { + obj_install_dispatch_table_for_class (probj, class); + imp = get_imp (probj, class, sel); + } else { + imp = probj->obj_forward; + } + } + return imp; +} + +static int +obj_reponds_to (probj_t *probj, pr_id_t *obj, pr_sel_t *sel) +{ + progs_t *pr = probj->pr; + pr_class_t *class; + dtable_t *dtable; + func_t imp = 0; + + class = &G_STRUCT (pr, pr_class_t, obj->class_pointer); + dtable = obj_check_dtable_installed (probj, class); + + if (sel->sel_id < dtable->size) { + imp = dtable->imp[sel->sel_id]; + } + return imp != 0; +} + +static func_t +obj_msg_lookup (probj_t *probj, pr_id_t *receiver, pr_sel_t *op) +{ + progs_t *pr = probj->pr; pr_class_t *class; if (!receiver) return 0; class = &G_STRUCT (pr, pr_class_t, receiver->class_pointer); if (PR_CLS_ISCLASS (class)) { if (!PR_CLS_ISINITIALIZED (class)) - obj_send_initialize (pr, class); + obj_send_initialize (probj, class); } else if (PR_CLS_ISMETA (class) && PR_CLS_ISCLASS ((pr_class_t *) receiver)) { if (!PR_CLS_ISINITIALIZED ((pr_class_t *) receiver)) - obj_send_initialize (pr, (pr_class_t *) receiver); + obj_send_initialize (probj, (pr_class_t *) receiver); } - return get_imp (pr, class, op); + return get_imp (probj, class, op); } static func_t -obj_msg_lookup_super (progs_t *pr, pr_super_t *super, pr_sel_t *op) +obj_msg_lookup_super (probj_t *probj, pr_super_t *super, pr_sel_t *op) { + progs_t *pr = probj->pr; pr_class_t *class; if (!super->self) return 0; class = &G_STRUCT (pr, pr_class_t, super->class); - return get_imp (pr, class, op); + return get_imp (probj, class, op); } static void -obj_verror (progs_t *pr, pr_id_t *object, int code, const char *fmt, int count, +obj_verror (probj_t *probj, pr_id_t *object, int code, const char *fmt, int count, pr_type_t **args) { + progs_t *pr = probj->pr; dstring_t *dstr = dstring_newstr (); PR_Sprintf (pr, dstr, "obj_verror", fmt, count, args); @@ -792,8 +1028,9 @@ obj_verror (progs_t *pr, pr_id_t *object, int code, const char *fmt, int count, } static void -dump_ivars (progs_t *pr, pointer_t _ivars) +dump_ivars (probj_t *probj, pointer_t _ivars) { + progs_t *pr = probj->pr; pr_ivar_list_t *ivars; int i; @@ -808,9 +1045,55 @@ dump_ivars (progs_t *pr, pointer_t _ivars) } } +static void +obj_init_statics (probj_t *probj) +{ + progs_t *pr = probj->pr; + obj_list **cell = &probj->uninitialized_statics; + pointer_t *ptr; + pointer_t *inst; + + Sys_MaskPrintf (SYS_RUA_OBJ, "Initializing statics\n"); + while (*cell) { + int initialized = 1; + + for (ptr = (*cell)->data; *ptr; ptr++) { + __auto_type statics = &G_STRUCT (pr, pr_static_instances_t, *ptr); + const char *class_name = PR_GetString (pr, statics->class_name); + pr_class_t *class = Hash_Find (probj->classes, class_name); + + Sys_MaskPrintf (SYS_RUA_OBJ, " %s %p\n", class_name, class); + if (!class) { + initialized = 0; + continue; + } + + if (strcmp (class_name, "Protocol") == 0) { + // protocols are special + for (inst = statics->instances; *inst; inst++) { + obj_init_protocol (probj, class, + &G_STRUCT (pr, pr_protocol_t, *inst)); + } + } else { + for (inst = statics->instances; *inst; inst++) { + pr_id_t *id = &G_STRUCT (pr, pr_id_t, *inst); + id->class_pointer = PR_SetPointer (pr, class); + } + } + } + + if (initialized) { + list_remove (cell); + } else { + cell = &(*cell)->next; + } + } +} + static void rua___obj_exec_class (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_module_t *module = &P_STRUCT (pr, pr_module_t, 0); pr_symtab_t *symtab; pr_sel_t *sel; @@ -825,22 +1108,25 @@ rua___obj_exec_class (progs_t *pr) return; Sys_MaskPrintf (SYS_RUA_OBJ, "Initializing %s module\n" "symtab @ %x : %d selector%s @ %x, " - "%d class%s and %d categor%s\n", + "%d class%s and %d categor%s\n" + "static instance lists: %s\n", PR_GetString (pr, module->name), module->symtab, symtab->sel_ref_cnt, symtab->sel_ref_cnt == 1 ? "" : "s", symtab->refs, symtab->cls_def_cnt, symtab->cls_def_cnt == 1 ? "" : "es", symtab->cat_def_cnt, - symtab->cat_def_cnt == 1 ? "y" : "ies"); + symtab->cat_def_cnt == 1 ? "y" : "ies", + symtab->defs[symtab->cls_def_cnt + + symtab->cat_def_cnt] ? "yes" : "no"); - pr->module_list = list_cons (module, pr->module_list); + probj->module_list = list_cons (module, probj->module_list); sel = &G_STRUCT (pr, pr_sel_t, symtab->refs); for (i = 0; i < symtab->sel_ref_cnt; i++) { const char *name, *types; name = PR_GetString (pr, sel->sel_id); types = PR_GetString (pr, sel->sel_types); - sel_register_typed_name (pr, name, types, sel); + sel_register_typed_name (probj, name, types, sel); sel++; } @@ -860,7 +1146,7 @@ rua___obj_exec_class (progs_t *pr) class->instance_size, class->ivars); if (developer->int_val & SYS_RUA_OBJ) - dump_ivars (pr, class->ivars); + dump_ivars (probj, class->ivars); Sys_MaskPrintf (SYS_RUA_OBJ, " instance methods: %x\n", class->methods); Sys_MaskPrintf (SYS_RUA_OBJ, " protocols: %x\n", class->protocols); @@ -870,30 +1156,31 @@ rua___obj_exec_class (progs_t *pr) meta->instance_size, meta->ivars); if (developer->int_val & SYS_RUA_OBJ) - dump_ivars (pr, meta->ivars); + dump_ivars (probj, meta->ivars); class->subclass_list = 0; - Hash_Add (pr->classes, class); + Hash_Add (probj->classes, class); - obj_register_selectors_from_class (pr, class); - obj_register_selectors_from_class (pr, meta); + obj_register_selectors_from_class (probj, class); + obj_register_selectors_from_class (probj, meta); if (class->protocols) { pr_protocol_list_t *protocol_list; protocol_list = &G_STRUCT (pr, pr_protocol_list_t, class->protocols); - obj_init_protocols (pr, protocol_list); + obj_init_protocols (probj, protocol_list); } - if (class->super_class && !Hash_Find (pr->classes, super_class)) - pr->unresolved_classes = list_cons (class, pr->unresolved_classes); + if (class->super_class && !Hash_Find (probj->classes, super_class)) + probj->unresolved_classes = list_cons (class, + probj->unresolved_classes); } for (i = 0; i < symtab->cat_def_cnt; i++, ptr++) { pr_category_t *category = &G_STRUCT (pr, pr_category_t, *ptr); const char *class_name = PR_GetString (pr, category->class_name); - pr_class_t *class = Hash_Find (pr->classes, class_name); + pr_class_t *class = Hash_Find (probj->classes, class_name); Sys_MaskPrintf (SYS_RUA_OBJ, "Category %s (%s) @ %x\n", PR_GetString (pr, category->class_name), @@ -906,55 +1193,155 @@ rua___obj_exec_class (progs_t *pr) category->protocols); if (class) { - finish_category (pr, category, class); + finish_category (probj, category, class); } else { - pr->unclaimed_categories = list_cons (category, - pr->unclaimed_categories); + probj->unclaimed_categories + = list_cons (category, probj->unclaimed_categories); } } - for (cell = &pr->unclaimed_categories; *cell; ) { + if (*ptr) { + Sys_MaskPrintf (SYS_RUA_OBJ, "Static instances lists: %x\n", *ptr); + probj->uninitialized_statics + = list_cons (&G_STRUCT (pr, pointer_t, *ptr), + probj->uninitialized_statics); + } + if (probj->uninitialized_statics) { + obj_init_statics (probj); + } + + for (cell = &probj->unclaimed_categories; *cell; ) { pr_category_t *category = (*cell)->data; const char *class_name = PR_GetString (pr, category->class_name); - pr_class_t *class = Hash_Find (pr->classes, class_name); + pr_class_t *class = Hash_Find (probj->classes, class_name); if (class) { list_remove (cell); - finish_category (pr, category, class); + finish_category (probj, category, class); } else { cell = &(*cell)->next; } } - if (pr->unclaimed_proto_list && Hash_Find (pr->classes, "Protocol")) { - for (cell = &pr->unclaimed_proto_list; *cell; ) { - obj_init_protocols (pr, (*cell)->data); + if (probj->unclaimed_proto_list + && Hash_Find (probj->classes, "Protocol")) { + for (cell = &probj->unclaimed_proto_list; *cell; ) { + obj_init_protocols (probj, (*cell)->data); list_remove (cell); } } Sys_MaskPrintf (SYS_RUA_OBJ, "Finished initializing %s module\n", PR_GetString (pr, module->name)); - obj_send_load (pr); + obj_send_load (probj); Sys_MaskPrintf (SYS_RUA_OBJ, "Leaving %s module init\n", PR_GetString (pr, module->name)); } +static void +rua___obj_forward (progs_t *pr) +{ + probj_t *probj = pr->pr_objective_resources; + pr_id_t *obj = &P_STRUCT (pr, pr_id_t, 0); + pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 1); + pr_sel_t *fwd_sel = probj->forward_selector; + pr_sel_t *err_sel; + pr_class_t *class =&G_STRUCT (pr, pr_class_t, obj->class_pointer); + func_t imp; + + if (!fwd_sel) { + //FIXME sel_register_typed_name is really not the way to go about + //looking for a selector by name + fwd_sel = sel_register_typed_name (probj, "forward::", "", 0); + probj->forward_selector = fwd_sel; + } + if (obj_reponds_to (probj, obj, fwd_sel)) { + imp = get_imp (probj, class, fwd_sel); + // forward:(SEL) sel :(@va_list) args + // args is full param list + //FIXME oh for a stack + size_t parm_size = pr->pr_param_size * sizeof(pr_type_t); + size_t size = pr->pr_argc * parm_size; + string_t args_block = PR_AllocTempBlock (pr, size); + + int argc = pr->pr_argc; + __auto_type argv = (pr_type_t *) PR_GetString (pr, args_block); + // can't memcpy all params because 0 and 1 could be anywhere + memcpy (argv + 0, &P_INT (pr, 0), 4 * sizeof (pr_type_t)); + memcpy (argv + 4, &P_INT (pr, 1), 4 * sizeof (pr_type_t)); + memcpy (argv + 8, &P_INT (pr, 2), (argc - 2) * parm_size); + + PR_RESET_PARAMS (pr); + P_POINTER (pr, 0) = PR_SetPointer (pr, obj); + P_POINTER (pr, 1) = PR_SetPointer (pr, fwd_sel); + P_POINTER (pr, 2) = PR_SetPointer (pr, sel); + P_PACKED (pr, pr_va_list_t, 3).count = argc; + P_PACKED (pr, pr_va_list_t, 3).list = PR_SetPointer (pr, argv); + PR_PushTempString (pr, args_block); + PR_CallFunction (pr, imp); + return; + } + //FIXME ditto + err_sel = sel_register_typed_name (probj, "doesNotRecognize:", "", 0); + if (obj_reponds_to (probj, obj, err_sel)) { + imp = get_imp (probj, class, err_sel); + PR_RESET_PARAMS (pr); + P_POINTER (pr, 0) = PR_SetPointer (pr, obj); + P_POINTER (pr, 1) = PR_SetPointer (pr, err_sel); + P_POINTER (pr, 2) = PR_SetPointer (pr, sel); + pr->pr_argc = 3; + PR_CallFunction (pr, imp); + return; + } + + dsprintf (probj->msg, "(%s) %s does not recognize %s", + PR_CLS_ISMETA (class) ? "class" : "instance", + PR_GetString (pr, class->name), + PR_GetString (pr, probj->selector_names[sel->sel_id])); + + //FIXME ditto + err_sel = sel_register_typed_name (probj, "error:", "", 0); + if (obj_reponds_to (probj, obj, err_sel)) { + imp = get_imp (probj, class, err_sel); + PR_RESET_PARAMS (pr); + P_POINTER (pr, 0) = PR_SetPointer (pr, obj); + P_POINTER (pr, 1) = PR_SetPointer (pr, err_sel); + P_POINTER (pr, 2) = PR_SetTempString (pr, probj->msg->str); + pr->pr_argc = 3; + PR_CallFunction (pr, imp); + return; + } + + PR_RunError (pr, "%s", probj->msg->str); +} + +static void +rua___obj_responds_to (progs_t *pr) +{ + probj_t *probj = pr->pr_objective_resources; + pr_id_t *obj = &P_STRUCT (pr, pr_id_t, 0); + pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 1); + + R_INT (pr) = obj_reponds_to (probj, obj, sel); +} + static void rua_obj_error (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); int code = P_INT (pr, 1); const char *fmt = P_GSTRING (pr, 2); int count = pr->pr_argc - 3; pr_type_t **args = &pr->pr_params[3]; - obj_verror (pr, object, code, fmt, count, args); + obj_verror (probj, object, code, fmt, count, args); } static void rua_obj_verror (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); int code = P_INT (pr, 1); const char *fmt = P_GSTRING (pr, 2); @@ -965,12 +1352,13 @@ rua_obj_verror (progs_t *pr) for (i = 0; i < val->count; i++) args[i] = params + i * pr->pr_param_size; - obj_verror (pr, object, code, fmt, val->count, args); + obj_verror (probj, object, code, fmt, val->count, args); } static void rua_obj_set_error_handler (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //func_t func = P_INT (pr, 0); //arglist //XXX @@ -980,40 +1368,62 @@ rua_obj_set_error_handler (progs_t *pr) static void rua_obj_msg_lookup (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *receiver = &P_STRUCT (pr, pr_id_t, 0); pr_sel_t *op = &P_STRUCT (pr, pr_sel_t, 1); - R_INT (pr) = obj_msg_lookup (pr, receiver, op); + R_INT (pr) = obj_msg_lookup (probj, receiver, op); } static void rua_obj_msg_lookup_super (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_super_t *super = &P_STRUCT (pr, pr_super_t, 0); pr_sel_t *_cmd = &P_STRUCT (pr, pr_sel_t, 1); - R_INT (pr) = obj_msg_lookup_super (pr, super, _cmd); + R_INT (pr) = obj_msg_lookup_super (probj, super, _cmd); } static void rua_obj_msg_sendv (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; + pointer_t obj = P_POINTER (pr, 0); pr_id_t *receiver = &P_STRUCT (pr, pr_id_t, 0); + pointer_t sel = P_POINTER (pr, 1); pr_sel_t *op = &P_STRUCT (pr, pr_sel_t, 1); - pr_va_list_t *args = (pr_va_list_t *) &P_POINTER (pr, 2); - pr_type_t *params = G_GPOINTER (pr, args->list); - int count = args->count; - func_t imp = obj_msg_lookup (pr, receiver, op); + func_t imp = obj_msg_lookup (probj, receiver, op); - count = bound (0, count, 6); - if (count && pr_boundscheck->int_val) + __auto_type args = &P_PACKED (pr, pr_va_list_t, 2); + int count = args->count; + pr_type_t *params = G_GPOINTER (pr, args->list); + + if (count < 2 || count > MAX_PARMS) { + PR_RunError (pr, "bad args count in obj_msg_sendv: %d", count); + } + if (pr_boundscheck->int_val) { PR_BoundsCheckSize (pr, args->list, count * pr->pr_param_size); - if (!imp) + } + + if (!imp) { PR_RunError (pr, "%s does not respond to %s", - PR_GetString (pr, object_get_class_name (pr, receiver)), - PR_GetString (pr, pr->selector_names[op->sel_id])); - if (count) - memcpy (pr->pr_params[2], params, count * 4 * pr->pr_param_size); + PR_GetString (pr, object_get_class_name (probj, receiver)), + PR_GetString (pr, probj->selector_names[op->sel_id])); + } + + pr->pr_argc = count; + // skip over the first two parameters because receiver and op will + // replace them + count -= 2; + params += 2 * pr->pr_param_size; + PR_RESET_PARAMS (pr); + P_POINTER (pr, 0) = obj; + P_POINTER (pr, 1) = sel; + if (count) { + memcpy (&P_INT (pr, 2), params, + count * sizeof (pr_type_t) * pr->pr_param_size); + } PR_CallFunction (pr, imp); } @@ -1096,6 +1506,7 @@ rua_obj_free (progs_t *pr) static void rua_obj_get_uninstalled_dtable (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //XXX PR_RunError (pr, "%s, not implemented", __FUNCTION__); } @@ -1103,6 +1514,7 @@ rua_obj_get_uninstalled_dtable (progs_t *pr) static void rua_obj_msgSend (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *self = &P_STRUCT (pr, pr_id_t, 0); pr_sel_t *_cmd = &P_STRUCT (pr, pr_sel_t, 1); func_t imp; @@ -1113,11 +1525,11 @@ rua_obj_msgSend (progs_t *pr) } if (!_cmd) PR_RunError (pr, "null selector"); - imp = obj_msg_lookup (pr, self, _cmd); + imp = obj_msg_lookup (probj, self, _cmd); if (!imp) PR_RunError (pr, "%s does not respond to %s", - PR_GetString (pr, object_get_class_name (pr, self)), - PR_GetString (pr, pr->selector_names[_cmd->sel_id])); + PR_GetString (pr, object_get_class_name (probj, self)), + PR_GetString (pr, probj->selector_names[_cmd->sel_id])); PR_CallFunction (pr, imp); } @@ -1125,16 +1537,17 @@ rua_obj_msgSend (progs_t *pr) static void rua_obj_msgSend_super (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_super_t *super = &P_STRUCT (pr, pr_super_t, 0); pr_sel_t *_cmd = &P_STRUCT (pr, pr_sel_t, 1); func_t imp; - imp = obj_msg_lookup_super (pr, super, _cmd); + imp = obj_msg_lookup_super (probj, super, _cmd); if (!imp) { pr_id_t *self = &G_STRUCT (pr, pr_id_t, super->self); PR_RunError (pr, "%s does not respond to %s", - PR_GetString (pr, object_get_class_name (pr, self)), - PR_GetString (pr, pr->selector_names[_cmd->sel_id])); + PR_GetString (pr, object_get_class_name (probj, self)), + PR_GetString (pr, probj->selector_names[_cmd->sel_id])); } pr->pr_params[0] = pr->pr_real_params[0]; P_POINTER (pr, 0) = super->self; @@ -1144,10 +1557,11 @@ rua_obj_msgSend_super (progs_t *pr) static void rua_obj_get_class (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; const char *name = P_GSTRING (pr, 0); pr_class_t *class; - class = Hash_Find (pr->classes, name); + class = Hash_Find (probj->classes, name); if (!class) PR_RunError (pr, "could not find class %s", name); RETURN_POINTER (pr, class); @@ -1156,16 +1570,18 @@ rua_obj_get_class (progs_t *pr) static void rua_obj_lookup_class (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; const char *name = P_GSTRING (pr, 0); pr_class_t *class; - class = Hash_Find (pr->classes, name); + class = Hash_Find (probj->classes, name); RETURN_POINTER (pr, class); } static void rua_obj_next_class (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //XXX PR_RunError (pr, "%s, not implemented", __FUNCTION__); } @@ -1175,10 +1591,11 @@ rua_obj_next_class (progs_t *pr) static void rua_sel_get_name (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 0); - if (sel->sel_id > 0 && sel->sel_id <= pr->selector_index) - R_STRING (pr) = pr->selector_names[sel->sel_id]; + if (sel->sel_id > 0 && sel->sel_id <= probj->selector_index) + R_STRING (pr) = probj->selector_names[sel->sel_id]; else R_STRING (pr) = 0; } @@ -1194,25 +1611,28 @@ rua_sel_get_type (progs_t *pr) static void rua_sel_get_uid (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; const char *name = P_GSTRING (pr, 0); - RETURN_POINTER (pr, sel_register_typed_name (pr, name, "", 0)); + RETURN_POINTER (pr, sel_register_typed_name (probj, name, "", 0)); } static void rua_sel_register_name (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; const char *name = P_GSTRING (pr, 0); - RETURN_POINTER (pr, sel_register_typed_name (pr, name, "", 0)); + RETURN_POINTER (pr, sel_register_typed_name (probj, name, "", 0)); } static void rua_sel_is_mapped (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; // FIXME might correspond to a string pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 0); - R_INT (pr) = sel->sel_id > 0 && sel->sel_id <= pr->selector_index; + R_INT (pr) = sel->sel_id > 0 && sel->sel_id <= probj->selector_index; } //==================================================================== @@ -1220,20 +1640,22 @@ rua_sel_is_mapped (progs_t *pr) static void rua_class_get_class_method (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_class_t *class = &P_STRUCT (pr, pr_class_t, 0); pr_sel_t *aSel = &P_STRUCT (pr, pr_sel_t, 1); pr_method_t *method; class = &G_STRUCT (pr, pr_class_t, class->class_pointer); - method = obj_find_message (pr, class, aSel); + method = obj_find_message (probj, class, aSel); RETURN_POINTER (pr, method); } static void rua_class_get_instance_method (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_class_t *class = &P_STRUCT (pr, pr_class_t, 0); pr_sel_t *aSel = &P_STRUCT (pr, pr_sel_t, 1); - pr_method_t *method = obj_find_message (pr, class, aSel); + pr_method_t *method = obj_find_message (probj, class, aSel); RETURN_POINTER (pr, method); } @@ -1363,6 +1785,7 @@ rua_class_get_gc_object_type (progs_t *pr) static void rua_class_ivar_set_gcinvisible (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //pr_class_t *impostor = &P_STRUCT (pr, pr_class_t, 0); //const char *ivarname = P_GSTRING (pr, 1); //int gcInvisible = P_INT (pr, 2); @@ -1383,10 +1806,11 @@ rua_method_get_imp (progs_t *pr) static void rua_get_imp (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_class_t *class = &P_STRUCT (pr, pr_class_t, 0); pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 1); - R_INT (pr) = get_imp (pr, class, sel); + R_INT (pr) = get_imp (probj, class, sel); } //==================================================================== @@ -1476,9 +1900,10 @@ rua_object_get_meta_class (progs_t *pr) static void rua_object_get_class_name (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); - R_STRING (pr) = object_get_class_name (pr, object); + R_STRING (pr) = object_get_class_name (probj, object); } static void @@ -1496,9 +1921,10 @@ rua_object_is_class (progs_t *pr) static void rua_object_is_instance (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); - R_INT (pr) = object_is_instance (pr, object); + R_INT (pr) = object_is_instance (probj, object); } static void @@ -1524,6 +1950,7 @@ rua__i_Object__hash (progs_t *pr) static void rua__i_Object_error_error_ (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *self = &P_STRUCT (pr, pr_id_t, 0); const char *fmt = P_GSTRING (pr, 2); dstring_t *dstr = dstring_new (); @@ -1531,37 +1958,113 @@ rua__i_Object_error_error_ (progs_t *pr) pr_type_t **args = &pr->pr_params[3]; dsprintf (dstr, "error: %s (%s)\n%s", - PR_GetString (pr, object_get_class_name (pr, self)), - object_is_instance (pr, self) ? "instance" : "class", fmt); - obj_verror (pr, self, 0, dstr->str, count, args); + PR_GetString (pr, object_get_class_name (probj, self)), + object_is_instance (probj, self) ? "instance" : "class", fmt); + obj_verror (probj, self, 0, dstr->str, count, args); +} + +static int +obj_protocol_conformsToProtocol (probj_t *probj, pr_protocol_t *proto, + pr_protocol_t *protocol) +{ + progs_t *pr = probj->pr; + + pr_protocol_list_t *proto_list; + + if (!proto || !protocol) { + return 0; + } + if (proto == protocol) { + return 1; + } + if (proto->protocol_name == protocol->protocol_name + || strcmp (PR_GetString (pr, proto->protocol_name), + PR_GetString (pr, protocol->protocol_name)) == 0) { + return 1; + } + proto_list = &G_STRUCT (pr, pr_protocol_list_t, proto->protocol_list); + while (proto_list) { + Sys_MaskPrintf (SYS_RUA_OBJ, "%x %x %d\n", + PR_SetPointer (pr, proto_list), proto_list->next, + proto_list->count); + for (int i = 0; i < proto_list->count; i++) { + proto = &G_STRUCT (pr, pr_protocol_t, proto_list->list[i]); + if (proto == protocol + || obj_protocol_conformsToProtocol (probj, proto, protocol)) { + return 1; + } + } + + proto_list = &G_STRUCT (pr, pr_protocol_list_t, proto_list->next); + } + return 0; } static void rua__c_Object__conformsToProtocol_ (progs_t *pr) { - //pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); - //pr_protocol_t *proto = &P_STRUCT (pr, pr_protocol_t, 2); - //... - //XXX - PR_RunError (pr, "%s, not implemented", __FUNCTION__); + probj_t *probj = pr->pr_objective_resources; + // class points to _OBJ_CLASS_foo, and class->class_pointer points to + // _OBJ_METACLASS_foo + pr_class_t *class = &P_STRUCT (pr, pr_class_t, 0); + // protocol->class_pointer must point to _OBJ_CLASS_Protocol (ie, if + // protocol is not actually a protocol, then the class cannot conform + // to it) + pr_protocol_t *protocol = &P_STRUCT (pr, pr_protocol_t, 2); + pr_protocol_list_t *proto_list; + + if (!class || !protocol) { + goto not_conforms; + } + if (protocol->class_pointer != PR_SetPointer (pr, + Hash_Find (probj->classes, + "Protocol"))) { + goto not_conforms; + } + proto_list = &G_STRUCT (pr, pr_protocol_list_t, class->protocols); + while (proto_list) { + Sys_MaskPrintf (SYS_RUA_OBJ, "%x %x %d\n", + PR_SetPointer (pr, proto_list), proto_list->next, + proto_list->count); + for (int i = 0; i < proto_list->count; i++) { + __auto_type proto = &G_STRUCT (pr, pr_protocol_t, + proto_list->list[i]); + if (proto == protocol + || obj_protocol_conformsToProtocol (probj, proto, protocol)) { + goto conforms; + } + } + + proto_list = &G_STRUCT (pr, pr_protocol_list_t, proto_list->next); + } +not_conforms: + Sys_MaskPrintf (SYS_RUA_OBJ, "does not conform\n"); + R_INT (pr) = 0; + return; +conforms: + Sys_MaskPrintf (SYS_RUA_OBJ, "conforms\n"); + R_INT (pr) = 1; + return; } static void rua_PR_FindGlobal (progs_t *pr) { const char *name = P_GSTRING (pr, 0); - ddef_t *def; + pr_def_t *def; R_POINTER (pr) = 0; def = PR_FindGlobal (pr, name); if (def) - R_POINTER (pr) = def->ofs; //FIXME def's can't access > 32k + R_POINTER (pr) = def->ofs; } //==================================================================== static builtin_t obj_methods [] = { {"__obj_exec_class", rua___obj_exec_class, -1}, + {"__obj_forward", rua___obj_forward, -1}, + {"__obj_responds_to", rua___obj_responds_to, -1}, {"obj_error", rua_obj_error, -1}, {"obj_verror", rua_obj_verror, -1}, @@ -1631,20 +2134,21 @@ static builtin_t obj_methods [] = { static int rua_init_finish (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_class_t **class_list, **class; - class_list = (pr_class_t **) Hash_GetList (pr->classes); + class_list = (pr_class_t **) Hash_GetList (probj->classes); if (*class_list) { pr_class_t *object_class; pointer_t object_ptr; - object_class = Hash_Find (pr->classes, "Object"); + object_class = Hash_Find (probj->classes, "Object"); if (object_class && !object_class->super_class) object_ptr = (pr_type_t *)object_class - pr->pr_globals; else PR_Error (pr, "root class Object not found"); for (class = class_list; *class; class++) - finish_class (pr, *class, object_ptr); + finish_class (probj, *class, object_ptr); } free (class_list); @@ -1652,59 +2156,84 @@ rua_init_finish (progs_t *pr) } static int -rua_init_runtime (progs_t *pr) +rua_obj_init_runtime (progs_t *pr) { - ddef_t *def; - unsigned i; - - if (!pr->selector_hash) - pr->selector_hash = Hash_NewTable (1021, selector_get_key, 0, pr); - else - Hash_FlushTable (pr->selector_hash); - pr->selector_index = 0; - for (i = 0; i < pr->selector_index_max; i++) { - obj_list_free (pr->selector_sels[i]); - pr->selector_sels[i] = 0; - pr->selector_names[i] = 0; - } - - if (!pr->classes) - pr->classes = Hash_NewTable (1021, class_get_key, 0, pr); - else - Hash_FlushTable (pr->classes); - - if (!pr->load_methods) { - pr->load_methods = Hash_NewTable (1021, 0, 0, pr); - Hash_SetHashCompare (pr->load_methods, load_methods_get_hash, - load_methods_compare); - } else { - Hash_FlushTable (pr->load_methods); - } - - pr->unresolved_classes = 0; - pr->unclaimed_categories = 0; - pr->unclaimed_proto_list = 0; - pr->module_list = 0; - pr->class_tree_list = 0; + probj_t *probj = pr->pr_objective_resources; + pr_def_t *def; + dfunction_t *obj_forward; if ((def = PR_FindField (pr, ".this"))) pr->fields.this = def->ofs; + probj->obj_forward = 0; + if ((obj_forward = PR_FindFunction (pr, "__obj_forward"))) { + probj->obj_forward = (intptr_t) (obj_forward - pr->pr_functions); + } + PR_AddLoadFinishFunc (pr, rua_init_finish); return 1; } +static void +rua_obj_cleanup (progs_t *pr, void *data) +{ + unsigned i; + + __auto_type probj = (probj_t *) data; + pr->pr_objective_resources = probj; + + Hash_FlushTable (probj->selector_hash); + probj->selector_index = 0; + for (i = 0; i < probj->selector_index_max; i++) { + obj_list_free (probj->selector_sels[i]); + probj->selector_sels[i] = 0; + probj->selector_names[i] = 0; + } + + for (i = 0; i < probj->dtables._size; i++) { + dtable_t *dtable = dtable_get (probj, i); + if (!dtable->imp) { + break; + } + free (dtable->imp); + } + dtable_reset (probj); + + Hash_FlushTable (probj->classes); + Hash_FlushTable (probj->protocols); + Hash_FlushTable (probj->load_methods); + probj->unresolved_classes = 0; + probj->unclaimed_categories = 0; + probj->unclaimed_proto_list = 0; + probj->module_list = 0; + probj->class_tree_list = 0; +} + void RUA_Obj_Init (progs_t *pr, int secure) { + probj_t *probj = calloc (1, sizeof (*probj)); + + probj->pr = pr; + probj->selector_hash = Hash_NewTable (1021, selector_get_key, 0, probj); + probj->classes = Hash_NewTable (1021, class_get_key, 0, probj); + probj->protocols = Hash_NewTable (1021, protocol_get_key, 0, probj); + probj->load_methods = Hash_NewTable (1021, 0, 0, probj); + probj->msg = dstring_newstr(); + Hash_SetHashCompare (probj->load_methods, load_methods_get_hash, + load_methods_compare); + + PR_Resources_Register (pr, "RUA_ObjectiveQuakeC", probj, rua_obj_cleanup); + PR_RegisterBuiltins (pr, obj_methods); - PR_AddLoadFunc (pr, rua_init_runtime); + PR_AddLoadFunc (pr, rua_obj_init_runtime); } func_t RUA_Obj_msg_lookup (progs_t *pr, pointer_t _self, pointer_t __cmd) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *self = &G_STRUCT (pr, pr_id_t, _self); pr_sel_t *_cmd = &G_STRUCT (pr, pr_sel_t, __cmd); func_t imp; @@ -1713,11 +2242,11 @@ RUA_Obj_msg_lookup (progs_t *pr, pointer_t _self, pointer_t __cmd) return 0; if (!_cmd) PR_RunError (pr, "null selector"); - imp = obj_msg_lookup (pr, self, _cmd); + imp = obj_msg_lookup (probj, self, _cmd); if (!imp) PR_RunError (pr, "%s does not respond to %s", - PR_GetString (pr, object_get_class_name (pr, self)), - PR_GetString (pr, pr->selector_names[_cmd->sel_id])); + PR_GetString (pr, object_get_class_name (probj, self)), + PR_GetString (pr, probj->selector_names[_cmd->sel_id])); return imp; } diff --git a/libs/ruamoko/rua_qfile.c b/libs/ruamoko/rua_qfile.c index 057ff0ef6..d96c433a2 100644 --- a/libs/ruamoko/rua_qfile.c +++ b/libs/ruamoko/rua_qfile.c @@ -38,9 +38,7 @@ #include "QF/dstring.h" #include "QF/progs.h" -#include "QF/quakefs.h" -#include "QF/va.h" -#include "QF/zone.h" +#include "QF/quakeio.h" #include "rua_internal.h" diff --git a/libs/ruamoko/rua_qfs.c b/libs/ruamoko/rua_qfs.c index 35d69d0c8..87b2c5add 100644 --- a/libs/ruamoko/rua_qfs.c +++ b/libs/ruamoko/rua_qfs.c @@ -181,6 +181,12 @@ bi_QFS_FilelistFree (progs_t *pr) PR_Zone_Free (pr, list); } +static void +bi_QFS_GetDirectory (progs_t *pr) +{ + RETURN_STRING (pr, qfs_gamedir->dir.def); +} + static builtin_t builtins[] = { {"QFS_Open", bi_QFS_Open, -1}, {"QFS_WOpen", bi_QFS_WOpen, -1}, @@ -190,6 +196,7 @@ static builtin_t builtins[] = { {"QFS_WriteFile", bi_QFS_WriteFile, -1}, {"QFS_Filelist", bi_QFS_Filelist, -1}, {"QFS_FilelistFree", bi_QFS_FilelistFree, -1}, + {"QFS_GetDirectory", bi_QFS_GetDirectory, -1}, {0} }; diff --git a/libs/ruamoko/rua_script.c b/libs/ruamoko/rua_script.c index c6fae5750..ff5b2ab0a 100644 --- a/libs/ruamoko/rua_script.c +++ b/libs/ruamoko/rua_script.c @@ -48,7 +48,6 @@ typedef struct { script_t script; string_t dstr; progs_t *pr; - string_t err_msg; } rua_script_t; typedef struct { @@ -92,13 +91,6 @@ bi_script_clear (progs_t *pr, void *data) script_reset (res); } -static void -bi_script_error (script_t *_script, const char *msg) -{ - rua_script_t *script = (rua_script_t *)_script; - script->err_msg = PR_SetString (script->pr, msg); -} - static void bi_Script_New (progs_t *pr) { @@ -110,7 +102,6 @@ bi_Script_New (progs_t *pr) script->dstr = PR_NewMutableString (pr); script->script.token = PR_GetMutableString (pr, script->dstr); - script->script.error = bi_script_error; script->pr = pr; R_INT (pr) = script_index (res, script); } @@ -180,8 +171,8 @@ bi_Script_Error (progs_t *pr) if (!script) PR_RunError (pr, "invalid script handle"); - R_STRING (pr) = script->err_msg; - script->err_msg = 0; + R_STRING (pr) = PR_SetString (pr, script->script.error); + script->script.error = 0; } static void diff --git a/libs/ruamoko/rua_string.c b/libs/ruamoko/rua_string.c index 7f233e362..c96f44e57 100644 --- a/libs/ruamoko/rua_string.c +++ b/libs/ruamoko/rua_string.c @@ -112,6 +112,10 @@ bi_str_mid (progs_t *pr) end = size; if (pos < 0 || pos >= size || end <= pos) return; + if (end == size) { + R_STRING (pr) = str + pos - pr->pr_strings; + return; + } temp = alloca (end - pos + 1); strncpy (temp, str + pos, end - pos); temp[end - pos] = 0; @@ -130,6 +134,18 @@ bi_str_str (progs_t *pr) R_STRING (pr) = res - pr->pr_strings; } +static void +bi_str_char (progs_t *pr) +{ + const char *str = P_GSTRING (pr, 0); + int ind = P_INT (pr, 1); + + if (ind < 0) { + PR_RunError (pr, "negative index to str_char"); + } + R_INT (pr) = str[ind]; +} + static builtin_t builtins[] = { {"str_new", bi_str_new, -1}, {"str_free", bi_str_free, -1}, @@ -139,6 +155,7 @@ static builtin_t builtins[] = { {"str_mid|*i", bi_str_mid, -1}, {"str_mid|*ii", bi_str_mid, -1}, {"str_str", bi_str_str, -1}, + {"str_char", bi_str_char, -1}, {0} }; diff --git a/libs/util/Makefile.am b/libs/util/Makefile.am index 0c6421450..c35e4e305 100644 --- a/libs/util/Makefile.am +++ b/libs/util/Makefile.am @@ -53,7 +53,8 @@ libQFutil_la_SOURCES= \ fendian.c hash.c idparse.c info.c link.c llist.c \ mathlib.c mdfour.c mersenne.c msg.c pakfile.c plugin.c qargs.c qendian.c \ qfplist.c quakefs.c quakeio.c riff.c script.c segtext.c set.c sizebuf.c \ - string.c sys.c va.c ver_check.c vrect.c wad.c wadfile.c zone.c \ + string.c sys.c txtbuffer.c va.c ver_check.c vrect.c wad.c wadfile.c \ + zone.c \ $(dirent) $(fnmatch) $(getopt) EXTRA_DIST= $(fnmatch_src) $(getopt_src) diff --git a/libs/util/dstring.c b/libs/util/dstring.c index 18d83f44a..fb495403c 100644 --- a/libs/util/dstring.c +++ b/libs/util/dstring.c @@ -299,7 +299,7 @@ dstring_clearstr (dstring_t *dstr) dstr->str[0] = 0; } -static __attribute__((format(printf, 3, 0))) int +static __attribute__((format(printf, 3, 0))) char * _dvsprintf (dstring_t *dstr, int offs, const char *fmt, va_list args) { int size; @@ -325,20 +325,20 @@ _dvsprintf (dstring_t *dstr, int offs, const char *fmt, va_list args) } dstr->size = size + offs + 1; dstr->str[dstr->size - 1] = 0; - return size; + return dstr->str; } -VISIBLE int +VISIBLE char * dvsprintf (dstring_t *dstr, const char *fmt, va_list args) { return _dvsprintf (dstr, 0, fmt, args); } -VISIBLE int +VISIBLE char * dsprintf (dstring_t *dstr, const char *fmt, ...) { va_list args; - int ret; + char *ret; va_start (args, fmt); ret = _dvsprintf (dstr, 0, fmt, args); @@ -347,7 +347,7 @@ dsprintf (dstring_t *dstr, const char *fmt, ...) return ret; } -VISIBLE int +VISIBLE char * davsprintf (dstring_t *dstr, const char *fmt, va_list args) { int offs = 0; @@ -357,11 +357,11 @@ davsprintf (dstring_t *dstr, const char *fmt, va_list args) return _dvsprintf (dstr, offs, fmt, args); } -VISIBLE int +VISIBLE char * dasprintf (dstring_t *dstr, const char *fmt, ...) { va_list args; - int ret; + char *ret; int offs = 0; if (dstr->size) diff --git a/libs/util/mdfour.c b/libs/util/mdfour.c index 99f57bef2..61bc46e9a 100644 --- a/libs/util/mdfour.c +++ b/libs/util/mdfour.c @@ -37,7 +37,6 @@ #endif #include "QF/mdfour.h" -#include "QF/uint32.h" /* NOTE: This code makes no attempt to be fast! It assumes that a int is at least 32 bits long @@ -62,12 +61,12 @@ static struct mdfour *m; /* this applies md4 to 64 byte chunks */ static void -mdfour64 (uint32 * M) +mdfour64 (uint32_t * M) { int j; - uint32 AA, BB, CC, DD; - uint32 X[16]; - uint32 A, B, C, D; + uint32_t AA, BB, CC, DD; + uint32_t X[16]; + uint32_t A, B, C, D; for (j = 0; j < 16; j++) X[j] = M[j]; @@ -154,7 +153,7 @@ mdfour64 (uint32 * M) } static void -copy64 (uint32 * M, const unsigned char *in) +copy64 (uint32_t * M, const unsigned char *in) { int i; @@ -164,7 +163,7 @@ copy64 (uint32 * M, const unsigned char *in) } static void -copy4 (unsigned char *out, uint32 x) +copy4 (unsigned char *out, uint32_t x) { out[0] = x & 0xFF; out[1] = (x >> 8) & 0xFF; @@ -186,8 +185,8 @@ static void mdfour_tail (const unsigned char *in, int n) { unsigned char buf[128]; - uint32 M[16]; - uint32 b; + uint32_t M[16]; + uint32_t b; m->totalN += n; @@ -214,7 +213,7 @@ mdfour_tail (const unsigned char *in, int n) VISIBLE void mdfour_update (struct mdfour *md, const unsigned char *in, int n) { - uint32 M[16]; + uint32_t M[16]; if (n == 0) mdfour_tail (in, n); diff --git a/libs/util/script.c b/libs/util/script.c index eeb1df977..fa8b51ae0 100644 --- a/libs/util/script.c +++ b/libs/util/script.c @@ -34,19 +34,6 @@ #include "QF/dstring.h" #include "QF/script.h" -static void __attribute__ ((format (printf, 2, 3), noreturn)) -script_error (script_t *script, const char *fmt, ...) -{ - va_list args; - - va_start (args, fmt); - fprintf (stderr, "%s:%d: ", script->file, script->line); - vfprintf (stderr, fmt, args); - fprintf (stderr, "\n"); - va_end (args); - exit (1); -} - VISIBLE script_t * Script_New (void) { @@ -69,11 +56,16 @@ Script_Start (script_t *script, const char *file, const char *data) script->file = file; script->p = data; script->unget = false; + script->error = 0; } VISIBLE qboolean Script_TokenAvailable (script_t *script, qboolean crossline) { + if (script->error) { + return false; + } + if (script->unget) return true; skipspace: @@ -111,6 +103,10 @@ Script_GetToken (script_t *script, qboolean crossline) { const char *token_p; + if (script->error) { + return false; + } + if (script->unget) { // is a token allready waiting? script->unget = false; return true; @@ -118,10 +114,7 @@ Script_GetToken (script_t *script, qboolean crossline) if (!Script_TokenAvailable (script, crossline)) { if (!crossline) { - if (script->error) - script->error (script, "line is incomplete"); - else - script_error (script, "line is incomplete"); + script->error = "line is incomplete"; } return false; } @@ -134,18 +127,13 @@ Script_GetToken (script_t *script, qboolean crossline) while (*script->p != '"') { if (!*script->p) { script->line = start_line; - if (script->error) - script->error (script, "EOF inside quoted token"); - else - script_error (script, "EOF inside quoted token"); + script->error = "EOF inside quoted token"; return false; } if (*script->p == '\n') { if (script->no_quote_lines) { - if (script->error) - script->error (script, "EOL inside quoted token"); - else - script_error (script, "EOL inside quoted token"); + script->error = "EOL inside quoted token"; + return false; } script->line++; } @@ -175,11 +163,16 @@ Script_GetToken (script_t *script, qboolean crossline) VISIBLE void Script_UngetToken (script_t *script) { - script->unget = true; + if (!script->error) { + script->unget = true; + } } VISIBLE const char * Script_Token (script_t *script) { + if (script->error) { + return 0; + } return script->token->str; } diff --git a/libs/util/sys.c b/libs/util/sys.c index b2e28f71d..811cac886 100644 --- a/libs/util/sys.c +++ b/libs/util/sys.c @@ -126,18 +126,18 @@ qboolean stdin_ready; /* The translation table between the graphical font and plain ASCII --KB */ VISIBLE const char sys_char_map[256] = { - '\0', '#', '#', '#', '#', '.', '#', '#', - '#', 9, 10, '#', ' ', 13, '.', '.', + 0, '#', '#', '#', '#', '.', '#', '#', + '#', 9, 10, '#', ' ', 13, '.', '.', '[', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '<', '=', '>', - ' ', '!', '"', '#', '$', '%', '&', '\'', + ' ', '!', '"', '#', '$', '%', '&','\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + 'X', 'Y', 'Z', '[','\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', @@ -147,14 +147,14 @@ VISIBLE const char sys_char_map[256] = { '#', '#', ' ', '#', ' ', '>', '.', '.', '[', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '<', '=', '>', - ' ', '!', '"', '#', '$', '%', '&', '\'', + ' ', '!', '"', '#', '$', '%', '&','\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + 'X', 'Y', 'Z', '[','\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', @@ -240,16 +240,20 @@ Sys_FileExists (const char *path) for want of a better name, but it sets the function pointer for the actual implementation of Sys_Printf. */ -VISIBLE void +VISIBLE sys_printf_t Sys_SetStdPrintf (sys_printf_t func) { + sys_printf_t prev = sys_std_printf_function; sys_std_printf_function = func; + return prev; } -VISIBLE void +VISIBLE sys_printf_t Sys_SetErrPrintf (sys_printf_t func) { + sys_printf_t prev = sys_err_printf_function; sys_err_printf_function = func; + return prev; } void diff --git a/libs/util/test/Makefile.am b/libs/util/test/Makefile.am index f6dd4115a..74d9a2f4e 100644 --- a/libs/util/test/Makefile.am +++ b/libs/util/test/Makefile.am @@ -4,7 +4,8 @@ AM_CPPFLAGS= -I$(top_srcdir)/include check_PROGRAMS= \ test-bary test-cs test-darray test-dq test-half test-mat3 test-mat4 \ - test-plist test-qfs test-quat test-seb test-seg test-set test-vrect + test-plist test-qfs test-quat test-seb test-seg test-set test-txtbuffer \ + test-vrect test_bary_SOURCES=test-bary.c test_bary_LDADD=$(top_builddir)/libs/util/libQFutil.la @@ -58,6 +59,10 @@ test_set_SOURCES=test-set.c test_set_LDADD=$(top_builddir)/libs/util/libQFutil.la test_set_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la +test_txtbuffer_SOURCES=test-txtbuffer.c +test_txtbuffer_LDADD=$(top_builddir)/libs/util/libQFutil.la +test_txtbuffer_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la + test_vrect_SOURCES=test-vrect.c test_vrect_LDADD=$(top_builddir)/libs/util/libQFutil.la test_vrect_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la diff --git a/libs/util/test/test-txtbuffer.c b/libs/util/test/test-txtbuffer.c new file mode 100644 index 000000000..44ccebdc9 --- /dev/null +++ b/libs/util/test/test-txtbuffer.c @@ -0,0 +1,240 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include + +#include "QF/txtbuffer.h" + +static size_t +check_text_ptr (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->text != 0; +} + +static size_t +get_textSize (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->textSize; +} + +static size_t +get_bufferSize (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->bufferSize; +} + +static size_t +get_gapOffset (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->gapOffset; +} + +static size_t +get_gapSize (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->gapSize; +} + +static size_t +insert_text (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + if (TextBuffer_InsertAt (buffer, offset, txt, length)) { + memset (buffer->text + buffer->gapOffset, 0xff, buffer->gapSize); + return 1; + } + return 0; +} + +static size_t +delete_text (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + if (TextBuffer_DeleteAt (buffer, offset, length)) { + memset (buffer->text + buffer->gapOffset, 0xff, buffer->gapSize); + return 1; + } + return 0; +} + +static size_t +destroy_buffer (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + TextBuffer_Destroy (buffer); + return 0; +} + +typedef size_t (*test_func) (txtbuffer_t *buffer, size_t offset, + const char *text, size_t length); + +static const char test_text[] = { + "Guarding the entrance to the Grendal\n" + "Gorge is the Shadow Gate, a small keep\n" + "and monastary which was once the home\n" + "of the Shadow cult.\n\n" + "For years the Shadow Gate existed in\n" + "obscurity but after the cult discovered\n" + "the \3023\354\341\343\353\240\307\341\364\345 in the caves below\n" + "the empire took notice.\n" + "A batallion of Imperial Knights were\n" + "sent to the gate to destroy the cult\n" + "and claim the artifact for the King.", +}; +static const char empty[TXTBUFFER_GROW] = { }; + +static size_t +compare_text (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + //printf("%zd %ld %zd\n", offset, txt - test_text, length); + size_t res = memcmp (buffer->text + offset, txt, length) == 0; + if (!res) { + for (size_t i = 0; i < length; i++) { + //printf ("%02x %02x\n", txt[i] & 0xff, buffer->text[offset + i] & 0xff); + } + } + return res; +} + +#define txtsize (sizeof (test_text) - 1) +#define txtsize0 txtsize +#define bufsize0 (TXTBUFFER_GROW) +#define gapoffs0 txtsize0 +#define gapsize0 (bufsize0 - txtsize0) +#define subtxtlen 200 +#define suboffs 200 +#define txtsize1 (txtsize0 + subtxtlen) +#define bufsize1 (TXTBUFFER_GROW) +#define gapoffs1 (suboffs + subtxtlen) +#define gapsize1 (bufsize1 - txtsize1) +#define deltxtlen 350 +#define deloffs 150 +#define txtsize2 (txtsize + subtxtlen - deltxtlen) +#define bufsize2 (TXTBUFFER_GROW) +#define gapoffs2 (deloffs) +#define gapsize2 (bufsize2 - txtsize2) +#define deltxtrem (txtsize2 - gapoffs2) +#define emptyoffs 370 +#define txtsize3 (txtsize + sizeof (empty)) +#define bufsize3 (2 * TXTBUFFER_GROW) +#define gapoffs3 (emptyoffs + sizeof (empty)) +#define gapsize3 (bufsize3 - txtsize3) +#define txtsize4 (txtsize + 2 * sizeof (empty)) +#define bufsize4 (3 * TXTBUFFER_GROW) +#define gapoffs4 (emptyoffs + sizeof (empty)) +#define gapsize4 (bufsize4 - txtsize4) + +struct { + test_func test; + size_t offset_param; + const char *text_param; + size_t length_param; + int test_expect; +} tests[] = { + { check_text_ptr, 0, 0, 0, 0 }, + { get_textSize, 0, 0, 0, 0 }, + { get_bufferSize, 0, 0, 0, 0 }, + { get_gapOffset, 0, 0, 0, 0 }, + { get_gapSize, 0, 0, 0, 0 }, + { insert_text, 0, test_text, txtsize, 1 }, + { get_textSize, 0, 0, 0, txtsize0 }, + { get_bufferSize, 0, 0, 0, bufsize0 }, + { get_gapOffset, 0, 0, 0, gapoffs0 }, + { get_gapSize, 0, 0, 0, gapsize0 }, + { compare_text, 0, test_text, txtsize, 1 }, + { insert_text, suboffs, test_text, subtxtlen, 1 }, + { get_textSize, 0, 0, 0, txtsize1 }, + { get_bufferSize, 0, 0, 0, bufsize1 }, + { get_gapOffset, 0, 0, 0, gapoffs1 }, + { get_gapSize, 0, 0, 0, gapsize1 }, + { compare_text, 0, test_text, txtsize, 0 }, + { compare_text, 0, test_text, suboffs, 1 }, + { compare_text, suboffs, test_text, subtxtlen, 1 }, + { compare_text, gapoffs1 + gapsize1, test_text + subtxtlen, txtsize - subtxtlen, 1 }, + { delete_text, deloffs, 0, deltxtlen, 1 }, + { get_textSize, 0, 0, 0, txtsize2 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, gapoffs2 }, + { get_gapSize, 0, 0, 0, gapsize2 }, + { compare_text, 0, test_text, suboffs, 0 }, + { compare_text, suboffs, test_text, subtxtlen, 0 }, + { compare_text, gapoffs1 + gapsize1, test_text + subtxtlen, txtsize - subtxtlen, 0 }, + { compare_text, 0, test_text, deloffs, 1 }, + { compare_text, gapoffs2 + gapsize2, test_text + txtsize - deltxtrem, deltxtrem, 1 }, + { compare_text, gapoffs2 + gapsize2 - 1, test_text + txtsize - deltxtrem - 1, 1, 0 }, + { delete_text, 0, 0, -1, 1 }, + { check_text_ptr, 0, 0, 0, 1 }, + { get_textSize, 0, 0, 0, 0 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, 0 }, + { get_gapSize, 0, 0, 0, bufsize2 }, + { insert_text, 1, test_text, txtsize, 0 }, + { get_textSize, 0, 0, 0, 0 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, 0 }, + { get_gapSize, 0, 0, 0, bufsize2 }, + { insert_text, 0, test_text, txtsize, 1 }, + { insert_text, 300, 0, 0, 1 }, + { get_textSize, 0, 0, 0, txtsize0 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, 300 }, + { get_gapSize, 0, 0, 0, gapsize0 }, + { compare_text, 0, test_text, 300, 1 }, + { compare_text, 300, test_text + 300, 1, 0 }, + { compare_text, 300 + gapsize0, test_text + 300, txtsize - 300, 1 }, + { compare_text, 300 + gapsize0 - 1, test_text + 300 - 1, 1, 0 }, + { insert_text, 350, 0, 0, 1 }, + { compare_text, (emptyoffs - 20) + gapsize0, test_text + (emptyoffs - 20), txtsize - (emptyoffs - 20), 1 }, + { get_textSize, 0, 0, 0, txtsize0 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, (emptyoffs - 20) }, + { get_gapSize, 0, 0, 0, gapsize0 }, + { insert_text, emptyoffs, empty, sizeof (empty), 1 }, + { get_textSize, 0, 0, 0, txtsize3 }, + { get_bufferSize, 0, 0, 0, bufsize3 }, + { get_gapOffset, 0, 0, 0, gapoffs3 }, + { get_gapSize, 0, 0, 0, gapsize3 }, + { insert_text, emptyoffs, empty, sizeof (empty), 1 }, + { get_textSize, 0, 0, 0, txtsize4 }, + { get_bufferSize, 0, 0, 0, bufsize4 }, + { get_gapOffset, 0, 0, 0, gapoffs4 }, + { get_gapSize, 0, 0, 0, gapsize4 }, + { destroy_buffer, 0, 0, 0, 0 }, +}; +#define num_tests (sizeof (tests) / sizeof (tests[0])) +int test_start_line = __LINE__ - num_tests - 2; + +int +main (int argc, const char **argv) +{ + size_t i; + int res = 0; + + txtbuffer_t *buffer = TextBuffer_Create (); + + for (i = 0; i < num_tests; i++) { + if (tests[i].test) { + int test_res; + test_res = tests[i].test (buffer, + tests[i].offset_param, + tests[i].text_param, + tests[i].length_param); + if (test_res != tests[i].test_expect) { + res |= 1; + printf ("test %d (line %d) failed\n", (int) i, + (int) i + test_start_line); + printf ("expect: %d\n", tests[i].test_expect); + printf ("got : %d\n", test_res); + continue; + } + } + } + return res; +} diff --git a/libs/util/txtbuffer.c b/libs/util/txtbuffer.c new file mode 100644 index 000000000..59ee0da16 --- /dev/null +++ b/libs/util/txtbuffer.c @@ -0,0 +1,194 @@ +/* + txtbuffer.c + + Text buffer + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/alloc.h" +#include "QF/qtypes.h" +#include "QF/sys.h" +#include "QF/txtbuffer.h" + +#include "compat.h" + +static txtbuffer_t *txtbuffers_freelist; + +static char * +txtbuffer_open_gap (txtbuffer_t *buffer, size_t offset, size_t length) +{ + size_t len; + char *dst; + char *src; + + if (offset == buffer->gapOffset && length <= buffer->gapSize) { + return buffer->text + buffer->gapOffset; + } + if (length <= buffer->gapSize) { + // no resize needed + if (offset < buffer->gapOffset) { + len = buffer->gapOffset - offset; + dst = buffer->text + buffer->gapOffset + buffer->gapSize - len; + src = buffer->text + offset; + } else { + len = offset - buffer->gapOffset; + dst = buffer->text + buffer->gapOffset; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + } + memmove (dst, src, len); + } else { + // need to resize the buffer + // grow the buffer by the difference in lengths rounded up to the + // next multiple of TXTBUFFER_GROW + size_t new_size = buffer->bufferSize + length - buffer->gapSize; + new_size = (new_size + TXTBUFFER_GROW - 1) & ~(TXTBUFFER_GROW - 1); + char *new_text = realloc (buffer->text, new_size); + + if (!new_text) { + return 0; + } + buffer->text = new_text; + + if (offset < buffer->gapOffset) { + // move the old post-gap to the end of the new buffer + len = buffer->bufferSize - (buffer->gapOffset + buffer->gapSize); + dst = buffer->text + new_size - len; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + memmove (dst, src, len); + // move the remaining chunk to after the end of the new gap or + // just before the location of the previous move + len = buffer->gapOffset - offset; + dst -= len; + src = buffer->text + offset; + memmove (dst, src, len); + } else if (offset > buffer->gapOffset) { + // move the old post-offset to the end of the new buffer + len = buffer->bufferSize - (offset + buffer->gapSize); + dst = buffer->text + new_size - len; + src = buffer->text + offset + buffer->gapSize; + memmove (dst, src, len); + // move the old post-gap to offset block to before the new gap + len = offset - buffer->gapOffset; + dst = buffer->text + buffer->gapOffset; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + memmove (dst, src, len); + } else { + // the gap only grew, did not move + len = buffer->bufferSize - (offset + buffer->gapSize); + dst = buffer->text + new_size - len; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + memmove (dst, src, len); + } + buffer->gapSize += new_size - buffer->bufferSize; + buffer->bufferSize = new_size; + } + buffer->gapOffset = offset; + return buffer->text + buffer->gapOffset; +} + +static char * +txtbuffer_delete_text (txtbuffer_t *buffer, size_t offset, size_t length) +{ + size_t len; + char *dst; + char *src; + + if (offset > buffer->gapOffset) { + len = offset - buffer->gapOffset; + dst = buffer->text + buffer->gapOffset; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + memmove (dst, src, len); + } else if (offset + length < buffer->gapOffset) { + len = buffer->gapOffset - (offset + length); + dst = buffer->text + buffer->gapSize + (offset + length); + src = buffer->text + (offset + length); + memmove (dst, src, len); + } + // don't need to do any copying when offset <= gapOffset && + // offset + length >= offset + buffer->gapOffset = offset; + buffer->gapSize += length; + buffer->textSize -= length; + return buffer->text + buffer->gapOffset; +} + +VISIBLE txtbuffer_t * +TextBuffer_Create (void) +{ + txtbuffer_t *buffer; + ALLOC (16, txtbuffer_t, txtbuffers, buffer); + return buffer; +} + +VISIBLE void +TextBuffer_Destroy (txtbuffer_t *buffer) +{ + if (buffer->text) { + free (buffer->text); + } + FREE (txtbuffers, buffer); +} + +VISIBLE int +TextBuffer_InsertAt (txtbuffer_t *buffer, size_t offset, + const char *text, size_t text_len) +{ + char *dst; + + if (offset > buffer->textSize) { + return 0; + } + dst = txtbuffer_open_gap (buffer, offset, text_len); + if (!dst) { + return 0; + } + memcpy (dst, text, text_len); + buffer->textSize += text_len; + buffer->gapOffset += text_len; + buffer->gapSize -= text_len; + return 1; +} + +VISIBLE int +TextBuffer_DeleteAt (txtbuffer_t *buffer, size_t offset, size_t len) +{ + if (offset > buffer->textSize) { + return 0; + } + // clamp len to the amount of text beyond offset + if (len > buffer->textSize - offset) { + len = buffer->textSize - offset; + } + txtbuffer_delete_text (buffer, offset, len); + return 1; +} diff --git a/libs/util/va.c b/libs/util/va.c index aa99f7955..dd24c05d1 100644 --- a/libs/util/va.c +++ b/libs/util/va.c @@ -51,16 +51,23 @@ VISIBLE char * va (const char *fmt, ...) { va_list args; - static dstring_t *string; + static dstring_t *string[4]; +#define NUM_STRINGS (sizeof (string) / sizeof (string[0])) + static int str_index; + dstring_t *dstr; - if (!string) - string = dstring_new (); + if (!string[0]) { + for (size_t i = 0; i < NUM_STRINGS; i++) { + string[i] = dstring_new (); + } + } + dstr = string[str_index++ % NUM_STRINGS]; va_start (args, fmt); - dvsprintf (string, fmt, args); + dvsprintf (dstr, fmt, args); va_end (args); - return string->str; + return dstr->str; } VISIBLE char * diff --git a/libs/video/targets/in_x11.c b/libs/video/targets/in_x11.c index dc689a7d5..8ef111ec2 100644 --- a/libs/video/targets/in_x11.c +++ b/libs/video/targets/in_x11.c @@ -672,7 +672,7 @@ event_focusin (XEvent *event) static void center_pointer (void) { - XEvent event; + XEvent event = {}; event.type = MotionNotify; event.xmotion.display = x_disp; diff --git a/nq/source/host.c b/nq/source/host.c index 0d85b9a1a..a1f90a4fa 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -893,14 +893,9 @@ Host_Init (void) Game_Init (); - PR_Init_Cvars (); - SV_Progs_Init_Cvars (); - if (!isDedicated) CL_InitCvars (); - PR_Init (); - if (isDedicated) { PI_RegisterPlugins (server_plugin_list); Con_Init ("server"); diff --git a/nq/source/sv_progs.c b/nq/source/sv_progs.c index 7e98550d4..8626ade59 100644 --- a/nq/source/sv_progs.c +++ b/nq/source/sv_progs.c @@ -379,7 +379,7 @@ set_address (sv_def_t *def, void *address) static int resolve_globals (progs_t *pr, sv_def_t *def, int mode) { - ddef_t *ddef; + pr_def_t *ddef; int ret = 1; if (mode == 2) { @@ -425,7 +425,7 @@ resolve_functions (progs_t *pr, sv_def_t *def, int mode) static int resolve_fields (progs_t *pr, sv_def_t *def, int mode) { - ddef_t *ddef; + pr_def_t *ddef; int ret = 1; if (mode == 2) { @@ -521,6 +521,8 @@ SV_LoadProgs (void) void SV_Progs_Init (void) { + SV_Progs_Init_Cvars (); + pr_gametype = "netquake"; sv_pr_state.edicts = &sv.edicts; sv_pr_state.num_edicts = &sv.num_edicts; @@ -531,6 +533,8 @@ SV_Progs_Init (void) sv_pr_state.bi_map = bi_map; sv_pr_state.resolve = resolve; + PR_Init (&sv_pr_state); + SV_PR_Cmds_Init (); Cmd_AddCommand ("edict", ED_PrintEdict_f, "Report information on a given " @@ -548,6 +552,7 @@ SV_Progs_Init (void) void SV_Progs_Init_Cvars (void) { + PR_Init_Cvars (); sv_progs = Cvar_Get ("sv_progs", "", CVAR_NONE, NULL, "Override the default game progs."); sv_progs_zone = Cvar_Get ("sv_progs_zone", "256", CVAR_NONE, NULL, diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index 3cb0e1432..4bd6ebbed 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -1803,12 +1803,10 @@ Host_Init (void) Netchan_Init_Cvars (); - PR_Init_Cvars (); + PR_Init_Cvars (); // FIXME location CL_Init_Cvars (); - PR_Init (); - CL_Chat_Init (); CL_Cmd_Init (); diff --git a/qw/source/sv_ccmds.c b/qw/source/sv_ccmds.c index aa359c576..318a2edaf 100644 --- a/qw/source/sv_ccmds.c +++ b/qw/source/sv_ccmds.c @@ -950,6 +950,7 @@ SV_SetLocalinfo (const char *key, const char *value) P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key); P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, oldvalue); P_STRING (&sv_pr_state, 2) = PR_SetTempString (&sv_pr_state, value); + sv_pr_state.pr_argc = 3; PR_ExecuteProgram (&sv_pr_state, sv_funcs.LocalinfoChanged); PR_PopFrame (&sv_pr_state); } diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index a121ba5ce..e6191f32b 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -2520,8 +2520,6 @@ SV_Init (void) Mod_Init_Cvars (); Netchan_Init_Cvars (); Pmove_Init_Cvars (); - SV_Progs_Init_Cvars (); - PR_Init_Cvars (); // and now reprocess the cmdline's sets for overrides Cmd_StuffCmds (sv_cbuf); @@ -2531,7 +2529,6 @@ SV_Init (void) Game_Init (); - PR_Init (); SV_Progs_Init (); Mod_Init (); diff --git a/qw/source/sv_pr_cpqw.c b/qw/source/sv_pr_cpqw.c index 594f66219..4263cc097 100644 --- a/qw/source/sv_pr_cpqw.c +++ b/qw/source/sv_pr_cpqw.c @@ -818,10 +818,11 @@ cpqw_user_cmd (void) PR_PushFrame (pr); P_FLOAT (pr, 0) = argc; - for (i = 1; i < argc; i++) + for (i = 1; i < argc + 1; i++) P_STRING (pr, i) = PR_SetTempString (pr, Cmd_Argv (i - 1)); - for (; i < 7; i++) + for (; i < 8; i++) P_STRING (pr, i) = 0; + pr->pr_argc = 8; PR_ExecuteProgram (pr, cpqw_funcs.ClientCommand); PR_PopFrame (pr); return (int) R_FLOAT (pr); diff --git a/qw/source/sv_pr_qwe.c b/qw/source/sv_pr_qwe.c index 0c844abd8..9a84892cf 100644 --- a/qw/source/sv_pr_qwe.c +++ b/qw/source/sv_pr_qwe.c @@ -353,6 +353,7 @@ PF_calltimeofday (progs_t *pr) P_FLOAT (pr, 5) = (float) date.year; P_STRING (pr, 6) = PR_SetReturnString (pr, date.str); + pr->pr_argc = 7; PR_ExecuteProgram (pr, (func_t) (f - sv_pr_state.pr_functions)); PR_PopFrame (&sv_pr_state); } @@ -551,7 +552,7 @@ static int qwe_load_finish (progs_t *pr) { edict_t *ent; - ddef_t *targetname; + pr_def_t *targetname; targetname = PR_FindField (pr, "targetname"); ent = EDICT_NUM (pr, 0); diff --git a/qw/source/sv_progs.c b/qw/source/sv_progs.c index e4856f69b..2c4ff5c3f 100644 --- a/qw/source/sv_progs.c +++ b/qw/source/sv_progs.c @@ -389,7 +389,7 @@ set_address (sv_def_t *def, void *address) static int resolve_globals (progs_t *pr, sv_def_t *def, int mode) { - ddef_t *ddef; + pr_def_t *ddef; int ret = 1; if (mode == 2) { @@ -435,7 +435,7 @@ resolve_functions (progs_t *pr, sv_def_t *def, int mode) static int resolve_fields (progs_t *pr, sv_def_t *def, int mode) { - ddef_t *ddef; + pr_def_t *ddef; int ret = 1; if (mode == 2) { @@ -544,6 +544,8 @@ SV_LoadProgs (void) void SV_Progs_Init (void) { + SV_Progs_Init_Cvars (); + pr_gametype = "quakeworld"; sv_pr_state.edicts = &sv.edicts; sv_pr_state.num_edicts = &sv.num_edicts; @@ -556,6 +558,8 @@ SV_Progs_Init (void) sv_pr_state.bi_map = bi_map; sv_pr_state.resolve = resolve; + PR_Init (&sv_pr_state); + SV_PR_Cmds_Init (); SV_PR_QWE_Init (&sv_pr_state); SV_PR_CPQW_Init (&sv_pr_state); @@ -575,6 +579,8 @@ SV_Progs_Init (void) void SV_Progs_Init_Cvars (void) { + PR_Init_Cvars (); + r_skyname = Cvar_Get ("r_skyname", "", CVAR_NONE, NULL, "Default name of skybox if none given by map"); sv_progs = Cvar_Get ("sv_progs", "", CVAR_NONE, NULL, diff --git a/qw/source/sv_user.c b/qw/source/sv_user.c index 5398eff6c..a6b56c219 100644 --- a/qw/source/sv_user.c +++ b/qw/source/sv_user.c @@ -1211,6 +1211,7 @@ SV_SetUserinfo (client_t *client, const char *key, const char *value) P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key); P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, oldvalue); P_STRING (&sv_pr_state, 2) = PR_SetTempString (&sv_pr_state, value); + sv_pr_state.pr_argc = 3; PR_ExecuteProgram (&sv_pr_state, sv_funcs.UserInfoChanged); PR_PopFrame (&sv_pr_state); send_changes = !R_FLOAT (&sv_pr_state); @@ -1261,6 +1262,7 @@ SV_SetInfo_f (void *unused) PR_RESET_PARAMS (&sv_pr_state); P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key); P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, value); + sv_pr_state.pr_argc = 2; PR_ExecuteProgram (&sv_pr_state, sv_funcs.UserInfoCallback); PR_PopFrame (&sv_pr_state); if (R_FLOAT (&sv_pr_state)) diff --git a/ruamoko/Makefile.am b/ruamoko/Makefile.am index 779fc1439..b899690f8 100644 --- a/ruamoko/Makefile.am +++ b/ruamoko/Makefile.am @@ -1,4 +1,5 @@ -SUBDIRS= include lib game gui cl_menu scheme +SUBDIRS= include lib game gui cl_menu scheme @ruamoko_dirs@ +DIST_SUBDIRS=qwaq doc: Doxyfile doxygen diff --git a/ruamoko/cl_menu/Makefile.am b/ruamoko/cl_menu/Makefile.am index 55c21a857..ceaef7fe5 100644 --- a/ruamoko/cl_menu/Makefile.am +++ b/ruamoko/cl_menu/Makefile.am @@ -1,43 +1,66 @@ ## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -pkgdatadir=@sharepath@/QF +AUTOMAKE_OPTIONS= foreign no-exeext QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) QFCC=$(QFCC_DEP) -QCFLAGS=-qq -O -g -Wall -Werror -Wno-integer-divide --no-default-paths -QCPPFLAGS=-I. -I$(srcdir) -I$(top_builddir)/ruamoko/include -I$(top_srcdir)/ruamoko/include -I$(top_builddir)/include -I$(top_srcdir)/include -GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi + GZ=@progs_gz@ +menu_libexec=menu.dat +menu_data=menu.plist menu.sym + +pkglibexecdir=@sharepath@/QF +pkgdatadir=@sharepath@/QF + +pkgdata_DATA= $(menu_data) +pkglibexec_PROGRAMS= $(menu_libexec) +EXTRA_PROGRAMS= $(menu_libexec) + +QCFLAGS=-qq -O -g -Wall -Werror -Wno-integer-divide +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) + +MKDIR_P = @MKDIR_P@ +am__mv = mv -f + +GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi # BSD make can't handle $(shell foo) directives, and GNU make can't handle |= # so we have to bite the bullet and pass this to the shell every time. STRIP=`echo -n $(srcdir)/ | sed -e 's/[^/]//g' | wc -c` -menu_data=menu.dat$(GZ) menu.sym$(GZ) menu.plist - -data=$(menu_data) - -pkgdata_DATA= $(data) -EXTRA_DATA= $(menu_data) +SUFFIXES=.o .r +.r.o: + $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -p $(STRIP) -c -o $@ $< + sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo + $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo menu_src= \ client_menu.r controls_o.r options.r options_util.r servlist.r \ - Frame.r menu.r HUD.r plistmenu.r ../lib/debug.r \ + Frame.r HUD.r menu.r plistmenu.r \ \ CrosshairCvar.r CrosshairView.r CvarColor.r CvarColorView.r \ CvarObject.r CvarRange.r CvarRangeView.r CvarString.r CvarStringView.r \ CvarToggle.r CvarToggleView.r \ MenuGroup.r MouseToggle.r ProxyView.r RunToggle.r SubMenu.r -SUFFIXES=.qfo .r -.r.qfo: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -p $(STRIP) -c -o $@ $< -menu_obj=$(menu_src:.r=.qfo) +r_depfiles_remade= -menu.dat$(GZ): $(menu_obj) $(QFCC_DEP) ../lib/libcsqc.a ../lib/libr.a ../gui/libgui.a - $(QFCC) $(QCFLAGS) -p $(STRIP) -o menu.dat $(menu_obj) ../gui/libgui.a ../lib/libcsqc.a ../lib/libr.a - $(GZIP) -menu.sym$(GZ): menu.dat$(GZ) +menu_dat_SOURCES=$(menu_src) +menu_obj=$(menu_src:.r=.o) +menu_dep=$(addprefix ./$(DEPDIR)/,$(menu_obj:.o=.Qo)) +menu.dat: $(menu_obj) $(QFCC_DEP) ../lib/libcsqc.a ../lib/libr.a ../gui/libgui.a + $(QLINK) -p $(STRIP) -o menu.dat $(menu_obj) ../gui/libgui.a ../lib/libcsqc.a ../lib/libr.a +include $(menu_dep) # am--include-marker +r_depfiles_remade += $(menu_dep) + +menu.sym: menu.dat + +$(r_depfiles_remade): + $(MKDIR_P) $(@D) + echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) EXTRA_DIST= $(menu_src) \ CrosshairCvar.h CrosshairView.h CvarColor.h CvarColorView.h CvarObject.h \ @@ -46,4 +69,4 @@ EXTRA_DIST= $(menu_src) \ MenuGroup.h MouseToggle.h ProxyView.h RunToggle.h SubMenu.h client_menu.h \ controls_o.h menu.h options.h options_util.h plistmenu.h servlist.h \ menu.plist -CLEANFILES= *.dat *.sym *.gz *.qfo +CLEANFILES= *.dat *.sym *.gz *.qfo *.o diff --git a/ruamoko/cl_menu/client_menu.r b/ruamoko/cl_menu/client_menu.r index 769ad9cae..dc4cd487e 100644 --- a/ruamoko/cl_menu/client_menu.r +++ b/ruamoko/cl_menu/client_menu.r @@ -1,6 +1,5 @@ #include "AutoreleasePool.h" #include "menu.h" -#include "file.h" #include "cmd.h" #include "gib.h" #include "draw.h" @@ -10,6 +9,7 @@ #include "options.h" #include "servlist.h" #include "system.h" +#include "qfs.h" #include "debug.h" #include "HUD.h" #include "client_menu.h" @@ -137,17 +137,18 @@ void (int quick) scan_saves = local QFile f; local string line; local int max = MAX_SAVEGAMES; - if (quick) + string basename = "s"; + if (quick) { max = MAX_QUICK; + basename = "quick"; + } for (i = 0; i < max; i++) { if (!filenames[i]) filenames[i] = str_new (); loadable[i] = 0; - if (quick) { - f = File_Open (sprintf ("quick%i.sav", i + 1), "rz"); - } else { - f = File_Open (sprintf ("s%i.sav", i), "rz"); - } + string path = sprintf ("%s%i.sav", basename, i); + //dprint(path + "\n"); + f = QFS_OpenFile (path); if (!f) { str_copy (filenames[i], "--- UNUSED SLOT ---"); continue; diff --git a/ruamoko/cl_menu/options.r b/ruamoko/cl_menu/options.r index e0529c23e..a228b1062 100644 --- a/ruamoko/cl_menu/options.r +++ b/ruamoko/cl_menu/options.r @@ -130,7 +130,7 @@ MENU_video_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"video_options"]); - video_options = ret.pointer_val; + video_options = (Group *) ret.pointer_val; } Menu_End (); @@ -177,7 +177,7 @@ MENU_audio_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"audio_options"]); - audio_options = ret.pointer_val; + audio_options = (Group *) ret.pointer_val; } Menu_End (); @@ -224,7 +224,7 @@ MENU_control_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"control_options"]); - control_options = ret.pointer_val; + control_options = (Group *) ret.pointer_val; } MENU_control_binding (); //FIXME how to hook in the bindings menu? @@ -275,7 +275,7 @@ MENU_feature_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"feature_options"]); - feature_options = ret.pointer_val; + feature_options = (Group *) ret.pointer_val; } Menu_End (); @@ -361,7 +361,7 @@ MENU_player_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"player_options"]); - player_options = ret.pointer_val; + player_options = (Group *) ret.pointer_val; } Menu_End (); @@ -426,7 +426,7 @@ MENU_network_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"network_options"]); - network_options = ret.pointer_val; + network_options = (Group *) ret.pointer_val; } Menu_End (); diff --git a/ruamoko/cl_menu/plistmenu.r b/ruamoko/cl_menu/plistmenu.r index d5e722377..00d2a61e0 100644 --- a/ruamoko/cl_menu/plistmenu.r +++ b/ruamoko/cl_menu/plistmenu.r @@ -58,6 +58,7 @@ class_from_plist (PLDictionary *pldict) return ret; } obj = [class alloc]; + params[0].pointer_val = obj; messages = (PLArray*) [pldict getObjectForKey:"Messages"]; message_count = [messages count]; @@ -65,9 +66,10 @@ class_from_plist (PLDictionary *pldict) msg = (PLArray*) [messages getObjectAtIndex:i]; selname = [(PLString*) [msg getObjectAtIndex:0] string]; sel = sel_get_uid (selname); - va_list.count = [msg count] - 1; - for (j = 0; j < va_list.count; j++) { - paramstr = [(PLString*) [msg getObjectAtIndex:j + 1] string]; + params[1].pointer_val = sel; + va_list.count = [msg count] + 1; + for (j = 2; j < va_list.count; j++) { + paramstr = [(PLString*) [msg getObjectAtIndex:j - 1] string]; switch (str_mid (paramstr, 0, 1)) { case "\"": va_list.list[j].string_val = str_mid (paramstr, 1, -1); @@ -103,7 +105,7 @@ array_from_plist (PLArray *plarray) count = [plarray count]; for (i = 0; i < count; i++) { ret = object_from_plist ([plarray getObjectAtIndex:i]); - [array addObject: ret.pointer_val]; + [array addObject: (id) ret.pointer_val]; } ret.pointer_val = array; return ret; diff --git a/ruamoko/game/Makefile.am b/ruamoko/game/Makefile.am index e1ff2fbf2..95093647f 100644 --- a/ruamoko/game/Makefile.am +++ b/ruamoko/game/Makefile.am @@ -1,35 +1,57 @@ ## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -#FIXME should qf data be installed somewhere other than id1 that gets -#searched after everything else? -pkgdatadir=@sharepath@/id1 +AUTOMAKE_OPTIONS= foreign no-exeext QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) QFCC=$(QFCC_DEP) -QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide --no-default-paths -QCPPFLAGS=-I. -I$(srcdir) -I$(top_builddir)/ruamoko/include -I$(top_srcdir)/ruamoko/include -GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi + GZ=@progs_gz@ +game_libexec=game.dat + +pkglibexecdir=@sharepath@/QF + +# this will eventually go into pkglibexecdir, but for now... +noinst_PROGRAMS= $(game_libexec) +EXTRA_PROGRAMS= $(game_libexec) + +QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) + +MKDIR_P = @MKDIR_P@ +am__mv = mv -f + +GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi # BSD make can't handle $(shell foo) directives, and GNU make can't handle |= # so we have to bite the bullet and pass this to the shell every time. STRIP=`echo -n $(srcdir)/ | sed -e 's/[^/]//g' | wc -c` -data=game.dat$(GZ) - -noinst_DATA= $(data) -EXTRA_DATA= game.dat +SUFFIXES=.o .r +.r.o: + $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -p $(STRIP) -c -o $@ $< + sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo + $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo game_src= Axe.r GameEntity.r World.r tempent.r -SUFFIXES=.qfo .r -.r.qfo: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -p $(STRIP) -c -o $@ $< +r_depfiles_remade= -game_obj=$(game_src:.r=.qfo) -game.dat$(GZ): $(game_obj) ../lib/libr.a ../lib/libqw.a - $(QFCC) $(QCFLAGS) -p $(STRIP) -o game.dat $(game_obj) ../lib/libr.a ../lib/libqw.a ../lib/libr.a - $(GZIP) +game_dat_SOURCES=$(game_src) +game_obj=$(game_src:.r=.o) +game_dep=$(addprefix ./$(DEPDIR)/,$(game_obj:.o=.Qo)) +game.dat: $(game_obj) $(QFCC_DEP) ../lib/libr.a ../lib/libqw.a + $(QLINK) -p $(STRIP) -o game.dat $(game_obj) ../lib/libr.a ../lib/libqw.a ../lib/libr.a +include $(game_dep) # am--include-marker +r_depfiles_remade += $(game_dep) + +game.sym: game.dat + +$(r_depfiles_remade): + $(MKDIR_P) $(@D) + echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) EXTRA_DIST= $(game_src) Axe.h GameEntity.h tempent.h Weapon.h World.h -CLEANFILES= *.dat *.sym *.gz *.qfo +CLEANFILES= *.dat *.sym *.gz *.o *.qfo diff --git a/ruamoko/gui/Group.r b/ruamoko/gui/Group.r index 4bcccadf1..56b7303c7 100644 --- a/ruamoko/gui/Group.r +++ b/ruamoko/gui/Group.r @@ -1,6 +1,6 @@ -#include "gui/Group.h" -#include "gui/Point.h" -#include "Array.h" +#include +#include +#include @implementation Group diff --git a/ruamoko/gui/InputLine.r b/ruamoko/gui/InputLine.r index 781e56b78..e4fb8df8a 100644 --- a/ruamoko/gui/InputLine.r +++ b/ruamoko/gui/InputLine.r @@ -1,6 +1,6 @@ -#include "draw.h" -#include "gui/InputLine.h" -#include "gui/Rect.h" +#include +#include +#include inputline_t InputLine_Create (int lines, int size, int prompt) = #0; void InputLine_SetPos (inputline_t il, int x, int y) = #0; diff --git a/ruamoko/gui/Makefile.am b/ruamoko/gui/Makefile.am index e4866e856..35d2624df 100644 --- a/ruamoko/gui/Makefile.am +++ b/ruamoko/gui/Makefile.am @@ -1,27 +1,48 @@ AUTOMAKE_OPTIONS= foreign -pkglibdir=$(datarootdir)/qfcc/lib - -QFCC=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) -QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide --no-default-paths -QCPPFLAGS=$(AM_CPPFLAGS) -PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) -RANLIB=touch - -AM_CPPFLAGS= -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include +QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) +QFCC=$(QFCC_DEP) gui_libs=libgui.a libs=$(gui_libs) +pkglibdir=$(datarootdir)/qfcc/lib + pkglib_LIBRARIES= $(libs) EXTRA_LIBRARIES= $(gui_libs) -SUFFIXES= .qfo .r .qc +QFCC=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) +QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide --no-default-paths +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) + +MKDIR_P = @MKDIR_P@ +am__mv = mv -f + +PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) +RANLIB=touch + +SUFFIXES= .o .r .r.o: $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -c -o $@ $< +r_depfiles_remade= + libgui_a_SOURCES= \ Group.r InputLine.r Pic.r Point.r Rect.r Size.r Slider.r Text.r View.r +libgui_a_obj=$(libgui_a_SOURCES:.r=.o) +libgui_a_dep=$(addprefix ./$(DEPDIR)/,$(libgui_a_obj:.o=.Qo)) libgui_a_AR= $(PAK) -cf +include $(libgui_a_dep) # am--include-marker +r_depfiles_remade += $(libgui_a_dep) + +$(r_depfiles_remade): + $(MKDIR_P) $(@D) + echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) + CLEANFILES= *.qfo *.o diff --git a/ruamoko/gui/Pic.r b/ruamoko/gui/Pic.r index 89cf93950..748393cc5 100644 --- a/ruamoko/gui/Pic.r +++ b/ruamoko/gui/Pic.r @@ -1,6 +1,6 @@ -#include "draw.h" -#include "string.h" -#include "gui/Pic.h" +#include +#include +#include @implementation Pic -(id)init diff --git a/ruamoko/gui/Point.r b/ruamoko/gui/Point.r index c25c72000..91163087b 100644 --- a/ruamoko/gui/Point.r +++ b/ruamoko/gui/Point.r @@ -1,4 +1,4 @@ -#include "gui/Point.h" +#include Point makePoint (int x, int y) { diff --git a/ruamoko/gui/Rect.r b/ruamoko/gui/Rect.r index be1c69384..a7280cea3 100644 --- a/ruamoko/gui/Rect.r +++ b/ruamoko/gui/Rect.r @@ -1,7 +1,7 @@ -#include "Object.h" -#include "gui/Point.h" -#include "gui/Size.h" -#include "gui/Rect.h" +#include +#include +#include +#include Rect makeRect (int x, int y, int w, int h) { diff --git a/ruamoko/gui/Size.r b/ruamoko/gui/Size.r index d4565a33f..da1bf04a9 100644 --- a/ruamoko/gui/Size.r +++ b/ruamoko/gui/Size.r @@ -1,4 +1,4 @@ -#include "gui/Size.h" +#include Size makeSize (int width, int height) { diff --git a/ruamoko/gui/Slider.r b/ruamoko/gui/Slider.r index d43cdcf21..275a64de4 100644 --- a/ruamoko/gui/Slider.r +++ b/ruamoko/gui/Slider.r @@ -1,7 +1,7 @@ -#include "draw.h" +#include -#include "gui/Slider.h" -#include "gui/Rect.h" +#include +#include @implementation Slider diff --git a/ruamoko/gui/Text.r b/ruamoko/gui/Text.r index 731f661ce..6011273d8 100644 --- a/ruamoko/gui/Text.r +++ b/ruamoko/gui/Text.r @@ -1,6 +1,6 @@ -#include "gui/Text.h" -#include "string.h" -#include "draw.h" +#include +#include +#include @implementation Text - (id) init diff --git a/ruamoko/gui/View.r b/ruamoko/gui/View.r index 2accc4fe7..a83ebeb33 100644 --- a/ruamoko/gui/View.r +++ b/ruamoko/gui/View.r @@ -1,7 +1,7 @@ -#include "gui/Size.h" -#include "gui/Point.h" -#include "gui/Rect.h" -#include "gui/View.h" +#include +#include +#include +#include @implementation View diff --git a/ruamoko/include/Array.h b/ruamoko/include/Array.h index 8a9f91f36..060f50956 100644 --- a/ruamoko/include/Array.h +++ b/ruamoko/include/Array.h @@ -1,8 +1,8 @@ #ifndef __ruamoko_Array_h #define __ruamoko_Array_h -#include "Object.h" -#include "runtime.h" +#include +#include /** The Array class is a general ordered collection class. @@ -271,7 +271,7 @@ Iteratively sends #performSelector:withObject: to each contained object. */ - (void) makeObjectsPerformSelector: (SEL)selector - withObject: (id)arg; + withObject: (void *)arg; //\} @end diff --git a/ruamoko/include/AutoreleasePool.h b/ruamoko/include/AutoreleasePool.h index a02600c9e..c8202e0f0 100644 --- a/ruamoko/include/AutoreleasePool.h +++ b/ruamoko/include/AutoreleasePool.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_AutoreleasePool_h #define __ruamoko_AutoreleasePool_h -#include "Object.h" +#include @class Array; diff --git a/ruamoko/include/Entity.h b/ruamoko/include/Entity.h index 85f304efb..8ff0f568c 100644 --- a/ruamoko/include/Entity.h +++ b/ruamoko/include/Entity.h @@ -30,7 +30,7 @@ #ifndef __ruamoko_Entity_h #define __ruamoko_Entity_h -#include "Object.h" +#include @interface Entity: Object { diff --git a/ruamoko/include/Makefile.am b/ruamoko/include/Makefile.am index d978b3a70..17167cbec 100644 --- a/ruamoko/include/Makefile.am +++ b/ruamoko/include/Makefile.am @@ -3,11 +3,11 @@ pkgincludedir= $(datarootdir)/qfcc/include nobase_pkginclude_HEADERS= \ crudefile.h debug.h entities.h infokey.h math.h message.h nq_message.h \ physics.h msgbuf.h qfile.h qfs.h qw_message.h qw_physics.h qw_sys.h \ - server.h sound.h script.h string.h sv_sound.h system.h \ + server.h sound.h script.h string.h sv_sound.h system.h types.h \ \ draw.h key.h \ \ - cbuf.h cmd.h cvar.h file.h gib.h hash.h plist.h runtime.h \ + cbuf.h cmd.h cvar.h gib.h hash.h plist.h runtime.h \ Object.h Protocol.h \ AutoreleasePool.h Array.h Entity.h PropertyList.h Set.h \ \ diff --git a/ruamoko/include/Object.h b/ruamoko/include/Object.h index 23623ef06..981977651 100644 --- a/ruamoko/include/Object.h +++ b/ruamoko/include/Object.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_Object_h #define __ruamoko_Object_h -#include "runtime.h" +#include @class Protocol; @@ -20,10 +20,14 @@ - (id) performSelector: (SEL)aSelector; - (id) performSelector: (SEL)aSelector - withObject: (id)anObject; + withObject: (void *)anObject; - (id) performSelector: (SEL)aSelector - withObject: (id)anObject - withObject: (id)anotherObject; + withObject: (void *)anObject + withObject: (void *)anotherObject; +// void return does not touch the actual return value (effectively retval) +// so if the target returns a value, and the forwarding method simply returns +// (and is void), the vallue will get out to the caller +- (void) performv: (SEL) sel : (@va_list) args; - (BOOL) respondsToSelector: (SEL)aSelector; - (BOOL) conformsToProtocol: (Protocol *)aProtocol; diff --git a/ruamoko/include/PropertyList.h b/ruamoko/include/PropertyList.h index 0f255cdfe..3deb99a2b 100644 --- a/ruamoko/include/PropertyList.h +++ b/ruamoko/include/PropertyList.h @@ -1,8 +1,8 @@ #ifndef __ruamoko_PropertyList_h #define __ruamoko_PropertyList_h -#include "plist.h" -#include "Object.h" +#include +#include @interface PLItem: Object { diff --git a/ruamoko/include/Protocol.h b/ruamoko/include/Protocol.h index 2894ee4fa..3d377ab75 100644 --- a/ruamoko/include/Protocol.h +++ b/ruamoko/include/Protocol.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_Protocol_h #define __ruamoko_Protocol_h -#include "Object.h" +#include struct obj_method_description { string name; diff --git a/ruamoko/include/draw.h b/ruamoko/include/draw.h index df4a1470f..ae868ff36 100644 --- a/ruamoko/include/draw.h +++ b/ruamoko/include/draw.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_draw_h #define __ruamoko_draw_h -#include "Object.h" +#include struct _qpic_t { int width; diff --git a/ruamoko/include/file.h b/ruamoko/include/file.h deleted file mode 100644 index f1c3a580b..000000000 --- a/ruamoko/include/file.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __ruamoko_file_h -#define __ruamoko_file_h - -#include "qfile.h" - -@extern QFile File_Open (string path, string mode); - -#endif//__ruamoko_file_h diff --git a/ruamoko/include/gui/Group.h b/ruamoko/include/gui/Group.h index f20cca09c..ccd4baa65 100644 --- a/ruamoko/include/gui/Group.h +++ b/ruamoko/include/gui/Group.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_gui_Group_h #define __ruamoko_gui_Group_h -#include "View.h" +#include /** \addtogroup gui */ ///@{ diff --git a/ruamoko/include/gui/InputLine.h b/ruamoko/include/gui/InputLine.h index 363cc0b8c..c0b14cfb4 100644 --- a/ruamoko/include/gui/InputLine.h +++ b/ruamoko/include/gui/InputLine.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_gui_InputLine_h #define __ruamoko_gui_InputLine_h -#include "View.h" +#include /** \defgroup inputline Low level intputline interface. \ingroup gui diff --git a/ruamoko/include/gui/Pic.h b/ruamoko/include/gui/Pic.h index 9ed9e3380..9bfe29fbc 100644 --- a/ruamoko/include/gui/Pic.h +++ b/ruamoko/include/gui/Pic.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_gui_Pic_h #define __ruamoko_gui_Pic_h -#include "gui/View.h" +#include /** \addtogroup gui */ ///@{ diff --git a/ruamoko/include/gui/Rect.h b/ruamoko/include/gui/Rect.h index 005ce4a70..d1432f460 100644 --- a/ruamoko/include/gui/Rect.h +++ b/ruamoko/include/gui/Rect.h @@ -1,8 +1,8 @@ #ifndef __ruamoko_gui_Rect_h #define __ruamoko_gui_Rect_h -#include "gui/Point.h" -#include "gui/Size.h" +#include +#include /** \addtogroup gui */ ///@{ diff --git a/ruamoko/include/gui/Slider.h b/ruamoko/include/gui/Slider.h index 66710d28e..99840af7e 100644 --- a/ruamoko/include/gui/Slider.h +++ b/ruamoko/include/gui/Slider.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_gui_Slider_h #define __ruamoko_gui_Slider_h -#include "View.h" +#include /** \addtogroup gui */ ///@{ diff --git a/ruamoko/include/gui/Text.h b/ruamoko/include/gui/Text.h index d5654d555..ef389bf9c 100644 --- a/ruamoko/include/gui/Text.h +++ b/ruamoko/include/gui/Text.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_gui_Text_h #define __ruamoko_gui_Text_h -#include "View.h" +#include /** \addtogroup gui */ ///@{ diff --git a/ruamoko/include/gui/View.h b/ruamoko/include/gui/View.h index c2a99e036..3cb51ee67 100644 --- a/ruamoko/include/gui/View.h +++ b/ruamoko/include/gui/View.h @@ -1,8 +1,8 @@ #ifndef __ruamoko_gui_View_h #define __ruamoko_gui_View_h -#include "Object.h" -#include "gui/Rect.h" +#include +#include /** \defgroup gui GUI goo for gooey chewing */ diff --git a/ruamoko/include/hash.h b/ruamoko/include/hash.h index 8c07169aa..2d0aa80fc 100644 --- a/ruamoko/include/hash.h +++ b/ruamoko/include/hash.h @@ -1,24 +1,24 @@ #ifndef __ruamoko_hash_h #define __ruamoko_hash_h -typedef struct _hashtab_t *hashtab_t; +typedef struct _hashtab_t hashtab_t; -@extern hashtab_t Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud); -@extern void Hash_SetHashCompare (hashtab_t tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)); -@extern void Hash_DelTable (hashtab_t tab); -@extern void Hash_FlushTable (hashtab_t tab); -@extern int Hash_Add (hashtab_t tab, void *ele); -@extern int Hash_AddElement (hashtab_t tab, void *ele); -@extern void *Hash_Find (hashtab_t tab, string key); -@extern void *Hash_FindElement (hashtab_t tab, void *ele); -@extern void **Hash_FindList (hashtab_t tab, string key); -@extern void **Hash_FindElementList (hashtab_t tab, void *ele); -@extern void *Hash_Del (hashtab_t tab, string key); -@extern void *Hash_DelElement (hashtab_t tab, void *ele); -@extern void Hash_Free (hashtab_t tab, void *ele); +@extern hashtab_t *Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud); +@extern void Hash_SetHashCompare (hashtab_t *tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)); +@extern void Hash_DelTable (hashtab_t *tab); +@extern void Hash_FlushTable (hashtab_t *tab); +@extern int Hash_Add (hashtab_t *tab, void *ele); +@extern int Hash_AddElement (hashtab_t *tab, void *ele); +@extern void *Hash_Find (hashtab_t *tab, string key); +@extern void *Hash_FindElement (hashtab_t *tab, void *ele); +@extern void **Hash_FindList (hashtab_t *tab, string key); +@extern void **Hash_FindElementList (hashtab_t *tab, void *ele); +@extern void *Hash_Del (hashtab_t *tab, string key); +@extern void *Hash_DelElement (hashtab_t *tab, void *ele); +@extern void Hash_Free (hashtab_t *tab, void *ele); @extern int Hash_String (string str); @extern int Hash_Buffer (void *buf, int len); -@extern void **Hash_GetList (hashtab_t tab); -@extern void Hash_Stats (hashtab_t tab); +@extern void **Hash_GetList (hashtab_t *tab); +@extern void Hash_Stats (hashtab_t *tab); #endif // __ruamoko_hash_h diff --git a/ruamoko/include/key.h b/ruamoko/include/key.h index bc7d04801..f3355b3d2 100644 --- a/ruamoko/include/key.h +++ b/ruamoko/include/key.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_key_h #define __ruamoko_key_h -#include "QF/keys.h" +#include @extern int Key_keydown (int keynum); @extern string Key_SetBinding (string imt, int keynum, string binding); diff --git a/ruamoko/include/msgbuf.h b/ruamoko/include/msgbuf.h index d26ba4de9..172d7338a 100644 --- a/ruamoko/include/msgbuf.h +++ b/ruamoko/include/msgbuf.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_msgbuf_h #define __ruamoko_msgbuf_h -#include "qfile.h" +#include struct msgbuf_s; typedef struct msgbuf_s msgbuf_t; diff --git a/ruamoko/include/plist.h b/ruamoko/include/plist.h index 949419ea9..4544e00ff 100644 --- a/ruamoko/include/plist.h +++ b/ruamoko/include/plist.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_plist_h #define __ruamoko_plist_h -#include "qfile.h" +#include typedef struct plitem_s *plitem_t; typedef enum {QFDictionary, QFArray, QFBinary, QFString} pltype_t; // possible types diff --git a/ruamoko/include/qfs.h b/ruamoko/include/qfs.h index 484a020c0..379e29ad2 100644 --- a/ruamoko/include/qfs.h +++ b/ruamoko/include/qfs.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_qfs_h #define __ruamoko_qfs_h -#include "qfile.h" +#include struct _qfslist_t { int count; @@ -17,5 +17,6 @@ typedef struct _qfslist_t *QFSlist; @extern int QFS_WriteFile (string filename, void *buf, int count); @extern QFSlist QFS_Filelist (string path, string ext, int strip); @extern void QFS_FilelistFree (QFSlist list); +@extern string QFS_GetDirectory (void); #endif//__ruamoko_qfs_h diff --git a/ruamoko/include/qw_message.h b/ruamoko/include/qw_message.h index 5bd7efb0d..60c8587d1 100644 --- a/ruamoko/include/qw_message.h +++ b/ruamoko/include/qw_message.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_qw_message_h #define __ruamoko_qw_message_h -#include "message.h" +#include @extern void multicast (vector where, float set); diff --git a/ruamoko/include/runtime.h b/ruamoko/include/runtime.h index bbcd793ed..80e0aff7e 100644 --- a/ruamoko/include/runtime.h +++ b/ruamoko/include/runtime.h @@ -38,6 +38,8 @@ typedef enum { YES ///< a true value } BOOL; +@extern void __obj_forward(id obj, SEL sel, ...); +@extern BOOL __obj_responds_to(id obj, SEL sel); @extern void obj_error (id object, int code, string fmt, ...); @extern void obj_verror (id object, int code, string fmt, @va_list args); //obj_error_handler obj_set_error_handler (objc_error_handler func); diff --git a/ruamoko/include/string.h b/ruamoko/include/string.h index c4136e2fc..3951c94c5 100644 --- a/ruamoko/include/string.h +++ b/ruamoko/include/string.h @@ -7,6 +7,7 @@ @extern float strlen (string s); @extern float charcount (string goal, string s); @extern string sprintf (string fmt, ...); +@extern string vsprintf (string fmt, @va_list args); @extern string itos (int i); @extern int stoi (string s); @extern vector stov (string s); @@ -19,5 +20,6 @@ @extern @overload string str_mid (string str, int start); @extern @overload string str_mid (string str, int start, int len); @extern string str_str (string haystack, string needle); +@extern int str_char (string str, int ind); #endif//__ruamoko_string_h diff --git a/ruamoko/include/types.h b/ruamoko/include/types.h new file mode 100644 index 000000000..b435a6bab --- /dev/null +++ b/ruamoko/include/types.h @@ -0,0 +1,92 @@ +#ifndef __types_h +#define __types_h + +typedef enum { + ev_void, + ev_string, + ev_float, + ev_vector, + ev_entity, + ev_field, + ev_func, + ev_pointer, // end of v6 types + ev_quat, + ev_integer, + ev_uinteger, + ev_short, // value is embedded in the opcode + ev_double, + + ev_invalid, // invalid type. used for instruction checking + ev_type_count // not a type, gives number of types +} etype_t; + +typedef enum { + ty_basic, ///< VM type (float, int, pointer, field, etc) + ty_struct, + ty_union, + ty_enum, + ty_array, + ty_class, + ty_alias, +} ty_meta_e; + +typedef struct qfot_alias_s { + etype_t type; + struct qfot_type_s *aux_type; + string name; +} qfot_alias_t; + +typedef struct qfot_fldptr_s { + etype_t type; + struct qfot_type_s *aux_type; +} qfot_fldptr_t; + +typedef struct qfot_func_s { + etype_t type; + struct qfot_type_s *return_type; + int num_params; + struct qfot_type_s *param_types[1]; +} qfot_func_t; + +typedef struct qfot_var_s { + struct qfot_type_s *type; + string name; + int offset; // value for enum, 0 for union +} qfot_var_t; + +typedef struct qfot_struct_s { + string tag; + int num_fields; + qfot_var_t fields[1]; +} qfot_struct_t; + +typedef struct qfot_array_s { + struct qfot_type_s *type; + int base; + int size; +} qfot_array_t; + +typedef struct qfot_type_s { + ty_meta_e meta; + int size; + string encoding; + union { + etype_t type; + qfot_fldptr_t fldptr; + qfot_func_t func; + qfot_struct_t strct; + qfot_array_t array; + string class; + qfot_alias_t alias; + } t; +} qfot_type_t; + +typedef struct qfot_type_encodings_s { + qfot_type_t *types; + int size; +} qfot_type_encodings_t; + +@extern string ty_meta_name[6]; +@extern string pr_type_name[ev_type_count]; + +#endif diff --git a/ruamoko/lib/Array.r b/ruamoko/lib/Array.r index 4673c31d8..2946141cc 100644 --- a/ruamoko/lib/Array.r +++ b/ruamoko/lib/Array.r @@ -1,7 +1,7 @@ -#include "math.h" +#include -#include "Array.h" -#include "runtime.h" +#include +#include #define STANDARD_CAPACITY 16 #define ARRAY_MAX_GRANULARITY 100 @@ -162,7 +162,7 @@ - (id) objectAtIndex: (unsigned)index { if (index >= count) // FIXME: need exceptions - [self error: "-replaceObjectAtIndex:withObject: index out of range"]; + [self error: "-objectAtIndex:withObject: index out of range"]; return _objs[index]; } @@ -261,7 +261,7 @@ { local unsigned i; - if (index >= count) // FIXME: need exceptions + if (index > count) // FIXME: need exceptions [self error: "-insertObject:atIndex: index out of range"]; if (count == capacity) { // at capacity, expand @@ -401,7 +401,7 @@ } - (void) makeObjectsPerformSelector: (SEL)selector - withObject: (id)anObject + withObject: (void *)anObject { local int i; diff --git a/ruamoko/lib/AutoreleasePool.r b/ruamoko/lib/AutoreleasePool.r index 6d8077cfc..b4aadd36f 100644 --- a/ruamoko/lib/AutoreleasePool.r +++ b/ruamoko/lib/AutoreleasePool.r @@ -1,7 +1,6 @@ -#include "AutoreleasePool.h" -#include "Array+Private.h" +#include -#include "Array.h" +#include #include "Array+Private.h" @static Array *poolStack; diff --git a/ruamoko/lib/Entity.r b/ruamoko/lib/Entity.r index 5cc1f4f11..474bc3db1 100644 --- a/ruamoko/lib/Entity.r +++ b/ruamoko/lib/Entity.r @@ -1,10 +1,10 @@ -#include "Entity.h" +#include -#include "debug.h" -#include "entities.h" -#include "plist.h" -#include "script.h" -#include "string.h" +#include +#include +#include +#include +#include typedef void () void_function; diff --git a/ruamoko/lib/Makefile.am b/ruamoko/lib/Makefile.am index 53a20875b..da1157a82 100644 --- a/ruamoko/lib/Makefile.am +++ b/ruamoko/lib/Makefile.am @@ -1,50 +1,96 @@ AUTOMAKE_OPTIONS= foreign -pkglibdir=$(datarootdir)/qfcc/lib - -QFCC=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) -QCFLAGS=-qq -O -g -Wall -Wno-integer-divide -Werror --no-default-paths -QCPPFLAGS=$(AM_CPPFLAGS) -PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) -RANLIB=touch - -AM_CPPFLAGS= -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include - -noinst_HEADERS= \ - Array+Private.h +QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) +QFCC=$(QFCC_DEP) ruamoko_libs=libr.a libqw.a libnq.a libcsqc.a libs=$(ruamoko_libs) +pkglibdir=$(datarootdir)/qfcc/lib + pkglib_LIBRARIES= $(libs) EXTRA_LIBRARIES= $(ruamoko_libs) -SUFFIXES= .o .r .qc +noinst_HEADERS= \ + Array+Private.h + +QCFLAGS=-qq -O -g -Wall -Wno-integer-divide -Werror +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) + +MKDIR_P = @MKDIR_P@ +am__mv = mv -f + +PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) +RANLIB=touch + +SUFFIXES= .o .r .r.o: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -c -o $@ $< -.qc.o: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -c -o $@ $< + $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -p $(STRIP) -c -o $@ $< + sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo + $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo + +r_depfiles_remade= libr_a_SOURCES=\ - cbuf.r cmd.r cvar.r file.r hash.r msgbuf.r plist.r qfile.r qfs.r script.r \ - sound.r string.r math.r \ + cbuf.r cmd.r cvar.r hash.r msgbuf.r plist.r qfile.r qfs.r script.r \ + sound.r string.r math.r types.r \ + obj_forward.r \ Object.r Protocol.r \ AutoreleasePool.r Array.r Array+Private.r Entity.r PropertyList.r Set.r +libr_a_obj=$(libr_a_SOURCES:.r=.o) +libr_a_dep=$(addprefix ./$(DEPDIR)/,$(libr_a_obj:.o=.Qo)) libr_a_AR=$(PAK) -cf +include $(libr_a_dep) # am--include-marker +r_depfiles_remade += $(libr_a_dep) -libqw_a_SOURCES=\ - crudefile.r debug.r entities.r infokey.r math.r message.r \ - physics.r qw_message.r qw_physics.r qw_sys.r \ - server.r sv_sound.r system.r +common_src=debug.r system.r +server_src= \ + crudefile.r entities.r infokey.r message.r \ + physics.r server.r sv_sound.r +libqw_a_src= \ + qw_message.r qw_physics.r qw_sys.r +libnq_a_src= \ + nq_message.r +libcsqc_a_src= draw.r gib.r key.r + +common_obj=$(common_src:.r=.o) +common_dep=$(addprefix ./$(DEPDIR)/,$(common_obj:.o=.Qo)) +include $(common_dep) # am--include-marker +r_depfiles_remade += $(common_dep) + +server_obj=$(server_src:.r=.o) +server_dep=$(addprefix ./$(DEPDIR)/,$(server_obj:.o=.Qo)) +include $(server_dep) # am--include-marker +r_depfiles_remade += $(server_dep) + +libqw_a_SOURCES=$(libqw_a_src) $(common_src) $(server_src) math.r +libqw_a_obj=$(libqw_a_src:.r=.o) +libqw_a_dep=$(addprefix ./$(DEPDIR)/,$(libqw_a_obj:.o=.Qo)) libqw_a_AR=$(PAK) -cf +include $(libqw_a_dep) # am--include-marker +r_depfiles_remade += $(libqw_a_dep) -libnq_a_SOURCES=\ - crudefile.r debug.r entities.r infokey.r math.r message.r \ - nq_message.r physics.r server.r sv_sound.r system.r +libnq_a_SOURCES=$(libnq_a_src) $(common_src) $(server_src) math.r +libnq_a_obj=$(libnq_a_src:.r=.o) +libnq_a_dep=$(addprefix ./$(DEPDIR)/,$(libnq_a_obj:.o=.Qo)) libnq_a_AR=$(PAK) -cf +include $(libnq_a_dep) # am--include-marker +r_depfiles_remade += $(libnq_a_dep) -libcsqc_a_SOURCES= \ - debug.r draw.r gib.r key.r system.r +libcsqc_a_SOURCES=$(libcsqc_a_src) $(common_src) +libcsqc_a_obj=$(libcsqc_a_src:.r=.o) +libcsqc_a_dep=$(addprefix ./$(DEPDIR)/,$(libcsqc_a_obj:.o=.Qo)) libcsqc_a_AR= $(PAK) -cf +include $(libcsqc_a_dep) # am--include-marker +r_depfiles_remade += $(libcsqc_a_dep) + +$(r_depfiles_remade): + $(MKDIR_P) $(@D) + echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) CLEANFILES= *.qfo *.o diff --git a/ruamoko/lib/Object.r b/ruamoko/lib/Object.r index a6b0e9d85..6c7e0e6f4 100644 --- a/ruamoko/lib/Object.r +++ b/ruamoko/lib/Object.r @@ -1,9 +1,15 @@ -#include "Object.h" -#include "AutoreleasePool.h" +#include +#include + +static void link__obj_forward (void) +{ + __obj_forward (nil, nil); +} void *PR_FindGlobal (string name) = #0; //FIXME where? void __obj_exec_class (struct obj_module *msg) = #0; +BOOL __obj_responds_to(id obj, SEL sel) = #0; void (id object, int code, string fmt, ...) obj_error = #0; void (id object, int code, string fmt, @va_list args) obj_verror = #0; //obj_error_handler (objc_error_handler func) obj_set_error_handler = #0; @@ -247,7 +253,7 @@ BOOL (id object) object_is_meta_class = #0; return msg (self, aSelector); } -- (id) performSelector: (SEL)aSelector withObject: (id)anObject +- (id) performSelector: (SEL)aSelector withObject: (void *)anObject { local IMP msg = nil; // FIXME teach qfcc about noreturn @@ -260,8 +266,8 @@ BOOL (id object) object_is_meta_class = #0; } - (id) performSelector: (SEL)aSelector - withObject: (id)anObject - withObject: (id)anotherObject + withObject: (void *)anObject + withObject: (void *)anotherObject { local IMP msg; @@ -274,6 +280,11 @@ BOOL (id object) object_is_meta_class = #0; return msg (self, aSelector, anObject, anotherObject); } +- (void) performv: (SEL) sel : (@va_list) args +{ + obj_msg_sendv (self, sel, args); +} + - (void) doesNotRecognizeSelector: (SEL)aSelector { [self error: "%s does not recognize %s", diff --git a/ruamoko/lib/PropertyList.r b/ruamoko/lib/PropertyList.r index 0bcfa9850..b65edc85d 100644 --- a/ruamoko/lib/PropertyList.r +++ b/ruamoko/lib/PropertyList.r @@ -1,4 +1,4 @@ -#include "PropertyList.h" +#include @implementation PLItem diff --git a/ruamoko/lib/Protocol.r b/ruamoko/lib/Protocol.r index 715ca30a7..8893d13bb 100644 --- a/ruamoko/lib/Protocol.r +++ b/ruamoko/lib/Protocol.r @@ -1,4 +1,4 @@ -#include "Protocol.h" +#include struct obj_protocol_list { struct obj_protocol_list *next; diff --git a/ruamoko/lib/Set.r b/ruamoko/lib/Set.r index 10cf6397d..9e215ec51 100644 --- a/ruamoko/lib/Set.r +++ b/ruamoko/lib/Set.r @@ -1,4 +1,4 @@ -#include "Set.h" +#include void set_del_iter (set_iter_t *set_iter) = #0; set_t *set_new (void) = #0; @@ -27,6 +27,15 @@ string set_as_string (set_t *set) = #0; @implementation SetIterator: Object +- initWithIterator: (set_iter_t *) iter +{ + if (!(self = [super init])) { + return nil; + } + self.iter = iter; + return self; +} + - (SetIterator *) next { if ((iter = set_next (iter))) @@ -84,8 +93,7 @@ string set_as_string (set_t *set) = #0; if (!iter) return nil; - iterator = [[SetIterator alloc] init]; - iterator.iter = iter; + iterator = [[SetIterator alloc] initWithIterator: iter]; return iterator; } diff --git a/ruamoko/lib/cbuf.r b/ruamoko/lib/cbuf.r index 496585fd5..f22498f3c 100644 --- a/ruamoko/lib/cbuf.r +++ b/ruamoko/lib/cbuf.r @@ -1,4 +1,4 @@ -#include "cbuf.h" +#include void (string text) Cbuf_AddText = #0; void (string text) Cbuf_InsertText = #0; diff --git a/ruamoko/lib/cmd.r b/ruamoko/lib/cmd.r index 2ecb6d100..ba86632f8 100644 --- a/ruamoko/lib/cmd.r +++ b/ruamoko/lib/cmd.r @@ -1,4 +1,4 @@ -#include "cmd.h" +#include void (string name, void () func) Cmd_AddCommand = #0; int () Cmd_Argc = #0; diff --git a/ruamoko/lib/crudefile.r b/ruamoko/lib/crudefile.r index c8d4b9e27..2987af452 100644 --- a/ruamoko/lib/crudefile.r +++ b/ruamoko/lib/crudefile.r @@ -1,4 +1,4 @@ -#include "crudefile.h" +#include float (string path, string mode) cfopen = #0x000f0000 + 103; void (float desc) cfclose = #0x000f0000 + 104; diff --git a/ruamoko/lib/cvar.r b/ruamoko/lib/cvar.r index 168c38e18..be12b212e 100644 --- a/ruamoko/lib/cvar.r +++ b/ruamoko/lib/cvar.r @@ -1,4 +1,4 @@ -#include "cvar.h" +#include float (string s) cvar = #45; void (string var, string val) cvar_set = #72; diff --git a/ruamoko/lib/debug.r b/ruamoko/lib/debug.r index 844c88eff..7cf9c8895 100644 --- a/ruamoko/lib/debug.r +++ b/ruamoko/lib/debug.r @@ -1,4 +1,4 @@ -#include "debug.h" +#include void abort (void) = #6; void coredump (void) = #28; diff --git a/ruamoko/lib/draw.r b/ruamoko/lib/draw.r index 741857bf5..5aef3ab75 100644 --- a/ruamoko/lib/draw.r +++ b/ruamoko/lib/draw.r @@ -1,4 +1,4 @@ -#include "draw.h" +#include void Draw_FreePic (qpic_t pic) = #0; qpic_t Draw_MakePic (int width, int heiight, string data) = #0; diff --git a/ruamoko/lib/entities.r b/ruamoko/lib/entities.r index f55bd91a7..f49cc9a53 100644 --- a/ruamoko/lib/entities.r +++ b/ruamoko/lib/entities.r @@ -1,4 +1,4 @@ -#include "entities.h" +#include void setmodel (entity e, string m) = #3; void setorigin (entity e, vector o) = #2; diff --git a/ruamoko/lib/file.r b/ruamoko/lib/file.r deleted file mode 100644 index 02494d317..000000000 --- a/ruamoko/lib/file.r +++ /dev/null @@ -1,3 +0,0 @@ -#include "file.h" - -QFile (string path, string mode) File_Open = #0; diff --git a/ruamoko/lib/gib.r b/ruamoko/lib/gib.r index c3fead7b1..26baacd2f 100644 --- a/ruamoko/lib/gib.r +++ b/ruamoko/lib/gib.r @@ -1,4 +1,4 @@ -#include "gib.h" +#include void GIB_Builtin_Add (string name, void func (int argc, string *argv)) = #0; int (string value) GIB_Return = #0; diff --git a/ruamoko/lib/hash.r b/ruamoko/lib/hash.r index 24844bfc2..120d140f9 100644 --- a/ruamoko/lib/hash.r +++ b/ruamoko/lib/hash.r @@ -1,19 +1,19 @@ -#include "hash.h" +#include -hashtab_t Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud) = #0; -void Hash_SetHashCompare (hashtab_t tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)) = #0; -void Hash_DelTable (hashtab_t tab) = #0; -void Hash_FlushTable (hashtab_t tab) = #0; -int Hash_Add (hashtab_t tab, void *ele) = #0; -int Hash_AddElement (hashtab_t tab, void *ele) = #0; -void *Hash_Find (hashtab_t tab, string key) = #0; -void *Hash_FindElement (hashtab_t tab, void *ele) = #0; -void **Hash_FindList (hashtab_t tab, string key) = #0; -void **Hash_FindElementList (hashtab_t tab, void *ele) = #0; -void *Hash_Del (hashtab_t tab, string key) = #0; -void *Hash_DelElement (hashtab_t tab, void *ele) = #0; -void Hash_Free (hashtab_t tab, void *ele) = #0; +hashtab_t *Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud) = #0; +void Hash_SetHashCompare (hashtab_t *tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)) = #0; +void Hash_DelTable (hashtab_t *tab) = #0; +void Hash_FlushTable (hashtab_t *tab) = #0; +int Hash_Add (hashtab_t *tab, void *ele) = #0; +int Hash_AddElement (hashtab_t *tab, void *ele) = #0; +void *Hash_Find (hashtab_t *tab, string key) = #0; +void *Hash_FindElement (hashtab_t *tab, void *ele) = #0; +void **Hash_FindList (hashtab_t *tab, string key) = #0; +void **Hash_FindElementList (hashtab_t *tab, void *ele) = #0; +void *Hash_Del (hashtab_t *tab, string key) = #0; +void *Hash_DelElement (hashtab_t *tab, void *ele) = #0; +void Hash_Free (hashtab_t *tab, void *ele) = #0; int Hash_String (string str) = #0; int Hash_Buffer (void *buf, int len) = #0; -void **Hash_GetList (hashtab_t tab) = #0; -void Hash_Stats (hashtab_t tab) = #0; +void **Hash_GetList (hashtab_t *tab) = #0; +void Hash_Stats (hashtab_t *tab) = #0; diff --git a/ruamoko/lib/infokey.r b/ruamoko/lib/infokey.r index d0049a4fd..a2913df18 100644 --- a/ruamoko/lib/infokey.r +++ b/ruamoko/lib/infokey.r @@ -1,4 +1,4 @@ -#include "infokey.h" +#include string (entity e, string key) infokey = #80; void (entity ent, string key, string value) setinfokey = #0x000f0000 + 102; diff --git a/ruamoko/lib/key.r b/ruamoko/lib/key.r index 19662f138..4b8c1a09a 100644 --- a/ruamoko/lib/key.r +++ b/ruamoko/lib/key.r @@ -1,4 +1,4 @@ -#include "key.h" +#include int Key_keydown (int keynum) = #0; string (string imt, int keynum, string binding) Key_SetBinding = #0; diff --git a/ruamoko/lib/math.r b/ruamoko/lib/math.r index 80db2b710..47624527a 100644 --- a/ruamoko/lib/math.r +++ b/ruamoko/lib/math.r @@ -1,4 +1,4 @@ -#include "math.h" +#include vector v_forward, v_up, v_right; diff --git a/ruamoko/lib/message.r b/ruamoko/lib/message.r index 3136cd678..4ddb31571 100644 --- a/ruamoko/lib/message.r +++ b/ruamoko/lib/message.r @@ -1,4 +1,4 @@ -#include "message.h" +#include void (...) bprint = #23; void (entity client, string s) sprint = #24; diff --git a/ruamoko/lib/msgbuf.r b/ruamoko/lib/msgbuf.r index c1352a43e..1bd4e09b1 100644 --- a/ruamoko/lib/msgbuf.r +++ b/ruamoko/lib/msgbuf.r @@ -1,4 +1,4 @@ -#include "msgbuf.h" +#include msgbuf_t *MsgBuf_New (int size) = #0; void MsgBuf_Delete (msgbuf_t *msgbuf) = #0; diff --git a/ruamoko/lib/nq_message.r b/ruamoko/lib/nq_message.r index 14c06827a..223d1c604 100644 --- a/ruamoko/lib/nq_message.r +++ b/ruamoko/lib/nq_message.r @@ -1,3 +1,3 @@ -#include "nq_message.h" +#include void (vector o, vector d, float color, float count) particle = #48; diff --git a/ruamoko/lib/obj_forward.r b/ruamoko/lib/obj_forward.r new file mode 100644 index 000000000..60ad819b5 --- /dev/null +++ b/ruamoko/lib/obj_forward.r @@ -0,0 +1,3 @@ +// __obj_foward is the only thing in this file so it can be readily replaced +// at link time +void __obj_forward(id object, SEL sel, ...) = #0; diff --git a/ruamoko/lib/physics.r b/ruamoko/lib/physics.r index ca19e052f..b42585d00 100644 --- a/ruamoko/lib/physics.r +++ b/ruamoko/lib/physics.r @@ -1,4 +1,4 @@ -#include "physics.h" +#include float trace_allsolid; float trace_startsolid; diff --git a/ruamoko/lib/plist.r b/ruamoko/lib/plist.r index 4b01c653b..40ab2e1fc 100644 --- a/ruamoko/lib/plist.r +++ b/ruamoko/lib/plist.r @@ -1,4 +1,4 @@ -#include "plist.h" +#include plitem_t PL_GetFromFile (QFile file) = #0; plitem_t PL_GetPropertyList (string str) = #0; diff --git a/ruamoko/lib/qfile.r b/ruamoko/lib/qfile.r index 072d72a1c..487beb5c5 100644 --- a/ruamoko/lib/qfile.r +++ b/ruamoko/lib/qfile.r @@ -1,4 +1,4 @@ -#include "qfile.h" +#include int Qrename (string old, string new) = #0; int Qremove (string path) = #0; diff --git a/ruamoko/lib/qfs.r b/ruamoko/lib/qfs.r index e1d374fc4..d467b09ce 100644 --- a/ruamoko/lib/qfs.r +++ b/ruamoko/lib/qfs.r @@ -1,4 +1,4 @@ -#include "qfs.h" +#include QFile QFS_Open (string path, string mode) = #0; QFile QFS_WOpen (string path, int zip) = #0; @@ -8,3 +8,4 @@ QFile QFS_OpenFile (string filename) = #0; int QFS_WriteFile (string filename, void *buf, int count) = #0; QFSlist QFS_Filelist (string path, string ext, int strip) = #0; void QFS_FilelistFree (QFSlist list) = #0; +string QFS_GetDirectory (void) = #0; diff --git a/ruamoko/lib/qw_message.r b/ruamoko/lib/qw_message.r index fcc714c37..218db52cd 100644 --- a/ruamoko/lib/qw_message.r +++ b/ruamoko/lib/qw_message.r @@ -1,3 +1,3 @@ -#include "qw_message.h" +#include void (vector where, float set) multicast = #82; diff --git a/ruamoko/lib/qw_physics.r b/ruamoko/lib/qw_physics.r index 431e97e63..0ff633569 100644 --- a/ruamoko/lib/qw_physics.r +++ b/ruamoko/lib/qw_physics.r @@ -1,4 +1,4 @@ -#include "qw_physics.h" +#include entity (entity ent) testentitypos = #0x000f0000 + 92; void (vector start, vector mins, vector maxs, vector end, float type, entity passent) checkmove = #0x000f0000 + 98; diff --git a/ruamoko/lib/qw_sys.r b/ruamoko/lib/qw_sys.r index 8d8643576..529f42947 100644 --- a/ruamoko/lib/qw_sys.r +++ b/ruamoko/lib/qw_sys.r @@ -1,3 +1,3 @@ -#include "qw_sys.h" +#include void (entity killer, entity killee) logfrag = #79; diff --git a/ruamoko/lib/script.r b/ruamoko/lib/script.r index 74c120075..e72c4b72a 100644 --- a/ruamoko/lib/script.r +++ b/ruamoko/lib/script.r @@ -1,4 +1,4 @@ -#include "script.h" +#include script_t Script_New (void) = #0; void Script_Delete (script_t script) = #0; diff --git a/ruamoko/lib/server.r b/ruamoko/lib/server.r index 42bd99eb5..b65c3ac7d 100644 --- a/ruamoko/lib/server.r +++ b/ruamoko/lib/server.r @@ -1,4 +1,4 @@ -#include "server.h" +#include void (string s) precache_sound = #19; void (string s) precache_model = #20; diff --git a/ruamoko/lib/sound.r b/ruamoko/lib/sound.r index 863800c81..000ef7047 100644 --- a/ruamoko/lib/sound.r +++ b/ruamoko/lib/sound.r @@ -1,3 +1,3 @@ -#include "sound.h" +#include void (string sound) S_LocalSound = #0; diff --git a/ruamoko/lib/string.r b/ruamoko/lib/string.r index f7eda6b48..58f64911a 100644 --- a/ruamoko/lib/string.r +++ b/ruamoko/lib/string.r @@ -1,4 +1,4 @@ -#include "string.h" +#include string (float f) ftos = #26; string (vector v) vtos = #27; @@ -6,6 +6,7 @@ float (string s) stof = #81; float (string s) strlen = #0x000f0000 + 100; float (string goal, string s) charcount = #0x000f0000 + 101; string (string fmt, ...) sprintf = #0x000f0000 + 109; +string vsprintf (string fmt, @va_list args) = #0; string (int i) itos = #0x000f0000 + 112; int (string s) stoi = #0x000f0000 + 113; vector (string s) stov = #0x000f0000 + 114; @@ -18,3 +19,4 @@ string (string str) str_clear = #0; string (string str, int start) str_mid = #0; string (string str, int start, int len) str_mid = #0; string (string haystack, string needle) str_str = #0; +int str_char (string str, int ind) = #0; diff --git a/ruamoko/lib/sv_sound.r b/ruamoko/lib/sv_sound.r index 7880c6b1b..cd4b4f43e 100644 --- a/ruamoko/lib/sv_sound.r +++ b/ruamoko/lib/sv_sound.r @@ -1,4 +1,4 @@ -#include "sound.h" +#include void (entity e, float chan, string samp, float vol, float atten) sound = #8; void (vector pos, string samp, float vol, float atten) ambientsound = #74; diff --git a/ruamoko/lib/system.r b/ruamoko/lib/system.r index 1a387f890..753a41d99 100644 --- a/ruamoko/lib/system.r +++ b/ruamoko/lib/system.r @@ -1,4 +1,4 @@ -#include "system.h" +#include float time; diff --git a/ruamoko/lib/types.r b/ruamoko/lib/types.r new file mode 100644 index 000000000..66140b83f --- /dev/null +++ b/ruamoko/lib/types.r @@ -0,0 +1,28 @@ +#include +#include + +string ty_meta_name[6] = { + "basic", + "struct", + "union", + "enum", + "array", + "class", +}; + +string pr_type_name[ev_type_count] = { + "void", + "string", + "float", + "vector", + "entity", + "field", + "function", + "pointer", + "quaternion", + "integer", + "uinteger", + "short", + "double" + "invalid", +}; diff --git a/tools/qwaq/.gdbinit b/ruamoko/qwaq/.gdbinit similarity index 100% rename from tools/qwaq/.gdbinit rename to ruamoko/qwaq/.gdbinit diff --git a/ruamoko/qwaq/Makefile.am b/ruamoko/qwaq/Makefile.am new file mode 100644 index 000000000..683a0923c --- /dev/null +++ b/ruamoko/qwaq/Makefile.am @@ -0,0 +1,88 @@ +AUTOMAKE_OPTIONS= foreign + +QWAQ_LIBS=@QWAQ_LIBS@ +QWAQ_DEPS=@QWAQ_DEPS@ +QWAQ_INCS=@QWAQ_INCS@ + +AM_CPPFLAGS= -I$(top_srcdir)/include $(QWAQ_INCS) $(PTHREAD_CFLAGS) + +noinst_PROGRAMS=@QWAQ_TARGETS@ qwaq-app.dat$(EXEEXT) + +QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) +QFCC=$(top_builddir)/tools/qfcc/source/qfcc + +QCFLAGS=-qq -O -g -Werror +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) + +SUFFIXES=.o .r +.r.o: + $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -c -o $@ $< + sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo + $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo + +qwaq_app_dat_src= \ + qwaq-app.r \ + qwaq-button.r \ + qwaq-draw.r \ + qwaq-garray.r \ + qwaq-group.r \ + qwaq-listener.r \ + qwaq-rect.r \ + qwaq-screen.r \ + qwaq-textcontext.r \ + qwaq-view.r \ + qwaq-window.r + +qwaq_curses_libs= +qwaq_curses_SOURCES=main.c qwaq-curses.c +qwaq_curses_LDADD= $(qwaq_curses_libs) $(QWAQ_LIBS) \ + $(PANEL_LIBS) $(CURSES_LIBS) $(PTHREAD_LDFLAGS) $(DL_LIBS) +qwaq_curses_LDFLAGS= +qwaq_curses_DEPENDENCIES= $(qwaq_curses_libs) $(QWAQ_DEPS) + +cl_plugin_libs= \ + @client_static_plugin_libs@ + +client_libs= \ + $(top_builddir)/libs/console/libQFconsole.la \ + $(top_builddir)/libs/video/targets/libQFjs.la \ + $(top_builddir)/libs/audio/libQFcd.la \ + $(top_builddir)/libs/audio/libQFsound.la \ + $(top_builddir)/libs/image/libQFimage.la + +qwaq_x11_libs= \ + $(cl_plugin_libs) \ + $(top_builddir)/libs/video/renderer/libQFrenderer.la \ + $(top_builddir)/libs/models/libQFmodels.la \ + $(top_builddir)/libs/video/targets/libQFx11.la \ + $(client_libs) \ + $(top_builddir)/libs/gib/libQFgib.la +qwaq_x11_SOURCES=qwaq.c qwaq-bi.c +qwaq_x11_LDADD= $(qwaq_x11_libs) $(QWAQ_LIBS) \ + $(VIDMODE_LIBS) $(DGA_LIBS) $(X_LIBS) -lX11 \ + $(X_EXTRA_LIBS) $(X_SHM_LIB) $(DL_LIBS) +qwaq_x11_LDFLAGS= +qwaq_x11_DEPENDENCIES= $(qwaq_x11_libs) $(QWAQ_DEPS) + +r_depfiles_remade= + +qwaq_app_dat_SOURCES=$(qwaq_app_dat_src) +qwaq_app_obj=$(qwaq_app_dat_SOURCES:.r=.o) +qwaq_app_dep=$(addprefix ./$(DEPDIR)/,$(qwaq_app_obj:.o=.Qo)) +qwaq-app.dat$(EXEEXT): $(qwaq_app_obj) $(QFCC_DEP) + $(QLINK) -o $@ $(qwaq_app_obj) -lr +include $(qwaq_app_dep) # am--include-marker +r_depfiles_remade += $(qwaq_app_dep) + +$(r_depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) + +EXTRA_PROGRAMS=qwaq-curses qwaq-x11 +EXTRA_DIST=$(qwaq_dat_src) qwaq.h +CLEANFILES= *.dat *.sym qwaq-curses.log diff --git a/tools/qwaq/builtins.c b/ruamoko/qwaq/builtins.c similarity index 100% rename from tools/qwaq/builtins.c rename to ruamoko/qwaq/builtins.c diff --git a/ruamoko/qwaq/color.h b/ruamoko/qwaq/color.h new file mode 100644 index 000000000..95067b5de --- /dev/null +++ b/ruamoko/qwaq/color.h @@ -0,0 +1,21 @@ +#ifndef __qwaq_color_h +#define __qwaq_color_h + +#ifndef COLOR_PAIR +// double protection in case this header is included in a C file + +#define COLOR_PAIR(cp) ((cp) << 8) + +// taken from ncurses.h +#define COLOR_BLACK 0 +#define COLOR_RED 1 +#define COLOR_GREEN 2 +#define COLOR_YELLOW 3 +#define COLOR_BLUE 4 +#define COLOR_MAGENTA 5 +#define COLOR_CYAN 6 +#define COLOR_WHITE 7 + +#endif + +#endif//__qwaq_color_h diff --git a/ruamoko/qwaq/event.h b/ruamoko/qwaq/event.h new file mode 100644 index 000000000..03f479fdc --- /dev/null +++ b/ruamoko/qwaq/event.h @@ -0,0 +1,73 @@ +#ifndef __qwaq_event_h +#define __qwaq_event_h + +typedef enum { + qe_mousedown = 0x0001, + qe_mouseup = 0x0002, + qe_mouseclick= 0x0004, + qe_mousemove = 0x0008, + qe_mouseauto = 0x0010, +} qwaq_mouse_event; + +typedef enum { + qe_keydown = 0x0020, +} qwaq_key_event; + +typedef enum { + qe_command = 0x0200, // application level command + qe_broadcast = 0x0400, +} qwaq_message_event; + +typedef enum { + qe_none = 0x0000, + qe_mouse = 0x001f, + qe_key = 0x0020, + qe_system = 0x01c0, + qe_message = 0xfe00, + + qe_focused = qe_key | qe_command, + qe_positional = qe_mouse, +} qwaq_event_mask; + +typedef enum { + qc_valid, + qc_exit, + qc_error, +} qwaq_command; + +typedef struct qwaq_mevent_s { + int x, y; + int buttons; + int click; +} qwaq_mevent_t; + +typedef struct qwaq_message_s { + qwaq_command command; +} qwaq_message_t; + +typedef struct qwaq_event_s { + int what; + union { + int key; + qwaq_mevent_t mouse; + qwaq_message_t message; + }; +} qwaq_event_t; + +#ifdef __QFCC__ // don't want C gcc to see this :) +@protocol HandleEvent +-handleEvent: (struct qwaq_event_s *) event; +@end + +@protocol HandleFocusedEvent +-takeFocus; +-loseFocus; +@end + +@protocol HandleMouseEvent +-(struct Rect_s *)getRect; +@end + +#endif + +#endif//__qwaq_event_h diff --git a/tools/qwaq/main.c b/ruamoko/qwaq/main.c similarity index 79% rename from tools/qwaq/main.c rename to ruamoko/qwaq/main.c index 15270d5e4..ae82758ad 100644 --- a/tools/qwaq/main.c +++ b/ruamoko/qwaq/main.c @@ -32,32 +32,37 @@ #endif #include +#include +#include -#include -#include -#include -#include +#include "QF/cbuf.h" +#include "QF/cmd.h" +#include "QF/cvar.h" +#include "QF/gib.h" +#include "QF/idparse.h" +#include "QF/progs.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" #include "QF/ruamoko.h" -#include +#include "QF/sys.h" #include "QF/va.h" -#include +#include "QF/zone.h" #include "qwaq.h" #define MAX_EDICTS 1024 -static edict_t *edicts; -static int num_edicts; -static int reserved_edicts; static progs_t pr; +cbuf_t *qwaq_cbuf; + static QFile * open_file (const char *path, int *len) { QFile *file = Qopen (path, "rbz"); if (!file) { - perror (path); + Sys_Printf ("%s\n", sys_errlist[errno]); return 0; } *len = Qfilesize (file); @@ -65,7 +70,7 @@ open_file (const char *path, int *len) } static void * -load_file (progs_t *pr, const char *name) +load_file (progs_t *pr, const char *name, off_t *_size) { QFile *file; int size; @@ -81,6 +86,7 @@ load_file (progs_t *pr, const char *name) sym = malloc (size + 1); sym[size] = 0; Qread (file, sym, size); + *_size = size; return sym; } @@ -99,26 +105,27 @@ free_progs_mem (progs_t *pr, void *mem) static void init_qf (void) { - Sys_Init (); - //Cvar_Get ("developer", "128", 0, 0, 0); + qwaq_cbuf = Cbuf_New (&id_interp); - Memory_Init (malloc (1024 * 1024), 1024 * 1024); + Sys_Init (); + COM_ParseConfig (); + + //Cvar_Set (developer, "1"); + + Memory_Init (malloc (8 * 1024 * 1024), 8 * 1024 * 1024); Cvar_Get ("pr_debug", "2", 0, 0, 0); Cvar_Get ("pr_boundscheck", "0", 0, 0, 0); - pr.edicts = &edicts; - pr.num_edicts = &num_edicts; - pr.reserved_edicts = &reserved_edicts; pr.load_file = load_file; pr.allocate_progs_mem = allocate_progs_mem; pr.free_progs_mem = free_progs_mem; pr.no_exec_limit = 1; PR_Init_Cvars (); - PR_Init (); + PR_Init (&pr); RUA_Init (&pr, 0); - PR_Cmds_Init(&pr); + PR_Cmds_Init (&pr); BI_Init (&pr); } @@ -143,21 +150,26 @@ load_progs (const char *name) } int -main (int argc, char **argv) +main (int argc, const char **argv) { dfunction_t *dfunc; func_t main_func = 0; - const char *name = "qwaq.dat"; + const char *name = "qwaq-app.dat"; string_t *pr_argv; int pr_argc = 1, i; + COM_InitArgv (argc, argv); init_qf (); if (argc > 1) name = argv[1]; - if (!load_progs (name)) + if (!load_progs (name)) { Sys_Error ("couldn't load %s", name); + } + + //pr.pr_trace = 1; + //pr.pr_trace_depth = -1; PR_PushFrame (&pr); if (argc > 2) @@ -176,7 +188,9 @@ main (int argc, char **argv) PR_RESET_PARAMS (&pr); P_INT (&pr, 0) = pr_argc; P_POINTER (&pr, 1) = PR_SetPointer (&pr, pr_argv); + pr.pr_argc = 2; PR_ExecuteProgram (&pr, main_func); PR_PopFrame (&pr); + Sys_Shutdown (); return R_INT (&pr); } diff --git a/tools/qwaq/progs.src.in b/ruamoko/qwaq/progs.src.in similarity index 100% rename from tools/qwaq/progs.src.in rename to ruamoko/qwaq/progs.src.in diff --git a/ruamoko/qwaq/qwaq-app.h b/ruamoko/qwaq/qwaq-app.h new file mode 100644 index 000000000..db341c7a3 --- /dev/null +++ b/ruamoko/qwaq/qwaq-app.h @@ -0,0 +1,26 @@ +#ifndef __qwaq_app_h +#define __qwaq_app_h + +#include + +#include "event.h" + +@class Group; +@class TextContext; + +@interface QwaqApplication: Object +{ + qwaq_event_t event; + qwaq_command endState; + + Group *objects; + + TextContext *screen; + int autocount; +} +-run; +-draw; +-handleEvent: (qwaq_event_t *) event; +@end + +#endif//__qwaq_app_h diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r new file mode 100644 index 000000000..beeb02788 --- /dev/null +++ b/ruamoko/qwaq/qwaq-app.r @@ -0,0 +1,159 @@ +int fence; +#include + +#include "color.h" +#include "qwaq-app.h" +#include "qwaq-button.h" +#include "qwaq-curses.h" +#include "qwaq-group.h" +#include "qwaq-listener.h" +#include "qwaq-window.h" +#include "qwaq-screen.h" +#include "qwaq-view.h" + +static AutoreleasePool *autorelease_pool; +static void +arp_start (void) +{ + autorelease_pool = [[AutoreleasePool alloc] init]; +} + +static void +arp_end (void) +{ + [autorelease_pool release]; + autorelease_pool = nil; +} + +@implementation QwaqApplication ++app +{ + return [[[self alloc] init] autorelease]; +} + +-init +{ + if (!(self = [super init])) { + return nil; + } + + initialize (); + init_pair (1, COLOR_WHITE, COLOR_BLUE); + init_pair (2, COLOR_WHITE, COLOR_BLACK); + init_pair (3, COLOR_BLACK, COLOR_GREEN); + init_pair (4, COLOR_YELLOW, COLOR_RED); + + screen = [TextContext screen]; + objects = [[Group alloc] initWithContext: screen owner: nil]; + + [screen bkgd: COLOR_PAIR (1)]; + Rect r = { nil, [screen size] }; + r.offset.x = r.extent.width / 4; + r.offset.y = r.extent.height / 4; + r.extent.width /= 2; + r.extent.height /= 2; + Window *w; + [objects insert: w = [[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; + DrawBuffer *released = [DrawBuffer buffer: {12, 1}]; + DrawBuffer *pressed = [DrawBuffer buffer: {12, 1}]; + Button *b = [[Button alloc] initWithPos: {3, 4} releasedIcon: released + pressedIcon: pressed]; + [w addView: b]; + [released bkgd: COLOR_PAIR(3)]; + [released clear]; + [released mvaddstr: {2, 0}, "press me"]; + [pressed bkgd: COLOR_PAIR(4)]; + [pressed clear]; + [pressed mvaddstr: {1, 0}, "release me"]; + [[b onPress] addListener: self : @selector (buttonPressed:)]; + [[b onRelease] addListener: self : @selector (buttonReleased:)]; + [[b onClick] addListener: self : @selector (buttonClick:)]; + [[b onDrag] addListener: self : @selector (buttonDrag:)]; + [[b onAuto] addListener: self : @selector (buttonAuto:)]; + return self; +} + +-(void) buttonPressed: (id) sender +{ + [screen mvaddstr: {2, 0}, " pressed "]; + [screen refresh]; +} + +-(void) buttonReleased: (id) sender +{ + [screen mvaddstr: {2, 0}, "released "]; + [screen refresh]; +} + +-(void) buttonClick: (id) sender +{ + [screen mvprintf: {2, 1}, "clicked %d", [sender click]]; + [screen refresh]; +} + +-(void) buttonDrag: (id) sender +{ + [screen mvaddstr: {2, 0}, "dragged "]; + Point delta = [sender delta]; + [screen mvprintf: {15, 0}, "%3d %3d", delta.x, delta.y]; + [screen refresh]; +} + +-(void) buttonAuto: (id) sender +{ + [screen mvprintf: {2, 2}, "%d", autocount++]; + [screen refresh]; +} + +-run +{ + [self draw]; + do { + arp_start (); + + get_event (&event); + if (event.what != qe_none) { + [self handleEvent: &event]; + } + + arp_end (); + } while (!endState); + return self; +} + +-draw +{ + [objects draw]; + [TextContext refresh]; + return self; +} + +-handleEvent: (qwaq_event_t *) event +{ + [objects handleEvent: event]; + if (event.what == qe_key && event.key == '\x18') { + event.what = qe_command; + event.message.command = qc_exit; + } + if (event.what == qe_command + && (event.message.command == qc_exit + || event.message.command == qc_error)) { + endState = event.message.command; + } + return self; +} +@end + +int main (int argc, string *argv) +{ + fence = 0; + //while (!fence) {} + + id app = [[QwaqApplication app] retain]; + + [app run]; + [app release]; + qwaq_event_t event; + get_event (&event); // XXX need a "wait for queue idle" + return 0; +} diff --git a/tools/qwaq/qwaq-bi.c b/ruamoko/qwaq/qwaq-bi.c similarity index 100% rename from tools/qwaq/qwaq-bi.c rename to ruamoko/qwaq/qwaq-bi.c diff --git a/ruamoko/qwaq/qwaq-button.h b/ruamoko/qwaq/qwaq-button.h new file mode 100644 index 000000000..bab624e35 --- /dev/null +++ b/ruamoko/qwaq/qwaq-button.h @@ -0,0 +1,36 @@ +#ifndef __qwaq_button_h +#define __qwaq_button_h + +#include "qwaq-draw.h" +#include "qwaq-view.h" + +@class ListenerGroup; + +@interface Button : View +{ + DrawBuffer *icon[2]; + int pressed; + int click; + Point dragBase; + Point dragPos; + ListenerGroup *onPress; + ListenerGroup *onRelease; + ListenerGroup *onClick; + ListenerGroup *onDrag; + ListenerGroup *onAuto; + ListenerGroup *onHover; +} +-initWithPos: (Point) pos releasedIcon: (DrawBuffer *) released + pressedIcon: (DrawBuffer *) pressed; +-(ListenerGroup *) onPress; +-(ListenerGroup *) onRelease; +-(ListenerGroup *) onClick; +-(ListenerGroup *) onDrag; +-(ListenerGroup *) onAuto; +-(ListenerGroup *) onHover; + +- (int) click; +- (Point) delta; +@end + +#endif//__qwaq_button_h diff --git a/ruamoko/qwaq/qwaq-button.r b/ruamoko/qwaq/qwaq-button.r new file mode 100644 index 000000000..fe7aa5f2f --- /dev/null +++ b/ruamoko/qwaq/qwaq-button.r @@ -0,0 +1,120 @@ +#include "qwaq-button.h" +#include "qwaq-listener.h" + +@implementation Button +-initWithPos: (Point) pos releasedIcon: (DrawBuffer *) released + pressedIcon: (DrawBuffer *) pressed +{ + Extent size = mergeExtents ([released size], [pressed size]); + + if (!(self = [super initWithRect: {pos, size}])) { + return nil; + } + icon[0] = released; + icon[1] = pressed; + onPress = [[ListenerGroup alloc] init]; + onRelease = [[ListenerGroup alloc] init]; + onClick = [[ListenerGroup alloc] init]; + onDrag = [[ListenerGroup alloc] init]; + onAuto = [[ListenerGroup alloc] init]; + onHover = [[ListenerGroup alloc] init]; + return self; +} + +-draw +{ + [super draw]; + [textContext blitFromBuffer: icon[pressed] + to: pos + from: [icon[pressed] rect]]; + return self; +} + +-handleEvent: (qwaq_event_t *) event +{ + ListenerGroup *action = nil; + + if (event.what & qe_mouse) { + switch ((qwaq_mouse_event) (event.what & qe_mouse)) { + case qe_mousedown: + pressed = 1; + click = 0; + dragBase = {event.mouse.x, event.mouse.y}; + action = onPress; + [self grabMouse]; + [self redraw]; + break; + case qe_mouseup: + pressed = 0; + click = 0; + action = onRelease; + [self releaseMouse]; + if ([self containsPoint: {event.mouse.x, event.mouse.y}]) { + [onClick respond: self]; + } + [self redraw]; + break; + case qe_mouseclick: + action = onClick; + click = event.mouse.click; + break; + case qe_mousemove: + click = 0; + if (pressed) { + dragPos = {event.mouse.x, event.mouse.y}; + action = onDrag; + } + break; + case qe_mouseauto: + click = 0; + action = onAuto; + break; + } + if (action) { + [action respond: self]; + } + } + return self; +} + +-(ListenerGroup *) onPress +{ + return onPress; +} + +-(ListenerGroup *) onRelease +{ + return onRelease; +} + +-(ListenerGroup *) onClick +{ + return onClick; +} + +-(ListenerGroup *) onDrag +{ + return onDrag; +} + +-(ListenerGroup *) onAuto +{ + return onAuto; +} + +-(ListenerGroup *) onHover +{ + return onHover; +} + +- (int) click +{ + return click; +} + +- (Point) delta +{ + return {dragPos.x - dragBase.x, dragPos.y - dragBase.y}; +} + +@end diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c new file mode 100644 index 000000000..3837d2f8c --- /dev/null +++ b/ruamoko/qwaq/qwaq-curses.c @@ -0,0 +1,1811 @@ +/* + #FILENAME# + + #DESCRIPTION# + + Copyright (C) 2001 #AUTHOR# + + Author: #AUTHOR# + Date: #DATE# + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "QF/dstring.h" +#include "QF/progs.h" +#include "QF/ringbuffer.h" +#include "QF/sys.h" + +#include "qwaq.h" +#include "event.h" +#include "qwaq-curses.h" +#include "qwaq-rect.h" +#include "qwaq-textcontext.h" + +#define always_inline inline __attribute__((__always_inline__)) +#define QUEUE_SIZE 16 +#define MOUSE_MOVES_ON "\033[?1003h"// Make the terminal report mouse movements +#define MOUSE_MOVES_OFF "\033[?1003l"// Make the terminal report mouse movements +#define STRING_ID_QUEUE_SIZE 8 // must be > 1 +#define COMMAND_QUEUE_SIZE 1280 +#define CMD_SIZE(x) sizeof(x)/sizeof(x[0]) + +typedef enum qwaq_commands_e { + qwaq_cmd_newwin, + qwaq_cmd_delwin, + qwaq_cmd_getwrect, + qwaq_cmd_new_panel, + qwaq_cmd_del_panel, + qwaq_cmd_hide_panel, + qwaq_cmd_show_panel, + qwaq_cmd_top_panel, + qwaq_cmd_bottom_panel, + qwaq_cmd_move_panel, + qwaq_cmd_panel_window, + qwaq_cmd_update_panels, + qwaq_cmd_doupdate, + qwaq_cmd_mvwaddstr, + qwaq_cmd_waddstr, + qwaq_cmd_mvwaddch, + qwaq_cmd_waddch, + qwaq_cmd_wrefresh, + qwaq_cmd_init_pair, + qwaq_cmd_wbkgd, + qwaq_cmd_werase, + qwaq_cmd_scrollok, + qwaq_cmd_move, + qwaq_cmd_curs_set, + qwaq_cmd_wborder, + qwaq_cmd_mvwblit_line, +} qwaq_commands; + +const char *qwaq_command_names[]= { + "newwin", + "delwin", + "getwrect", + "new_panel", + "del_panel", + "hide_panel", + "show_panel", + "top_panel", + "bottom_panel", + "move_panel", + "panel_window", + "update_panels", + "doupdate", + "mvwaddstr", + "waddstr", + "mvwaddch", + "waddch", + "wrefresh", + "init_pair", + "wbkgd", + "werase", + "scrollok", + "move", + "curs_set", + "wborder", + "mvwblit_line", +}; + +typedef struct window_s { + WINDOW *win; +} window_t; + +typedef struct panel_s { + PANEL *panel; + int window_id; +} panel_t; + +typedef struct qwaq_resources_s { + progs_t *pr; + int initialized; + window_t stdscr; + PR_RESMAP (window_t) window_map; + PR_RESMAP (panel_t) panel_map; + RING_BUFFER (qwaq_event_t, QUEUE_SIZE) event_queue; + RING_BUFFER (int, COMMAND_QUEUE_SIZE) command_queue; + RING_BUFFER (int, COMMAND_QUEUE_SIZE) results; + RING_BUFFER (int, STRING_ID_QUEUE_SIZE) string_ids; + dstring_t strings[STRING_ID_QUEUE_SIZE - 1]; +} qwaq_resources_t; + +static window_t * +window_new (qwaq_resources_t *res) +{ + PR_RESNEW (window_t, res->window_map); +} + +static void +window_free (qwaq_resources_t *res, window_t *win) +{ + PR_RESFREE (window_t, res->window_map, win); +} + +static void +window_reset (qwaq_resources_t *res) +{ + PR_RESRESET (window_t, res->window_map); +} + +static inline window_t * +window_get (qwaq_resources_t *res, unsigned index) +{ + PR_RESGET(res->window_map, index); +} + +static inline int +window_index (qwaq_resources_t *res, window_t *win) +{ + PR_RESINDEX (res->window_map, win); +} + +static always_inline window_t * __attribute__((pure)) +get_window (qwaq_resources_t *res, const char *name, int handle) +{ + if (handle == 1) { + return &res->stdscr; + } + + window_t *window = window_get (res, handle); + + if (!window || !window->win) { + PR_RunError (res->pr, "invalid window passed to %s", name + 3); + } + return window; +} + +static panel_t * +panel_new (qwaq_resources_t *res) +{ + PR_RESNEW (panel_t, res->panel_map); +} + +static void +panel_free (qwaq_resources_t *res, panel_t *win) +{ + PR_RESFREE (panel_t, res->panel_map, win); +} + +static void +panel_reset (qwaq_resources_t *res) +{ + PR_RESRESET (panel_t, res->panel_map); +} + +static inline panel_t * +panel_get (qwaq_resources_t *res, unsigned index) +{ + PR_RESGET(res->panel_map, index); +} + +static inline int +panel_index (qwaq_resources_t *res, panel_t *win) +{ + PR_RESINDEX (res->panel_map, win); +} + +static always_inline panel_t * __attribute__((pure)) +get_panel (qwaq_resources_t *res, const char *name, int handle) +{ + panel_t *panel = panel_get (res, handle); + + if (!panel || !panel->panel) { + PR_RunError (res->pr, "invalid panel passed to %s", name + 3); + } + return panel; +} + +//XXX goes away with threads +static void process_commands (qwaq_resources_t *); +static void process_input (qwaq_resources_t *); +static int +acquire_string (qwaq_resources_t *res) +{ + int string_id = -1; + + // XXX add locking and loop for available + if (!RB_DATA_AVAILABLE (res->string_ids)) { + process_commands(res); + } + if (RB_DATA_AVAILABLE (res->string_ids)) { + RB_READ_DATA (res->string_ids, &string_id, 1); + } + // XXX unlock and end of loop + return string_id; +} + +static void +release_string (qwaq_resources_t *res, int string_id) +{ + // locking shouldn't be necessary as there should be only one writer + // but if it becomes such that there is more than one writer, locks as per + // acquire + if (RB_SPACE_AVAILABLE (res->string_ids)) { + RB_WRITE_DATA (res->string_ids, &string_id, 1); + } +} + +static void +qwaq_submit_command (qwaq_resources_t *res, const int *cmd) +{ + unsigned len = cmd[1]; + + if (RB_SPACE_AVAILABLE (res->command_queue) >= len) { + RB_WRITE_DATA (res->command_queue, cmd, len); + } else { + PR_RunError (res->pr, "command buffer full"); + } +} + +static void +qwaq_submit_result (qwaq_resources_t *res, const int *result, unsigned len) +{ + // loop + if (RB_SPACE_AVAILABLE (res->results) >= len) { + RB_WRITE_DATA (res->results, result, len); + } else { + PR_RunError (res->pr, "result buffer full"); + } +} + +static void +qwaq_wait_result (qwaq_resources_t *res, int *result, int cmd, unsigned len) +{ + // XXX should just wait on the mutex + process_commands (res); + process_input (res); + // locking and loop until id is correct + if (RB_DATA_AVAILABLE (res->results) >= len + && RB_PEEK_DATA (res->results, 0) == cmd) { + RB_READ_DATA (res->results, result, len); + } +} + +static void +cmd_newwin (qwaq_resources_t *res) +{ + int xpos = RB_PEEK_DATA (res->command_queue, 2); + int ypos = RB_PEEK_DATA (res->command_queue, 3); + int xlen = RB_PEEK_DATA (res->command_queue, 4); + int ylen = RB_PEEK_DATA (res->command_queue, 5); + + window_t *window = window_new (res); + window->win = newwin (ylen, xlen, ypos, xpos); + keypad (window->win, TRUE); + + int window_id = window_index (res, window); + int cmd_result[] = { qwaq_cmd_newwin, window_id }; + qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result)); +} + +static void +cmd_delwin (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + + window_t *window = get_window (res, __FUNCTION__, window_id); + delwin (window->win); + window_free (res, window); +} + +static void +cmd_getwrect (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int xpos, ypos; + int xlen, ylen; + + window_t *window = get_window (res, __FUNCTION__, window_id); + getparyx (window->win, ypos, xpos); + if (xpos == -1 && ypos ==-1) { + getbegyx (window->win, ypos, xpos); + } + getmaxyx (window->win, ylen, xlen); + + int cmd_result[] = { qwaq_cmd_getwrect, xpos, ypos, xlen, ylen }; + qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result)); +} + +static void +cmd_new_panel (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + + window_t *window = get_window (res, __FUNCTION__, window_id); + panel_t *panel = panel_new (res); + panel->panel = new_panel (window->win); + panel->window_id = window_id; + + int panel_id = panel_index (res, panel); + int cmd_result[] = { qwaq_cmd_new_panel, panel_id }; + qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result)); +} + +static void +cmd_del_panel (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + del_panel (panel->panel); + panel_free (res, panel); +} + +static void +cmd_hide_panel (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + hide_panel (panel->panel); +} + +static void +cmd_show_panel (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + show_panel (panel->panel); +} + +static void +cmd_top_panel (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + top_panel (panel->panel); +} + +static void +cmd_bottom_panel (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + bottom_panel (panel->panel); +} + +static void +cmd_move_panel (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + int x = RB_PEEK_DATA (res->command_queue, 3); + int y = RB_PEEK_DATA (res->command_queue, 4); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + move_panel (panel->panel, y, x); +} + +static void +cmd_panel_window (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + + int window_id = panel->window_id; + int cmd_result[] = { qwaq_cmd_panel_window, window_id, }; + qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result)); +} + +static void +cmd_update_panels (qwaq_resources_t *res) +{ + update_panels (); +} + +static void +cmd_doupdate (qwaq_resources_t *res) +{ + doupdate (); +} + +static void +cmd_mvwaddstr (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int x = RB_PEEK_DATA (res->command_queue, 3); + int y = RB_PEEK_DATA (res->command_queue, 4); + int string_id = RB_PEEK_DATA (res->command_queue, 5); + + window_t *window = get_window (res, __FUNCTION__, window_id); + mvwaddstr (window->win, y, x, res->strings[string_id].str); + release_string (res, string_id); +} + +static void +cmd_waddstr (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int string_id = RB_PEEK_DATA (res->command_queue, 3); + + window_t *window = get_window (res, __FUNCTION__, window_id); + waddstr (window->win, res->strings[string_id].str); + release_string (res, string_id); +} + +static void +cmd_mvwaddch (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int x = RB_PEEK_DATA (res->command_queue, 3); + int y = RB_PEEK_DATA (res->command_queue, 4); + int ch = RB_PEEK_DATA (res->command_queue, 5); + + window_t *window = get_window (res, __FUNCTION__, window_id); + mvwaddch (window->win, y, x, ch); +} + +static void +cmd_waddch (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int ch = RB_PEEK_DATA (res->command_queue, 3); + + window_t *window = get_window (res, __FUNCTION__, window_id); + waddch (window->win, ch); +} + +static void +cmd_wrefresh (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + + window_t *window = get_window (res, __FUNCTION__, window_id); + wrefresh (window->win); +} + +static void +cmd_init_pair (qwaq_resources_t *res) +{ + int pair = RB_PEEK_DATA (res->command_queue, 2); + int f = RB_PEEK_DATA (res->command_queue, 3); + int b = RB_PEEK_DATA (res->command_queue, 4); + + init_pair (pair, f, b); +} + +static void +cmd_wbkgd (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int ch = RB_PEEK_DATA (res->command_queue, 3); + + window_t *window = get_window (res, __FUNCTION__, window_id); + wbkgd (window->win, ch); +} + +static void +cmd_werase (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + + window_t *window = get_window (res, __FUNCTION__, window_id); + werase (window->win); +} + +static void +cmd_scrollok (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int flag = RB_PEEK_DATA (res->command_queue, 3); + + window_t *window = get_window (res, __FUNCTION__, window_id); + scrollok (window->win, flag); +} + +static void +cmd_move (qwaq_resources_t *res) +{ + int x = RB_PEEK_DATA (res->command_queue, 2); + int y = RB_PEEK_DATA (res->command_queue, 3); + + move (y, x); +} + +static void +cmd_curs_set (qwaq_resources_t *res) +{ + int visibility = RB_PEEK_DATA (res->command_queue, 2); + + curs_set (visibility); +} + +static void +cmd_wborder (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int ls = RB_PEEK_DATA (res->command_queue, 3); + int rs = RB_PEEK_DATA (res->command_queue, 4); + int ts = RB_PEEK_DATA (res->command_queue, 5); + int bs = RB_PEEK_DATA (res->command_queue, 6); + int tl = RB_PEEK_DATA (res->command_queue, 7); + int tr = RB_PEEK_DATA (res->command_queue, 8); + int bl = RB_PEEK_DATA (res->command_queue, 9); + int br = RB_PEEK_DATA (res->command_queue, 10); + + window_t *window = get_window (res, __FUNCTION__, window_id); + wborder (window->win, ls, rs, ts, bs, tl, tr, bl, br); +} + +static void +cmd_mvwblit_line (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int x = RB_PEEK_DATA (res->command_queue, 3); + int y = RB_PEEK_DATA (res->command_queue, 4); + int chs_id = RB_PEEK_DATA (res->command_queue, 5); + int len = RB_PEEK_DATA (res->command_queue, 6); + int *chs = (int *) res->strings[chs_id].str; + int save_x; + int save_y; + + window_t *window = get_window (res, __FUNCTION__, window_id); + getyx (window->win, save_y, save_x); + for (int i = 0; i < len; i++) { + if (chs[i] & 0xff) { + mvwaddch (window->win, y, x + i, chs[i]); + } + } + wmove (window->win, save_y, save_x); + release_string (res, chs_id); +} + +static void +process_commands (qwaq_resources_t *res) +{ + while (RB_DATA_AVAILABLE (res->command_queue) >= 2) { + qwaq_commands cmd = RB_PEEK_DATA (res->command_queue, 0); + //int len = RB_PEEK_DATA (res->command_queue, 1); + //Sys_Printf ("%s[%d]", qwaq_command_names[cmd], len); + //for (int i = 2; i < len; i++) { + // Sys_Printf (" %d", RB_PEEK_DATA (res->command_queue, i)); + //} + //Sys_Printf ("\n"); + switch (cmd) { + case qwaq_cmd_newwin: + cmd_newwin (res); + break; + case qwaq_cmd_delwin: + cmd_delwin (res); + break; + case qwaq_cmd_getwrect: + cmd_getwrect (res); + break; + case qwaq_cmd_new_panel: + cmd_new_panel (res); + break; + case qwaq_cmd_del_panel: + cmd_del_panel (res); + break; + case qwaq_cmd_hide_panel: + cmd_hide_panel (res); + break; + case qwaq_cmd_show_panel: + cmd_show_panel (res); + break; + case qwaq_cmd_top_panel: + cmd_top_panel (res); + break; + case qwaq_cmd_bottom_panel: + cmd_bottom_panel (res); + break; + case qwaq_cmd_move_panel: + cmd_move_panel (res); + break; + case qwaq_cmd_panel_window: + cmd_panel_window (res); + break; + case qwaq_cmd_update_panels: + cmd_update_panels (res); + break; + case qwaq_cmd_doupdate: + cmd_doupdate (res); + break; + case qwaq_cmd_mvwaddstr: + cmd_mvwaddstr (res); + break; + case qwaq_cmd_waddstr: + cmd_waddstr (res); + break; + case qwaq_cmd_mvwaddch: + cmd_mvwaddch (res); + break; + case qwaq_cmd_waddch: + cmd_waddch (res); + break; + case qwaq_cmd_wrefresh: + cmd_wrefresh (res); + break; + case qwaq_cmd_init_pair: + cmd_init_pair (res); + break; + case qwaq_cmd_wbkgd: + cmd_wbkgd (res); + break; + case qwaq_cmd_werase: + cmd_werase (res); + break; + case qwaq_cmd_scrollok: + cmd_scrollok (res); + break; + case qwaq_cmd_move: + cmd_move (res); + break; + case qwaq_cmd_curs_set: + cmd_curs_set (res); + break; + case qwaq_cmd_wborder: + cmd_wborder (res); + break; + case qwaq_cmd_mvwblit_line: + cmd_mvwblit_line (res); + break; + } + RB_DROP_DATA (res->command_queue, RB_PEEK_DATA (res->command_queue, 1)); + } +} + +static void +add_event (qwaq_resources_t *res, qwaq_event_t *event) +{ + // lock + // { + // merge motion events + unsigned last = RB_DATA_AVAILABLE (res->event_queue); + if (event->what == qe_mousemove && last > 1 + && RB_PEEK_DATA(res->event_queue, last - 1).what == qe_mousemove) { + RB_POKE_DATA(res->event_queue, last - 1, *event); + return; // unlock + } + // } + if (RB_SPACE_AVAILABLE (res->event_queue) >= 1) { + RB_WRITE_DATA (res->event_queue, event, 1); + } +} + +static int +get_event (qwaq_resources_t *res, qwaq_event_t *event) +{ + if (RB_DATA_AVAILABLE (res->event_queue) >= 1) { + if (event) { + RB_READ_DATA (res->event_queue, event, 1); + } + return 1; + } + event->what = qe_none; + return 0; +} + +#define M_MOVE REPORT_MOUSE_POSITION +#define M_PRESS ( BUTTON1_PRESSED \ + | BUTTON2_PRESSED \ + | BUTTON3_PRESSED \ + | BUTTON4_PRESSED \ + | BUTTON5_PRESSED) +#define M_RELEASE ( BUTTON1_RELEASED \ + | BUTTON2_RELEASED \ + | BUTTON3_RELEASED \ + | BUTTON4_RELEASED \ + | BUTTON5_RELEASED) +#define M_CLICK ( BUTTON1_CLICKED \ + | BUTTON2_CLICKED \ + | BUTTON3_CLICKED \ + | BUTTON4_CLICKED \ + | BUTTON5_CLICKED) +#define M_DCLICK ( BUTTON1_DOUBLE_CLICKED \ + | BUTTON2_DOUBLE_CLICKED \ + | BUTTON3_DOUBLE_CLICKED \ + | BUTTON4_DOUBLE_CLICKED \ + | BUTTON5_DOUBLE_CLICKED) +#define M_TCLICK ( BUTTON1_TRIPLE_CLICKED \ + | BUTTON2_TRIPLE_CLICKED \ + | BUTTON3_TRIPLE_CLICKED \ + | BUTTON4_TRIPLE_CLICKED \ + | BUTTON5_TRIPLE_CLICKED) + +static void +mouse_event (qwaq_resources_t *res, const MEVENT *mevent) +{ + int mask = mevent->bstate; + qwaq_event_t event = {}; + + event.mouse.x = mevent->x; + event.mouse.y = mevent->y; + event.mouse.buttons = mevent->bstate; + if (mask & M_MOVE) { + event.what = qe_mousemove; + mask &= ~M_MOVE; + } + if (mask & M_PRESS) { + event.what = qe_mousedown; + mask &= ~M_PRESS; + } + if (mask & M_RELEASE) { + event.what = qe_mouseup; + mask &= ~M_RELEASE; + } + if (mask & M_CLICK) { + event.what = qe_mouseclick; + mask &= ~M_CLICK; + event.mouse.click = 1; + } + if (mask & M_DCLICK) { + event.what = qe_mouseclick; + mask &= ~M_DCLICK; + event.mouse.click = 2; + } + if (mask & M_TCLICK) { + event.what = qe_mouseclick; + mask &= ~M_TCLICK; + event.mouse.click = 3; + } + add_event (res, &event); +} + +static void +key_event (qwaq_resources_t *res, int key) +{ + qwaq_event_t event = {}; + event.what = qe_keydown; + event.key = key; + add_event (res, &event); +} + +static void +process_input (qwaq_resources_t *res) +{ + if (Sys_CheckInput (1, -1)) { + int ch; + while ((ch = getch ()) != ERR && ch) { + fflush (stderr); + if (ch == KEY_MOUSE) { + MEVENT mevent; + getmouse (&mevent); + mouse_event (res, &mevent); + } else { + key_event (res, ch); + } + } + } +} + +static int need_endwin; +static void +bi_shutdown (void) +{ + if (need_endwin) { + write(1, MOUSE_MOVES_OFF, sizeof (MOUSE_MOVES_OFF) - 1); + endwin (); + } +} + +static void +bi_newwin (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int xpos = P_INT (pr, 0); + int ypos = P_INT (pr, 1); + int xlen = P_INT (pr, 2); + int ylen = P_INT (pr, 3); + int command[] = { + qwaq_cmd_newwin, 0, + xpos, ypos, xlen, ylen, + }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + + int cmd_result[2]; + qwaq_wait_result (res, cmd_result, qwaq_cmd_newwin, CMD_SIZE (cmd_result)); + R_INT (pr) = cmd_result[1]; +} + +static void +bi_delwin (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_delwin, 0, window_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} + +static void +qwaq_getwrect (progs_t *pr, int window_id) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_getwrect, 0, window_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + + int cmd_result[5]; + qwaq_wait_result (res, cmd_result, qwaq_cmd_getwrect, + CMD_SIZE (cmd_result)); + // return xpos, ypos, xlen, ylen + (&R_INT (pr))[0] = cmd_result[1]; + (&R_INT (pr))[1] = cmd_result[2]; + (&R_INT (pr))[2] = cmd_result[3]; + (&R_INT (pr))[3] = cmd_result[4]; + } +} +static void +bi_getwrect (progs_t *pr) +{ + qwaq_getwrect (pr, P_INT (pr, 0)); +} + +static void +bi_new_panel (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_new_panel, 0, window_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + + int cmd_result[2]; + qwaq_wait_result (res, cmd_result, qwaq_cmd_new_panel, + CMD_SIZE (cmd_result)); + R_INT (pr) = cmd_result[1]; + } +} + +static void +panel_command (progs_t *pr, qwaq_commands cmd) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int panel_id = P_INT (pr, 0); + + if (get_panel (res, __FUNCTION__, panel_id)) { + int command[] = { cmd, 0, panel_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} + +static void +bi_del_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_del_panel); +} + +static void +bi_hide_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_hide_panel); +} + +static void +bi_show_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_show_panel); +} + +static void +bi_top_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_top_panel); +} + +static void +bi_bottom_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_bottom_panel); +} + +static void +bi_move_panel (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int panel_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + + if (get_panel (res, __FUNCTION__, panel_id)) { + int command[] = { qwaq_cmd_move_panel, 0, panel_id, x, y, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} + +static void +bi_panel_window (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int panel_id = P_INT (pr, 0); + + if (get_panel (res, __FUNCTION__, panel_id)) { + int command[] = { qwaq_cmd_panel_window, 0, panel_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + + int cmd_result[2]; + qwaq_wait_result (res, cmd_result, qwaq_cmd_panel_window, + CMD_SIZE (cmd_result)); + (&R_INT (pr))[0] = cmd_result[1]; + } +} + +static void +qwaq_update_panels (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_update_panels, 0, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} +static void +bi_update_panels (progs_t *pr) +{ + qwaq_update_panels (pr); +} + +static void +qwaq_doupdate (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_doupdate, 0, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} +static void +bi_doupdate (progs_t *pr) +{ + qwaq_doupdate (pr); +} + +static void +qwaq_waddstr (progs_t *pr, int window_id, const char *str) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_waddstr, 0, + window_id, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_copystr (print_buffer, str); + qwaq_submit_command (res, command); + } +} +static void +bi_waddstr (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + const char *str = P_GSTRING (pr, 1); + + qwaq_waddstr (pr, window_id, str); +} + +static void +qwaq_mvwaddstr (progs_t *pr, int window_id, int x, int y, const char *str) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_mvwaddstr, 0, + window_id, x, y, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_copystr (print_buffer, str); + qwaq_submit_command (res, command); + } +} +static void +bi_mvwaddstr (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + const char *str = P_GSTRING (pr, 3); + + qwaq_mvwaddstr (pr, window_id, x, y, str); +} + +static void +qwaq_mvwprintf (progs_t *pr, int window_id, int x, int y, const char *fmt, + int count, pr_type_t **args) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_mvwaddstr, 0, + window_id, x, y, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "mvwaddstr", fmt, count, args); + + qwaq_submit_command (res, command); + } +} +static void +bi_mvwprintf (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + const char *fmt = P_GSTRING (pr, 3); + int count = pr->pr_argc - 4; + pr_type_t **args = pr->pr_params + 4; + + qwaq_mvwprintf (pr, window_id, x, y, fmt, count, args); +} + +static void +qwaq_wprintf (progs_t *pr, int window_id, const char *fmt, + int count, pr_type_t **args) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_waddstr, 0, + window_id, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "waddstr", fmt, count, args); + + qwaq_submit_command (res, command); + } +} +static void +bi_wprintf (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + const char *fmt = P_GSTRING (pr, 1); + int count = pr->pr_argc - 2; + pr_type_t **args = pr->pr_params + 2; + + qwaq_wprintf (pr, window_id, fmt, count, args); +} + +static void +qwaq_wvprintf (progs_t *pr, int window_id, const char *fmt, pr_va_list_t *args) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + pr_type_t *list_start = PR_GetPointer (pr, args->list); + pr_type_t **list = alloca (args->count * sizeof (*list)); + + for (int i = 0; i < args->count; i++) { + list[i] = list_start + i * pr->pr_param_size; + } + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_waddstr, 0, + window_id, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "waddstr", fmt, args->count, list); + + qwaq_submit_command (res, command); + } +} +static void +bi_wvprintf (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + const char *fmt = P_GSTRING (pr, 1); + __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 2); + + qwaq_wvprintf (pr, window_id, fmt, args); +} + +static void +qwaq_waddch (progs_t *pr, int window_id, int ch) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_waddch, 0, window_id, ch }; + + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_waddch (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int ch = P_INT (pr, 0); + + qwaq_waddch (pr, window_id, ch); +} + +static void +qwaq_mvwvprintf (progs_t *pr, int window_id, int x, int y, + const char *fmt, pr_va_list_t *args) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + pr_type_t *list_start = PR_GetPointer (pr, args->list); + pr_type_t **list = alloca (args->count * sizeof (*list)); + + for (int i = 0; i < args->count; i++) { + list[i] = list_start + i * pr->pr_param_size; + } + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_mvwaddstr, 0, + window_id, x, y, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "waddstr", fmt, args->count, list); + + qwaq_submit_command (res, command); + } +} +static void +bi_mvwvprintf (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + const char *fmt = P_GSTRING (pr, 2); + __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 3); + + qwaq_mvwvprintf (pr, x, y, window_id, fmt, args); +} + +static void +qwaq_mvwaddch (progs_t *pr, int window_id, int x, int y, int ch) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { + qwaq_cmd_mvwaddch, 0, + window_id, x, y, ch + }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_mvwaddch (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + int ch = P_INT (pr, 3); + + qwaq_mvwaddch (pr, window_id, x, y, ch); +} + +static void +qwaq_wrefresh (progs_t *pr, int window_id) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_wrefresh, 0, window_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_wrefresh (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + + qwaq_wrefresh (pr, window_id); +} + +static void +bi_get_event (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + qwaq_event_t *event = &G_STRUCT (pr, qwaq_event_t, P_INT (pr, 0)); + + process_commands (res); + process_input (res); + R_INT (pr) = get_event (res, event); +} + +static void +bi_max_colors (progs_t *pr) +{ + R_INT (pr) = COLORS; +} + +static void +bi_max_color_pairs (progs_t *pr) +{ + R_INT (pr) = COLOR_PAIRS; +} + +static void +qwaq_init_pair (progs_t *pr, int pair, int f, int b) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_init_pair, 0, pair, f, b, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} +static void +bi_init_pair (progs_t *pr) +{ + int pair = P_INT (pr, 0); + int f = P_INT (pr, 1); + int b = P_INT (pr, 2); + + qwaq_init_pair (pr, pair, f, b); +} + +static void +qwaq_wbkgd (progs_t *pr, int window_id, int ch) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_wbkgd, 0, window_id, ch, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_wbkgd (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int ch = P_INT (pr, 1); + + qwaq_wbkgd (pr, window_id, ch); +} + +static void +qwaq_werase (progs_t *pr, int window_id, int ch) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_werase, 0, window_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_werase (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int ch = P_INT (pr, 1); + + qwaq_werase (pr, window_id, ch); +} + +static void +qwaq_scrollok (progs_t *pr, int window_id, int flag) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_scrollok, 0, window_id, flag, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_scrollok (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int flag = P_INT (pr, 1); + + qwaq_scrollok (pr, window_id, flag); +} + +static const char qwaq_acs_char_map[] = "lmkjtuvwqxnos`afg~,+.-hi0pryz{|}"; +static void +qwaq_acs_char (progs_t *pr, unsigned acs) +{ + if (acs < 256) { + R_INT (pr) = NCURSES_ACS(acs); + } else if (acs - 256 < sizeof (qwaq_acs_char_map)) { + R_INT (pr) = NCURSES_ACS(qwaq_acs_char_map[acs - 256]); + } else { + R_INT (pr) = 0; + } +} +static void +bi_acs_char (progs_t *pr) +{ + int acs = P_INT (pr, 0); + + qwaq_acs_char (pr, acs); +} + +static void +qwaq_move (progs_t *pr, int x, int y) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_move, 0, x, y, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} +static void +bi_move (progs_t *pr) +{ + int x = P_INT (pr, 0); + int y = P_INT (pr, 1); + + qwaq_move (pr, x, y); +} + +static void +qwaq_curs_set (progs_t *pr, int visibility) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_curs_set, 0, visibility, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} +static void +bi_curs_set (progs_t *pr) +{ + int visibility = P_INT (pr, 0); + + qwaq_curs_set (pr, visibility); +} + +static void +qwaq_wborder (progs_t *pr, int window_id, + box_sides_t sides, box_corners_t corns) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_wborder, 0, window_id, + sides.ls, sides.rs, sides.ts, sides.bs, + corns.tl, corns.tr, corns.bl, corns.br, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_wborder (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + __auto_type sides = P_PACKED (pr, box_sides_t, 1); + __auto_type corns = P_PACKED (pr, box_corners_t, 2); + + qwaq_wborder (pr, window_id, sides, corns); +} + +static void +qwaq__mvwblit_line (progs_t *pr, int window_id, int x, int y, + int *chs, int len) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int chs_id = acquire_string (res); + dstring_t *chs_buf = res->strings + chs_id; + int command[] = { qwaq_cmd_mvwblit_line, 0, window_id, + x, y, chs_id, len,}; + + command[1] = CMD_SIZE(command); + + chs_buf->size = len * sizeof (int); + dstring_adjust (chs_buf); + memcpy (chs_buf->str, chs, len * sizeof (int)); + + qwaq_submit_command (res, command); + } +} +static void +bi_mvwblit_line (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + int *chs = (int *) P_GPOINTER (pr, 3); + int len = P_INT (pr, 4); + qwaq__mvwblit_line (pr, window_id, x, y, chs, len); +} + +static void +bi_initialize (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + initscr (); + need_endwin = 1; + res->initialized = 1; + start_color (); + raw (); + keypad (stdscr, TRUE); + noecho (); + nonl (); + nodelay (stdscr, TRUE); + mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); + write(1, MOUSE_MOVES_ON, sizeof (MOUSE_MOVES_ON) - 1); + refresh(); + + res->stdscr.win = stdscr; +} + +static void +bi_printf (progs_t *pr) +{ + const char *fmt = P_GSTRING (pr, 0); + int count = pr->pr_argc - 1; + pr_type_t **args = pr->pr_params + 1; + dstring_t *dstr = dstring_new (); + + PR_Sprintf (pr, dstr, "bi_printf", fmt, count, args); + if (dstr->str) + Sys_Printf (dstr->str, stdout); + dstring_delete (dstr); +} + +static void +bi_c_TextContext__is_initialized (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + R_INT (pr) = res->initialized; +} + +static void +bi_c_TextContext__max_colors (progs_t *pr) +{ + bi_max_colors (pr); +} + +static void +bi_c_TextContext__max_color_pairs (progs_t *pr) +{ + bi_max_color_pairs (pr); +} + +static void +bi_c_TextContext__init_pair_ (progs_t *pr) +{ + int pair = P_INT (pr, 2); + int f = P_INT (pr, 3); + int b = P_INT (pr, 4); + + qwaq_init_pair (pr, pair, f, b); +} + +static void +bi_c_TextContext__acs_char_ (progs_t *pr) +{ + int acs = P_INT (pr, 2); + + qwaq_acs_char (pr, acs); +} + +static void +bi_c_TextContext__move_ (progs_t *pr) +{ + Point *pos = &P_PACKED (pr, Point, 2); + + qwaq_move (pr, pos->x, pos->y); +} + +static void +bi_c_TextContext__curs_set_ (progs_t *pr) +{ + int visibility = P_INT (pr, 2); + + qwaq_curs_set (pr, visibility); +} + +static void +bi_c_TextContext__doupdate (progs_t *pr) +{ + bi_doupdate (pr); +} + +static void +bi_i_TextContext__mvprintf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + Point *pos = &P_PACKED (pr, Point, 2); + const char *fmt = P_GSTRING (pr, 3); + int count = pr->pr_argc - 4; + pr_type_t **args = pr->pr_params + 4; + + qwaq_mvwprintf (pr, window_id, pos->x, pos->y, fmt, count, args); +} + +static void +bi_i_TextContext__printf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + const char *fmt = P_GSTRING (pr, 2); + int count = pr->pr_argc - 3; + pr_type_t **args = pr->pr_params + 3; + + qwaq_wprintf (pr, window_id, fmt, count, args); +} + +static void +bi_i_TextContext__vprintf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + const char *fmt = P_GSTRING (pr, 2); + __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 3); + + qwaq_wvprintf (pr, window_id, fmt, args); +} + +static void +bi_i_TextContext__addch_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int ch = P_INT (pr, 2); + + qwaq_waddch (pr, window_id, ch); +} + +static void +bi_i_TextContext__addstr_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + const char *str = P_GSTRING (pr, 2); + + qwaq_waddstr (pr, window_id, str); +} + +static void +bi_i_TextContext__mvvprintf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + Point *pos = &P_PACKED (pr, Point, 2); + const char *fmt = P_GSTRING (pr, 3); + __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 4); + + qwaq_mvwvprintf (pr, pos->x, pos->y, window_id, fmt, args); +} + +static void +bi_c_TextContext__refresh (progs_t *pr) +{ + qwaq_update_panels (pr); + qwaq_doupdate (pr); +} + +static void +bi_i_TextContext__refresh (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + + //qwaq_wrefresh (pr, window_id); + qwaq_update_panels (pr); + if (window_id == 1) { + qwaq_doupdate (pr); + } +} + +static void +bi_i_TextContext__mvaddch_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + Point *pos = &P_PACKED (pr, Point, 2); + int ch = P_INT (pr, 3); + + qwaq_mvwaddch (pr, window_id, pos->x, pos->y, ch); +} + +static void +bi_i_TextContext__mvaddstr_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + Point *pos = &P_PACKED (pr, Point, 2); + const char *str = P_GSTRING (pr, 3); + + qwaq_mvwaddstr (pr, window_id, pos->x, pos->y, str); +} + +static void +bi_i_TextContext__bkgd_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int ch = P_INT (pr, 2); + + qwaq_wbkgd (pr, window_id, ch); +} + +static void +bi_i_TextContext__clear (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int ch = P_INT (pr, 2); + + qwaq_werase (pr, window_id, ch); +} + +static void +bi_i_TextContext__scrollok_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int flag = P_INT (pr, 2); + + qwaq_scrollok (pr, window_id, flag); +} + +static void +bi_i_TextContext__border_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + __auto_type sides = P_PACKED (pr, box_sides_t, 2); + __auto_type corns = P_PACKED (pr, box_corners_t, 3); + + qwaq_wborder (pr, window_id, sides, corns); +} + +static void +bi_qwaq_clear (progs_t *pr, void *data) +{ + __auto_type res = (qwaq_resources_t *) data; + + if (res->initialized) { + write(1, MOUSE_MOVES_OFF, sizeof (MOUSE_MOVES_OFF) - 1); + endwin (); + } + need_endwin = 0; + window_reset (res); + panel_reset (res); +} + +static builtin_t builtins[] = { + {"initialize", bi_initialize, -1}, + {"create_window", bi_newwin, -1}, + {"destroy_window", bi_delwin, -1}, + {"getwrect", bi_getwrect, -1}, + {"create_panel", bi_new_panel, -1}, + {"destroy_panel", bi_del_panel, -1}, + {"hide_panel", bi_hide_panel, -1}, + {"show_panel", bi_show_panel, -1}, + {"top_panel", bi_top_panel, -1}, + {"bottom_panel", bi_bottom_panel, -1}, + {"move_panel", bi_move_panel, -1}, + {"panel_window", bi_panel_window, -1}, + {"update_panels", bi_update_panels, -1}, + {"doupdate", bi_doupdate, -1}, + {"mvwprintf", bi_mvwprintf, -1}, + {"wprintf", bi_wprintf, -1}, + {"wvprintf", bi_wvprintf, -1}, + {"mvwvprintf", bi_mvwvprintf, -1}, + {"mvwaddch", bi_mvwaddch, -1}, + {"waddch", bi_waddch, -1}, + {"mvwaddstr", bi_mvwaddstr, -1}, + {"waddstr", bi_waddstr, -1}, + {"wrefresh", bi_wrefresh, -1}, + {"get_event", bi_get_event, -1}, + {"max_colors", bi_max_colors, -1}, + {"max_color_pairs", bi_max_color_pairs, -1}, + {"init_pair", bi_init_pair, -1}, + {"wbkgd", bi_wbkgd, -1}, + {"werase", bi_werase, -1}, + {"scrollok", bi_scrollok, -1}, + {"acs_char", bi_acs_char, -1}, + {"move", bi_move, -1}, + {"curs_set", bi_curs_set, -1}, + {"wborder", bi_wborder, -1}, + {"mvwblit_line", bi_mvwblit_line, -1}, + + {"printf", bi_printf, -1}, + + {"_c_TextContext__is_initialized", bi_c_TextContext__is_initialized, -1}, + {"_c_TextContext__max_colors", bi_c_TextContext__max_colors, -1}, + {"_c_TextContext__max_color_pairs", bi_c_TextContext__max_color_pairs, -1}, + {"_c_TextContext__init_pair_", bi_c_TextContext__init_pair_, -1}, + {"_c_TextContext__acs_char_", bi_c_TextContext__acs_char_, -1}, + {"_c_TextContext__move_", bi_c_TextContext__move_, -1}, + {"_c_TextContext__curs_set_", bi_c_TextContext__curs_set_, -1}, + {"_c_TextContext__doupdate", bi_c_TextContext__doupdate, -1}, + {"_i_TextContext__mvprintf_", bi_i_TextContext__mvprintf_, -1}, + {"_i_TextContext__printf_", bi_i_TextContext__printf_, -1}, + {"_i_TextContext__vprintf_", bi_i_TextContext__vprintf_, -1}, + {"_i_TextContext__addch_", bi_i_TextContext__addch_, -1}, + {"_i_TextContext__addstr_", bi_i_TextContext__addstr_, -1}, + {"_i_TextContext__mvvprintf_", bi_i_TextContext__mvvprintf_, -1}, + {"_c_TextContext__refresh", bi_c_TextContext__refresh, -1}, + {"_i_TextContext__refresh", bi_i_TextContext__refresh, -1}, + {"_i_TextContext__mvaddch_", bi_i_TextContext__mvaddch_, -1}, + {"_i_TextContext__mvaddstr_", bi_i_TextContext__mvaddstr_, -1}, + {"_i_TextContext__bkgd_", bi_i_TextContext__bkgd_, -1}, + {"_i_TextContext__clear", bi_i_TextContext__clear, -1}, + {"_i_TextContext__scrollok_", bi_i_TextContext__scrollok_, -1}, + {"_i_TextContext__border_", bi_i_TextContext__border_, -1}, + + {0} +}; + +static FILE *logfile; + +static __attribute__((format(printf, 1, 0))) void +qwaq_print (const char *fmt, va_list args) +{ + vfprintf (logfile, fmt, args); + fflush (logfile); +} + +void +BI_Init (progs_t *pr) +{ + qwaq_resources_t *res = calloc (sizeof (*res), 1); + res->pr = pr; + for (int i = 0; i < STRING_ID_QUEUE_SIZE - 1; i++) { + RB_WRITE_DATA (res->string_ids, &i, 1); + res->strings[i].mem = &dstring_default_mem; + } + + PR_Resources_Register (pr, "qwaq", res, bi_qwaq_clear); + PR_RegisterBuiltins (pr, builtins); + Sys_RegisterShutdown (bi_shutdown); + logfile = fopen ("qwaq-curses.log", "wt"); + Sys_SetStdPrintf (qwaq_print); +} diff --git a/ruamoko/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h new file mode 100644 index 000000000..6d0c43df2 --- /dev/null +++ b/ruamoko/qwaq/qwaq-curses.h @@ -0,0 +1,135 @@ +#ifndef __qwaq_curses_h +#define __qwaq_curses_h + +#include "event.h" + +typedef struct box_sides_s { + int ls; + int rs; + int ts; + int bs; +} box_sides_t; + +typedef struct box_corners_s { + int tl; + int tr; + int bl; + int br; +} box_corners_t; + +#ifdef __QFCC__ +#include "qwaq-rect.h" + +// names, order and comments lifted from ncurses.h +typedef enum { +/* VT100 symbols begin here */ + ACS_ULCORNER = 256, /* upper left corner */ + ACS_LLCORNER, /* lower left corner */ + ACS_URCORNER, /* upper right corner */ + ACS_LRCORNER, /* lower right corner */ + ACS_LTEE, /* tee pointing right */ + ACS_RTEE, /* tee pointing left */ + ACS_BTEE, /* tee pointing up */ + ACS_TTEE, /* tee pointing down */ + ACS_HLINE, /* horizontal line */ + ACS_VLINE, /* vertical line */ + ACS_PLUS, /* large plus or crossover */ + ACS_S1, /* scan line 1 */ + ACS_S9, /* scan line 9 */ + ACS_DIAMOND, /* diamond */ + ACS_CKBOARD, /* checker board (stipple) */ + ACS_DEGREE, /* degree symbol */ + ACS_PLMINUS, /* plus/minus */ + ACS_BULLET, /* bullet */ +/* Teletype 5410v1 symbols begin here */ + ACS_LARROW, /* arrow pointing left */ + ACS_RARROW, /* arrow pointing right */ + ACS_DARROW, /* arrow pointing down */ + ACS_UARROW, /* arrow pointing up */ + ACS_BOARD, /* board of squares */ + ACS_LANTERN, /* lantern symbol */ + ACS_BLOCK, /* solid square block */ +/* + * These aren't documented, but a lot of System Vs have them anyway + * (you can spot pprryyzz{{||}} in a lot of AT&T terminfo strings). + * The ACS_names may not match AT&T's, our source didn't know them. + */ + ACS_S3, /* scan line 3 */ + ACS_S7, /* scan line 7 */ + ACS_LEQUAL, /* less/equal */ + ACS_GEQUAL, /* greater/equal */ + ACS_PI, /* Pi */ + ACS_NEQUAL, /* not equal */ + ACS_STERLING, /* UK pound sign */ + +/* + * Line drawing ACS names are of the form ACS_trbl, where t is the top, r + * is the right, b is the bottom, and l is the left. t, r, b, and l might + * be B (blank), S (single), D (double), or T (thick). The subset defined + * here only uses B and S. + */ + ACS_BSSB = ACS_ULCORNER, + ACS_SSBB = ACS_LLCORNER, + ACS_BBSS = ACS_URCORNER, + ACS_SBBS = ACS_LRCORNER, + ACS_SBSS = ACS_RTEE, + ACS_SSSB = ACS_LTEE, + ACS_SSBS = ACS_BTEE, + ACS_BSSS = ACS_TTEE, + ACS_BSBS = ACS_HLINE, + ACS_SBSB = ACS_VLINE, + ACS_SSSS = ACS_PLUS, +} qwaq_acs_chars; + +typedef struct window_s *window_t; +typedef struct panel_s *panel_t; + +@extern window_t stdscr; + +@extern void initialize (void); +@extern window_t create_window (int xpos, int ypos, int xlen, int ylen); +@extern void destroy_window (window_t win); +@extern void mvwprintf (window_t win, int x, int y, string fmt, ...); +@extern void wprintf (window_t win, string fmt, ...); +@extern void wvprintf (window_t win, string fmt, @va_list args); +@extern void mvwvprintf (window_t win, int x, int y, + string fmt, @va_list args); +@extern void wrefresh (window_t win); +@extern void mvwaddch (window_t win, int x, int y, int ch); +@extern void waddch (window_t win, int ch); +@extern void mvwaddstr (window_t win, int x, int y, string str); +@extern void waddstr (window_t win, string str); + +@extern panel_t create_panel (window_t window); +@extern void destroy_panel (panel_t panel); +@extern void hide_panel (panel_t panel); +@extern void show_panel (panel_t panel); +@extern void top_panel (panel_t panel); +@extern void bottom_panel (panel_t panel); +@extern void move_panel (panel_t panel, int x, int y); +@extern window_t panel_window (panel_t panel); +@extern void update_panels (void); +@extern void doupdate (void); + +@extern int get_event (qwaq_event_t *event); +@extern int max_colors (void); +@extern int max_color_pairs (void); +@extern int init_pair (int pair, int f, int b); +@extern void wbkgd (window_t win, int ch); +@extern void werase (window_t win); +@extern void scrollok (window_t win, int flag); + +@extern int acs_char (int acs); +@extern int curs_set (int visibility); +@extern int move (int x, int y); + +@extern void wborder (window_t window, + box_sides_t sides, box_corners_t corners); +@extern void mvwblit_line (window_t window, int x, int y, int *wch, int len); + +@extern Rect getwrect (struct window_s *window); + +@extern void printf(string fmt, ...); +#endif + +#endif//__qwaq_curses_h diff --git a/ruamoko/qwaq/qwaq-draw.h b/ruamoko/qwaq/qwaq-draw.h new file mode 100644 index 000000000..65599347f --- /dev/null +++ b/ruamoko/qwaq/qwaq-draw.h @@ -0,0 +1,44 @@ +#ifndef __qwaq_draw_h +#define __qwaq_draw_h + +#include + +#include "qwaq-rect.h" + +@class DrawBuffer; + +@protocol DrawBuffer +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; +- (Rect) rect; +- (Extent) size; +- (int *) buffer; +@end + +@protocol TextContext +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; +- (Extent) size; + +- (void) bkgd: (int) ch; +- (void) clear; +- (void) printf: (string) fmt, ...; +- (void) vprintf: (string) fmt, @va_list args; +- (void) addch: (int) ch; +- (void) addstr: (string) str; +- (void) mvprintf: (Point) pos, string fmt, ...; +- (void) mvvprintf: (Point) pos, string fmt, @va_list args; +- (void) mvaddch: (Point) pos, int ch; +- (void) mvaddstr: (Point) pos, string str; +@end + +@interface DrawBuffer : Object +{ + int *buffer; + Extent size; + Point cursor; + int background; +} ++ (DrawBuffer *) buffer: (Extent) size; +- initWithSize: (Extent) size; +@end + +#endif diff --git a/ruamoko/qwaq/qwaq-draw.r b/ruamoko/qwaq/qwaq-draw.r new file mode 100644 index 000000000..757f00e90 --- /dev/null +++ b/ruamoko/qwaq/qwaq-draw.r @@ -0,0 +1,198 @@ +#include + +#include "qwaq-curses.h" +#include "qwaq-draw.h" + +@implementation DrawBuffer + ++ (DrawBuffer *) buffer: (Extent) size +{ + return [[self alloc] initWithSize: size]; +} + +- initWithSize: (Extent) size +{ + if (!(self = [super init])) { + return nil; + } + buffer = obj_malloc (size.width * size.height); + self.size = size; + return self; +} + +- (Extent) size +{ + return size; +} + +- (int *) buffer +{ + return buffer; +} +- (Rect) rect +{ + Rect rect = { nil, size }; + return rect; +} + +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect +{ + Extent srcSize = srcBuffer.size; + Rect r = { {}, size }; + Rect t = { pos, rect.extent }; + + wprintf (stdscr, "src: %p\n", srcBuffer); + wprintf (stdscr, "srcSize: %d %d\n", srcSize.width, srcSize.height); + + t = clipRect (r, t); + if (t.extent.width < 0 || t.extent.height < 0) { + return self; + } + + rect.offset.x += t.offset.x - pos.x; + rect.offset.y += t.offset.y - pos.y; + rect.extent = t.extent; + pos = t.offset; + + r.offset = nil; + r.extent = size; + + rect = clipRect (r, rect); + if (rect.extent.width < 0 || rect.extent.height < 0) { + return self; + } + + int *dst = buffer + pos.y * size.width + pos.x; + int *src = srcBuffer.buffer + + rect.offset.y * srcSize.width + rect.offset.x; + for (int y = 0; y < rect.extent.height; y++) { + int *d = dst; + int *s = src; + dst += size.width; + src += srcSize.width; + for (int x = 0; x < rect.extent.width; x++) { + // FIXME 1) need memcpy/memmove + // 2) the generated code could be better + // github issue #3 + *d++ = *s++; + } + } + return self; +} + +- (void) bkgd: (int) ch +{ + background = ch; +} + +- (void) clear +{ + int ch = background; + int *dst = buffer; + int *end = buffer + size.width * size.height; + + if (ch && !(ch & 0xff)) { + ch |= ' '; + } + while (dst < end) { + *dst++ = ch; + } + cursor = {0, 0}; +} + +- (void) printf: (string) fmt, ... +{ + string str = vsprintf (fmt, @args); + [self addstr: str]; +} + +- (void) vprintf: (string) fmt, @va_list args +{ + string str = vsprintf (fmt, args); + [self addstr: str]; +} + +- (void) addch: (int) ch +{ + if (cursor.x < 0) { + cursor.x = 0; + } + if (cursor.y < 0) { + cursor.y = 0; + } + if (cursor.x >= size.width && cursor.y < size.height) { + cursor.x = 0; + cursor.y++; + } + if (cursor.y >= size.height) { + return; + } + if (ch == '\n') { + cursor.x = 0; + cursor.y++; + } else if (ch == '\r') { + cursor.x = 0; + } else { + if (!(ch & ~0xff)) { + ch |= background & ~0xff; + } + buffer[cursor.y * size.width + cursor.x++] = ch; + } +} + +- (void) addstr: (string) str +{ + int ind = 0; + int ch; + + if (cursor.y >= size.height) { + return; + } + while (cursor.x < size.width && (ch = str_char (str, ind++))) { + [self addch: ch]; + } +} + +- (void) mvprintf: (Point) pos, string fmt, ... +{ + if (pos.x < 0 || pos.x >= size.width + || pos.y < 0 || pos.y >= size.height) { + return; + } + cursor = pos; + string str = vsprintf (fmt, @args); + [self addstr: str]; +} + +- (void) mvvprintf: (Point) pos, string fmt, @va_list args +{ + if (pos.x < 0 || pos.x >= size.width + || pos.y < 0 || pos.y >= size.height) { + return; + } + cursor = pos; + string str = vsprintf (fmt, args); + [self addstr: str]; +} + +- (void) mvaddch: (Point) pos, int ch +{ + if (pos.x < 0 || pos.x >= size.width + || pos.y < 0 || pos.y >= size.height) { + return; + } + cursor = pos; + [self addch: ch]; +} + +- (void) mvaddstr: (Point) pos, string str +{ + if (pos.x < 0 || pos.x >= size.width + || pos.y < 0 || pos.y >= size.height) { + return; + } + cursor = pos; + [self addstr: str]; +} + +@end diff --git a/ruamoko/qwaq/qwaq-garray.h b/ruamoko/qwaq/qwaq-garray.h new file mode 100644 index 000000000..1a2e53576 --- /dev/null +++ b/ruamoko/qwaq/qwaq-garray.h @@ -0,0 +1,29 @@ +#ifndef __qwaq_garray_h +#define __qwaq_garray_h + +#include + +typedef BOOL condition_func (id object, void *data); +typedef BOOL condition_func2 (id object, void *anObject, void *data); + +@interface Array (Group) +- (void) makeObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data; +- (void) makeObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data; +- (void) makeReversedObjectsPerformSelector: (SEL)selector; +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject; +- (void) makeReversedObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data; +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data; +@end + +#endif//__qwaq_garray_h diff --git a/ruamoko/qwaq/qwaq-garray.r b/ruamoko/qwaq/qwaq-garray.r new file mode 100644 index 000000000..b3298ffa4 --- /dev/null +++ b/ruamoko/qwaq/qwaq-garray.r @@ -0,0 +1,66 @@ +#include +#include "event.h" +#include "qwaq-garray.h" + +@implementation Array (Group) +- (void) makeObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data +{ + for (int i = 0; i < [self count]; i++) { + if (condition (_objs[i], data)) { + [_objs[i] performSelector: selector]; + } + } +} + +- (void) makeObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data +{ + for (int i = 0; i < [self count]; i++) { + if (condition (_objs[i], anObject, data)) { + [_objs[i] performSelector: selector withObject: anObject]; + } + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector +{ + for (int i = [self count]; i-->0; ) { + [_objs[i] performSelector: selector]; + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject +{ + for (int i = [self count]; i-->0; ) { + [_objs[i] performSelector: selector withObject: anObject]; + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data +{ + for (int i = [self count]; i-->0; ) { + if (condition (_objs[i], data)) { + [_objs[i] performSelector: selector]; + } + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data +{ + for (int i = [self count]; i-->0; ) { + if (condition (_objs[i], anObject, data)) { + [_objs[i] performSelector: selector withObject: anObject]; + } + } +} +@end diff --git a/ruamoko/qwaq/qwaq-group.h b/ruamoko/qwaq/qwaq-group.h new file mode 100644 index 000000000..eaa7606eb --- /dev/null +++ b/ruamoko/qwaq/qwaq-group.h @@ -0,0 +1,33 @@ +#ifndef __qwaq_group_h +#define __qwaq_group_h + +#include + +#include "event.h" +#include "qwaq-draw.h" + +@class View; + +@interface Group : Object +{ + View *owner; + Array *views; + View *mouse_grabbed; + View *mouse_within; + int focused; + id context; +} +-initWithContext: (id) context owner: (View *) owner; +-insert: (View *) view; +-remove: (View *) view; +-(Rect) rect; +-(Point) origin; +-(Extent) size; +-draw; +-redraw; +-handleEvent: (qwaq_event_t *) event; +-(void) grabMouse; +-(void) releaseMouse; +@end + +#endif//__qwaq_group_h diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r new file mode 100644 index 000000000..2df05bcba --- /dev/null +++ b/ruamoko/qwaq/qwaq-group.r @@ -0,0 +1,167 @@ +#include +#include "event.h" +#include "qwaq-draw.h" +#include "qwaq-garray.h" +#include "qwaq-group.h" +#include "qwaq-view.h" + +@implementation Group + +-initWithContext: (id) context owner: (View *) owner +{ + if (!(self = [super init])) { + return nil; + } + self.owner = owner; + self.context = context; + focused = -1; + views = [[Array array] retain]; + return self; +} + +-(void)dealloc +{ + [views release]; +} + +-insert: (View *) view +{ + [views addObject: view]; + [view setOwner: self]; + [view setContext: context]; + return self; +} + +-remove: (View *) view +{ + int index = [views indexOfObject: view]; + if (index != NotFound) { + if (focused == index) { + focused = -1; + } else if (focused > index) { + focused--; + } + [views removeObjectAtIndex: index]; + } + return self; +} + +-(Rect) rect +{ + if (owner) { + return [owner rect]; + } + return {[self origin], [self size]}; +} + +-(Point) origin +{ + if (owner) { + return [owner origin]; + } + return {0, 0}; +} + +-(Extent) size +{ + if (owner) { + return [owner size]; + } + return [context size]; +} + +static BOOL +not_dont_draw (id aView, void *aGroup) +{ + View *view = aView; + Group *group = (Group *) aGroup; + + return !([view options] & ofDontDraw); +} + +-draw +{ + [views makeObjectsPerformSelector: @selector(draw) + if: not_dont_draw + with: self]; + return self; +} + +-redraw +{ + if (owner) { + [owner redraw]; + } else { + [self draw]; + if (__obj_responds_to (context, @selector(refresh))) { + [(id)context refresh]; + } + } + return self; +} + +static View * +find_mouse_view(Group *group, Point pos) +{ + for (int i = [group.views count]; i--; ) { + View *v = [group.views objectAtIndex: i]; + if ([v containsPoint: pos]) { + return v; + } + } + return nil; +} + +-handleEvent: (qwaq_event_t *) event +{ + if (event.what & qe_focused) { + if (focused >= 0) { + [[views objectAtIndex:focused] handleEvent: event]; + } + } else if (event.what & qe_positional) { + Point origin = {}; + if (owner) { + origin = [owner origin]; + } + event.mouse.x -= origin.x; + event.mouse.y -= origin.y; + Point pos = {event.mouse.x, event.mouse.y}; + if (mouse_grabbed) { + [mouse_grabbed handleEvent: event]; + } else { + if (mouse_within && ![mouse_within containsPoint: pos]) { + [mouse_within onMouseLeave: pos]; + mouse_within = nil; + } + if (!mouse_within) { + mouse_within = find_mouse_view (self, pos); + if (mouse_within) { + [mouse_within onMouseEnter: pos]; + } + } + if (mouse_within) { + [mouse_within handleEvent: event]; + } + } + event.mouse.x += origin.x; + event.mouse.y += origin.y; + } else { + // broadcast + [views makeObjectsPerformSelector: @selector(draw) withObject: event]; + } + return self; +} + +-(void) grabMouse +{ + mouse_grabbed = mouse_within; + [owner grabMouse]; +} + +-(void) releaseMouse +{ + mouse_grabbed = nil; + [owner releaseMouse]; +} + +@end diff --git a/ruamoko/qwaq/qwaq-listener.h b/ruamoko/qwaq/qwaq-listener.h new file mode 100644 index 000000000..2f7ec02b3 --- /dev/null +++ b/ruamoko/qwaq/qwaq-listener.h @@ -0,0 +1,29 @@ +#ifndef __qwaq_listener_h +#define __qwaq_listener_h + +#include + +@class Array; + +@interface Listener : Object +{ + id responder; + SEL message; + IMP imp; +} +-initWithResponder: (id) responder :(SEL)message; +-(void) respond: (id) caller; +-(BOOL) matchResponder: (id) responder :(SEL)message; +@end + +@interface ListenerGroup : Object +{ + Array *listeners; +} +-init; +-addListener: (id) responder :(SEL)message; +-removeListener: (id) responder :(SEL)message; +-(void) respond: (id) caller; +@end + +#endif//__qwaq_listener_h diff --git a/ruamoko/qwaq/qwaq-listener.r b/ruamoko/qwaq/qwaq-listener.r new file mode 100644 index 000000000..26e6f28c5 --- /dev/null +++ b/ruamoko/qwaq/qwaq-listener.r @@ -0,0 +1,66 @@ +#include + +#include "qwaq-listener.h" + +@class Array; + +@implementation Listener +-initWithResponder: (id) responder :(SEL)message +{ + if (!(self = [super init])) { + return nil; + } + self.responder = responder; + self.message = message; + imp = [responder methodForSelector: message]; + return self; +} + +-(void)respond: (id) caller +{ + imp (responder, message, caller); +} + +-(BOOL) matchResponder: (id) responder :(SEL)message +{ + return self.responder == responder && self.message == message; +} +@end + +@implementation ListenerGroup : Object +-init +{ + if (!(self = [super init])) { + return nil; + } + listeners = [[Array array] retain]; + return self; +} + +-addListener: (id) responder :(SEL)message +{ + Listener *listener = [[Listener alloc] initWithResponder: responder + : message]; + if (listener) { + [listeners addObject: listener]; + } + return self; +} + +-removeListener: (id) responder :(SEL)message +{ + for (int i = [listeners count]; i-- > 0; ) { + Listener *l = [listeners objectAtIndex: i]; + if ([l matchResponder: responder : message]) { + [listeners removeObjectAtIndex: i]; + } + } + return self; +} + +-(void)respond: (id) caller +{ + [listeners makeObjectsPerformSelector: @selector (respond:) + withObject: caller]; +} +@end diff --git a/ruamoko/qwaq/qwaq-rect.h b/ruamoko/qwaq/qwaq-rect.h new file mode 100644 index 000000000..2ab79788e --- /dev/null +++ b/ruamoko/qwaq/qwaq-rect.h @@ -0,0 +1,28 @@ +#ifndef __qwaq_rect_h +#define __qwaq_rect_h + +typedef struct { + int x; + int y; +} Point; + +typedef struct { + int width; + int height; +} Extent; + +typedef struct Rect_s { + Point offset; + Extent extent; +} Rect; + +#ifdef __QFCC__ +@extern Rect makeRect (int xpos, int ypos, int xlen, int ylen); +@extern Point makePoint (int x, int y); +@extern Extent makeExtent (int width, int height); +@extern Extent mergeExtents (Extent a, Extent b); +@extern int rectContainsPoint (Rect rect, Point point); +@extern Rect clipRect (Rect clipRect, Rect rect); +#endif + +#endif//__qwaq_rect_h diff --git a/ruamoko/qwaq/qwaq-rect.r b/ruamoko/qwaq/qwaq-rect.r new file mode 100644 index 000000000..c2677decc --- /dev/null +++ b/ruamoko/qwaq/qwaq-rect.r @@ -0,0 +1,55 @@ +#include "qwaq-rect.h" + +Rect +clipRect (Rect clipRect, Rect rect) +{ + if (rect.offset.x < clipRect.offset.x) { + int dist = clipRect.offset.x - rect.offset.x; + rect.offset.x += dist; + rect.extent.width -= dist; + } + if (rect.offset.y < clipRect.offset.y) { + int dist = clipRect.offset.y - rect.offset.y; + rect.offset.y += dist; + rect.extent.height -= dist; + } + if (rect.offset.x + rect.extent.width > clipRect.extent.width) { + rect.extent.width = clipRect.extent.width - rect.offset.x; + } + if (rect.offset.y + rect.extent.height > clipRect.extent.height) { + rect.extent.height = clipRect.extent.height - rect.offset.y; + } + return rect; +} + +Rect +makeRect (int xpos, int ypos, int xlen, int ylen) +{ + Rect rect = {{xpos, ypos}, {xlen, ylen}}; + return rect; +} + +Point makePoint (int x, int y) +{ + return {x, y}; +} + +Extent makeExtent (int width, int height) +{ + return {width, height}; +} + +Extent mergeExtents (Extent a, Extent b) +{ + return { a.width < b.width ? b.width : a.width, + a.height < b.height ? b.height : a.height }; +} + +int +rectContainsPoint (Rect rect, Point point) +{ + return ((point.x >= rect.offset.x + && point.x < rect.offset.x + rect.extent.width) + && (point.y >= rect.offset.y + && point.y < rect.offset.y + rect.extent.height)); +} diff --git a/ruamoko/qwaq/qwaq-screen.h b/ruamoko/qwaq/qwaq-screen.h new file mode 100644 index 000000000..9ec2ba8f3 --- /dev/null +++ b/ruamoko/qwaq/qwaq-screen.h @@ -0,0 +1,15 @@ +#ifndef __qwaq_screen_h +#define __qwaq_screen_h + +#include "qwaq-draw.h" +#include "qwaq-rect.h" +#include "qwaq-view.h" + +@interface Screen: View +{ +} ++(Screen *) screen; +-handleEvent: (qwaq_event_t *) event; +@end + +#endif//__qwaq_screen_h diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r new file mode 100644 index 000000000..b6149db25 --- /dev/null +++ b/ruamoko/qwaq/qwaq-screen.r @@ -0,0 +1,43 @@ +#include +#include "qwaq-curses.h" +#include "qwaq-screen.h" + +@implementation Screen ++(Screen *) screen +{ + return [[[self alloc] init] autorelease]; +} + +-init +{ + if (!(self = [super initWithRect:getwrect (stdscr)])) { + return nil; + } + textContext = [TextContext screen]; + [(id)textContext scrollok: 1]; + return self; +} + +-handleEvent: (qwaq_event_t *) event +{ + if (event.what & qe_mouse) { + [self printf:"%04x %2d %2d %d %08x \r", event.what, event.mouse.x, event.mouse.y, event.mouse.click, event.mouse.buttons]; + [self redraw]; + } + return self; +} + +-draw +{ + return self; +} + +-redraw +{ + //update_panels (); + [TextContext refresh]; + //[TextContext doupdate]; + return self; +} + +@end diff --git a/ruamoko/qwaq/qwaq-textcontext.h b/ruamoko/qwaq/qwaq-textcontext.h new file mode 100644 index 000000000..ce0f5ef2c --- /dev/null +++ b/ruamoko/qwaq/qwaq-textcontext.h @@ -0,0 +1,65 @@ +#ifndef __qwaq_textcontect_h +#define __qwaq_textcontect_h + +#ifdef __QFCC__ +#include +#include "qwaq-curses.h" +#include "qwaq-draw.h" +#include "qwaq-rect.h" + +@class DrawBuffer; + +@interface TextContext : Object +{ + window_t window; + union { + Rect rect; + struct { + Point offset; + Extent size; + }; + struct { + int xpos; + int ypos; + int xlen; + int ylen; + }; + }; +} ++ (int) max_colors; ++ (int) max_color_pairs; ++ (void) init_pair: (int) pair, int fg, int bg; ++ (int) acs_char: (int) acs; ++ (void) move: (Point) pos; ++ (void) curs_set: (int) visibility; ++ (void) doupdate; ++ (TextContext *) screen; + +-init; +-initWithRect: (Rect) rect; +-initWithWindow: (window_t) window; + +- (window_t) window; +- (Extent) size; + +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; + +- (void) refresh; ++ (void) refresh; +- (void) bkgd: (int) ch; +- (void) scrollok: (int) flag; +- (void) border: (box_sides_t) sides, box_corners_t corners; +@end + +#else + +#include "QF/pr_obj.h" + +typedef struct qwaq_textcontext_s { + pr_id_t isa; + pointer_t window; +} qwaq_textcontext_t; + +#endif + +#endif//__qwaq_textcontect_h diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r new file mode 100644 index 000000000..d2fd9144b --- /dev/null +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -0,0 +1,164 @@ +#include "qwaq-draw.h" +#include "qwaq-textcontext.h" + +@implementation TextContext ++ (int) is_initialized = #0; ++ (void) initialize +{ + if (![self is_initialized]) { + initialize (); + } +} + ++ (int) max_colors = #0; ++ (int) max_color_pairs = #0; ++ (void) init_pair: (int) pair, int fg, int bg = #0; ++ (int) acs_char: (int) acs = #0; ++ (void) move: (Point) pos = #0; ++ (void) curs_set: (int) visibility = #0; ++ (void) doupdate = #0; + +static TextContext *screen; ++ (TextContext *) screen +{ + if (!screen) { + screen = [[TextContext alloc] init]; + } + return screen; +} + +- init +{ + if (!(self = [super init])) { + return nil; + } + window = stdscr; + rect = getwrect (window); + return self; +} + +- initWithRect: (Rect) rect +{ + if (!(self = [super init])) { + return nil; + } + window = create_window (rect.offset.x, rect.offset.y, + rect.extent.width, rect.extent.height); + offset = {}; + size = rect.extent; + return self; +} + +- initWithWindow: (window_t) window +{ + if (!(self = [super init])) { + return nil; + } + self.window = window; + return self; +} + +-(window_t) window +{ + return window; +} + +-(Extent) size +{ + return size; +} + +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect +{ + Extent srcSize = [srcBuffer size]; + Rect r = { {}, size }; + Rect t = { pos, rect.extent }; + + t = clipRect (r, t); + if (t.extent.width < 0 || t.extent.height < 0) { + return self; + } + + rect.offset.x += t.offset.x - pos.x; + rect.offset.y += t.offset.y - pos.y; + rect.extent = t.extent; + pos = t.offset; + + r.offset = nil; + r.extent = size; + + rect = clipRect (r, rect); + if (rect.extent.width < 0 || rect.extent.height < 0) { + return self; + } + + int *src = [srcBuffer buffer] + + rect.offset.y * srcSize.width + rect.offset.x; + for (int y = 0; y < rect.extent.height; y++) { + mvwblit_line (window, pos.x, y + pos.y, src, rect.extent.width); + src += srcSize.width; + } + return self; +} + +- (void) printf: (string) fmt, ... = #0; +- (void) vprintf: (string) mft, @va_list args = #0; +- (void) addch: (int) ch = #0; +- (void) addstr: (string) str = #0; + +- (void) mvprintf: (Point) pos, string fmt, ... = #0; +- (void) mvvprintf: (Point) pos, string mft, @va_list args = #0; +- (void) mvaddch: (Point) pos, int ch = #0; +- (void) mvaddstr: (Point) pos, string str = #0; + +- (void) refresh = #0; ++ (void) refresh = #0; + +- (void) bkgd: (int) ch = #0; +- (void) clear = #0; +- (void) scrollok: (int) flag = #0; +- (void) border: (box_sides_t) sides, box_corners_t corners = #0; + +@end + +window_t stdscr = (window_t) 1; + +void initialize (void) = #0; +window_t create_window (int xpos, int ypos, int xlen, int ylen) = #0; +void destroy_window (window_t win) = #0; +void mvwprintf (window_t win, int x, int y, string fmt, ...) = #0; +void wprintf (window_t win, string fmt, ...) = #0; +void wvprintf (window_t win, string fmt, @va_list args) = #0; +void mvwvprintf (window_t win, int x, int y, string fmt, @va_list args) = #0; +void wrefresh (window_t win) = #0; +void mvwaddch (window_t win, int x, int y, int ch) = #0; +void waddch (window_t win, int ch) = #0; +void mvwaddstr (window_t win, int x, int y, string str) = #0; +void waddstr (window_t win, string str) = #0; +int get_event (qwaq_event_t *event) = #0; +int max_colors (void) = #0; +int max_color_pairs (void) = #0; +int init_pair (int pair, int f, int b) = #0; +void wbkgd (window_t win, int ch) = #0; +void werase (window_t win) = #0; +void scrollok (window_t win, int flag) = #0; +int acs_char (int acs) = #0; + +panel_t create_panel (window_t window) = #0; +void destroy_panel (panel_t panel) = #0; +void hide_panel (panel_t panel) = #0; +void show_panel (panel_t panel) = #0; +void top_panel (panel_t panel) = #0; +void bottom_panel (panel_t panel) = #0; +void move_panel (panel_t panel, int x, int y) = #0; +window_t panel_window (panel_t panel) = #0; +void update_panels (void) = #0; + +void doupdate (void) = #0; +int curs_set (int visibility) = #0; +int move (int x, int y) = #0; +void wborder (window_t window, box_sides_t sides, box_corners_t corners) = #0; +void mvwblit_line (window_t window, int x, int y, int *wch, int len) = #0; +Rect getwrect (window_t window) = #0; + +void printf(string fmt, ...) = #0; diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h new file mode 100644 index 000000000..2bb646653 --- /dev/null +++ b/ruamoko/qwaq/qwaq-view.h @@ -0,0 +1,91 @@ +#ifndef __qwaq_view_h +#define __qwaq_view_h + +#include +#include + +#include "qwaq-draw.h" +#include "qwaq-rect.h" +#include "qwaq-textcontext.h" + +@class Group; + +enum { + ofCanFocus =0x0001, + ofFirstClick =0x0002, + ofDontDraw =0x0004, + ofPreProcess =0x0008, + ofPostProcess =0x0010, + ofMakeFirst =0x0020, + ofTileable =0x0040, + ofCentered =0x0080, + + ofCallHasObject =0x8000, +}; + +enum { + sfDrawn =0x0001, + sfDisabled =0x0002, + sfInFocus =0x0004, + sfModal =0x0008, + sfLocked =0x0010, +}; + +@interface View: Object +{ + union { + Rect rect; + struct { + int xpos; + int ypos; + int xlen; + int ylen; + }; + struct { + Point pos; + Extent size; + }; + }; + Rect absRect; + Point point; // can't be local :( + Group *owner; + id textContext; + int state; + int options; + int cursorState; + Point cursor; +} +-initWithRect: (Rect) rect; +- (void) dealloc; + +-setOwner: (Group *) owner; + +-(Rect)rect; +-(Point)origin; +-(Extent)size; + +-(int) containsPoint: (Point) point; +-(void) grabMouse; +-(void) releaseMouse; + +-(int) options; + +-setContext: (id) context; +-draw; +-redraw; +-handleEvent: (qwaq_event_t *) event; + +- (void) onMouseEnter: (Point) pos; +- (void) onMouseLeave: (Point) pos; + + +- (void) refresh; +- (void) mvprintf: (Point) pos, string fmt, ...; +- (void) mvvprintf: (Point) pos, string fmt, @va_list args; +- (void) mvaddch: (Point) pos, int ch; +@end + +@interface View (TextContext) +@end + +#endif//__qwaq_view_h diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r new file mode 100644 index 000000000..936a83352 --- /dev/null +++ b/ruamoko/qwaq/qwaq-view.r @@ -0,0 +1,182 @@ +#include "qwaq-curses.h" +#include "qwaq-view.h" +#include "qwaq-group.h" + +@implementation View + +-init +{ + return [super init]; +} + +-initWithRect: (Rect) rect +{ + if (!(self = [super init])) { + return nil; + } + self.rect = rect; + self.absRect = rect; + return self; +} + +- (void) dealloc +{ + if (owner) { + [owner remove:self]; + } + [super dealloc]; +} + +- setContext: (id) context +{ + textContext = context; + return self; +} + +- (int) options +{ + return options; +} + +static void +updateScreenCursor (View *view) +{ + while ((view.state & sfInFocus) && view.owner) { + View *owner = (View *) view.owner; + if (view.cursor.x >= 0 && view.cursor.x < view.xlen + && view.cursor.y >= 0 && view.cursor.y < view.ylen) { + owner.cursor.x = view.cursor.x + view.xpos; + owner.cursor.y = view.cursor.y + view.ypos; + owner.cursorState = view.cursorState; + } else { + owner.cursorState = 0; + } + view = owner; + } + if (view.state & sfInFocus) { + if (view.cursor.x >= 0 && view.cursor.x < view.xlen + && view.cursor.y >= 0 && view.cursor.y < view.ylen) { + curs_set (view.cursorState); + move(view.cursor.x, view.cursor.y); + } else { + curs_set (0); + } + } +} + +-draw +{ + state |= sfDrawn; + updateScreenCursor (self); + return self; +} + +-hide +{ + if (state & sfDrawn) { + state &= ~sfDrawn; + updateScreenCursor (self); + } + return self; +} + +-redraw +{ + if ((state & sfDrawn) && !(options & ofDontDraw)) { + [self draw]; + [owner redraw]; + } + return self; +} + +-setOwner: (Group *) owner +{ + self.owner = owner; + return self; +} + +- (Rect) rect +{ + return rect; +} + +-(Point)origin +{ + return pos; +} + +-(Extent)size +{ + return size; +} + + +-(int) containsPoint: (Point) point +{ + return rectContainsPoint (rect, point); +} + +-(void) grabMouse +{ + [owner grabMouse]; +} + +-(void) releaseMouse +{ + [owner releaseMouse]; +} + +- (void) forward: (SEL) sel : (@va_list) args +{ + if (!textContext) { + return; + } + if (!__obj_responds_to (textContext, sel)) { + [self error: "no implementation for %s", sel_get_name (sel)]; + } + obj_msg_sendv (textContext, sel, args); +} + +- (void) refresh +{ + if (__obj_responds_to (textContext, @selector(refresh))) { + [(id)textContext refresh]; + } +} + +- (void) mvprintf: (Point) pos, string fmt, ... +{ + pos.x += xpos; + pos.y += ypos; + [textContext mvvprintf: pos, fmt, @args]; +} + +- (void) mvvprintf: (Point) pos, string fmt, @va_list args +{ + pos.x += xpos; + pos.y += ypos; + [textContext mvvprintf: pos, fmt, args]; +} + +- (void) mvaddch: (Point) pos, int ch +{ + pos.x += xpos; + pos.y += ypos; + [textContext mvaddch: pos, ch]; +} + +-handleEvent: (qwaq_event_t *) event +{ + return self; +} + +- (void) onMouseEnter: (Point) pos +{ +} + +- (void) onMouseLeave: (Point) pos +{ +} + + +@end diff --git a/ruamoko/qwaq/qwaq-window.h b/ruamoko/qwaq/qwaq-window.h new file mode 100644 index 000000000..215fcc2db --- /dev/null +++ b/ruamoko/qwaq/qwaq-window.h @@ -0,0 +1,24 @@ +#ifndef __qwaq_window_h +#define __qwaq_window_h + +#include "Object.h" + +@class Group; + +#include "qwaq-draw.h" +#include "qwaq-rect.h" +#include "qwaq-view.h" + +@interface Window: View +{ + struct panel_s *panel; + Group *objects; + Point point; // FIXME can't be local :( + DrawBuffer *buf; +} ++windowWithRect: (Rect) rect; +-setBackground: (int) ch; +-addView: (View *) view; +@end + +#endif//__qwaq_window_h diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r new file mode 100644 index 000000000..1c772867f --- /dev/null +++ b/ruamoko/qwaq/qwaq-window.r @@ -0,0 +1,133 @@ +#include +#include + +#include "event.h" +#include "qwaq-button.h" +#include "qwaq-curses.h" +#include "qwaq-group.h" +#include "qwaq-listener.h" +#include "qwaq-window.h" +#include "qwaq-view.h" + +@implementation Window + ++windowWithRect: (Rect) rect +{ + return [[[self alloc] initWithRect: rect] autorelease]; +} + +-initWithRect: (Rect) rect +{ + if (!(self = [super init])) { + return nil; + } + self.rect = rect; + textContext = [[TextContext alloc] initWithRect: rect]; + panel = create_panel ([(id)textContext window]); + + objects = [[Group alloc] initWithContext: textContext owner: self]; + + string titlestr = "drag me"; + DrawBuffer *title = [DrawBuffer buffer: {xlen, 1}]; + [title mvaddstr: {(xlen - strlen(titlestr)) / 2, 0}, titlestr]; + + Button *b = [[Button alloc] initWithPos: {0, 0} releasedIcon: title + pressedIcon: title]; + [[b onDrag] addListener: self : @selector(dragWindow:)]; + [self addView: b]; + + buf = [DrawBuffer buffer: {3, 3}]; + [buf mvaddstr: {0, 0}, "XOX"]; + [buf mvaddstr: {0, 1}, "OXO"]; + [buf mvaddstr: {0, 2}, "XOX"]; + return self; +} + +- (void) dragWindow: (Button *) sender +{ + Point delta = [sender delta]; + Point p = {xpos + delta.x, ypos + delta.y}; + Extent bounds = [owner size]; + if (p.x < 0) { + p.x = 0; + } + if (p.x + xlen > bounds.width) { + p.x = bounds.width - xlen; + } + if (p.y < 0) { + p.y = 0; + } + if (p.y + ylen > bounds.height) { + p.y = bounds.height - ylen; + } + xpos = p.x; + ypos = p.y; + move_panel (panel, p.x, p.y); + [owner redraw]; +} + +-setContext: (id) context +{ + return self; +} + +-handleEvent: (qwaq_event_t *) event +{ + [objects handleEvent: event]; + return self; +} + +-addView: (View *) view +{ + [objects insert: view]; + return self; +} + +-setBackground: (int) ch +{ + [(id)textContext bkgd: ch]; + return self; +} + +-draw +{ + static box_sides_t box_sides = { + ACS_VLINE, ACS_VLINE, + ACS_HLINE, ACS_HLINE, + }; + static box_corners_t box_corners = { + ACS_ULCORNER, ACS_URCORNER, + ACS_LLCORNER, ACS_LRCORNER, + }; + if (box_sides.ls == ACS_VLINE) { + int *foo = &box_sides.ls; + for (int i = 0; i < 8; i++) { + foo[i] = acs_char (foo[i]); + } + } + [super draw]; + [(id)textContext border: box_sides, box_corners]; + [objects draw]; + return self; +} + +-redraw +{ + return [owner redraw]; +} + +- (void) mvprintf: (Point) pos, string fmt, ... +{ + [textContext mvvprintf: pos, fmt, @args]; +} + +- (void) mvvprintf: (Point) pos, string fmt, @va_list args +{ + [textContext mvvprintf: pos, fmt, args]; +} + +- (void) mvaddch: (Point) pos, int ch +{ + [textContext mvaddch: pos, ch]; +} +@end diff --git a/tools/qwaq/qwaq.c b/ruamoko/qwaq/qwaq.c similarity index 97% rename from tools/qwaq/qwaq.c rename to ruamoko/qwaq/qwaq.c index 40576e868..05d515f4e 100644 --- a/tools/qwaq/qwaq.c +++ b/ruamoko/qwaq/qwaq.c @@ -71,7 +71,7 @@ open_file (const char *path, int *len) } static void * -load_file (progs_t *pr, const char *name) +load_file (progs_t *pr, const char *name, off_t *_size) { QFile *file; int size; @@ -87,6 +87,7 @@ load_file (progs_t *pr, const char *name) sym = malloc (size + 1); sym[size] = 0; Qread (file, sym, size); + *_size = size; return sym; } @@ -127,7 +128,7 @@ init_qf (void) pr.no_exec_limit = 1; PR_Init_Cvars (); - PR_Init (); + PR_Init (&pr); RUA_Init (&pr, 0); PR_Cmds_Init (&pr); BI_Init (&pr); @@ -188,6 +189,7 @@ main (int argc, const char **argv) PR_RESET_PARAMS (&pr); P_INT (&pr, 0) = pr_argc; P_POINTER (&pr, 1) = PR_SetPointer (&pr, pr_argv); + pr.pr_argc = 2; PR_ExecuteProgram (&pr, main_func); PR_PopFrame (&pr); return R_INT (&pr); diff --git a/tools/qwaq/qwaq.h b/ruamoko/qwaq/qwaq.h similarity index 100% rename from tools/qwaq/qwaq.h rename to ruamoko/qwaq/qwaq.h diff --git a/ruamoko/scheme/Machine.h b/ruamoko/scheme/Machine.h index 7c99a2433..a7da59f61 100644 --- a/ruamoko/scheme/Machine.h +++ b/ruamoko/scheme/Machine.h @@ -11,7 +11,7 @@ { state_t state; SchemeObject *value; - hashtab_t globals; + hashtab_t *globals; SchemeObject *all_globals; } - (void) loadCode: (CompiledCode *) code; diff --git a/ruamoko/scheme/Makefile.am b/ruamoko/scheme/Makefile.am index 75f784ef5..f62c36191 100644 --- a/ruamoko/scheme/Makefile.am +++ b/ruamoko/scheme/Makefile.am @@ -1,30 +1,75 @@ -AUTOMAKE_OPTIONS= foreign - -pkglibdir=$(datarootdir)/qfcc/lib +AUTOMAKE_OPTIONS= foreign no-exeext QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) QFCC=$(QFCC_DEP) -QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide --no-default-paths -QCPPFLAGS=$(AM_CPPFLAGS) + +GZ=@progs_gz@ +scheme_libs=libscheme.a +scheme_libexec=main.dat + +pkglibdir=$(datarootdir)/qfcc/lib +#FIXME where to put pkglibexec? +#pkglibexecdir=$(datarootdir)/qfcc/bin + +pkglib_LIBRARIES= $(scheme_libs) +EXTRA_LIBRARIES= $(scheme_libs) + +noinst_PROGRAMS= $(scheme_libexec) +EXTRA_PROGRAMS = $(scheme_libexec) + +QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) + +MKDIR_P = @MKDIR_P@ +am__mv = mv -f + PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi -GZ=@progs_gz@ # BSD make can't handle $(shell foo) directives, and GNU make can't handle |= # so we have to bite the bullet and pass this to the shell every time. STRIP=`echo -n $(srcdir)/ | sed -e 's/[^/]//g' | wc -c` - RANLIB=touch -AM_CPPFLAGS= -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include +SUFFIXES=.o .r +.r.o: + $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -p $(STRIP) -c -o $@ $< + sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo + $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo -scheme_libs=libscheme.a -libs=$(scheme_libs) -data=$(scheme_data) +r_depfiles_remade= -pkglib_LIBRARIES= $(libs) -EXTRA_LIBRARIES= $(scheme_libs) -#pkgdata_DATA= $(data) -EXTRA_DATA = $(scheme_data) +libscheme_a_SOURCES=\ + SchemeObject.r Cons.r Number.r SchemeString.r Symbol.r Lexer.r Parser.r \ + Nil.r Procedure.r Primitive.r Lambda.r Scope.r Instruction.r builtins.r \ + Frame.r CompiledCode.r Compiler.r Continuation.r Machine.r Void.r \ + Error.r Boolean.r BaseContinuation.r +libscheme_a_obj=$(libscheme_a_SOURCES:.r=.o) +libscheme_a_dep=$(addprefix ./$(DEPDIR)/,$(libscheme_a_obj:.o=.Qo)) +libscheme_a_AR=$(PAK) -cf +include $(libscheme_a_dep) # am--include-marker +r_depfiles_remade += $(libscheme_a_dep) + +scheme_src=\ + main.r defs.r + +main_dat_SOURCES=$(scheme_src) +main_obj=$(scheme_src:.r=.o) +main_dep=$(addprefix ./$(DEPDIR)/,$(main_obj:.o=.Qo)) +main.dat: $(main_obj) $(QFCC_DEP) libscheme.a ../lib/libcsqc.a ../lib/libr.a + $(QLINK) -p $(STRIP) -o main.dat $(main_obj) libscheme.a ../lib/libcsqc.a ../lib/libr.a +include $(main_dep) # am--include-marker +r_depfiles_remade += $(main_dep) + +main.sym: main.dat + +$(r_depfiles_remade): + $(MKDIR_P) $(@D) + echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) EXTRA_DIST = \ BaseContinuation.h Boolean.h CompiledCode.h Compiler.h Cons.h \ @@ -34,30 +79,4 @@ EXTRA_DIST = \ debug.h defs.h state.h \ \ main.r defs.r - -SUFFIXES=.qc .qfo .r -.r.qfo: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -p $(STRIP) -c -o $@ $< -.r.o: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -p $(STRIP) -c -o $@ $< - -libscheme_a_SOURCES=\ - SchemeObject.r Cons.r Number.r SchemeString.r Symbol.r Lexer.r Parser.r \ - Nil.r Procedure.r Primitive.r Lambda.r Scope.r Instruction.r builtins.r \ - Frame.r CompiledCode.r Compiler.r Continuation.r Machine.r Void.r \ - Error.r Boolean.r BaseContinuation.r -libscheme_a_AR=$(PAK) -cf - -scheme_data=\ - main.dat$(GZ) - -scheme_src=\ - main.r defs.r - -scheme_obj=$(scheme_src:.qc=.o) - -main.dat$(GZ): $(scheme_obj) $(QFCC_DEP) ../lib/libcsqc.a ../lib/libr.a libscheme.a - $(QFCC) $(QCFLAGS) -p $(STRIP) -o main.dat $(scheme_obj) libscheme.a ../lib/libcsqc.a ../lib/libr.a - $(GZIP) - CLEANFILES= *.dat *.sym *.gz *.qfo *.o diff --git a/ruamoko/scheme/SchemeObject.h b/ruamoko/scheme/SchemeObject.h index 262c700f4..e831b50bd 100644 --- a/ruamoko/scheme/SchemeObject.h +++ b/ruamoko/scheme/SchemeObject.h @@ -14,6 +14,7 @@ int line; string source; } ++ (void) finishCollecting; + (void) collectCheckPoint; - (void) mark; - (void) markReachable; diff --git a/ruamoko/scheme/Symbol.r b/ruamoko/scheme/Symbol.r index 0704b3a50..2adfc6a25 100644 --- a/ruamoko/scheme/Symbol.r +++ b/ruamoko/scheme/Symbol.r @@ -16,7 +16,7 @@ void SymbolFree (void *ele, void *data) [s release]; } -hashtab_t symbols; +hashtab_t *symbols; Symbol *lparen; Symbol *rparen; Symbol *quote; @@ -45,7 +45,7 @@ Symbol *symbol (string str) { local Symbol *res; - if ((res = Hash_Find (symbols, s))) { + if ((res = (Symbol *) Hash_Find (symbols, s))) { return res; } else { res = (Symbol*) [self newFromString: s]; diff --git a/ruamoko/scheme/defs.h b/ruamoko/scheme/defs.h index a1d691684..7f1e4289c 100644 --- a/ruamoko/scheme/defs.h +++ b/ruamoko/scheme/defs.h @@ -1,13 +1,13 @@ -@extern void (string str) print = #0; -@extern int () errno = #0; -@extern string (int err) strerror = #0; -@extern int (...) open = #0; // string path, float flags[, float mode] -@extern int (int handle) close = #0; -@extern string read (int handle, int count, int *result) = #0; -@extern int (int handle, string buffer, int count) write = #0; -@extern int (int handle, int pos, int whence) seek = #0; +@extern void (string str) print; +@extern int () errno; +@extern string (int err) strerror; +@extern int (...) open; // string path, float flags[, float mode] +@extern int (int handle) close; +@extern string read (int handle, int count, int *result); +@extern int (int handle, string buffer, int count) write; +@extern int (int handle, int pos, int whence) seek; -@extern void() traceon = #0; // turns statment trace on -@extern void() traceoff = #0; +@extern void() traceon; // turns statment trace on +@extern void() traceoff; -@extern void (...) printf = #0; +@extern void (...) printf; diff --git a/ruamoko/scheme/defs.r b/ruamoko/scheme/defs.r index 943ef9173..1c638232d 100644 --- a/ruamoko/scheme/defs.r +++ b/ruamoko/scheme/defs.r @@ -3,7 +3,7 @@ int () errno = #0; string (int err) strerror = #0; int (...) open = #0; // string path, float flags[, float mode] int (int handle) close = #0; -string (int handle, int count, int []result) read = #0; +string read (int handle, int count, int *result) = #0; int (int handle, string buffer, int count) write = #0; int (int handle, int pos, int whence) seek = #0; diff --git a/ruamoko/scheme/main.r b/ruamoko/scheme/main.r index fb1fa3e33..be7d8bca6 100644 --- a/ruamoko/scheme/main.r +++ b/ruamoko/scheme/main.r @@ -22,23 +22,23 @@ string readfile (string filename) str_copy(res, acc); return res; } - -int main (int argc, string []argv) +int main (int argc, string *argv) { - local Parser parser; - local CompiledCode code; - local Compiler comp; - local Machine vm; - local Lambda lm; - local SchemeObject stuff, res; + local Parser *parser; + local CompiledCode *code; + local Compiler *comp; + local Machine *vm; + local Lambda *lm; + local SchemeObject *stuff, *res; + local Error *err; if (argc < 1) { return -1; } //traceon(); - + parser = [Parser newFromSource: readfile(argv[1]) file: argv[1]]; vm = [Machine new]; [vm makeRootCell]; @@ -46,26 +46,29 @@ int main (int argc, string []argv) builtin_addtomachine (vm); while ((stuff = [parser read])) { if ([stuff isError]) { - printf(">> %s: %i\n", [stuff source], [stuff line]); - printf(">> Error (%s): %s\n", [stuff type], [stuff message]); + err = (Error *) stuff; + printf(">> %s: %i\n", [err source], [err line]); + printf(">> Error (%s): %s\n", [err type], [err message]); return -1; } comp = [Compiler newWithLambda: cons ([Symbol forString: "lambda"], cons ([Nil nil], cons(stuff, [Nil nil]))) scope: nil]; - code = (CompiledCode) [comp compile]; + code = (CompiledCode *) [comp compile]; if ([code isError]) { - printf(">> %s: %i\n", [code source], [code line]); - printf(">> Error (%s): %s\n", [code type], [code message]); + err = (Error *) code; + printf(">> %s: %i\n", [err source], [err line]); + printf(">> Error (%s): %s\n", [err type], [err message]); return -1; } lm = [Lambda newWithCode: code environment: nil]; [lm invokeOnMachine: vm]; res = [vm run]; if ([res isError]) { - printf(">> %s: %i\n", [res source], [res line]); - printf(">> Error (%s): %s\n", [res type], [res message]); + err = (Error *) res; + printf(">> %s: %i\n", [err source], [err line]); + printf(">> Error (%s): %s\n", [err type], [err message]); return -1; } [vm reset]; diff --git a/tools/Makefile.am b/tools/Makefile.am index 008638b4a..768efdccb 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,5 +1,5 @@ SUBDIRS=@tools_dirs@ -DIST_SUBDIRS=bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis qwaq wad wav +DIST_SUBDIRS=bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis wad wav EXTRA_DIST= \ io_mesh_qfmdl/export_mdl.py io_mesh_qfmdl/import_mdl.py \ io_mesh_qfmdl/__init__.py io_mesh_qfmdl/mdl.py io_mesh_qfmdl/qfplist.py \ diff --git a/tools/qfcc/TODO b/tools/qfcc/TODO index 5bce50696..8180ed95d 100644 --- a/tools/qfcc/TODO +++ b/tools/qfcc/TODO @@ -18,5 +18,6 @@ o isset() intrinsic for more consistent string handling. o arrays in entities o optional arguments for functions (alternative to overloading) vector(vector fwd, optional vector up) vectoangles = #51; +o rewrite type system to be const-correct (hard!) ? try to reduce memory consumption ?? embedded nul characters in strings (why?) diff --git a/tools/qfcc/doc/man/qfcc.1 b/tools/qfcc/doc/man/qfcc.1 index a5e2794e0..3162f813d 100644 --- a/tools/qfcc/doc/man/qfcc.1 +++ b/tools/qfcc/doc/man/qfcc.1 @@ -85,7 +85,8 @@ No compilation or linking is done. .TP .B \-\-extended -Allow extended keywords in traditional mode. +Allow extended keywords in traditional mode. Otherwise, it has \fIall\fP +the implications of \fB\-\-traditional\fP. .TP .B \-F, \-\-files @@ -198,9 +199,9 @@ Look for \*[progs.src] in \fBDIR\fP instead of the current directory. .TP .B \-\-traditional Use traditional QuakeC syntax, semantics and \*(lqbugs\*(rq. -Also implies the \fBv6only\fP, \fBno-short-circuit\fP and -\fBno-local-merging\fP code generation options (see -\fBCODE GENERATION OPTIONS\fP). +Also implies the \fBv6only\fP, \fBno-short-circuit\fP, +\fBconst-initializers\fP and \fBno-local-merging\fP code generation options +(see \fBCODE GENERATION OPTIONS\fP). This is the default when using \fBprogs.src\fP mode. .TP @@ -236,15 +237,23 @@ command line. Unsupported options are ignored. The following options are supported by \*[qfcc]'s \fB\-\-code\fP argument: +.TP +.B const-initializers +Treat initialized globals as constants. +This option is implied by \fB\-\-traditional\fP and \fB\-\-extended\fP, and is +turned off by \fB\-\-advanced\fP. + .TP .B cow Allow assignment to initialized globals. -In Quake-C and Ruamoko, a global that has been initialized to a value is not -a variable, but a named constant. +When initialized globals are treated as constants (traditional Quake-C, or +when const-initializers is activated), a global that has been initialized to a +value is not a variable, but a named constant. However, \fBqcc\fP never really enforced this. The \fBcow\fP option allows \*[qfcc] to gracefully cope with QuakeC source that assigns values to initialized globals in this manner. -(also known as \*(lqcopy on write\*(rq\(emnever mind the bovine connotations) +(also known as \*(lqcopy on write\*(rq\(emlo and behold the bovine +connotations) .TP .B cpp @@ -286,6 +295,12 @@ This can be a problem because instructions can access addresses up to 32767 in older servers or 65535 in most modern servers. Defaults to off for traditional mode, and on for advanced mode. +.TP +.B promote\-float +Promote float when passed to a function that takes a variable number of +arguements. Defaults to enabled for advanced code, is forced off for +traditional or v6only code (mostly because such code does not have doubles). + .TP .B short\-circuit Generate short circuit code for logical operators (\fB&&\fP and \fB||\fP). diff --git a/tools/qfcc/include/class.h b/tools/qfcc/include/class.h index 323912591..68cefcd12 100644 --- a/tools/qfcc/include/class.h +++ b/tools/qfcc/include/class.h @@ -48,6 +48,7 @@ typedef struct class_type_s { typedef struct class_s { int defined; + int interface_declared; const char *name; struct class_s *super_class; struct category_s *categories; @@ -74,6 +75,7 @@ typedef struct protocol_s { const char *name; struct methodlist_s *methods; struct protocollist_s *protocols; + struct def_s *def; class_type_t class_type; } protocol_t; @@ -82,6 +84,11 @@ typedef struct protocollist_s { protocol_t **list; } protocollist_t; +typedef struct static_instance_s { + const char *class; + struct def_s *instance; +} static_instance_t; + extern struct type_s type_id; extern struct type_s type_obj_object; extern struct type_s type_obj_class; @@ -106,10 +113,11 @@ struct dstring_s; struct expr_s; struct method_s; struct symbol_s; +struct selector_s; int obj_is_id (const struct type_s *type) __attribute__((pure)); int obj_is_class (const struct type_s *type) __attribute__((pure)); -int obj_is_Class (const struct type_s *type) __attribute__((pure)); +int obj_is_Class (const struct type_s *type) __attribute__((const)); int obj_is_classptr (const struct type_s *type) __attribute__((pure)); int obj_types_assignable (const struct type_s *dst, const struct type_s *src); @@ -134,7 +142,7 @@ void class_finish_ivar_scope (class_type_t *class_type, struct symtab_s *param_scope); struct method_s *class_find_method (class_type_t *class_type, struct method_s *method); -struct method_s *class_message_response (class_t *class, int class_msg, +struct method_s *class_message_response (struct type_s *clstype, int class_msg, struct expr_s *sel); struct symbol_s *class_pointer_symbol (class_t *class_type); category_t *get_category (struct symbol_s *class_name, @@ -154,6 +162,11 @@ struct def_s *protocol_def (protocol_t *protocol); protocollist_t *new_protocol_list (void); protocollist_t *add_protocol (protocollist_t *protocollist, const char *name); int procollist_find_protocol (protocollist_t *protocollist, protocol_t *proto) __attribute__((pure)); +struct method_s *protocollist_find_method (protocollist_t *protocollist, + struct selector_s *selector, + int nstance) + __attribute__((pure)); + int compare_protocols (protocollist_t *protos1, protocollist_t *protos2) __attribute__((pure)); void print_protocollist (struct dstring_s *dstr, protocollist_t *protocollist); struct def_s *emit_protocol (protocol_t *protocol); diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 90e4f6313..be1640ffc 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -49,12 +49,15 @@ typedef enum { ex_block, ///< statement block expression (::ex_block_t) ex_expr, ///< binary expression (::ex_expr_t) ex_uexpr, ///< unary expression (::ex_expr_t) + ex_def, ///< non-temporary variable (::def_t) ex_symbol, ///< non-temporary variable (::symbol_t) ex_temp, ///< temporary variable (::ex_temp_t) ex_vector, ///< "vector" expression (::ex_vector_t) ex_nil, ///< umm, nil, null. nuff said (0 of any type) ex_value, ///< constant value (::ex_value_t) + ex_compound, ///< compound initializer + ex_memset, ///< memset needs three params... } expr_type; /** Binary and unary expressions. @@ -75,6 +78,7 @@ typedef struct ex_label_s { struct reloc_s *refs; ///< relocations associated with this label struct sblock_s *dest; ///< the location of this label if known const char *name; ///< the name of this label + struct symbol_s *symbol; ///< symbol used to define this label (maybe 0) int used; ///< label is used as a target struct daglabel_s *daglabel; } ex_label_t; @@ -83,11 +87,25 @@ typedef struct { ex_label_t *label; } ex_labelref_t; +typedef struct element_s { + struct element_s *next; ///< next in chain + int offset; + struct type_s *type; + struct expr_s *expr; ///< initializer expression + struct symbol_s *symbol; ///< for labeled initializers +} element_t; + +typedef struct element_chain_s { + element_t *head; + element_t **tail; +} element_chain_t; + typedef struct { struct expr_s *head; ///< the first expression in the block struct expr_s **tail; ///< last expression in the block, for appending struct expr_s *result; ///< the result of this block if non-void int is_call; ///< this block exprssion forms a function call + void *return_addr;///< who allocated this } ex_block_t; typedef struct { @@ -109,6 +127,7 @@ typedef struct ex_pointer_s { int val; struct type_s *type; struct def_s *def; + struct operand_s *tempop; } ex_pointer_t; typedef struct ex_func_s { @@ -127,6 +146,13 @@ typedef struct { struct expr_s *e; } ex_bool_t; +typedef struct ex_memset_s { + struct expr_s *dst; + struct expr_s *val; + struct expr_s *count; + struct type_s *type; +} ex_memset_t; + /** State expression used for think function state-machines. State expressions are of the form [framenum, nextthink] @@ -191,12 +217,13 @@ typedef struct ex_value_s { typedef struct expr_s { struct expr_s *next; ///< the next expression in a block expression - expr_type type; ///< the type of the result of this expression - int line; ///< source line that generated this expression - string_t file; ///< source file that generated this expression + expr_type type; ///< the type of the result of this expression + int line; ///< source line that generated this expression + string_t file; ///< source file that generated this expression int printid; ///< avoid duplicate output when printing - unsigned paren:1; ///< the expression is enclosed in () - unsigned rvalue:1; ///< the expression is on the right side of = + unsigned paren:1; ///< the expression is enclosed in () + unsigned rvalue:1; ///< the expression is on the right side of = + unsigned implicit:1; ///< don't warn for implicit casts union { ex_label_t label; ///< label expression ex_labelref_t labelref; ///< label reference expression (&) @@ -204,10 +231,14 @@ typedef struct expr_s { ex_bool_t bool; ///< boolean logic expression ex_block_t block; ///< statement block expression ex_expr_t expr; ///< binary or unary expression + struct def_s *def; ///< def reference expression struct symbol_s *symbol; ///< symbol reference expression ex_temp_t temp; ///< temporary variable expression ex_vector_t vector; ///< vector expression list ex_value_t *value; ///< constant value + element_chain_t compound; ///< compound initializer + ex_memset_t memset; ///< memset expr params + struct type_s *nil; ///< type for nil if known } e; } expr_t; @@ -263,11 +294,19 @@ expr_t *new_expr (void); */ expr_t *copy_expr (expr_t *e); +/** Copy source expression's file and line to the destination expression + + \param dst The expression to receive the file and line + \param src The expression from which the file and line will be taken + \return \a dst +*/ +expr_t *expr_file_line (expr_t *dst, const expr_t *src); + /** Create a new label name. - The label name is guaranteed to to the compilation. It is made up of the - name of the current function plus an incrementing number. The number is - not reset between functions. + The label name is guaranteed to be unique to the compilation. It is made + up of the name of the current function plus an incrementing number. The + number is not reset between functions. \return The string representing the label name. */ @@ -281,6 +320,19 @@ const char *new_label_name (void); */ expr_t *new_label_expr (void); +/** Create a named label expression node. + + The label name is set using new_label_name(), but the symbol is used to add + the label to the function's label scope symbol table. If the label already + exists in the function's label scope, then the existing label is returned, + allowing for forward label declarations. + + \param label The name symbol to use for adding the label to the function + label scope. + \return The new label expression (::ex_label_t) node. +*/ +expr_t *named_label_expr (struct symbol_s *label); + /** Create a new label reference expression node. Used for taking the address of a label (eg. jump tables). @@ -325,6 +377,16 @@ expr_t *new_block_expr (void); */ expr_t *build_block_expr (expr_t *expr_list); +element_t *new_element (expr_t *expr, struct symbol_s *symbol); +expr_t *new_compound_init (void); +expr_t *append_element (expr_t *compound, element_t *element); +expr_t *initialized_temp_expr (struct type_s *type, expr_t *compound); +void assign_elements (expr_t *local_expr, expr_t *ptr, + element_chain_t *element_chain); +void build_element_chain (element_chain_t *element_chain, struct type_s *type, + expr_t *eles, int base_offset); +void free_element_chain (element_chain_t *element_chain); + /** Create a new binary expression node node. If either \a e1 or \a e2 are error expressions, then that expression will @@ -342,7 +404,7 @@ expr_t *new_binary_expr (int op, expr_t *e1, expr_t *e2); /** Create a new unary expression node node. If \a e1 is an error expression, then it will be returned instead of a - new binary expression. + new unary expression. \param op The op-code of the unary expression. \param e1 The "right" side of the expression. @@ -351,6 +413,12 @@ expr_t *new_binary_expr (int op, expr_t *e1, expr_t *e2); */ expr_t *new_unary_expr (int op, expr_t *e1); +/** Create a new def reference (non-temporary variable) expression node. + + \return The new def reference expression node (::def_t). +*/ +expr_t *new_def_expr (struct def_s *def); + /** Create a new symbol reference (non-temporary variable) expression node. \return The new symbol reference expression node (::symbol_t). @@ -499,6 +567,8 @@ unsigned expr_uinteger (expr_t *e) __attribute__((pure)); expr_t *new_short_expr (short short_val); short expr_short (expr_t *e) __attribute__((pure)); +int expr_integral (expr_t *e) __attribute__((pure)); + /** Check of the expression refers to a constant value. \param e The expression to check. @@ -539,12 +609,16 @@ int is_logic (int op) __attribute__((const)); int has_function_call (expr_t *e) __attribute__((pure)); +int is_nil (expr_t *e) __attribute__((pure)); int is_string_val (expr_t *e) __attribute__((pure)); int is_float_val (expr_t *e) __attribute__((pure)); int is_vector_val (expr_t *e) __attribute__((pure)); int is_quaternion_val (expr_t *e) __attribute__((pure)); int is_integer_val (expr_t *e) __attribute__((pure)); +int is_uinteger_val (expr_t *e) __attribute__((pure)); int is_short_val (expr_t *e) __attribute__((pure)); +int is_integral_val (expr_t *e) __attribute__((pure)); +int is_pointer_val (expr_t *e) __attribute__((pure)); /** Create a reference to the global .self entity variable. @@ -592,6 +666,9 @@ expr_t *new_param_expr (struct type_s *type, int num); expr_t *new_move_expr (expr_t *e1, expr_t *e2, struct type_s *type, int indirect); +expr_t *new_memset_expr (expr_t *dst, expr_t *val, struct type_s *type); + + /** Convert a name to an expression of the appropriate type. Converts the expression in-place. If the exprssion is not a name @@ -612,7 +689,8 @@ void dump_dot_expr (void *e, const char *filename); void convert_int (expr_t *e); void convert_short (expr_t *e); void convert_short_int (expr_t *e); -void convert_nil (expr_t *e, struct type_s *t); +void convert_double (expr_t *e); +expr_t *convert_nil (expr_t *e, struct type_s *t); expr_t *test_expr (expr_t *e); void backpatch (ex_list_t *list, expr_t *label); @@ -623,7 +701,7 @@ expr_t *binary_expr (int op, expr_t *e1, expr_t *e2); expr_t *field_expr (expr_t *e1, expr_t *e2); expr_t *asx_expr (int op, expr_t *e1, expr_t *e2); expr_t *unary_expr (int op, expr_t *e); -expr_t *build_function_call (expr_t *fexpr, struct type_s *ftype, +expr_t *build_function_call (expr_t *fexpr, const struct type_s *ftype, expr_t *params); expr_t *function_expr (expr_t *e1, expr_t *e2); struct function_s; @@ -646,6 +724,7 @@ expr_t *build_for_statement (expr_t *init, expr_t *test, expr_t *next, expr_t *break_label, expr_t *continue_label); expr_t *build_state_expr (expr_t *e); expr_t *think_expr (struct symbol_s *think_sym); +int is_lvalue (const expr_t *expr) __attribute__((pure)); expr_t *assign_expr (expr_t *dst, expr_t *src); expr_t *cast_expr (struct type_s *t, expr_t *e); diff --git a/tools/qfcc/include/flow.h b/tools/qfcc/include/flow.h index b4cc48cf5..f68c5d5cf 100644 --- a/tools/qfcc/include/flow.h +++ b/tools/qfcc/include/flow.h @@ -84,12 +84,6 @@ typedef struct flownode_s { struct set_s *in; struct set_s *out; } live_vars; - struct { - struct set_s *use; - struct set_s *def; - struct set_s *in; - struct set_s *out; - } init_vars; struct sblock_s *sblock; ///< original statement block struct dag_s *dag; ///< dag for this node } flownode_t; @@ -102,15 +96,16 @@ typedef struct flowgraph_s { flowedge_t *edges; ///< array of all edges in the graph int num_edges; struct set_s *dfst; ///< edges in the depth-first search tree - int *dfo; ///< depth-first order of nodes + int *depth_first; ///< depth-first order of nodes flowloop_t *loops; ///< linked list of natural loops } flowgraph_t; flowvar_t *flow_get_var (struct operand_s *op); +#define FLOW_OPERANDS 5 void flow_analyze_statement (struct statement_s *s, struct set_s *use, struct set_s *def, struct set_s *kill, - struct operand_s *operands[4]); + struct operand_s *operands[FLOW_OPERANDS]); void flow_data_flow (struct function_s *func); diff --git a/tools/qfcc/include/function.h b/tools/qfcc/include/function.h index 209f40026..951b40597 100644 --- a/tools/qfcc/include/function.h +++ b/tools/qfcc/include/function.h @@ -79,6 +79,7 @@ typedef struct function_s { scope symbol table's defspace. */ struct symtab_s *symtab; + struct symtab_s *label_scope; struct reloc_s *refs; ///< relocation targets for this function struct expr_s *var_init; const char *name; ///< nice name for __PRETTY_FUNCTION__ @@ -119,8 +120,8 @@ param_t *new_param (const char *selector, struct type_s *type, const char *name); param_t *param_append_identifiers (param_t *params, struct symbol_s *idents, struct type_s *type); -param_t *_reverse_params (param_t *params, param_t *next); param_t *reverse_params (param_t *params); +param_t *append_params (param_t *params, param_t *more_params); param_t *copy_params (param_t *params); struct type_s *parse_params (struct type_s *type, param_t *params); param_t *check_params (param_t *params); diff --git a/tools/qfcc/include/method.h b/tools/qfcc/include/method.h index ef51e1579..598e151ee 100644 --- a/tools/qfcc/include/method.h +++ b/tools/qfcc/include/method.h @@ -58,6 +58,10 @@ typedef struct methodlist_s { int instance; ///< used only for emitting } methodlist_t; +typedef struct methodset_s { + struct hashtab_s *tab; +} methodset_t; + typedef struct keywordarg_s { // the first two fields match the first two fields of param_t in // functionl.h @@ -80,7 +84,12 @@ struct symbol_s *method_symbol (struct class_type_s *class_type, void method_set_param_names (method_t *dst, method_t *src); methodlist_t *new_methodlist (void); -void copy_methods (methodlist_t *dst, methodlist_t *src); +methodset_t *new_methodset (void); +void methodset_add_methods (methodset_t *methodset, methodlist_t *methods); +int methodset_contains_method (methodset_t *methodset, method_t *method); +//NOTE frees the source list and any methods not copied +void merge_method_lists (methodlist_t *dst, methodlist_t *src); +void copy_methods (methodlist_t *dst, methodlist_t *src, methodset_t *except); int method_compare (method_t *m1, method_t *m2); keywordarg_t *new_keywordarg (const char *selector, struct expr_s *expr); @@ -89,6 +98,9 @@ keywordarg_t *copy_keywordargs (const keywordarg_t *kwargs); struct expr_s *send_message (int super); method_t *find_method (const char *sel_name); +method_t *methodlist_find_method (methodlist_t *methodlist, + selector_t *selector, int instance) + __attribute__((pure)); void selector_name (struct dstring_s *sel_id, keywordarg_t *selector); void method_types (struct dstring_s *sel_types, method_t *method); diff --git a/tools/qfcc/include/obj_file.h b/tools/qfcc/include/obj_file.h index ae1986245..62d7b80f0 100644 --- a/tools/qfcc/include/obj_file.h +++ b/tools/qfcc/include/obj_file.h @@ -60,13 +60,13 @@ */ typedef struct qfo_header_s { int8_t qfo[4]; ///< identifier string (includes nul) (#QFO) - pr_int_t version; ///< QFO format version (#QFO_VERSION) - pr_int_t num_spaces; - pr_int_t num_relocs; ///< number of relocation records - pr_int_t num_defs; ///< number of def records - pr_int_t num_funcs; ///< number of function records - pr_int_t num_lines; ///< number of line records - pr_int_t num_loose_relocs; ///< number of loose relocation records + pr_uint_t version; ///< QFO format version (#QFO_VERSION) + pr_uint_t num_spaces; + pr_uint_t num_relocs; ///< number of relocation records + pr_uint_t num_defs; ///< number of def records + pr_uint_t num_funcs; ///< number of function records + pr_uint_t num_lines; ///< number of line records + pr_uint_t num_loose_relocs; ///< number of loose relocation records ///< (included in num_relocs) } qfo_header_t; diff --git a/tools/qfcc/include/options.h b/tools/qfcc/include/options.h index cfcd350de..a43c908b6 100644 --- a/tools/qfcc/include/options.h +++ b/tools/qfcc/include/options.h @@ -45,6 +45,8 @@ typedef struct { unsigned progsversion; // Progs version to generate code for qboolean vector_components; // add *_[xyz] symbols for vectors qboolean ifstring; // expand if (str) to if (str != "") + qboolean const_initializers; // initialied globals are constant + qboolean promote_float; // promote float through ... } code_options_t; typedef struct { diff --git a/tools/qfcc/include/qfprogs.h b/tools/qfcc/include/qfprogs.h index 09fade09d..731a61194 100644 --- a/tools/qfcc/include/qfprogs.h +++ b/tools/qfcc/include/qfprogs.h @@ -55,8 +55,11 @@ struct dfunction_s *func_find (int st_num); void dump_strings (struct progs_s *pr); void qfo_globals (struct qfo_s *qfo); +void qfo_fields (struct qfo_s *qfo); void qfo_functions (struct qfo_s *qfo); +void qfo_lines (struct qfo_s *qfo); void qfo_relocs (struct qfo_s *qfo); +void qfo_strings (struct qfo_s *qfo); void qfo_types (struct qfo_s *qfo); #endif//__qfprogs_h diff --git a/tools/qfcc/include/reloc.h b/tools/qfcc/include/reloc.h index 2272dab5d..dc6e802c8 100644 --- a/tools/qfcc/include/reloc.h +++ b/tools/qfcc/include/reloc.h @@ -68,7 +68,7 @@ typedef enum { */ typedef struct reloc_s { struct reloc_s *next; ///< next reloc in reloc chain - struct ex_label_s *label; ///< instruction label for *_op relocs + const struct ex_label_s *label; ///< instruction label for *_op relocs struct defspace_s *space; ///< the space containing the location in ///< need of adjustment for def_* relocations ///< (op_* relocations always use the code @@ -78,7 +78,7 @@ typedef struct reloc_s { reloc_type type; ///< type type of relocation to perform int line; ///< current source line when creating reloc string_t file; ///< current source file when creating reloc - void *return_address; ///< for debugging + const void *return_address; ///< for debugging } reloc_t; struct statement_s; @@ -147,7 +147,7 @@ void reloc_op_def_ofs (struct def_s *def, int offset, int field); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_def (struct def_s *def, struct def_s *location); +void reloc_def_def (struct def_s *def, const struct def_s *location); /** Create a relocation record for a data location referencing a def. @@ -162,7 +162,7 @@ void reloc_def_def (struct def_s *def, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_def_ofs (struct def_s *def, struct def_s *location); +void reloc_def_def_ofs (struct def_s *def, const struct def_s *location); /** Create a relocation record for a data location referencing a function. @@ -177,7 +177,7 @@ void reloc_def_def_ofs (struct def_s *def, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_func (struct function_s *func, struct def_s *location); +void reloc_def_func (struct function_s *func, const struct def_s *location); /** Create a relocation record for a data location referencing a string. @@ -191,7 +191,7 @@ void reloc_def_func (struct function_s *func, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_string (struct def_s *location); +void reloc_def_string (const struct def_s *location); /** Create a relocation record for a data location referencing a field. @@ -206,7 +206,7 @@ void reloc_def_string (struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_field (struct def_s *def, struct def_s *location); +void reloc_def_field (struct def_s *def, const struct def_s *location); /** Create a relocation record for a data location referencing a field. @@ -221,7 +221,7 @@ void reloc_def_field (struct def_s *def, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_field_ofs (struct def_s *def, struct def_s *location); +void reloc_def_field_ofs (struct def_s *def, const struct def_s *location); /** Create a relocation record for a data location referencing an instruction. @@ -237,7 +237,8 @@ void reloc_def_field_ofs (struct def_s *def, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_op (struct ex_label_s *label, struct def_s *location); +void reloc_def_op (const struct ex_label_s *label, + const struct def_s *location); void reloc_attach_relocs (reloc_t *relocs, reloc_t **location); diff --git a/tools/qfcc/include/statements.h b/tools/qfcc/include/statements.h index ce230d9ec..829723729 100644 --- a/tools/qfcc/include/statements.h +++ b/tools/qfcc/include/statements.h @@ -38,9 +38,10 @@ typedef enum { op_label, op_temp, op_alias, + op_nil, } op_type_e; -typedef struct { +typedef struct tempop_s { struct def_s *def; int offset; struct type_s *type; @@ -55,8 +56,10 @@ typedef struct { typedef struct operand_s { struct operand_s *next; op_type_e op_type; - struct type_s *type; ///< possibly override def's type + struct type_s *type; ///< possibly override def's/nil's type int size; ///< for structures + struct expr_s *expr; ///< expression generating this operand + void *return_addr; ///< who created this operand union { struct def_s *def; struct ex_value_s *value; @@ -70,17 +73,20 @@ typedef struct operand_s { Statement types are broken down into expressions (binary and unary, includes address and pointer dereferencing (read)), assignment, pointer - assignment (write to dereference pointer), move (special case of pointer - assignment), state, function related (call, rcall, return and done), and - flow control (conditional branches, goto, jump (single pointer and jump - table)). + assignment (write to dereference pointer), move (special case of + assignment), pointer move (special case of pointer assignment), state, + function related (call, rcall, return and done), and flow control + (conditional branches, goto, jump (single pointer and jump table)). */ typedef enum { st_none, ///< not a (valid) statement. Used in dags. st_expr, ///< c = a op b; or c = op a; st_assign, ///< b = a st_ptrassign, ///< *b = a; or *(b + c) = a; - st_move, ///< memcpy (c, a, b); + st_move, ///< memcpy (c, a, b); c and a are direct def references + st_ptrmove, ///< memcpy (c, a, b); c and a are pointers + st_memset, ///< memset (c, a, b); c is direct def reference + st_ptrmemset, ///< memset (c, a, b); c is pointer st_state, ///< state (a, b); or state (a, b, c) st_func, ///< call, rcall or return/done st_flow, ///< if/ifa/ifae/ifb/ifbe/ifnot or goto or jump/jumpb @@ -113,16 +119,23 @@ struct expr_s; struct type_s; struct dstring_s; +extern const char *op_type_names[]; +extern const char *st_type_names[]; + const char *optype_str (op_type_e type) __attribute__((const)); -operand_t *def_operand (struct def_s *def, struct type_s *type); -operand_t *return_operand (struct type_s *type); -operand_t *value_operand (struct ex_value_s *value); +operand_t *nil_operand (struct type_s *type, struct expr_s *expr); +operand_t *def_operand (struct def_s *def, struct type_s *type, + struct expr_s *expr); +operand_t *return_operand (struct type_s *type, struct expr_s *expr); +operand_t *value_operand (struct ex_value_s *value, struct expr_s *expr); int tempop_overlap (tempop_t *t1, tempop_t *t2) __attribute__((pure)); -operand_t *temp_operand (struct type_s *type); +operand_t *temp_operand (struct type_s *type, struct expr_s *expr); int tempop_visit_all (tempop_t *tempop, int overlap, int (*visit) (tempop_t *, void *), void *data); -operand_t *alias_operand (struct type_s *type, operand_t *op); +operand_t *alias_operand (struct type_s *type, operand_t *op, + struct expr_s *expr); +operand_t *label_operand (struct expr_s *label); void free_operand (operand_t *op); sblock_t *new_sblock (void); diff --git a/tools/qfcc/include/symtab.h b/tools/qfcc/include/symtab.h index c0c064f3e..7a6904f1a 100644 --- a/tools/qfcc/include/symtab.h +++ b/tools/qfcc/include/symtab.h @@ -45,6 +45,7 @@ typedef enum vis_e { vis_public, vis_protected, vis_private, + vis_anonymous, } vis_t; typedef enum { @@ -55,8 +56,14 @@ typedef enum { sy_expr, ///< symbol refers to an expression sy_func, ///< symbol refers to a function sy_class, ///< symbol refers to a class + sy_convert, ///< symbol refers to a conversion function } sy_type_e; +typedef struct symconv_s { + struct expr_s *(*conv) (struct symbol_s *symbol, void *data); + void *data; +} symconv_t; + typedef struct symbol_s { struct symbol_s *next; ///< chain of symbols in symbol table struct symtab_s *table; ///< symbol table that owns this symbol @@ -71,6 +78,7 @@ typedef struct symbol_s { struct ex_value_s *value; ///< sy_const struct expr_s *expr; ///< sy_expr struct function_s *func; ///< sy_func + symconv_t convert; ///< sy_convert } s; } symbol_t; @@ -91,6 +99,7 @@ typedef struct symtab_s { symbol_t *symbols; ///< chain of symbols in this table symbol_t **symtail; ///< keep chain in declaration order struct defspace_s *space; ///< storage for vars in scope symtabs + struct class_s *class; ///< owning class if ivar scope } symtab_t; const char *symtype_str (sy_type_e type) __attribute__((const)); diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index fcb4a808a..ba3b82f1e 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -31,7 +31,7 @@ #ifndef __type_h #define __type_h -#include "QF/pr_comp.h" +#include "QF/pr_type.h" #include "def.h" @@ -51,15 +51,6 @@ typedef struct ty_array_s { int size; } ty_array_t; -typedef enum { - ty_none, ///< func/field/pointer or not used - ty_struct, - ty_union, - ty_enum, - ty_array, - ty_class, -} ty_meta_e; - typedef struct type_s { etype_t type; ///< ev_invalid means structure/array etc const char *name; @@ -67,6 +58,7 @@ typedef struct type_s { /// function/pointer/array/struct types are more complex ty_meta_e meta; union { + // no data for ty_basic when not a func, field or pointer ty_func_t func; ty_fldptr_t fldptr; ty_array_t array; @@ -84,6 +76,7 @@ typedef struct type_s { typedef struct { type_t *type; struct param_s *params; + struct symbol_s *sym; ///< for dealing with "int id" etc storage_class_t storage; unsigned multi_type:1; unsigned multi_store:1; @@ -119,6 +112,9 @@ extern type_t type_va_list; extern type_t type_param; extern type_t type_zero; extern type_t type_type_encodings; +extern type_t type_xdef; +extern type_t type_xdef_pointer; +extern type_t type_xdefs; extern struct symtab_s *vector_struct; extern struct symtab_s *quaternion_struct; @@ -132,8 +128,8 @@ void chain_type (type_t *type); /** Append a type to the end of a type chain. - The type chain must be made up of only field, pointer, function and array - types, as other types do not have auxiliary type fields. + The type chain must be made up of only field, pointer, function, and + array types, as other types do not have auxiliary type fields. \param type The type chain to which the type will be appended. \param new The type to be appended. May be any type. @@ -154,6 +150,9 @@ void encode_type (struct dstring_s *encoding, const type_t *type); const char *type_get_encoding (const type_t *type); int is_void (const type_t *type) __attribute__((pure)); int is_enum (const type_t *type) __attribute__((pure)); +int is_integer (const type_t *type) __attribute__((pure)); +int is_uinteger (const type_t *type) __attribute__((pure)); +int is_short (const type_t *type) __attribute__((pure)); int is_integral (const type_t *type) __attribute__((pure)); int is_double (const type_t *type) __attribute__((pure)); int is_float (const type_t *type) __attribute__((pure)); @@ -163,9 +162,12 @@ int is_quaternion (const type_t *type) __attribute__((pure)); int is_math (const type_t *type) __attribute__((pure)); int is_pointer (const type_t *type) __attribute__((pure)); int is_field (const type_t *type) __attribute__((pure)); +int is_entity (const type_t *type) __attribute__((pure)); int is_struct (const type_t *type) __attribute__((pure)); int is_array (const type_t *type) __attribute__((pure)); +int is_structural (const type_t *type) __attribute__((pure)); int is_func (const type_t *type) __attribute__((pure)); +int is_string (const type_t *type) __attribute__((pure)); int type_compatible (const type_t *dst, const type_t *src) __attribute__((pure)); int type_assignable (const type_t *dst, const type_t *src); int type_size (const type_t *type) __attribute__((pure)); diff --git a/tools/qfcc/include/value.h b/tools/qfcc/include/value.h index aaac286b7..a2f13dd67 100644 --- a/tools/qfcc/include/value.h +++ b/tools/qfcc/include/value.h @@ -36,7 +36,9 @@ */ ///@{ +struct def_s; struct ex_value_s; +struct tempop_s; struct type_s; struct ex_value_s *new_string_val (const char *string_val); @@ -48,7 +50,8 @@ struct ex_value_s *new_field_val (int field_val, struct type_s *type, struct def_s *def); struct ex_value_s *new_func_val (int func_val, struct type_s *type); struct ex_value_s *new_pointer_val (int val, struct type_s *type, - struct def_s *def); + struct def_s *def, + struct operand_s *tempop); struct ex_value_s *new_quaternion_val (const float *quaternion_val); struct ex_value_s *new_integer_val (int integer_val); struct ex_value_s *new_uinteger_val (int uinteger_val); diff --git a/tools/qfcc/source/Makefile.am b/tools/qfcc/source/Makefile.am index 7feed1dca..bbaf06ee6 100644 --- a/tools/qfcc/source/Makefile.am +++ b/tools/qfcc/source/Makefile.am @@ -41,7 +41,9 @@ bin_SCRIPTS= qfpreqcc common_src=\ class.c codespace.c constfold.c cpp.c dags.c debug.c def.c defspace.c \ diagnostic.c dot.c dot_dag.c dot_expr.c dot_flow.c dot_sblock.c emit.c \ - expr.c expr_assign.c expr_binary.c flow.c function.c grab.c idstuff.c \ + expr.c expr_assign.c expr_binary.c expr_bool.c expr_compound.c expr_obj.c \ + flow.c function.c grab.c \ + idstuff.c \ linker.c method.c \ obj_file.c \ obj_type.c opcodes.c options.c pragma.c qfcc.c reloc.c shared.c \ diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index b249069c2..6f4473e1d 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -66,33 +66,36 @@ static hashtab_t *class_hash; static hashtab_t *category_hash; static hashtab_t *protocol_hash; +static hashtab_t *static_instances; +static hashtab_t *static_instance_classes; // these will be built up further type_t type_obj_selector = { ev_invalid, 0, 0, ty_struct}; -type_t type_SEL = { ev_pointer, "SEL", 1, ty_none, {{&type_obj_selector}}}; +type_t type_SEL = { ev_pointer, "SEL", 1, ty_basic, + {{&type_obj_selector}}}; type_t *IMP_params[] = {&type_id, &type_SEL}; -type_t type_IMP = { ev_func, "IMP", 1, ty_none, +type_t type_IMP = { ev_func, "IMP", 1, ty_basic, {{&type_id, -3, IMP_params}}}; type_t type_obj_super = { ev_invalid, 0, 0 }; -type_t type_SuperPtr = { ev_pointer, 0, 1, ty_none, {{&type_obj_super}}}; +type_t type_SuperPtr = { ev_pointer, 0, 1, ty_basic, {{&type_obj_super}}}; type_t *supermsg_params[] = {&type_SuperPtr, &type_SEL}; -type_t type_supermsg = { ev_func, ".supermsg", 1, ty_none, +type_t type_supermsg = { ev_func, ".supermsg", 1, ty_basic, {{&type_id, -3, supermsg_params}}}; type_t type_obj_method = { ev_invalid, 0, 0, ty_struct }; type_t type_obj_method_description = { ev_invalid, 0, 0, ty_struct }; type_t type_obj_category = { ev_invalid, 0, 0, ty_struct}; type_t type_obj_ivar = { ev_invalid, 0, 0, ty_struct}; type_t type_obj_module = { ev_invalid, 0, 0, ty_struct}; -type_t type_moduleptr = { ev_pointer, 0, 1, ty_none, +type_t type_moduleptr = { ev_pointer, 0, 1, ty_basic, {{&type_obj_module}}}; type_t *obj_exec_class_params[] = { &type_moduleptr }; -type_t type_obj_exec_class = { ev_func, 0, 1, ty_none, +type_t type_obj_exec_class = { ev_func, 0, 1, ty_basic, {{&type_void, 1, obj_exec_class_params}}}; type_t type_obj_object = {ev_invalid, 0, 0, ty_struct}; -type_t type_id = { ev_pointer, "id", 1, ty_none, {{&type_obj_object}}}; +type_t type_id = { ev_pointer, "id", 1, ty_basic, {{&type_obj_object}}}; type_t type_obj_class = { ev_invalid, 0, 0, ty_struct}; -type_t type_Class = { ev_pointer, 0, 1, ty_none, {{&type_obj_class}}}; +type_t type_Class = { ev_pointer, 0, 1, ty_basic, {{&type_obj_class}}}; type_t type_obj_protocol = { ev_invalid, 0, 0, ty_struct}; int obj_initialized = 0; @@ -177,6 +180,141 @@ static struct_def_t object_struct[] = { {0, 0} }; +static const char * +static_instance_get_key (const void *instance, void *unused) +{ + return ((static_instance_t *) instance)->class; +} + +static void +add_static_instance (const char *class, def_t *instance_def) +{ + static_instance_t *instance = malloc (sizeof (*instance)); + + if (!static_instances) { + static_instances = Hash_NewTable (1021, static_instance_get_key, 0, 0); + static_instance_classes = Hash_NewTable (1021, static_instance_get_key, + 0, 0); + } + + instance->class = save_string (class); + instance->instance = instance_def; + Hash_Add (static_instances, instance); + + // uniqued set of class names for all static instances + if (!Hash_Find (static_instance_classes, class)) { + Hash_Add (static_instance_classes, instance); + } +} +typedef struct { + const char *class_name; + int num_instances; + static_instance_t **instances; +} obj_static_instances_data_t; + +static void +emit_instance_classname (def_t *def, void *data, int index) +{ + obj_static_instances_data_t *da = (obj_static_instances_data_t *)data; + + if (def->type != &type_string) + internal_error (0, "%s: expected string def", __FUNCTION__); + EMIT_STRING (def->space, D_STRING (def), da->class_name); +} + +static void +emit_instance_defs (def_t *def, void *data, int index) +{ + obj_static_instances_data_t *da = (obj_static_instances_data_t *)data; + + if (!is_array (def->type) || def->type->t.array.type->type != ev_pointer) + internal_error (0, "%s: expected array of pointers def", __FUNCTION__); + if (index < 0 || index >= da->num_instances + 1) + internal_error (0, "%s: out of bounds index: %d %d", + __FUNCTION__, index, da->num_instances + 1); + D_INT (def) = 0; + if (index < da->num_instances) { + EMIT_DEF (def->space, D_INT (def), da->instances[index]->instance); + } +} + +static def_t * +emit_static_instances (const char *classname) +{ + static struct_def_t instances_struct[] = { + {"class_name", &type_string, emit_instance_classname}, + {"instances", 0, emit_instance_defs}, + {0, 0} + }; + obj_static_instances_data_t data = {}; + def_t *instances_def; + + data.class_name = classname; + data.instances = (static_instance_t **) Hash_FindList (static_instances, + classname); + for (static_instance_t **inst = data.instances; *inst; inst++) { + data.num_instances++; + } + instances_struct[1].type = array_type (&type_pointer, + data.num_instances + 1); + instances_def = emit_structure (va ("_OBJ_STATIC_INSTANCES_%s", classname), + 's', instances_struct, 0, &data, + sc_static); + free (data.instances); + return instances_def; +} + +static def_t * +emit_static_instances_list (void) +{ + static_instance_t **classes; + int num_classes = 0; + def_t **instance_lists; + type_t *instance_lists_type; + symbol_t *instance_lists_sym; + def_t *instance_lists_def; + pointer_t *list; + defspace_t *space; + + if (!static_instance_classes || !static_instances) { + return 0; + } + + classes = (static_instance_t **) Hash_GetList (static_instance_classes); + for (static_instance_t **c = classes; *c; c++) { + num_classes++; + } + if (!num_classes) { + free (classes); + return 0; + } + instance_lists = alloca (num_classes * sizeof (*instance_lists)); + for (int i = 0; i < num_classes; i++) { + instance_lists[i] = emit_static_instances (classes[i]->class); + } + free (classes); + + // +1 for terminating null + instance_lists_type = array_type (&type_pointer, num_classes + 1); + instance_lists_sym = make_symbol ("_OBJ_STATIC_INSTANCES", + instance_lists_type, + pr.far_data, sc_static); + if (!instance_lists_sym->table) { + symtab_addsymbol (pr.symtab, instance_lists_sym); + } + instance_lists_def = instance_lists_sym->s.def; + instance_lists_def->initialized = instance_lists_def->constant = 1; + instance_lists_def->nosave = 1; + + list = D_POINTER (pointer_t, instance_lists_def); + space = instance_lists_def->space; + for (int i = 0; i < num_classes; i++, list++) { + EMIT_DEF (space, *list, instance_lists[i]); + } + *list = 0; + return instance_lists_def; +} + int obj_is_id (const type_t *type) { @@ -207,15 +345,6 @@ obj_is_Class (const type_t *type) { if (type == &type_Class) return 1; - // type may be a qualified Class, in which case it will be a pointer to - // a qualified obj_class struct - if (type->type != ev_pointer) - return 0; - if (!is_struct (type->t.fldptr.type)) - return 0; - // if the the symtabs match, then type is Class in disguise - if (type->t.fldptr.type->t.symtab == type_obj_class.t.symtab) - return 1; return 0; } @@ -307,8 +436,14 @@ obj_types_assignable (const type_t *dst, const type_t *src) int i; //puts ("%$$\"$#%"); - if (!obj_is_classptr (dst) || !obj_is_classptr (src)) + if (!obj_is_classptr (src)) { + // if dst is a class pointer, then the types are not compatible, + // otherwise unknown + return obj_is_classptr (dst) - 1; + } + if (!obj_is_classptr (dst)) { return -1; + } dst_is_proto = obj_is_id (dst) && (dst_protos = obj_get_protos (dst)); src_is_proto = obj_is_id (src) && (src_protos = obj_get_protos (src)); @@ -493,9 +628,7 @@ class_add_methods (class_t *class, methodlist_t *methods) if (!methods) return; - *class->methods->tail = methods->head; - class->methods->tail = methods->tail; - free (methods); + merge_method_lists (class->methods, methods); methods_set_self_type (class, class->methods); } @@ -506,15 +639,26 @@ class_add_protocols (class_t *class, protocollist_t *protocols) int i; protocol_t *p; methodlist_t *methods; + methodset_t *except; + class_t *super; if (!protocols) return; methods = class->methods; + except = new_methodset (); + for (super = class->super_class; super; super = super->super_class) { + methodset_add_methods (except, super->methods); + } + for (i = 0; i < protocols->count; i++) { p = protocols->list[i]; - copy_methods (methods, p->methods); + if (p->methods) { + copy_methods (methods, p->methods, except); + } else { + warning (0, "definition of protocol `%s' not found", p->name); + } if (p->protocols) class_add_protocols (class, p->protocols); } @@ -569,7 +713,7 @@ emit_ivar_list_item (def_t *def, void *data, int index) defspace_t *space; #if 0 - //FIXME the type is dynamic, so need a way to pass it before it cn be + //FIXME the type is dynamic, so need a way to pass it before it can be //checked if (def->type != &XXX) internal_error (0, "%s: expected XXX def", @@ -888,10 +1032,20 @@ class_find_ivar (class_t *class, int vis, const char *name) { symbol_t *ivar; + if (!class->ivars) { + if (!class->interface_declared) { + class->interface_declared = 1; + error (0, "accessing incomplete type %s", class->name); + } + return 0; + } ivar = symtab_lookup (class->ivars, name); if (ivar) { - if (ivar->visibility > (vis_t) vis) + if (ivar->visibility > (vis_t) vis + || (ivar->table->class != class + && ivar->visibility > vis_protected)) { goto access_error; + } return ivar; } error (0, "%s.%s does not exist", class->name, name); @@ -924,7 +1078,7 @@ class_find_method (class_type_t *class_type, method_t *method) start_methods = methods; start_class = class; while (class) { - for (m = methods->head; m; m = m->next) + for (m = methods->head; m; m = m->next) { if (method_compare (method, m)) { if (m->type != method->type) error (0, "method type mismatch"); @@ -936,6 +1090,7 @@ class_find_method (class_type_t *class_type, method_t *method) method_set_param_names (m, method); return m; } + } if (class->methods == methods) class = class->super_class; else @@ -949,48 +1104,86 @@ class_find_method (class_type_t *class_type, method_t *method) return method; } +static method_t * +cls_find_method (methodlist_t *methodlist, selector_t *selector, + int class_msg, int is_root) +{ + method_t *m = 0; + m = methodlist_find_method (methodlist, selector, !class_msg); + if (!m && is_root && class_msg + && (m = methodlist_find_method (methodlist, selector, 1))) { + return m; + } + return m; +} + method_t * -class_message_response (class_t *class, int class_msg, expr_t *sel) +class_message_response (type_t *clstype, int class_msg, expr_t *sel) { selector_t *selector; method_t *m; - class_t *c = class; + class_t *c; + class_t *class = 0; category_t *cat; + dstring_t *dstr; selector = get_selector (sel); if (!selector) return 0; - if (class && class->type != &type_obj_object) { - while (c) { - for (cat = c->categories; cat; cat = cat->next) { - for (m = cat->methods->head; m; m = m->next) { - if (((!c->super_class && class_msg) - || class_msg != m->instance) - && strcmp (selector->name, m->name) == 0) - return m; - } + + if (!obj_is_classptr (clstype) && !obj_is_class (clstype)) { + error (0, "neither class nor object"); + return 0; + } + if (obj_is_id (clstype)) { + protocollist_t *protos = clstype->t.fldptr.type->protos; + if (protos) { + if ((m = protocollist_find_method (protos, selector, !class_msg))) { + return m; } - for (m = c->methods->head; m; m = m->next) { - if (((!c->super_class && class_msg) - || class_msg != m->instance) - && strcmp (selector->name, m->name) == 0) - return m; - } - c = c->super_class; + dstr = dstring_new (); + print_protocollist (dstr, protos); + warning (sel, "id%s may not respond to %c%s", dstr->str, + class_msg ? '+' : '-', selector->name); + dstring_delete (dstr); } - //FIXME right option? - if (options.warnings.interface_check) + } else { + if (obj_is_class (clstype)) { + class = clstype->t.class; + } else if (obj_is_class (clstype->t.fldptr.type)) { + class = clstype->t.fldptr.type->t.class; + } + if (class && class->type != &type_obj_object) { + if (!class->interface_declared) { + class->interface_declared = 1; + warning (0, "cannot find interface declaration for `%s'", + class->name); + } + c = class; + while (c) { + for (cat = c->categories; cat; cat = cat->next) { + if ((m = cls_find_method (cat->methods, selector, + class_msg, + !c->super_class))) { + return m; + } + } + if ((m = cls_find_method (c->methods, selector, class_msg, + !c->super_class))) { + return m; + } + c = c->super_class; + } warning (sel, "%s may not respond to %c%s", class->name, class_msg ? '+' : '-', selector->name); + } } m = find_method (selector->name); - if (m) - return m; - //FIXME right option? - if (options.warnings.interface_check) + if (!m && (!class || class->type == &type_obj_object)) { warning (sel, "could not find method for %c%s", class_msg ? '+' : '-', selector->name); - return 0; + } + return m; } static uintptr_t @@ -1018,6 +1211,7 @@ class_new_ivars (class_t *class) if (class->super_class) super_ivars = class->super_class->ivars; ivars = new_symtab (super_ivars, stab_local); + ivars->class = class; return ivars; } @@ -1113,9 +1307,7 @@ category_add_methods (category_t *category, methodlist_t *methods) { if (!methods) return; - *category->methods->tail = methods->head; - category->methods->tail = methods->tail; - free (methods); + merge_method_lists (category->methods, methods); methods_set_self_type (category->class, category->methods); } @@ -1126,15 +1318,22 @@ category_add_protocols (category_t *category, protocollist_t *protocols) int i; protocol_t *p; methodlist_t *methods; + methodset_t *except; + class_t *class; if (!protocols) return; methods = category->methods; + except = new_methodset (); + for (class = category->class; class; class = class->super_class) { + methodset_add_methods (except, class->methods); + } + for (i = 0; i < protocols->count; i++) { p = protocols->list[i]; - copy_methods (methods, p->methods); + copy_methods (methods, p->methods, except); if (p->protocols) category_add_protocols (category, p->protocols); } @@ -1175,6 +1374,7 @@ typedef struct { int cls_def_cnt; category_t **categories; int cat_def_cnt; + def_t *instances_list; } obj_symtab_data_t; static void @@ -1228,10 +1428,10 @@ emit_symtab_defs (def_t *def, void *data, int index) if (!is_array (def->type) || def->type->t.array.type->type != ev_pointer) internal_error (0, "%s: expected array of pointers def", __FUNCTION__); - if (index < 0 || index >= da->cls_def_cnt + da->cat_def_cnt) + if (index < 0 || index >= da->cls_def_cnt + da->cat_def_cnt + 1) internal_error (0, "%s: out of bounds index: %d %d", __FUNCTION__, index, - da->cls_def_cnt + da->cat_def_cnt); + da->cls_def_cnt + da->cat_def_cnt + 1); if (index < da->cls_def_cnt) { class_t **cl; @@ -1240,7 +1440,7 @@ emit_symtab_defs (def_t *def, void *data, int index) if (!index--) break; EMIT_DEF (def->space, D_INT (def), (*cl)->def); - } else { + } else if (index < da->cls_def_cnt + da->cat_def_cnt) { category_t **ca; index -= da->cls_def_cnt; for (ca = da->categories; *ca; ca++) @@ -1248,6 +1448,11 @@ emit_symtab_defs (def_t *def, void *data, int index) if (!index--) break; EMIT_DEF (def->space, D_INT (def), (*ca)->def); + } else { + D_INT (def) = 0; + if (da->instances_list) { + EMIT_DEF (def->space, D_INT (def), da->instances_list); + } } } @@ -1263,7 +1468,7 @@ class_finish_module (void) {0, 0} }; - obj_symtab_data_t data = {0, 0, 0, 0, 0}; + obj_symtab_data_t data = {}; class_t **cl; category_t **ca; @@ -1289,10 +1494,14 @@ class_finish_module (void) if ((*ca)->def && !(*ca)->def->external) data.cat_def_cnt++; } - if (!data.refs && !data.cls_def_cnt && !data.cat_def_cnt) + data.instances_list = emit_static_instances_list (); + if (!data.refs && !data.cls_def_cnt && !data.cat_def_cnt + && !data.instances_list) return; symtab_struct[4].type = array_type (&type_pointer, - data.cls_def_cnt + data.cat_def_cnt); + data.cls_def_cnt + + data.cat_def_cnt + + 1); symtab_def = emit_structure ("_OBJ_SYMTAB", 's', symtab_struct, 0, &data, sc_static); free (data.classes); @@ -1350,7 +1559,7 @@ get_protocol (const char *name, int create) p = calloc (sizeof (protocol_t), 1); p->name = name; - p->methods = new_methodlist (); + p->methods = 0; p->class_type.type = ct_protocol; p->class_type.c.protocol = p; if (name) @@ -1363,9 +1572,7 @@ protocol_add_methods (protocol_t *protocol, methodlist_t *methods) { if (!methods) return; - *protocol->methods->tail = methods->head; - protocol->methods->tail = methods->tail; - free (methods); + merge_method_lists (protocol->methods, methods); } void @@ -1377,8 +1584,11 @@ protocol_add_protocols (protocol_t *protocol, protocollist_t *protocols) def_t * protocol_def (protocol_t *protocol) { - return make_symbol (protocol->name, &type_obj_protocol, - pr.far_data, sc_static)->s.def; + if (!protocol->def) { + protocol->def = emit_protocol (protocol); + add_static_instance ("Protocol", protocol->def); + } + return protocol->def; } protocollist_t * @@ -1419,6 +1629,34 @@ procollist_find_protocol (protocollist_t *protocollist, protocol_t *proto) return 0; } +static method_t * +protocol_find_method (protocol_t *protocol, selector_t *selector, int instance) +{ + method_t *m = 0; + if (protocol->methods) { + m = methodlist_find_method (protocol->methods, selector, instance); + } + if (!m && protocol->protocols) { + return protocollist_find_method (protocol->protocols, selector, + instance); + } + return m; +} + +method_t * +protocollist_find_method (protocollist_t *protocollist, selector_t *selector, + int instance) +{ + method_t *m; + for (int i = 0; i < protocollist->count; i++) { + if ((m = protocol_find_method (protocollist->list[i], selector, + instance))) { + return m; + } + } + return 0; +} + int compare_protocols (protocollist_t *protos1, protocollist_t *protos2) { @@ -1507,7 +1745,7 @@ emit_protocol_list_item (def_t *def, void *data, int index) internal_error (0, "%s: out of bounds index: %d %d", __FUNCTION__, index, protocols->count); } - EMIT_DEF (def->space, D_INT(def), emit_protocol (protocol)); + EMIT_DEF (def->space, D_INT(def), protocol_def (protocol)); } def_t * @@ -1536,6 +1774,10 @@ clear_classes (void) Hash_FlushTable (protocol_hash); if (category_hash) Hash_FlushTable (category_hash); + if (static_instances) + Hash_FlushTable (static_instances); + if (static_instance_classes) + Hash_FlushTable (static_instance_classes); obj_initialized = 0; } @@ -1574,6 +1816,15 @@ class_ivar_scope (class_type_t *class_type, symtab_t *parent) return symtab_flat_copy (class->ivars, parent); } +static expr_t * +class_dereference_ivar (symbol_t *sym, void *_self) +{ + expr_t *self = (expr_t *) _self; + + return field_expr (copy_expr (self), + new_symbol_expr (new_symbol (sym->name))); +} + void class_finish_ivar_scope (class_type_t *class_type, symtab_t *ivar_scope, symtab_t *param_scope) @@ -1587,8 +1838,9 @@ class_finish_ivar_scope (class_type_t *class_type, symtab_t *ivar_scope, if (!ivar_scope) return; self = symtab_lookup (param_scope, "self"); - if (!self) + if (!self) { internal_error (0, "I've lost my self!"); + } self_expr = new_symbol_expr (self); if (self->type != class_ptr) { debug (0, "class method scope"); @@ -1598,9 +1850,9 @@ class_finish_ivar_scope (class_type_t *class_type, symtab_t *ivar_scope, for (sym = ivar_scope->symbols; sym; sym = sym->next) { if (sym->sy_type != sy_var) continue; - sym->sy_type = sy_expr; - sym->s.expr = field_expr (copy_expr (self_expr), - new_symbol_expr (new_symbol (sym->name))); + sym->sy_type = sy_convert; + sym->s.convert.conv = class_dereference_ivar; + sym->s.convert.data = self_expr; } } diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index 3cba7f467..f367987a3 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -69,6 +69,16 @@ valid_op (int op, int *valid_ops) return *valid_ops == op; } +static expr_t * +cmp_result_expr (int result) +{ + if (is_float (type_default)) { + return new_float_expr (result); + } else { + return new_integer_expr(result); + } +} + static expr_t * do_op_string (int op, expr_t *e, expr_t *e1, expr_t *e2) { @@ -108,22 +118,22 @@ do_op_string (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_string_expr (save_string (temp_str->str)); break; case LT: - e = new_integer_expr (strcmp (s1, s2) < 0); + e = cmp_result_expr (strcmp (s1, s2) < 0); break; case GT: - e = new_integer_expr (strcmp (s1, s2) > 0); + e = cmp_result_expr (strcmp (s1, s2) > 0); break; case LE: - e = new_integer_expr (strcmp (s1, s2) <= 0); + e = cmp_result_expr (strcmp (s1, s2) <= 0); break; case GE: - e = new_integer_expr (strcmp (s1, s2) >= 0); + e = cmp_result_expr (strcmp (s1, s2) >= 0); break; case EQ: - e = new_integer_expr (strcmp (s1, s2) == 0); + e = cmp_result_expr (strcmp (s1, s2) == 0); break; case NE: - e = new_integer_expr (strcmp (s1, s2)); + e = cmp_result_expr (strcmp (s1, s2)); break; default: internal_error (e1, 0); @@ -148,8 +158,12 @@ convert_to_float (expr_t *e) case ev_short: convert_short (e); return e; + case ev_double: + convert_double (e); + return e; default: - internal_error (e, 0); + internal_error (e, "bad conversion to float: %d", + e->e.value->lltype); } break; case ex_symbol: @@ -212,7 +226,7 @@ do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2) if (!valid_op (op, valid)) return error (e1, "invalid operator for float"); - if (op == '=' || op == PAS) { + if (op == '=') { if ((type = get_type (e1)) != &type_float) { //FIXME optimize casting a constant e->e.expr.e2 = e2 = cf_cast_expr (type, e2); @@ -296,28 +310,28 @@ do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_float_expr ((int)f1 >> (int)f2); break; case AND: - e = new_integer_expr (f1 && f2); + e = cmp_result_expr (f1 && f2); break; case OR: - e = new_integer_expr (f1 || f2); + e = cmp_result_expr (f1 || f2); break; case LT: - e = new_integer_expr (f1 < f2); + e = cmp_result_expr (f1 < f2); break; case GT: - e = new_integer_expr (f1 > f2); + e = cmp_result_expr (f1 > f2); break; case LE: - e = new_integer_expr (f1 <= f2); + e = cmp_result_expr (f1 <= f2); break; case GE: - e = new_integer_expr (f1 >= f2); + e = cmp_result_expr (f1 >= f2); break; case EQ: - e = new_integer_expr (f1 == f2); + e = cmp_result_expr (f1 == f2); break; case NE: - e = new_integer_expr (f1 != f2); + e = cmp_result_expr (f1 != f2); break; default: internal_error (e1, 0); @@ -341,7 +355,7 @@ do_op_double (int op, expr_t *e, expr_t *e1, expr_t *e2) if (!valid_op (op, valid)) return error (e1, "invalid operator for double"); - if (op == '=' || op == PAS) { + if (op == '=') { if ((type = get_type (e1)) != &type_double) { //FIXME optimize casting a constant e->e.expr.e2 = e2 = cf_cast_expr (type, e2); @@ -407,22 +421,22 @@ do_op_double (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_double_expr ((int)d1 % (int)d2); break; case LT: - e = new_integer_expr (d1 < d2); + e = cmp_result_expr (d1 < d2); break; case GT: - e = new_integer_expr (d1 > d2); + e = cmp_result_expr (d1 > d2); break; case LE: - e = new_integer_expr (d1 <= d2); + e = cmp_result_expr (d1 <= d2); break; case GE: - e = new_integer_expr (d1 >= d2); + e = cmp_result_expr (d1 >= d2); break; case EQ: - e = new_integer_expr (d1 == d2); + e = cmp_result_expr (d1 == d2); break; case NE: - e = new_integer_expr (d1 != d2); + e = cmp_result_expr (d1 != d2); break; default: internal_error (e1, 0); @@ -535,10 +549,10 @@ do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2) } break; case EQ: - e = new_integer_expr (VectorCompare (v1, v2)); + e = cmp_result_expr (VectorCompare (v1, v2)); break; case NE: - e = new_integer_expr (!VectorCompare (v1, v2)); + e = cmp_result_expr (!VectorCompare (v1, v2)); break; default: internal_error (e1, 0); @@ -602,7 +616,7 @@ static expr_t * do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2) { type_t *type; - static int valid[] = {'=', PAS, '-', '&', 'M', '.', EQ, NE, 0}; + static int valid[] = {'=', '-', '&', 'M', '.', EQ, NE, 0}; if (is_integral (type = get_type (e2)) && (op == '-' || op == '+')) { // pointer arithmetic @@ -626,26 +640,13 @@ do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2) e = binary_expr ('/', e, new_integer_expr (type_size (type))); return e; } - if (op == PAS && (type = get_type (e1)->t.fldptr.type) != get_type (e2)) { - // make sure auto-convertions happen - expr_t *tmp = new_temp_def_expr (type); - expr_t *ass = new_binary_expr ('=', tmp, e2); - - tmp->file = e1->file; - ass->line = e2->line; - ass->file = e2->file; - ass = fold_constants (ass); - if (e->e.expr.e2 == tmp) - internal_error (e2, 0); - e->e.expr.e2 = ass->e.expr.e2; - } if (op == EQ || op == NE) { if (options.code.progsversion > PROG_ID_VERSION) e->e.expr.type = &type_integer; else e->e.expr.type = &type_float; } - if (op != PAS && op != '.' && op != '&' && op != 'M' + if (op != '.' && op != '&' && op != 'M' && extract_type (e1) != extract_type (e2)) return type_mismatch (e1, e2, op); if ((op == '.' || op == '&') && get_type (e2) == &type_uinteger) @@ -772,10 +773,10 @@ do_op_quaternion (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_quaternion_expr (q); break; case EQ: - e = new_integer_expr (QuatCompare (q1, q2)); + e = cmp_result_expr (QuatCompare (q1, q2)); break; case NE: - e = new_integer_expr (!QuatCompare (q1, q2)); + e = cmp_result_expr (!QuatCompare (q1, q2)); break; default: internal_error (e1, 0); @@ -788,7 +789,8 @@ do_op_quaternion (int op, expr_t *e, expr_t *e1, expr_t *e2) static expr_t * do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2) { - int i1, i2; + int isval1 = 0, isval2 = 0; + int val1 = 0, val2 = 0; static int valid[] = { '=', '+', '-', '*', '/', '&', '|', '^', '%', SHL, SHR, AND, OR, LT, GT, LE, GE, EQ, NE, 0 @@ -797,11 +799,23 @@ do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2) if (!valid_op (op, valid)) return error (e1, "invalid operator for integer"); - if (is_short_val (e1)) - convert_short_int (e1); + if (is_short_val (e1)) { + isval1 = 1; + val1 = expr_short (e1); + } + if (is_integer_val (e1)) { + isval1 = 1; + val1 = expr_integer (e1); + } - if (is_short_val (e2)) - convert_short_int (e2); + if (is_short_val (e2)) { + isval2 = 1; + val2 = expr_short (e2); + } + if (is_integer_val (e2)) { + isval2 = 1; + val2 = expr_integer (e2); + } if (is_compare (op) || is_logic (op)) { if (options.code.progsversion > PROG_ID_VERSION) @@ -812,89 +826,86 @@ do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2) e->e.expr.type = &type_integer; } - if (op == '*' && is_constant (e1) && expr_integer (e1) == 1) + if (op == '*' && isval1 && val1 == 1) return e2; - if (op == '*' && is_constant (e2) && expr_integer (e2) == 1) + if (op == '*' && isval2 && val2 == 1) return e1; - if (op == '*' && is_constant (e1) && expr_integer (e1) == 0) + if (op == '*' && isval1 && val1 == 0) return e1; - if (op == '*' && is_constant (e2) && expr_integer (e2) == 0) + if (op == '*' && isval2 && val2 == 0) return e2; - if (op == '/' && is_constant (e2) && expr_integer (e2) == 1) + if (op == '/' && isval2 && val2 == 1) return e1; - if (op == '/' && is_constant (e2) && expr_integer (e2) == 0) + if (op == '/' && isval2 && val2 == 0) return error (e, "division by zero"); - if (op == '/' && is_constant (e1) && expr_integer (e1) == 0) + if (op == '/' && isval1 && val1 == 0) return e1; - if (op == '+' && is_constant (e1) && expr_integer (e1) == 0) + if (op == '+' && isval1 && val1 == 0) return e2; - if (op == '+' && is_constant (e2) && expr_integer (e2) == 0) + if (op == '+' && isval2 && val2 == 0) return e1; - if (op == '-' && is_constant (e2) && expr_integer (e2) == 0) + if (op == '-' && isval2 && val2 == 0) return e1; - if (op == '=' || !is_constant (e1) || !is_constant (e2)) + if (op == '=' || !isval1 || !isval2) return e; - i1 = expr_integer (e1); - i2 = expr_integer (e2); - switch (op) { case '+': - e = new_integer_expr (i1 + i2); + e = new_integer_expr (val1 + val2); break; case '-': - e = new_integer_expr (i1 - i2); + e = new_integer_expr (val1 - val2); break; case '*': - e = new_integer_expr (i1 * i2); + e = new_integer_expr (val1 * val2); break; case '/': if (options.warnings.integer_divide) - warning (e2, "%d / %d == %d", i1, i2, i1 / i2); - e = new_integer_expr (i1 / i2); + warning (e2, "%d / %d == %d", val1, val2, val1 / val2); + e = new_integer_expr (val1 / val2); break; case '&': - e = new_integer_expr (i1 & i2); + e = new_integer_expr (val1 & val2); break; case '|': - e = new_integer_expr (i1 | i2); + e = new_integer_expr (val1 | val2); break; case '^': - e = new_integer_expr (i1 ^ i2); + e = new_integer_expr (val1 ^ val2); break; case '%': - e = new_integer_expr (i1 % i2); + e = new_integer_expr (val1 % val2); break; case SHL: - e = new_integer_expr (i1 << i2); + e = new_integer_expr (val1 << val2); break; case SHR: - e = new_integer_expr (i1 >> i2); + e = new_integer_expr (val1 >> val2); break; case AND: - e = new_integer_expr (i1 && i2); + e = cmp_result_expr (val1 && val2); break; case OR: - e = new_integer_expr (i1 || i2); + e = cmp_result_expr (val1 || val2); break; case LT: - e = new_integer_expr (i1 < i2); + e = cmp_result_expr (val1 < val2); break; case GT: - e = new_integer_expr (i1 > i2); + e = cmp_result_expr (val1 > val2); break; case LE: - e = new_integer_expr (i1 <= i2); + e = cmp_result_expr (val1 <= val2); break; case GE: - e = new_integer_expr (i1 >= i2); + e = cmp_result_expr (val1 >= val2); break; case EQ: - e = new_integer_expr (i1 == i2); + e = cmp_result_expr (val1 == val2); break; case NE: - e = new_integer_expr (i1 != i2); + e = cmp_result_expr (val1 != val2); break; default: internal_error (e1, 0); @@ -977,22 +988,22 @@ do_op_short (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_short_expr (i1 || i2); break; case LT: - e = new_integer_expr (i1 < i2); + e = cmp_result_expr (i1 < i2); break; case GT: - e = new_integer_expr (i1 > i2); + e = cmp_result_expr (i1 > i2); break; case LE: - e = new_integer_expr (i1 <= i2); + e = cmp_result_expr (i1 <= i2); break; case GE: - e = new_integer_expr (i1 >= i2); + e = cmp_result_expr (i1 >= i2); break; case EQ: - e = new_integer_expr (i1 == i2); + e = cmp_result_expr (i1 == i2); break; case NE: - e = new_integer_expr (i1 != i2); + e = cmp_result_expr (i1 != i2); break; default: internal_error (e1, 0); @@ -1371,7 +1382,7 @@ uop_string (int op, expr_t *e, expr_t *e1) return e; s = expr_string (e1); - return new_integer_expr (!s || !s[0]); + return cmp_result_expr (!s || !s[0]); } static expr_t * @@ -1395,7 +1406,7 @@ uop_float (int op, expr_t *e, expr_t *e1) return new_float_expr (-expr_float (e1)); case '!': print_type (get_type (e)); - return new_integer_expr (!expr_float (e1)); + return cmp_result_expr (!expr_float (e1)); case '~': return new_float_expr (~(int) expr_float (e1)); case 'C': @@ -1426,7 +1437,7 @@ uop_vector (int op, expr_t *e, expr_t *e1) VectorNegate (expr_vector (e), v); return new_vector_expr (v); case '!': - return new_integer_expr (!VectorIsZero (expr_vector (e1))); + return cmp_result_expr (!VectorIsZero (expr_vector (e1))); } internal_error (e, "vector unary op blew up"); } @@ -1520,7 +1531,7 @@ uop_quaternion (int op, expr_t *e, expr_t *e1) QuatNegate (expr_vector (e), q); return new_quaternion_expr (q); case '!': - return new_integer_expr (!QuatIsZero (expr_quaternion (e1))); + return cmp_result_expr (!QuatIsZero (expr_quaternion (e1))); case '~': QuatConj (expr_vector (e), q); return new_quaternion_expr (q); @@ -1546,7 +1557,7 @@ uop_integer (int op, expr_t *e, expr_t *e1) case '-': return new_integer_expr (-expr_integer (e1)); case '!': - return new_integer_expr (!expr_integer (e1)); + return cmp_result_expr (!expr_integer (e1)); case '~': return new_integer_expr (~expr_integer (e1)); case 'C': @@ -1571,7 +1582,7 @@ uop_uinteger (int op, expr_t *e, expr_t *e1) case '-': return new_uinteger_expr (-expr_uinteger (e1)); case '!': - return new_integer_expr (!expr_uinteger (e1)); + return cmp_result_expr (!expr_uinteger (e1)); case '~': return new_uinteger_expr (~expr_uinteger (e1)); } @@ -1594,7 +1605,7 @@ uop_short (int op, expr_t *e, expr_t *e1) case '-': return new_short_expr (-expr_short (e1)); case '!': - return new_integer_expr (!expr_short (e1)); + return cmp_result_expr (!expr_short (e1)); case '~': return new_short_expr (~expr_short (e1)); } @@ -1622,7 +1633,7 @@ uop_double (int op, expr_t *e, expr_t *e1) return new_double_expr (-expr_double (e1)); case '!': print_type (get_type (e)); - return new_integer_expr (!expr_double (e1)); + return cmp_result_expr (!expr_double (e1)); case 'C': if (type == &type_integer) { return new_integer_expr (expr_double (e1)); diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index 8de4d0e54..8b352e1c1 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -49,8 +49,10 @@ #include "dags.h" #include "diagnostic.h" +#include "dot.h" #include "flow.h" #include "function.h" +#include "options.h" #include "qfcc.h" #include "statements.h" #include "strpool.h" @@ -80,7 +82,7 @@ flush_daglabels (void) else if (op->op_type == op_label) op->o.label->daglabel = 0; else - internal_error (0, "unexpected operand type"); + internal_error (op->expr, "unexpected operand type"); } daglabel_chain = daglabel_chain->daglabel_chain; } @@ -133,6 +135,11 @@ daglabel_string (daglabel_t *label) // operand_string might use quote_string, which returns a pointer to // a static variable. dstring_copystr (str, operand_string (label->op)); +#if 0 + if (label->op->type) { + dstring_appendstr (str, label->op->type->encoding); + } +#endif return quote_string (str->str); } @@ -186,7 +193,7 @@ operand_label (dag_t *dag, operand_t *op) label->op = op; op->o.label->daglabel = label; } else { - internal_error (0, "unexpected operand type: %d", op->op_type); + internal_error (op->expr, "unexpected operand type: %d", op->op_type); } return label; } @@ -423,7 +430,8 @@ dagnode_set_edges (dag_t *dag, dagnode_t *n) param_node = def_visit_all (param_def, 0, dag_find_node, &daglabel); if (!param_node) { - bug (0, ".param_%d not set for %s", i, n->label->opcode); + bug (n->label->expr, ".param_%d not set for %s", i, + n->label->opcode); continue; } daglabel->live = 1; @@ -498,7 +506,7 @@ dag_kill_aliases (daglabel_t *l) def_visit_all (op->o.def, 1, dag_def_kill_aliases_visit, l); } } else { - internal_error (0, "rvalue assignment?"); + internal_error (op->expr, "rvalue assignment?"); } } @@ -555,7 +563,8 @@ dagnode_attach_label (dagnode_t *n, daglabel_t *l) internal_error (0, "attempt to attach operator label to dagnode " "identifiers"); if (!op_is_identifier (l->op)) - internal_error (0, "attempt to attach non-identifer label to dagnode " + internal_error (l->op->expr, + "attempt to attach non-identifer label to dagnode " "identifiers"); if (l->dagnode) { // if the node is a leaf, then kill its value so no attempt is made @@ -698,6 +707,8 @@ dag_create (flownode_t *flownode) dagnode_t **nodes; daglabel_t **labels; int num_statements = 0; + int num_nodes; + int num_lables; set_t *live_vars = set_new (); flush_daglabels (); @@ -711,32 +722,43 @@ dag_create (flownode_t *flownode) dag = new_dag (); dag->flownode = flownode; - // at most 4 per statement - dag->nodes = alloca (num_statements * 4 * sizeof (dagnode_t)); - // at most 4 per statement, + return + params - dag->labels = alloca (num_statements * (4 + 1 + 8) * sizeof (daglabel_t)); + // at most FLOW_OPERANDS per statement + num_nodes = num_statements * FLOW_OPERANDS; + dag->nodes = alloca (num_nodes * sizeof (dagnode_t)); + // at most FLOW_OPERANDS per statement, + return + params + num_lables = num_statements * (FLOW_OPERANDS + 1 + 8); + dag->labels = alloca (num_lables * sizeof (daglabel_t)); dag->roots = set_new (); for (s = block->statements; s; s = s->next) { - operand_t *operands[4]; + operand_t *operands[FLOW_OPERANDS]; dagnode_t *n = 0, *children[3] = {0, 0, 0}; daglabel_t *op, *lx; int i; dag_make_children (dag, s, operands, children); - if (s->type == st_flow || s->type == st_func) - for (i = 0; i < 3; i++) - if (children[i]) + if (s->type == st_flow || s->type == st_func) { + for (i = 0; i < 3; i++) { + if (children[i]) { dag_make_var_live (live_vars, operands[i + 1]); + } + } + } + if (operands[4]) { + // a movep instruction knew what it was reading, so mark that + // as live + dag_make_var_live (live_vars, operands[4]); + } op = opcode_label (dag, s->opcode, s->expr); n = children[0]; - if (s->type != st_assign - && !(n = dagnode_search (dag, op, children))) { - n = new_node (dag); - n->type = s->type; - n->label = op; - dagnode_add_children (dag, n, operands, children); - dagnode_set_edges (dag, n); + if (s->type != st_assign) { + if (!(n = dagnode_search (dag, op, children))) { + n = new_node (dag); + n->type = s->type; + n->label = op; + dagnode_add_children (dag, n, operands, children); + dagnode_set_edges (dag, n); + } } lx = operand_label (dag, operands[0]); if (lx && lx->dagnode != n) { @@ -753,7 +775,12 @@ dag_create (flownode_t *flownode) labels = malloc (dag->num_labels * sizeof (daglabel_t *)); memcpy (labels, dag->labels, dag->num_labels * sizeof (daglabel_t *)); dag->labels = labels; - +#if 0 + if (options.block_dot.dags) { + flownode->dag = dag; + dump_dot ("raw-dags", flownode->graph, dump_dot_flow_dags); + } +#endif dag_remove_dead_vars (dag, live_vars); dag_sort_nodes (dag); set_delete (live_vars); @@ -821,7 +848,7 @@ static operand_t * fix_op_type (operand_t *op, type_t *type) { if (op && op->op_type != op_label && op->type != type) - op = alias_operand (type, op); + op = alias_operand (type, op, op->expr); return op; } @@ -867,21 +894,101 @@ generate_moveps (dag_t *dag, sblock_t *block, dagnode_t *dagnode) statement_t *st; operand_t *dst = 0; type_t *type; + int offset = 0; + def_t *dstDef; operands[0] = make_operand (dag, block, dagnode, 0); operands[1] = make_operand (dag, block, dagnode, 1); + if (dagnode->children[2]) { + operands[2] = make_operand (dag, block, dagnode, 2); + st = build_statement ("", operands, dagnode->label->expr); + sblock_add_statement (block, st); + if ((var_iter = set_first (dagnode->identifiers))) { + var = dag->labels[var_iter->element]; + dst = var->op; + set_del_iter (var_iter); + } + } else { + for (var_iter = set_first (dagnode->identifiers); var_iter; + var_iter = set_next (var_iter)) { + var = dag->labels[var_iter->element]; + dst = var->op; + type = dst->o.def->type; + dstDef = dst->o.def; + if (dstDef->alias) { + offset = dstDef->offset; + dstDef = dstDef->alias; + } + operands[2] = value_operand (new_pointer_val (offset, type, dstDef, 0), + operands[1]->expr); + st = build_statement ("", operands, var->expr); + sblock_add_statement (block, st); + } + } + return dst; +} + +static operand_t * +generate_memsets (dag_t *dag, sblock_t *block, dagnode_t *dagnode) +{ + set_iter_t *var_iter; + daglabel_t *var; + operand_t *operands[3] = {0, 0, 0}; + statement_t *st; + operand_t *dst; + + operands[0] = make_operand (dag, block, dagnode, 0); + operands[1] = make_operand (dag, block, dagnode, 1); + dst = operands[0]; for (var_iter = set_first (dagnode->identifiers); var_iter; var_iter = set_next (var_iter)) { var = dag->labels[var_iter->element]; - dst = var->op; - type = dst->o.def->type; - operands[2] = value_operand (new_pointer_val (0, type, dst->o.def)); - st = build_statement ("", operands, var->expr); + operands[2] = var->op; + dst = operands[2]; + st = build_statement ("", operands, var->expr); sblock_add_statement (block, st); } return dst; } +static operand_t * +generate_memsetps (dag_t *dag, sblock_t *block, dagnode_t *dagnode) +{ + set_iter_t *var_iter; + daglabel_t *var; + operand_t *operands[3] = {0, 0, 0}; + statement_t *st; + operand_t *dst = 0; + type_t *type; + int offset = 0; + def_t *dstDef; + + operands[0] = make_operand (dag, block, dagnode, 0); + operands[1] = make_operand (dag, block, dagnode, 1); + if (dagnode->children[2]) { + operands[2] = make_operand (dag, block, dagnode, 2); + st = build_statement ("", operands, dagnode->label->expr); + sblock_add_statement (block, st); + } else { + for (var_iter = set_first (dagnode->identifiers); var_iter; + var_iter = set_next (var_iter)) { + var = dag->labels[var_iter->element]; + dst = var->op; + type = dst->o.def->type; + dstDef = dst->o.def; + if (dstDef->alias) { + offset = dstDef->offset; + dstDef = dstDef->alias; + } + operands[2] = value_operand (new_pointer_val (offset, type, dstDef, 0), + operands[1]->expr); + st = build_statement ("", operands, var->expr); + sblock_add_statement (block, st); + } + } + return dst; +} + static operand_t * generate_assignments (dag_t *dag, sblock_t *block, operand_t *src, set_iter_t *var_iter, type_t *type) @@ -930,7 +1037,8 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode) operands[1] = make_operand (dag, block, dagnode, 1); type = get_type (dagnode->label->expr); if (!(var_iter = set_first (dagnode->identifiers))) { - operands[2] = temp_operand (get_type (dagnode->label->expr)); + operands[2] = temp_operand (get_type (dagnode->label->expr), + dagnode->label->expr); } else { daglabel_t *var = dag->labels[var_iter->element]; @@ -957,16 +1065,17 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode) dst = operands[0]; break; case st_move: - if (!strcmp (dagnode->label->opcode, "")) { - dst = generate_moves (dag, block, dagnode); - break; - } - if (!strcmp (dagnode->label->opcode, "") - && !dagnode->children[2]) { - dst = generate_moveps (dag, block, dagnode); - break; - } - //fall through + dst = generate_moves (dag, block, dagnode); + break; + case st_ptrmove: + dst = generate_moveps (dag, block, dagnode); + break; + case st_memset: + dst = generate_memsets (dag, block, dagnode); + break; + case st_ptrmemset: + dst = generate_memsetps (dag, block, dagnode); + break; case st_state: case st_func: for (i = 0; i < 3; i++) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 6e545ba40..2fbf0bf08 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -153,6 +153,7 @@ new_def (const char *name, type_t *type, defspace_t *space, if (!size) { error (0, "%s has incomplete type", name); size = 1; + alignment = 1; } if (alignment < 1) { print_type (type); @@ -286,106 +287,118 @@ def_to_ddef (def_t *def, ddef_t *ddef, int aux) ddef->s_name = ReuseString (def->name); } +static int +zero_memory (expr_t *local_expr, def_t *def, type_t *zero_type, + int init_size, int init_offset) +{ + int zero_size = type_size (zero_type); + expr_t *zero = convert_nil (new_nil_expr (), zero_type); + expr_t *dst; + + for (; init_offset < init_size + 1 - zero_size; init_offset += zero_size) { + dst = new_def_expr (def); + dst = new_offset_alias_expr (zero_type, dst, init_offset); + append_expr (local_expr, assign_expr (dst, zero)); + } + return init_offset; +} + +static void +init_elements_nil (def_t *def) +{ + if (def->local && local_expr) { + // memset to 0 + int init_size = type_size (def->type); + int init_offset = 0; + + if (options.code.progsversion != PROG_ID_VERSION) { + init_offset = zero_memory (local_expr, def, &type_zero, + init_size, init_offset); + } + // probably won't happen any time soon, but who knows... + if (options.code.progsversion != PROG_ID_VERSION + && init_size - init_offset >= type_size (&type_quaternion)) { + init_offset = zero_memory (local_expr, def, &type_quaternion, + init_size, init_offset); + } + if (init_size - init_offset >= type_size (&type_vector)) { + init_offset = zero_memory (local_expr, def, &type_vector, + init_size, init_offset); + } + if (options.code.progsversion != PROG_ID_VERSION + && init_size - init_offset >= type_size (&type_double)) { + init_offset = zero_memory (local_expr, def, &type_double, + init_size, init_offset); + } + if (init_size - init_offset >= type_size (type_default)) { + zero_memory (local_expr, def, type_default, + init_size, init_offset); + } + } + // it's a global, so already initialized to 0 +} + static void init_elements (struct def_s *def, expr_t *eles) { - expr_t *e, *c; - int count, i, num_elements, base_offset; + expr_t *c; pr_type_t *g; - def_t *elements; + element_chain_t element_chain; + element_t *element; - base_offset = def->offset; - if (def->local && local_expr) - base_offset = 0; - if (is_array (def->type)) { - type_t *array_type = def->type->t.array.type; - int array_size = def->type->t.array.size; - elements = calloc (array_size, sizeof (def_t)); - for (i = 0; i < array_size; i++) { - elements[i].type = array_type; - elements[i].space = def->space; - elements[i].offset = base_offset + i * type_size (array_type); - } - num_elements = i; - } else if (is_struct (def->type) - || def->type == &type_vector - || def->type == &type_quaternion) { - symtab_t *symtab = def->type->t.symtab; - symbol_t *field; - - for (i = 0, field = symtab->symbols; field; field = field->next) { - if (field->sy_type != sy_var) - continue; - i++; - } - elements = calloc (i, sizeof (def_t)); - for (i = 0, field = symtab->symbols; field; field = field->next) { - if (field->sy_type != sy_var) - continue; - elements[i].type = field->type; - elements[i].space = def->space; - elements[i].offset = base_offset + field->s.offset; - i++; - } - num_elements = i; - } else { - error (eles, "invalid initializer"); + if (eles->type == ex_nil) { + init_elements_nil (def); return; } - for (count = 0, e = eles->e.block.head; e; count++, e = e->next) { - convert_name (e); - if (e->type == ex_nil && count < num_elements) - convert_nil (e, elements[count].type); - if (e->type == ex_error) { - free (elements); - return; - } - } - if (count > num_elements) { - if (options.warnings.initializer) - warning (eles, "excessive elements in initializer"); - count = num_elements; - } - for (i = 0, e = eles->e.block.head; i < count; i++, e = e->next) { - g = D_POINTER (pr_type_t, &elements[i]); - c = constant_expr (e); - if (c->type == ex_block) { - if (!is_array (elements[i].type) - && !is_struct (elements[i].type)) { - error (e, "type mismatch in initializer"); - continue; - } - init_elements (&elements[i], c); - continue; - } else if (c->type == ex_labelref) { - def_t loc; - loc.space = elements[i].space; - loc.offset = elements[i].offset; - reloc_def_op (c->e.labelref.label, &loc); - continue; - } else if (c->type == ex_value) { - if (c->e.value->lltype == ev_integer - && elements[i].type->type == ev_float) - convert_int (c); - if (get_type (c) != elements[i].type) { - error (e, "type mismatch in initializer"); - continue; - } - } else { - if (!def->local || !local_expr) { - error (e, "non-constant initializer"); - continue; - } - } - if (def->local && local_expr) { - int offset = elements[i].offset; - type_t *type = elements[i].type; - expr_t *ptr = new_pointer_expr (offset, type, def); - append_expr (local_expr, assign_expr (unary_expr ('.', ptr), c)); - } else { - if (c->type != ex_value) + element_chain.head = 0; + element_chain.tail = &element_chain.head; + build_element_chain (&element_chain, def->type, eles, 0); + + if (def->local && local_expr) { + expr_t *dst = new_def_expr (def); + assign_elements (local_expr, dst, &element_chain); + } else { + def_t dummy = *def; + for (element = element_chain.head; element; element = element->next) { + if (!element->expr + || ((c = constant_expr (element->expr))->type == ex_nil)) { + // nil is type agnostic 0 and defspaces are initialized to + // 0 on creation + continue; + } + if (c->type == ex_nil) { + c = convert_nil (c, element->type); + } + dummy.offset = def->offset + element->offset; + g = D_POINTER (pr_type_t, &dummy); + if (c->type == ex_labelref) { + // reloc_def_* use only the def's offset and space, so dummy + // is ok + reloc_def_op (c->e.labelref.label, &dummy); + continue; + } else if (c->type == ex_value) { + if (c->e.value->lltype == ev_integer + && is_float (element->type)) { + convert_int (c); + } + if (is_double (get_type (c)) && is_float (element->type) + && c->implicit) { + convert_double (c); + } + if (get_type (c) != element->type) { + error (c, "type mismatch in initializer"); + continue; + } + } else { + if (!def->local || !local_expr) { + error (c, "non-constant initializer"); + continue; + } + } + if (c->type != ex_value) { internal_error (c, "bogus expression type in init_elements()"); + } if (c->e.value->lltype == ev_string) { EMIT_STRING (def->space, g->string_var, c->e.value->v.string_val); @@ -394,7 +407,8 @@ init_elements (struct def_s *def, expr_t *eles) } } } - free (elements); + + free_element_chain (&element_chain); } static void @@ -523,7 +537,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, internal_error (0, "half defined var"); if (storage == sc_extern) { if (init) - warning (0, "initializing external variable"); + error (0, "initializing external variable"); return; } if (init && check->s.def->initialized) { @@ -545,7 +559,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, } if (!sym->s.def) { if (is_array (sym->type) && !type_size (sym->type) - && init->type == ex_block && !init->e.block.result) { + && init->type == ex_compound) { sym->type = array_type (sym->type->t.array.type, num_elements (init)); } @@ -559,7 +573,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, init_field_def (sym->s.def, init, storage); if (storage == sc_extern) { if (init) - warning (0, "initializing external variable"); + error (0, "initializing external variable"); return; } if (!init) @@ -567,15 +581,18 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, convert_name (init); if (init->type == ex_error) return; - if (init->type == ex_nil) - convert_nil (init, sym->type); if ((is_array (sym->type) || is_struct (sym->type) || sym->type == &type_vector || sym->type == &type_quaternion) - && init->type == ex_block && !init->e.block.result) { + && ((init->type == ex_compound) + || init->type == ex_nil)) { init_elements (sym->s.def, init); sym->s.def->initialized = 1; } else { - type_t *init_type = get_type (init); + type_t *init_type; + if (init->type == ex_nil) { + convert_nil (init, sym->type); + } + init_type = get_type (init); if (!type_assignable (sym->type, init_type)) { error (init, "type mismatch in initializer"); return; @@ -610,7 +627,8 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, reloc_def_field (init->e.value->v.pointer.def, sym->s.def); } else { ex_value_t *v = init->e.value; - if (is_double (init_type) + if (!init->implicit + && is_double (init_type) && (is_integral (sym->type) || is_float (sym->type))) { warning (init, "assigning double to %s in initializer " "(use a cast)", sym->type->name); @@ -626,7 +644,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, } } sym->s.def->initialized = 1; - if (options.traditional) { + if (options.code.const_initializers) { sym->s.def->constant = 1; sym->s.def->nosave = 1; } @@ -696,6 +714,8 @@ def_visit_all (def_t *def, int overlap, def = def->alias; if ((ret = visit (def, data))) return ret; + } else { + overlap = 0; } for (def = def->alias_defs; def; def = def->next) { if (def == start_def) diff --git a/tools/qfcc/source/diagnostic.c b/tools/qfcc/source/diagnostic.c index d38c1eecb..ab830280a 100644 --- a/tools/qfcc/source/diagnostic.c +++ b/tools/qfcc/source/diagnostic.c @@ -99,17 +99,22 @@ static __attribute__((format(printf, 4, 0))) void __warning (expr_t *e, const char *file, int line, const char *fmt, va_list args) { + static int promoted = 0; dstring_t *message = dstring_new (); report_function (e); if (options.warnings.promote) { - options.warnings.promote = 0; // want to do this only once - fprintf (stderr, "%s: warnings treated as errors\n", "qfcc"); + if (!promoted) { + promoted = 1; // want to do this only once + fprintf (stderr, "%s: warnings treated as errors\n", "qfcc"); + } pr.error_count++; + format_message (message, "error", e, fmt, args); + } else { + format_message (message, "warning", e, fmt, args); } - format_message (message, "warning", e, fmt, args); - if (options.verbosity > 1) { + if (options.verbosity > 0) { dasprintf (message, " (%s:%d)", file, line); } if (warning_hook) { @@ -125,7 +130,7 @@ _debug (expr_t *e, const char *file, int line, const char *fmt, ...) { va_list args; - if (options.verbosity < 1) + if (options.verbosity < 2) return; report_function (e); @@ -203,7 +208,7 @@ _notice (expr_t *e, const char *file, int line, const char *fmt, ...) report_function (e); format_message (message, "notice", e, fmt, args); - if (options.verbosity > 1) { + if (options.verbosity > 0) { dasprintf (message, " (%s:%d)", file, line); } if (notice_hook) { @@ -252,7 +257,7 @@ _error (expr_t *e, const char *file, int line, const char *fmt, ...) dstring_t *message = dstring_new (); format_message (message, "error", e, fmt, args); - if (options.verbosity > 1) { + if (options.verbosity > 0) { dasprintf (message, " (%s:%d)", file, line); } if (error_hook) { diff --git a/tools/qfcc/source/dot_dag.c b/tools/qfcc/source/dot_dag.c index bf0e26c63..e954f75d3 100644 --- a/tools/qfcc/source/dot_dag.c +++ b/tools/qfcc/source/dot_dag.c @@ -176,6 +176,7 @@ dot_dump_dag (void *_dag, const char *filename) dstring_t *dstr = dstring_newstr(); dasprintf (dstr, "digraph dag_%p {\n", dag); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); dasprintf (dstr, " layout=dot;\n"); dasprintf (dstr, " clusterrank=local;\n"); dasprintf (dstr, " rankdir=TB;\n"); diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index 081dbecec..27d535845 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -62,18 +62,20 @@ const char *expr_names[] = "block", "expr", "uexpr", + "def", "symbol", "temp", "vector", "nil", "value", + "compound", + "memset", }; const char * get_op_string (int op) { switch (op) { - case PAS: return ".="; case OR: return "||"; case AND: return "&&"; case EQ: return "=="; @@ -353,6 +355,15 @@ print_uexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) dstring_delete (typestr); } +static void +print_def (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + int indent = level * 2 + 2; + + dasprintf (dstr, "%*se_%p [label=\"d %s\\n%d\"];\n", indent, "", e, + e->e.def->name, e->line); +} + static void print_symbol (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) { @@ -506,6 +517,29 @@ print_value (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) e->line); } +static void +print_compound (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + int indent = level * 2 + 2; + dasprintf (dstr, "%*se_%p [label=\"compound init\"];\n", indent, "", e); +} + +static void +print_memset (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + int indent = level * 2 + 2; + expr_t *dst = e->e.memset.dst; + expr_t *val = e->e.memset.val; + expr_t *count = e->e.memset.count; + _print_expr (dstr, dst, level, id, next); + _print_expr (dstr, val, level, id, next); + _print_expr (dstr, count, level, id, next); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, dst); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, val); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, count); + dasprintf (dstr, "%*se_%p [label=\"memset\"];\n", indent, "", e); +} + static void _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) { @@ -518,11 +552,14 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) print_block, print_subexpr, print_uexpr, + print_def, print_symbol, print_temp, print_vector, print_nil, print_value, + print_compound, + print_memset, }; int indent = level * 2 + 2; @@ -534,7 +571,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) return; e->printid = id; - if ((int) e->type < 0 || e->type > ex_value) { + if ((int) e->type < 0 || e->type > ex_memset) { dasprintf (dstr, "%*se_%p [label=\"(bad expr type)\\n%d\"];\n", indent, "", e, e->line); return; @@ -551,6 +588,7 @@ dump_dot_expr (void *_e, const char *filename) expr_t *e = (expr_t *) _e; dasprintf (dstr, "digraph expr_%p {\n", e); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); dasprintf (dstr, " layout=dot; rankdir=TB; compound=true;\n"); _print_expr (dstr, e, 0, ++id, 0); dasprintf (dstr, "}\n"); diff --git a/tools/qfcc/source/dot_flow.c b/tools/qfcc/source/dot_flow.c index d702f7b9e..68f043d98 100644 --- a/tools/qfcc/source/dot_flow.c +++ b/tools/qfcc/source/dot_flow.c @@ -332,6 +332,7 @@ print_flowgraph (flow_dot_t *method, flowgraph_t *graph, const char *filename) dstring_t *dstr = dstring_newstr(); dasprintf (dstr, "digraph flowgraph_%s_%p {\n", method->type, graph); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); dasprintf (dstr, " layout=dot;\n"); dasprintf (dstr, " clusterrank=local;\n"); dasprintf (dstr, " rankdir=TB;\n"); diff --git a/tools/qfcc/source/dot_sblock.c b/tools/qfcc/source/dot_sblock.c index 72b245efe..8e003aa6b 100644 --- a/tools/qfcc/source/dot_sblock.c +++ b/tools/qfcc/source/dot_sblock.c @@ -41,6 +41,7 @@ #include #include +#include #include #include "dags.h" @@ -62,6 +63,30 @@ flow_statement (dstring_t *dstr, statement_t *s) dasprintf (dstr, "%s", html_string(operand_string (s->opa))); dasprintf (dstr, "%s", html_string(operand_string (s->opb))); dasprintf (dstr, "%s", html_string(operand_string (s->opc))); +#if 0 + if (s->number >= 0) { + set_t *use = set_new (); + set_t *def = set_new (); + set_t *kill = set_new (); + set_t *ops = set_new (); + operand_t *operands[FLOW_OPERANDS]; + + flow_analyze_statement (s, use, def, kill, operands); + for (int i = 0; i < FLOW_OPERANDS; i++) { + if (operands[i]) { + set_add (ops, i); + } + } + dasprintf (dstr, "%s", html_string(set_as_string (use))); + dasprintf (dstr, "%s", html_string(set_as_string (def))); + dasprintf (dstr, "%s", html_string(set_as_string (kill))); + dasprintf (dstr, "%s", html_string(set_as_string (ops))); + + set_delete (use); + set_delete (def); + set_delete (kill); + } +#endif dasprintf (dstr, "\n"); } @@ -77,11 +102,10 @@ dot_sblock (dstring_t *dstr, sblock_t *sblock, int blockno) dasprintf (dstr, " \n"); dasprintf (dstr, " %p(%d)\n", sblock, blockno); - dasprintf (dstr, " \n"); + dasprintf (dstr, " \n"); for (l = sblock->labels; l; l = l->next) dasprintf (dstr, " %s(%d)\n", l->name, l->used); dasprintf (dstr, " \n"); - dasprintf (dstr, " \n"); dasprintf (dstr, " \n"); for (s = sblock->statements; s; s = s->next) flow_statement (dstr, s); @@ -128,6 +152,7 @@ print_sblock (sblock_t *sblock, const char *filename) dstring_t *dstr = dstring_newstr(); dasprintf (dstr, "digraph sblock_%p {\n", sblock); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); dasprintf (dstr, " layout=dot; rankdir=TB;\n"); for (i = 0; sblock; sblock = sblock->next, i++) flow_sblock (dstr, sblock, i); diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index 9e0b5bd5f..9b5900454 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -52,14 +52,14 @@ static int cmp (const void *_a, const void *_b) { - const ddef_t *a = (const ddef_t *)_a; - const ddef_t *b = (const ddef_t *)_b; + const pr_def_t *a = (const pr_def_t *)_a; + const pr_def_t *b = (const pr_def_t *)_b; return a->ofs - b->ofs; } static void -dump_def (progs_t *pr, ddef_t *def, int indent) +dump_def (progs_t *pr, pr_def_t *def, int indent) { const char *name; const char *type; @@ -69,10 +69,10 @@ dump_def (progs_t *pr, ddef_t *def, int indent) const char *str; int saveglobal; - if (!def->type && !def->ofs && !def->s_name) + if (!def->type && !def->ofs && !def->name) return; - name = PR_GetString (pr, def->s_name); + name = PR_GetString (pr, def->name); type = pr_type_name[def->type & ~DEF_SAVEGLOBAL]; saveglobal = (def->type & DEF_SAVEGLOBAL) != 0; offset = def->ofs; @@ -86,7 +86,12 @@ dump_def (progs_t *pr, ddef_t *def, int indent) break; case ev_string: string = G_INT (pr, offset); - if (string < 0 || string >= pr->progs->numstrings) { + // at runtime, strings can be negative (thus string_t is + // signed), but negative strings means they have been + // dynamically allocated, thus a negative string index should + // never appear in compiled code + if (string < 0 + || (pr_uint_t) string >= pr->progs->numstrings) { str = "invalid string offset"; comment = va (" %d %s", string, str); } else { @@ -115,7 +120,7 @@ dump_def (progs_t *pr, ddef_t *def, int indent) { func_t func = G_FUNCTION (pr, offset); int start; - if (func >= 0 && func < pr->progs->numfunctions) { + if (func < pr->progs->numfunctions) { start = pr->pr_functions[func].first_statement; if (start > 0) comment = va (" %d @ %x", func, start); @@ -148,15 +153,16 @@ dump_def (progs_t *pr, ddef_t *def, int indent) break; } } - printf ("%*s %x %d %s %s%s\n", indent * 12, "", - offset, saveglobal, name, type, comment); + printf ("%*s %x:%d %d %s %s:%x %s\n", indent * 12, "", + offset, def->size, saveglobal, name, type, def->type_encoding, + comment); } void dump_globals (progs_t *pr) { unsigned int i; - ddef_t *global_defs = pr->pr_globaldefs; + pr_def_t *global_defs = pr->pr_globaldefs; if (sorted) { global_defs = malloc (pr->progs->numglobaldefs * sizeof (ddef_t)); @@ -165,7 +171,7 @@ dump_globals (progs_t *pr) qsort (global_defs, pr->progs->numglobaldefs, sizeof (ddef_t), cmp); } for (i = 0; i < pr->progs->numglobaldefs; i++) { - ddef_t *def = &global_defs[i]; + pr_def_t *def = &global_defs[i]; dump_def (pr, def, 0); } } @@ -180,9 +186,9 @@ dump_fields (progs_t *pr) const char *comment; for (i = 0; i < pr->progs->numfielddefs; i++) { - ddef_t *def = &pr->pr_fielddefs[i]; + pr_def_t *def = &pr->pr_fielddefs[i]; - name = PR_GetString (pr, def->s_name); + name = PR_GetString (pr, def->name); type = pr_type_name[def->type & ~DEF_SAVEGLOBAL]; offset = def->ofs; @@ -192,13 +198,55 @@ dump_fields (progs_t *pr) } } +void +qfo_fields (qfo_t *qfo) +{ + unsigned int i; + const char *name; + const char *typestr; + qfot_type_t *type; + int offset; + const char *comment; + qfo_mspace_t *space = &qfo->spaces[qfo_entity_space]; + + if (qfo_entity_space >= qfo->num_spaces) { + printf ("no entity space\n"); + return; + } + if (!space->num_defs) { + printf ("no fields\n"); + return; + } + + for (i = 0; i < space->num_defs; i++) { + qfo_def_t *def = space->defs + i; + + name = QFO_GETSTR (qfo, def->name); + //FIXME check type + type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, def->type); + typestr = QFO_GETSTR (qfo, type->encoding); + offset = def->offset; + + comment = ""; + + printf ("%d %s %s%s\n", offset, name, typestr, comment); + } +} + void dump_functions (progs_t *pr) { - int i, j; + pr_uint_t i, j, count; const char *name; - int start, count; + int start; const char *comment; + pr_def_t *encodings_def; + pointer_t type_encodings = 0; + + encodings_def = PR_FindGlobal (pr, ".type_encodings"); + if (encodings_def) { + type_encodings = encodings_def->ofs; + } for (i = 0; i < pr->progs->numfunctions; i++) { dfunction_t *func = &pr->pr_functions[i]; @@ -221,17 +269,23 @@ dump_functions (progs_t *pr) func->parm_size[j].size); printf (") %d @ %x", func->locals, func->parm_start); puts (""); - if (pr->debug) { - pr_auxfunction_t *aux = pr->auxfunction_map[i]; - if (!aux) + if (type_encodings) { + pr_auxfunction_t *aux = PR_Debug_MappedAuxFunction (pr, i); + if (!aux) { continue; + } printf (" %d %s:%d %d %d %d %x\n", aux->function, PR_GetString (pr, func->s_file), aux->source_line, aux->line_info, aux->local_defs, aux->num_locals, aux->return_type); - for (j = 0; j < (int)aux->num_locals; j++) - dump_def (pr, pr->local_defs + aux->local_defs + j, 1); + pr_def_t *local_defs = PR_Debug_LocalDefs (pr, aux); + if (!local_defs) { + continue; + } + for (j = 0; j < aux->num_locals; j++) { + dump_def (pr, local_defs + j, 1); + } } } } @@ -284,6 +338,8 @@ qfo_relocs (qfo_t *qfo) qfo_reloc_t *reloc; qfo_def_t *def; qfo_func_t *func; + int opind; + dstatement_t *statement; unsigned i; for (i = 0; i < qfo->num_relocs; i++) { @@ -346,10 +402,13 @@ qfo_relocs (qfo_t *qfo) case rel_op_b_def_ofs: case rel_op_c_def_ofs: def = qfo->defs + reloc->target; - printf (" op.%c@%x def#%d %s", - reloc->type - rel_op_a_def_ofs + 'a', + opind = reloc->type - rel_op_a_def_ofs; + statement = QFO_STATEMENT (qfo, reloc->offset); + printf (" op.%c@%x def#%d %s+%d", + opind + 'a', reloc->offset, reloc->target, - QFO_GETSTR (qfo, def->name)); + QFO_GETSTR (qfo, def->name), + ((pr_ushort_t *)statement)[opind + 1]); break; case rel_def_def_ofs: def = qfo->defs + reloc->target; @@ -417,12 +476,13 @@ qfo_functions (qfo_t *qfo) } static const char *ty_meta_names[] = { - "ty_none", + "ty_basic", "ty_struct", "ty_union", "ty_enum", "ty_array", "ty_class", + "ty_alias", }; #define NUM_META ((int)(sizeof (ty_meta_names) / sizeof (ty_meta_names[0]))) @@ -460,7 +520,7 @@ dump_qfo_types (qfo_t *qfo, int base_address) break; } switch ((ty_meta_e) type->meta) { - case ty_none: + case ty_basic: printf (" %-10s", (type->t.type < 0 || type->t.type >= ev_type_count) ? "invalid type" @@ -511,7 +571,7 @@ dump_types (progs_t *pr) { qfo_mspace_t spaces[qfo_num_spaces]; qfo_t qfo; - ddef_t *encodings_def; + pr_def_t *encodings_def; qfot_type_encodings_t *encodings; encodings_def = PR_FindGlobal (pr, ".type_encodings"); diff --git a/tools/qfcc/source/dump_lines.c b/tools/qfcc/source/dump_lines.c index 847bdb5c2..966203a72 100644 --- a/tools/qfcc/source/dump_lines.c +++ b/tools/qfcc/source/dump_lines.c @@ -41,49 +41,152 @@ #include #include "QF/progs.h" +#include "QF/pr_type.h" +#include "obj_file.h" #include "qfprogs.h" -void -dump_lines (progs_t *pr) +typedef struct { + const char *source_name; + const char *source_file; + pr_uint_t source_line; + pr_int_t first_statement; + pointer_t return_type; + pr_uint_t local_defs; + pr_uint_t num_locals; + pr_uint_t line_info; + pr_uint_t function; +} func_data_t; + +typedef func_data_t *(*get_func_data_t)(unsigned func, void *data); + +static func_data_t * +progs_get_func_data (unsigned func_index, void *data) { - unsigned int i, line, addr; - pr_lineno_t *lineno; - pr_auxfunction_t *aux_func = 0; - dfunction_t *func = 0; + static func_data_t func_data; + progs_t *pr = (progs_t *) data; + pr_auxfunction_t *aux_func; + dfunction_t *func; - if (!pr->debug) - return; - for (i = 0; i < pr->debug->num_linenos; i++) { - lineno = &pr->linenos[i]; + memset (&func_data, 0, sizeof (func_data)); + aux_func = PR_Debug_AuxFunction (pr, func_index); + if (aux_func) { + func_data.source_line = aux_func->source_line; + func_data.return_type = aux_func->return_type; + func_data.num_locals = aux_func->num_locals; + func_data.local_defs = aux_func->local_defs; + func_data.line_info = aux_func->line_info; + func_data.function = aux_func->function; + if (aux_func->function < (unsigned int) pr->progs->numfunctions) { + func = pr->pr_functions + aux_func->function; + func_data.source_file = pr->pr_strings + func->s_file; + func_data.source_name = pr->pr_strings + func->s_name; + func_data.first_statement = func->first_statement; + } + return &func_data; + } + return 0; +} +static void +dump_line_set (pr_lineno_t *lineno, unsigned count, + get_func_data_t get_func_data, void *data) +{ + unsigned int line, addr; + func_data_t *func_data = 0; + + for (; count-- > 0; lineno++) { if (!lineno->line) { - aux_func = 0; - func = 0; - if (lineno->fa.func < pr->debug->num_auxfunctions) - aux_func = pr->auxfunctions + lineno->fa.func; - if (aux_func - && aux_func->function < (unsigned int) pr->progs->numfunctions) - func = pr->pr_functions + aux_func->function; + func_data = get_func_data(lineno->fa.func, data); } printf ("%5u %5u", lineno->fa.addr, lineno->line); line = addr = -1; - if (aux_func) - line = aux_func->source_line + lineno->line; - if (func) - addr = lineno->line ? lineno->fa.addr - : (unsigned int) func->first_statement; - if (aux_func && func) - printf (" %05x %s:%u %s+%u %d", addr, pr->pr_strings + func->s_file, - line, pr->pr_strings + func->s_name, - addr - func->first_statement, aux_func->return_type); - else if (aux_func) - printf ("%u %u %u %u %u %d", aux_func->function, line, - aux_func->line_info, aux_func->local_defs, - aux_func->num_locals, aux_func->return_type); - else if (lineno->line) + if (func_data) { + line = func_data->source_line + lineno->line; + if (func_data->source_name) { + addr = lineno->line ? (pr_int_t) lineno->fa.addr + : func_data->first_statement; + printf (" %05x %s:%u %s+%u %d", addr, func_data->source_file, + line, func_data->source_name, + addr - func_data->first_statement, + func_data->return_type); + } else { + printf ("%u %u %u %u %u %d", func_data->function, line, + func_data->line_info, func_data->local_defs, + func_data->num_locals, func_data->return_type); + } + } else if (lineno->line) { printf ("%5x", lineno->fa.addr); + } printf ("\n"); } } + +void +dump_lines (progs_t *pr) +{ + pr_lineno_t *linenos; + pr_uint_t num_linenos; + if (!(linenos = PR_Debug_Linenos (pr, 0, &num_linenos))) + return; + dump_line_set (linenos, num_linenos, progs_get_func_data, pr); +} + +static func_data_t * +qfo_get_func_data (unsigned func_index, void *data) +{ + return (func_data_t *) data; +} + +static void +qfo_set_func_data (qfo_t *qfo, qfo_func_t *func, func_data_t *func_data) +{ + qfot_type_t *type; + + func_data->source_line = func->line; + //FIXME check type + type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, func->type); + func_data->return_type = type->t.func.return_type; + func_data->num_locals = -1; + if (func->locals_space < qfo->num_spaces) { + func_data->num_locals = qfo->spaces[func->locals_space].num_defs; + } + func_data->local_defs = func->locals_space; + func_data->line_info = func->line_info; + func_data->function = func - qfo->funcs; + func_data->source_file = QFO_GETSTR (qfo, func->file); + func_data->source_name = QFO_GETSTR (qfo, func->name); + func_data->first_statement = func->code; +} + +void +qfo_lines (qfo_t *qfo) +{ + static func_data_t func_data; + pr_lineno_t *start_lineno = 0; + pr_lineno_t *lineno; + qfo_func_t *func = 0; + + for (func = qfo->funcs; func - qfo->funcs < qfo->num_funcs; func++) { + if (!func->line_info) { + // builtin + continue; + } + if (func->line_info >= qfo->num_lines) { + printf ("%s: bad line info: %u >= %u\n", + QFO_GETSTR (qfo, func->name), + func->line_info, qfo->num_lines); + continue; + } + qfo_set_func_data(qfo, func, &func_data); + start_lineno = qfo->lines + func->line_info; + for (lineno = start_lineno + 1; + lineno - qfo->lines < qfo->num_lines && lineno->line; + lineno++) + { + } + dump_line_set (start_lineno, lineno-start_lineno, + qfo_get_func_data, &func_data); + } +} diff --git a/tools/qfcc/source/dump_modules.c b/tools/qfcc/source/dump_modules.c index d55195aaa..68cee44eb 100644 --- a/tools/qfcc/source/dump_modules.c +++ b/tools/qfcc/source/dump_modules.c @@ -89,22 +89,41 @@ dump_selector (progs_t *pr, pr_sel_t *sel) printf (" %s\n", sel_types); } +static void +dump_method_description_list (progs_t *pr, char c, + pr_method_description_list_t *list) +{ + if (list) { + for (int i = 0; i < list->count; i++) { + printf ("%*s%s\n", 20, "", PR_GetString (pr, list->list[i].name)); + printf ("%*s%s\n", 20, "", PR_GetString (pr, list->list[i].types)); + } + } +} + static void dump_protocol (progs_t *pr, pr_protocol_t *proto) { const char *protocol_name = ""; - printf (" %d ", proto->class_pointer); + printf (" %x %x ", + (pointer_t) ((pr_int_t *) proto - (pr_int_t *) pr->pr_globals), + proto->class_pointer); if (PR_StringValid (pr, proto->protocol_name)) protocol_name = PR_GetString (pr, proto->protocol_name); printf ("<%s>\n", protocol_name); + dump_method_description_list (pr, '-', + &G_STRUCT (pr, pr_method_description_list_t, + proto->instance_methods)); + dump_method_description_list (pr, '-', + &G_STRUCT (pr, pr_method_description_list_t, + proto->class_methods)); } static void dump_protocol_list (progs_t *pr, pr_protocol_list_t *list) { int i; - printf (" %d\n", list->next); - printf (" %d\n", list->count); + printf (" %x %d\n", list->next, list->count); for (i = 0; i < list->count; i++) { if (list->list[i] <= 0 || list->list[i] >= pr->globals_size) { printf ("invalid pointer\n"); @@ -171,6 +190,32 @@ dump_category (progs_t *pr, pr_category_t *category) category->protocols)); } +static void +dump_static_instance_lists (progs_t *pr, pointer_t instance_lists) +{ + pointer_t *ptr = &G_STRUCT (pr, pointer_t, instance_lists); + + printf (" static instance lists @ %x\n", instance_lists); + while (*ptr) { + __auto_type list = &G_STRUCT (pr, pr_static_instances_t, *ptr); + const char *class_name = "*** INVALID ***"; + + if (PR_StringValid (pr, list->class_name)) { + class_name = PR_GetString (pr, list->class_name); + } + printf (" %x %s\n", *ptr, class_name); + for (int i = 0; list->instances[i]; i++) { + if (!strcmp (class_name, "Protocol")) { + dump_protocol (pr, &G_STRUCT (pr, pr_protocol_t, + list->instances[i])); + } else { + printf (" %x\n", list->instances[i]); + } + } + ptr++; + } +} + static void dump_module (progs_t *pr, pr_module_t *module) { @@ -197,6 +242,9 @@ dump_module (progs_t *pr, pr_module_t *module) dump_class (pr, &G_STRUCT (pr, pr_class_t, *ptr++)); for (i = 0; i < symtab->cat_def_cnt; i++) dump_category (pr, &G_STRUCT (pr, pr_category_t, *ptr++)); + if (*ptr) { + dump_static_instance_lists (pr, *ptr); + } } void @@ -205,11 +253,11 @@ dump_modules (progs_t *pr) unsigned int i; for (i = 0; i < pr->progs->numglobaldefs; i++) { - ddef_t *def = &pr->pr_globaldefs[i]; + pr_def_t *def = &pr->pr_globaldefs[i]; const char *name = ""; - if (PR_StringValid (pr, def->s_name)) - name = PR_GetString (pr, def->s_name); + if (PR_StringValid (pr, def->name)) + name = PR_GetString (pr, def->name); if (strcmp (name, "_OBJ_MODULE") == 0) { printf ("module @ %x\n", def->ofs); dump_module (pr, &G_STRUCT (pr, pr_module_t, def->ofs)); diff --git a/tools/qfcc/source/dump_strings.c b/tools/qfcc/source/dump_strings.c index 91d6ca2ba..77f3c0ae4 100644 --- a/tools/qfcc/source/dump_strings.c +++ b/tools/qfcc/source/dump_strings.c @@ -36,21 +36,22 @@ #include "QF/progs.h" #include "QF/sys.h" +#include "obj_file.h" #include "qfprogs.h" -void -dump_strings (progs_t *pr) +static void +dump_string_block (const char *strblock, unsigned size) { - int i = 0; - char *s = pr->pr_strings; + const char *s = strblock; - printf ("%d ", 0); - while (i++ < pr->progs->numstrings) { - switch (*s) { + printf ("%x ", 0); + while (s - strblock < size) { + char c = *s++; + switch (c) { case 0: fputs ("\n", stdout); - if (i < pr->progs->numstrings) - printf ("%d ", i); + if (s - strblock < size) + printf ("%lx ", s - strblock); break; case 9: fputs ("\\t", stdout); @@ -62,9 +63,30 @@ dump_strings (progs_t *pr) fputs ("\\r", stdout); break; default: - fputc (sys_char_map[(unsigned char)*s], stdout); + fputc (sys_char_map[(unsigned char)c], stdout); break; } - s++; } } + +void +dump_strings (progs_t *pr) +{ + dump_string_block (pr->pr_strings, pr->progs->numstrings); +} + +void +qfo_strings (qfo_t *qfo) +{ + qfo_mspace_t *space = &qfo->spaces[qfo_strings_space]; + + if (qfo_strings_space >= qfo->num_spaces) { + printf ("no strings space\n"); + return; + } + if (!space->data_size) { + printf ("no strings\n"); + return; + } + dump_string_block (space->d.strings, space->data_size); +} diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index 253502206..e7a4b2465 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -60,16 +60,41 @@ static def_t zero_def; +static def_t *get_operand_def (expr_t *expr, operand_t *op); + static def_t * -get_value_def (ex_value_t *value, type_t *type) +get_tempop_def (expr_t *expr, operand_t *tmpop, type_t *type) +{ + tempop_t *tempop = &tmpop->o.tempop; + if (tempop->def) { + return tempop->def; + } + if (tempop->alias) { + def_t *tdef = get_operand_def (expr, tempop->alias); + int offset = tempop->offset; + tempop->def = alias_def (tdef, type, offset); + } + if (!tempop->def) { + tempop->def = temp_def (type); + } + return tempop->def; +} + +static def_t * +get_value_def (expr_t *expr, ex_value_t *value, type_t *type) { def_t *def; - if (type == &type_short) { + if (is_short (type)) { def = new_def (0, &type_short, 0, sc_extern); def->offset = value->v.short_val; return def; } + if (is_pointer (type) && value->v.pointer.tempop + && !value->v.pointer.def) { + value->v.pointer.def = get_tempop_def (expr, value->v.pointer.tempop, + type->t.fldptr.type); + } def = emit_value (value, 0); if (type != def->type) return alias_def (def, type, 0); @@ -85,28 +110,19 @@ get_operand_def (expr_t *expr, operand_t *op) case op_def: return op->o.def; case op_value: - return get_value_def (op->o.value, op->type); + return get_value_def (expr, op->o.value, op->type); case op_label: op->type = &type_short; zero_def.type = &type_short; return &zero_def; //FIXME case op_temp: - if (op->o.tempop.def) { - return op->o.tempop.def; - } - if (op->o.tempop.alias) { - def_t *tdef = get_operand_def (expr, op->o.tempop.alias); - int offset = op->o.tempop.offset; - type_t *type = op->type; - op->o.tempop.def = alias_def (tdef, type, offset); - } - if (!op->o.tempop.def) { - op->o.tempop.def = temp_def (op->type); - } - return op->o.tempop.def; + return get_tempop_def (expr, op, op->type); case op_alias: return get_operand_def (expr, op->o.alias); + case op_nil: + internal_error (expr, "unexpected nil operand"); } + internal_error (expr, "unexpected operand"); return 0; } diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 7d7e55a21..ac128e378 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -109,6 +109,10 @@ convert_name (expr_t *e) //FIXME need a def return; } + if (sym->sy_type == sy_convert) { + new = sym->s.convert.conv (sym, sym->s.convert.data); + goto convert; + } if (sym->sy_type == sy_expr) { new = copy_expr (sym->s.expr); goto convert; @@ -211,14 +215,21 @@ get_type (expr_t *e) switch (e->type) { case ex_labelref: return &type_void; + case ex_memset: + return e->e.memset.type; case ex_label: case ex_error: + case ex_compound: return 0; // something went very wrong case ex_bool: if (options.code.progsversion == PROG_ID_VERSION) return &type_float; return &type_integer; case ex_nil: + if (e->e.nil) { + return e->e.nil; + } + // fall through case ex_state: return &type_void; case ex_block: @@ -228,6 +239,8 @@ get_type (expr_t *e) case ex_expr: case ex_uexpr: return e->e.expr.type; + case ex_def: + return e->e.def->type; case ex_symbol: return e->e.symbol->type; case ex_temp: @@ -291,7 +304,7 @@ cast_error (expr_t *e, type_t *t1, type_t *t2) print_type_str (s1, t1); print_type_str (s2, t2); - e = error (e, "can not cast from %s to %s", s1->str, s2->str); + e = error (e, "cannot cast from %s to %s", s1->str, s2->str); dstring_delete (s1); dstring_delete (s2); return e; @@ -331,6 +344,7 @@ copy_expr (expr_t *e) return 0; switch (e->type) { case ex_error: + case ex_def: case ex_symbol: case ex_nil: case ex_value: @@ -416,28 +430,49 @@ copy_expr (expr_t *e) n = new_expr (); n->e.vector.type = e->e.vector.type; n->e.vector.list = copy_expr (e->e.vector.list); - n = n->e.vector.list; t = e->e.vector.list; + e = n->e.vector.list; while (t->next) { - n->next = copy_expr (t->next); - n = n->next; + e->next = copy_expr (t->next); + e = e->next; t = t->next; } return n; + case ex_compound: + n = new_expr (); + *n = *e; + for (element_t *i = e->e.compound.head; i; i = i->next) { + append_element (n, new_element (i->expr, i->symbol)); + } + return n; + case ex_memset: + n = new_expr (); + *n = *e; + n->e.memset.dst = copy_expr (e->e.memset.dst); + n->e.memset.val = copy_expr (e->e.memset.val); + n->e.memset.count = copy_expr (e->e.memset.count); + return n; } internal_error (e, "invalid expression"); } +expr_t * +expr_file_line (expr_t *dst, const expr_t *src) +{ + dst->file = src->file; + dst->line = src->line; + return dst; +} + const char * new_label_name (void) { static int label = 0; int lnum = ++label; const char *fname = current_func->sym->name; - char *lname; + const char *lname; - lname = nva ("$%s_%d", fname, lnum); - SYS_CHECKMEM (lname); + lname = save_string (va ("$%s_%d", fname, lnum)); return lname; } @@ -484,6 +519,31 @@ new_label_expr (void) return l; } +expr_t * +named_label_expr (symbol_t *label) +{ + symbol_t *sym; + expr_t *l; + + if (!current_func) { + // XXX this might be only an error + internal_error (0, "label defined outside of function scope"); + } + + sym = symtab_lookup (current_func->label_scope, label->name); + + if (sym) { + return sym->s.expr; + } + l = new_label_expr (); + l->e.label.name = save_string (va ("%s_%s", l->e.label.name, label->name)); + l->e.label.symbol = label; + label->sy_type = sy_expr; + label->s.expr = l; + symtab_addsymbol (current_func->label_scope, label); + return label->s.expr; +} + expr_t * new_label_ref (ex_label_t *label) { @@ -504,6 +564,7 @@ new_block_expr (void) b->type = ex_block; b->e.block.head = 0; b->e.block.tail = &b->e.block.head; + b->e.block.return_addr = __builtin_return_address (0); return b; } @@ -552,6 +613,15 @@ new_unary_expr (int op, expr_t *e1) return e; } +expr_t * +new_def_expr (def_t *def) +{ + expr_t *e = new_expr (); + e->type = ex_def; + e->e.def = def; + return e; +} + expr_t * new_symbol_expr (symbol_t *symbol) { @@ -655,15 +725,23 @@ new_vector_list (expr_t *e) case 3: // quaternion or vector. all expressions must be compatible with // a float (ie, a scalar) - for (t = e; t; t = t->next) - if (!is_scalar (get_type (t))) + for (t = e; t; t = t->next) { + if (t->type == ex_error) { + return t; + } + if (!is_scalar (get_type (t))) { return error (t, "invalid type for vector element"); + } + } vec = new_expr (); vec->type = ex_vector; vec->e.vector.type = type; vec->e.vector.list = e; break; case 2: + if (e->type == ex_error || e->next->type == ex_error) { + return e; + } if (is_scalar (get_type (e)) && is_scalar (get_type (e->next))) { // scalar, scalar // expand [x, y] to [x, y, 0] @@ -734,7 +812,7 @@ new_pointer_expr (int val, type_t *type, def_t *def) { expr_t *e = new_expr (); e->type = ex_value; - e->e.value = new_pointer_val (val, type, def); + e->e.value = new_pointer_val (val, type, def, 0); return e; } @@ -822,6 +900,12 @@ constant_expr (expr_t *e) return new; } +int +is_nil (expr_t *e) +{ + return e->type == ex_nil; +} + int is_string_val (expr_t *e) { @@ -955,98 +1039,167 @@ expr_quaternion (expr_t *e) int is_integer_val (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 1; - if (e->type == ex_value && e->e.value->lltype == ev_integer) + } + if (e->type == ex_value && e->e.value->lltype == ev_integer) { return 1; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const - && (e->e.symbol->type->type == ev_integer - || is_enum (e->e.symbol->type))) + && is_integral (e->e.symbol->type)) { return 1; + } + if (e->type == ex_def && e->e.def->constant + && is_integral (e->e.def->type)) { + return 1; + } return 0; } int expr_integer (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 0; - if (e->type == ex_value && e->e.value->lltype == ev_integer) + } + if (e->type == ex_value && e->e.value->lltype == ev_integer) { return e->e.value->v.integer_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const && (e->e.symbol->type->type == ev_integer - || is_enum (e->e.symbol->type))) + || is_enum (e->e.symbol->type))) { return e->e.symbol->s.value->v.integer_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var && e->e.symbol->s.def->constant - && is_integral (e->e.symbol->s.def->type)) + && is_integral (e->e.symbol->s.def->type)) { return D_INT (e->e.symbol->s.def); + } + if (e->type == ex_def && e->e.def->constant + && is_integral (e->e.def->type)) { + return D_INT (e->e.def); + } internal_error (e, "not an integer constant"); } +int +is_uinteger_val (expr_t *e) +{ + if (e->type == ex_nil) { + return 1; + } + if (e->type == ex_value && e->e.value->lltype == ev_uinteger) { + return 1; + } + if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const + && is_integral (e->e.symbol->type)) { + return 1; + } + if (e->type == ex_def && e->e.def->constant + && is_integral (e->e.def->type)) { + return 1; + } + return 0; +} + unsigned expr_uinteger (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 0; - if (e->type == ex_value && e->e.value->lltype == ev_uinteger) + } + if (e->type == ex_value && e->e.value->lltype == ev_uinteger) { return e->e.value->v.uinteger_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const - && e->e.symbol->type->type == ev_uinteger) + && e->e.symbol->type->type == ev_uinteger) { return e->e.symbol->s.value->v.uinteger_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var && e->e.symbol->s.def->constant - && is_integral (e->e.symbol->s.def->type)) + && is_integral (e->e.symbol->s.def->type)) { return D_INT (e->e.symbol->s.def); + } + if (e->type == ex_def && e->e.def->constant + && is_integral (e->e.def->type)) { + return D_INT (e->e.def); + } internal_error (e, "not an unsigned constant"); } int is_short_val (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 1; - if (e->type == ex_value && e->e.value->lltype == ev_short) + } + if (e->type == ex_value && e->e.value->lltype == ev_short) { return 1; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const - && e->e.symbol->type->type == ev_short) + && e->e.symbol->type->type == ev_short) { return 1; + } return 0; } short expr_short (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 0; - if (e->type == ex_value && e->e.value->lltype == ev_short) + } + if (e->type == ex_value && e->e.value->lltype == ev_short) { return e->e.value->v.short_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const - && e->e.symbol->type->type == ev_short) + && e->e.symbol->type->type == ev_short) { return e->e.symbol->s.value->v.short_val; + } internal_error (e, "not a short constant"); } -expr_t * -new_self_expr (void) +int +is_integral_val (expr_t *e) { - symbol_t *sym; - - sym = make_symbol (".self", &type_entity, pr.near_data, sc_extern); - if (!sym->table) - symtab_addsymbol (pr.symtab, sym); - return new_symbol_expr (sym); + if (is_constant (e)) { + if (is_integer_val (e)) { + return 1; + } + if (is_uinteger_val (e)) { + return 1; + } + if (is_short_val (e)) { + return 1; + } + } + return 0; } -expr_t * -new_this_expr (void) +int +expr_integral (expr_t *e) { - symbol_t *sym; + if (is_constant (e)) { + if (is_integer_val (e)) { + return expr_integer (e); + } + if (is_uinteger_val (e)) { + return expr_uinteger (e); + } + if (is_short_val (e)) { + return expr_short (e); + } + } + internal_error (e, "not an integral constant"); +} - sym = make_symbol (".this", field_type (&type_id), pr.near_data, sc_extern); - if (!sym->table) - symtab_addsymbol (pr.symtab, sym); - return new_symbol_expr (sym); +int +is_pointer_val (expr_t *e) +{ + if (e->type == ex_value && e->e.value->lltype == ev_pointer) { + return 1; + } + return 0; } expr_t * @@ -1119,6 +1272,25 @@ new_move_expr (expr_t *e1, expr_t *e2, type_t *type, int indirect) return e; } +expr_t * +new_memset_expr (expr_t *dst, expr_t *val, type_t *type) +{ + expr_t *e; + if (!is_pointer (get_type (dst))) { + return error (dst, "incorrect destination type for memset"); + } + if (!is_scalar (get_type (val))) { + return error (val, "memset value must be a scalar"); + } + e = new_expr (); + e->type = ex_memset; + e->e.memset.dst = dst; + e->e.memset.val = val; + e->e.memset.count = new_integer_expr (type_size (type)); + e->e.memset.type = type; + return e; +} + expr_t * append_expr (expr_t *block, expr_t *e) { @@ -1138,7 +1310,7 @@ append_expr (expr_t *block, expr_t *e) } static symbol_t * -get_struct_field (type_t *t1, expr_t *e1, expr_t *e2) +get_struct_field (const type_t *t1, expr_t *e1, expr_t *e2) { symtab_t *strct = t1->t.symtab; symbol_t *sym = e2->e.symbol;//FIXME need to check @@ -1159,12 +1331,12 @@ get_struct_field (type_t *t1, expr_t *e1, expr_t *e2) expr_t * field_expr (expr_t *e1, expr_t *e2) { - type_t *t1, *t2; + const type_t *t1, *t2; expr_t *e; + t1 = get_type (e1); if (e1->type == ex_error) return e1; - t1 = get_type (e1); if (t1->type == ev_entity) { symbol_t *field = 0; @@ -1202,8 +1374,9 @@ field_expr (expr_t *e1, expr_t *e2) class_t *class = t1->t.fldptr.type->t.class; symbol_t *sym = e2->e.symbol;//FIXME need to check symbol_t *ivar; + int protected = class_access (current_class, class); - ivar = class_find_ivar (class, vis_protected, sym->name); + ivar = class_find_ivar (class, protected, sym->name); if (!ivar) return new_error_expr (); e2->type = ex_value; @@ -1261,197 +1434,6 @@ field_expr (expr_t *e1, expr_t *e2) return type_mismatch (e1, e2, '.'); } -expr_t * -test_expr (expr_t *e) -{ - static float zero[4] = {0, 0, 0, 0}; - expr_t *new = 0; - type_t *type; - - if (e->type == ex_error) - return e; - - type = get_type (e); - if (e->type == ex_error) - return e; - switch (type->type) { - case ev_type_count: - internal_error (e, 0); - case ev_void: - if (options.traditional) { - if (options.warnings.traditional) - warning (e, "void has no value"); - return e; - } - return error (e, "void has no value"); - case ev_string: - if (!options.code.ifstring) - return new_alias_expr (type_default, e); - new = new_string_expr (0); - break; - case ev_uinteger: - case ev_integer: - case ev_short: - if (type_default != &type_integer) - return new_alias_expr (type_default, e); - return e; - case ev_float: - if (options.code.fast_float - || options.code.progsversion == PROG_ID_VERSION) { - if (type_default != &type_float) - return new_alias_expr (type_default, e); - return e; - } - new = new_float_expr (0); - break; - case ev_double: - new = new_double_expr (0); - break; - case ev_vector: - new = new_vector_expr (zero); - break; - case ev_entity: - return new_alias_expr (type_default, e); - case ev_field: - return new_alias_expr (type_default, e); - case ev_func: - return new_alias_expr (type_default, e); - case ev_pointer: - return new_alias_expr (type_default, e); - case ev_quat: - new = new_quaternion_expr (zero); - break; - case ev_invalid: - if (is_enum (type)) { - new = new_nil_expr (); - break; - } - return test_error (e, get_type (e)); - } - new->line = e->line; - new->file = e->file; - new = binary_expr (NE, e, new); - new->line = e->line; - new->file = e->file; - return new; -} - -void -backpatch (ex_list_t *list, expr_t *label) -{ - int i; - expr_t *e; - - if (!list) - return; - if (!label || label->type != ex_label) - internal_error (label, "not a label"); - - for (i = 0; i < list->size; i++) { - e = list->e[i]; - if (e->type == ex_uexpr && e->e.expr.op == 'g') - e->e.expr.e1 = label; - else if (e->type == ex_expr && (e->e.expr.op == 'i' - || e->e.expr.op == 'n')) - e->e.expr.e2 = label; - else { - internal_error (e, 0); - } - label->e.label.used++; - } -} - -static ex_list_t * -merge (ex_list_t *l1, ex_list_t *l2) -{ - ex_list_t *m; - - if (!l1 && !l2) - internal_error (0, 0); - if (!l2) - return l1; - if (!l1) - return l2; - m = malloc ((size_t)&((ex_list_t *)0)->e[l1->size + l2->size]); - m->size = l1->size + l2->size; - memcpy (m->e, l1->e, l1->size * sizeof (expr_t *)); - memcpy (m->e + l1->size, l2->e, l2->size * sizeof (expr_t *)); - return m; -} - -static ex_list_t * -make_list (expr_t *e) -{ - ex_list_t *m; - - m = malloc ((size_t)&((ex_list_t *) 0)->e[1]); - m->size = 1; - m->e[0] = e; - return m; -} - -expr_t * -convert_bool (expr_t *e, int block) -{ - expr_t *b; - - if (e->type == ex_expr && (e->e.expr.op == '=' || e->e.expr.op == PAS)) { - expr_t *src; - if (!e->paren && options.warnings.precedence) - warning (e, "suggest parentheses around assignment " - "used as truth value"); - src = e->e.expr.e2; - if (src->type == ex_block) { - src = new_temp_def_expr (get_type (src)); - e = new_binary_expr (e->e.expr.op, e->e.expr.e1, - assign_expr (src, e->e.expr.e2)); - } - b = convert_bool (src, 1); - if (b->type == ex_error) - return b; - // insert the assignment into the bool's block - e->next = b->e.bool.e->e.block.head; - b->e.bool.e->e.block.head = e; - if (b->e.bool.e->e.block.tail == &b->e.bool.e->e.block.head) { - // shouldn't happen, but just in case - b->e.bool.e->e.block.tail = &e->next; - } - return b; - } - - if (e->type == ex_uexpr && e->e.expr.op == '!' - && get_type (e->e.expr.e1) != &type_string) { - e = convert_bool (e->e.expr.e1, 0); - if (e->type == ex_error) - return e; - e = unary_expr ('!', e); - } - if (e->type != ex_bool) { - e = test_expr (e); - if (e->type == ex_error) - return e; - if (is_integer_val (e)) { - b = goto_expr (0); - if (expr_integer (e)) - e = new_bool_expr (make_list (b), 0, b); - else - e = new_bool_expr (0, make_list (b), b); - } else { - b = new_block_expr (); - append_expr (b, branch_expr ('i', e, 0)); - append_expr (b, goto_expr (0)); - e = new_bool_expr (make_list (b->e.block.head), - make_list (b->e.block.head->next), b); - } - } - if (block && e->e.bool.e->type != ex_block) { - expr_t *block = new_block_expr (); - append_expr (block, e->e.bool.e); - e->e.bool.e = block; - } - return e; -} - expr_t * convert_from_bool (expr_t *e, type_t *type) { @@ -1459,15 +1441,15 @@ convert_from_bool (expr_t *e, type_t *type) expr_t *one; expr_t *cond; - if (type == &type_float) { + if (is_float (type)) { one = new_float_expr (1); zero = new_float_expr (0); - } else if (type == &type_integer) { + } else if (is_integer (type)) { one = new_integer_expr (1); zero = new_integer_expr (0); } else if (is_enum (type) && enum_as_bool (type, &zero, &one)) { // don't need to do anything - } else if (type == &type_uinteger) { + } else if (is_uinteger (type)) { one = new_uinteger_expr (1); zero = new_uinteger_expr (0); } else { @@ -1483,44 +1465,6 @@ convert_from_bool (expr_t *e, type_t *type) return e; } -expr_t * -bool_expr (int op, expr_t *label, expr_t *e1, expr_t *e2) -{ - expr_t *block; - - if (!options.code.short_circuit) - return binary_expr (op, e1, e2); - - e1 = convert_bool (e1, 0); - if (e1->type == ex_error) - return e1; - - e2 = convert_bool (e2, 0); - if (e2->type == ex_error) - return e2; - - block = new_block_expr (); - append_expr (block, e1); - append_expr (block, label); - append_expr (block, e2); - - switch (op) { - case OR: - backpatch (e1->e.bool.false_list, label); - return new_bool_expr (merge (e1->e.bool.true_list, - e2->e.bool.true_list), - e2->e.bool.false_list, block); - break; - case AND: - backpatch (e1->e.bool.true_list, label); - return new_bool_expr (e2->e.bool.true_list, - merge (e1->e.bool.false_list, - e2->e.bool.false_list), block); - break; - } - internal_error (e1, 0); -} - void convert_int (expr_t *e) { @@ -1546,10 +1490,18 @@ convert_short_int (expr_t *e) } void +convert_double (expr_t *e) +{ + float float_val = expr_double (e); + e->type = ex_value; + e->e.value = new_float_val (float_val); +} + +expr_t * convert_nil (expr_t *e, type_t *t) { - e->type = ex_value; - e->e.value = new_nil_val (t); + e->e.nil = t; + return e; } int @@ -1625,6 +1577,8 @@ unary_expr (int op, expr_t *e) vec3_t v; quat_t q; const char *s; + expr_t *new; + type_t *t; convert_name (e); if (e->type == ex_error) @@ -1642,7 +1596,9 @@ unary_expr (int op, expr_t *e) case ev_pointer: internal_error (e, "type check failed!"); case ev_double: - return new_double_expr (-expr_double (e)); + new = new_double_expr (-expr_double (e)); + new->implicit = e->implicit; + return new; case ev_float: return new_float_expr (-expr_float (e)); case ev_vector: @@ -1670,6 +1626,8 @@ unary_expr (int op, expr_t *e) case ex_label: case ex_labelref: case ex_state: + case ex_compound: + case ex_memset: internal_error (e, 0); case ex_uexpr: if (e->e.expr.op == '-') @@ -1687,6 +1645,13 @@ unary_expr (int op, expr_t *e) n->e.expr.type = e->e.expr.type; return n; } + case ex_def: + { + expr_t *n = new_unary_expr (op, e); + + n->e.expr.type = e->e.def->type; + return n; + } case ex_symbol: { expr_t *n = new_unary_expr (op, e); @@ -1736,6 +1701,8 @@ unary_expr (int op, expr_t *e) case ex_label: case ex_labelref: case ex_state: + case ex_compound: + case ex_memset: internal_error (e, 0); case ex_bool: return new_bool_expr (e->e.bool.false_list, @@ -1745,6 +1712,7 @@ unary_expr (int op, expr_t *e) return error (e, "invalid type for unary !"); case ex_uexpr: case ex_expr: + case ex_def: case ex_symbol: case ex_temp: case ex_vector: @@ -1784,6 +1752,11 @@ unary_expr (int op, expr_t *e) case ev_short: return new_short_expr (~expr_short (e)); case ev_invalid: + t = get_type (e); + if (t->meta == ty_enum) { + return new_integer_expr (~expr_integer (e)); + } + break; case ev_type_count: case ev_void: break; @@ -1796,6 +1769,8 @@ unary_expr (int op, expr_t *e) case ex_label: case ex_labelref: case ex_state: + case ex_compound: + case ex_memset: internal_error (e, 0); case ex_uexpr: if (e->e.expr.op == '~') @@ -1807,6 +1782,7 @@ unary_expr (int op, expr_t *e) goto bitnot_expr; case ex_expr: case ex_bool: + case ex_def: case ex_symbol: case ex_temp: case ex_vector: @@ -1843,15 +1819,17 @@ bitnot_expr: } expr_t * -build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) +build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) { expr_t *e; + expr_t *p; int arg_count = 0, parm_count = 0; int i; expr_t *args = 0, **a = &args; type_t *arg_types[MAX_PARMS]; expr_t *arg_exprs[MAX_PARMS][2]; int arg_expr_count = 0; + expr_t *assign; expr_t *call; expr_t *err = 0; @@ -1884,7 +1862,21 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) parm_count = ftype->t.func.num_params; } for (i = arg_count - 1, e = params; i >= 0; i--, e = e->next) { - type_t *t = get_type (e); + type_t *t; + + if (e->type == ex_compound) { + if (i < parm_count) { + t = ftype->t.func.param_types[i]; + } else { + return error (e, "cannot pass compound initializer " + "through ..."); + } + } else { + t = get_type (e); + } + if (!t) { + return e; + } if (!type_size (t)) err = error (e, "type of formal parameter %d is incomplete", @@ -1892,11 +1884,6 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) if (type_size (t) > type_size (&type_param)) err = error (e, "formal parameter %d is too large to be passed by" " value", i + 1); - if (ftype->t.func.param_types[i] == &type_float - && is_integer_val (e)) { - convert_int (e); - t = &type_float; - } if (i < parm_count) { if (e->type == ex_nil) convert_nil (e, t = ftype->t.func.param_types[i]); @@ -1917,9 +1904,20 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) if (is_integer_val (e) && options.code.progsversion == PROG_ID_VERSION) convert_int (e); - if (is_float (get_type (e)) - && options.code.progsversion != PROG_ID_VERSION) { - t = &type_double; + if (options.code.promote_float) { + if (is_float (get_type (e))) { + t = &type_double; + } + } else { + if (is_double (get_type (e))) { + if (!e->implicit) { + warning (e, "passing double into ... function"); + } + if (is_constant (e)) { + // don't auto-demote non-constant doubles + t = &type_float; + } + } } if (is_integer_val (e) && options.warnings.vararg_integer) warning (e, "passing integer constant into ... function"); @@ -1929,28 +1927,40 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) if (err) return err; - call = new_block_expr (); + call = expr_file_line (new_block_expr (), fexpr); call->e.block.is_call = 1; - for (e = params, i = 0; e; e = e->next, i++) { + for (p = params, i = 0; p; p = p->next, i++) { + expr_t *e = p; + if (e->type == ex_compound) { + e = expr_file_line (initialized_temp_expr (arg_types[i], e), e); + } + // FIXME this is target-specific info and should not be in the + // expression tree + // That, or always use a temp, since it should get optimized out if (has_function_call (e)) { - *a = new_temp_def_expr (arg_types[i]); - arg_exprs[arg_expr_count][0] = cast_expr (arg_types[i], convert_vector (e)); + expr_t *cast = cast_expr (arg_types[i], convert_vector (e)); + expr_t *tmp = new_temp_def_expr (arg_types[i]); + *a = expr_file_line (tmp, e); + arg_exprs[arg_expr_count][0] = expr_file_line (cast, e); arg_exprs[arg_expr_count][1] = *a; arg_expr_count++; } else { - *a = cast_expr (arg_types[i], convert_vector (e)); + *a = expr_file_line (cast_expr (arg_types[i], convert_vector (e)), + e); } a = &(*a)->next; } for (i = 0; i < arg_expr_count - 1; i++) { - append_expr (call, assign_expr (arg_exprs[i][1], arg_exprs[i][0])); + assign = assign_expr (arg_exprs[i][1], arg_exprs[i][0]); + append_expr (call, expr_file_line (assign, arg_exprs[i][0])); } if (arg_expr_count) { e = assign_expr (arg_exprs[arg_expr_count - 1][1], arg_exprs[arg_expr_count - 1][0]); + e = expr_file_line (e, arg_exprs[arg_expr_count - 1][0]); append_expr (call, e); } - e = new_binary_expr ('c', fexpr, args); + e = expr_file_line (new_binary_expr ('c', fexpr, args), fexpr); e->e.expr.type = ftype->t.func.type; append_expr (call, e); if (ftype->t.func.type != &type_void) { @@ -2017,9 +2027,10 @@ expr_t * return_expr (function_t *f, expr_t *e) { type_t *t; + type_t *ret_type = f->sym->type->t.func.type; if (!e) { - if (f->sym->type->t.func.type != &type_void) { + if (ret_type != &type_void) { if (options.traditional) { if (options.warnings.traditional) warning (e, @@ -2037,28 +2048,32 @@ return_expr (function_t *f, expr_t *e) } } + if (e->type == ex_compound) { + e = expr_file_line (initialized_temp_expr (ret_type, e), e); + } + t = get_type (e); - if (e->type == ex_error) + if (e->type == ex_error) { return e; - if (f->sym->type->t.func.type == &type_void) { + } + if (ret_type == &type_void) { if (!options.traditional) return error (e, "returning a value for a void function"); if (options.warnings.traditional) warning (e, "returning a value for a void function"); } - if (e->type == ex_bool) - e = convert_from_bool (e, f->sym->type->t.func.type); - if (f->sym->type->t.func.type == &type_float && is_integer_val (e)) { + if (e->type == ex_bool) { + e = convert_from_bool (e, ret_type); + } + if (ret_type == &type_float && is_integer_val (e)) { convert_int (e); t = &type_float; } if (t == &type_void) { if (e->type == ex_nil) { - t = f->sym->type->t.func.type; + t = ret_type; convert_nil (e, t); - if (e->type == ex_nil) - return error (e, "invalid return type for NIL"); } else { if (!options.traditional) return error (e, "void value not ignored as it ought to be"); @@ -2067,7 +2082,7 @@ return_expr (function_t *f, expr_t *e) //FIXME does anything need to be done here? } } - if (!type_assignable (f->sym->type->t.func.type, t)) { + if (!type_assignable (ret_type, t)) { if (!options.traditional) return error (e, "type mismatch for return value of %s", f->sym->name); @@ -2075,8 +2090,8 @@ return_expr (function_t *f, expr_t *e) warning (e, "type mismatch for return value of %s", f->sym->name); } else { - if (f->sym->type->t.func.type != t) { - e = cast_expr (f->sym->type->t.func.type, e); + if (ret_type != t) { + e = cast_expr (ret_type, e); t = f->sym->type->t.func.type; } } @@ -2241,6 +2256,22 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) t = get_type (e1); switch (e1->type) { + case ex_def: + { + def_t *def = e1->e.def; + type_t *type = def->type; + + if (is_array (type)) { + e = e1; + e->type = ex_value; + e->e.value = new_pointer_val (0, t, def, 0); + } else { + e = new_pointer_expr (0, t, def); + e->line = e1->line; + e->file = e1->file; + } + } + break; case ex_symbol: if (e1->e.symbol->sy_type == sy_var) { def_t *def = e1->e.symbol->s.def; @@ -2249,7 +2280,7 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) if (is_array (type)) { e = e1; e->type = ex_value; - e->e.value = new_pointer_val (0, t, def); + e->e.value = new_pointer_val (0, t, def, 0); } else { e = new_pointer_expr (0, t, def); e->line = e1->line; @@ -2280,6 +2311,8 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) t = e1->e.expr.type; if (e2) { e2 = binary_expr ('+', e1->e.expr.e2, e2); + } else { + e2 = e1->e.expr.e2; } return address_expr (e1->e.expr.e1, e2, t); } @@ -2299,11 +2332,6 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) return address_expr (e1->e.expr.e1, e2, t); } return error (e1, "invalid type for unary &"); - case ex_block: - if (!e1->e.block.result) - return error (e1, "invalid type for unary &"); - e1->e.block.result = address_expr (e1->e.block.result, e2, t); - return e1; case ex_label: return new_label_ref (&e1->e.label); case ex_temp: @@ -2316,9 +2344,11 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) if (e2) { if (e2->type == ex_error) return e2; - if (e->type == ex_value && e->e.value->lltype == ev_pointer - && is_short_val (e2)) { - e->e.value = new_pointer_val (e->e.value->v.pointer.val + expr_short (e2), t, e->e.value->v.pointer.def); + if (is_pointer_val (e) && is_integral_val (e2)) { + int base = e->e.value->v.pointer.val; + int offset = expr_integral (e2); + def_t *def = e->e.value->v.pointer.def; + e->e.value = new_pointer_val (base + offset, t, def, 0); } else { if (!is_short_val (e2) || expr_short (e2)) { if (e->type == ex_expr && e->e.expr.op == '&') { @@ -2581,102 +2611,82 @@ think_expr (symbol_t *think_sym) } expr_t * -cast_expr (type_t *type, expr_t *e) +cast_expr (type_t *dstType, expr_t *e) { expr_t *c; - type_t *e_type; + type_t *srcType; convert_name (e); if (e->type == ex_error) return e; - e_type = get_type (e); + srcType = get_type (e); - if (type == e_type) + if (dstType == srcType) return e; - if ((type == type_default && is_enum (e_type)) - || (is_enum (type) && e_type == type_default)) + if ((dstType == type_default && is_enum (srcType)) + || (is_enum (dstType) && srcType == type_default)) return e; - if (!(type->type == ev_pointer - && (e_type->type == ev_pointer || is_integral (e_type) - || is_array (e_type))) - && !(is_integral (type) && e_type->type == ev_pointer) - && !(type->type == ev_func && e_type->type == ev_func) - && !(is_scalar (type) && is_scalar (e_type))) { - return cast_error (e, e_type, type); + if ((is_pointer (dstType) && is_string (srcType)) + || (is_string (dstType) && is_pointer (srcType))) { + c = new_alias_expr (dstType, e); + return c; } - if (is_array (e_type)) { - return address_expr (e, 0, type->t.fldptr.type); + if (!(is_pointer (dstType) + && (is_pointer (srcType) || is_integral (srcType) + || is_array (srcType))) + && !(is_integral (dstType) && is_pointer (srcType)) + && !(is_func (dstType) && is_func (srcType)) + && !(is_scalar (dstType) && is_scalar (srcType))) { + return cast_error (e, srcType, dstType); } - if (is_constant (e) && is_scalar (type) && is_scalar (e_type)) { + if (is_array (srcType)) { + return address_expr (e, 0, dstType->t.fldptr.type); + } + if (is_constant (e) && is_scalar (dstType) && is_scalar (srcType)) { ex_value_t *val = 0; if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const) { val = e->e.symbol->s.value; + } else if (e->type == ex_symbol + && e->e.symbol->sy_type == sy_var) { + // initialized global def treated as a constant + // from the tests above, the def is known to be constant + // and of one of the three storable scalar types + def_t *def = e->e.symbol->s.def; + if (is_float (def->type)) { + val = new_float_val (D_FLOAT (def)); + } else if (is_double (def->type)) { + val = new_double_val (D_DOUBLE (def)); + } else if (is_integral (def->type)) { + val = new_integer_val (D_INT (def)); + } } else if (e->type == ex_value) { val = e->e.value; } else if (e->type == ex_nil) { - convert_nil (e, type); + convert_nil (e, dstType); return e; } if (!val) internal_error (e, "unexpected constant expression type"); - e->e.value = convert_value (val, type); + e->e.value = convert_value (val, dstType); e->type = ex_value; c = e; - } else if (is_integral (type) && is_integral (e_type)) { - c = new_alias_expr (type, e); - } else if (is_scalar (type) && is_scalar (e_type)) { + } else if (is_integral (dstType) && is_integral (srcType)) { + c = new_alias_expr (dstType, e); + } else if (is_scalar (dstType) && is_scalar (srcType)) { c = new_unary_expr ('C', e); - c->e.expr.type = type; + c->e.expr.type = dstType; } else if (e->type == ex_uexpr && e->e.expr.op == '.') { - e->e.expr.type = type; + e->e.expr.type = dstType; c = e; } else { - c = new_alias_expr (type, e); + c = new_alias_expr (dstType, e); } return c; } -expr_t * -selector_expr (keywordarg_t *selector) -{ - dstring_t *sel_id = dstring_newstr (); - expr_t *sel; - symbol_t *sel_sym; - symbol_t *sel_table; - int index; - - selector = copy_keywordargs (selector); - selector = (keywordarg_t *) reverse_params ((param_t *) selector); - selector_name (sel_id, selector); - index = selector_index (sel_id->str); - index *= type_size (type_SEL.t.fldptr.type); - sel_sym = make_symbol ("_OBJ_SELECTOR_TABLE_PTR", &type_SEL, - pr.near_data, sc_static); - if (!sel_sym->table) { - symtab_addsymbol (pr.symtab, sel_sym); - sel_table = make_symbol ("_OBJ_SELECTOR_TABLE", - array_type (type_SEL.t.fldptr.type, 0), - pr.far_data, sc_extern); - if (!sel_table->table) - symtab_addsymbol (pr.symtab, sel_table); - reloc_def_def (sel_table->s.def, sel_sym->s.def); - } - sel = new_symbol_expr (sel_sym); - dstring_delete (sel_id); - sel = new_binary_expr ('&', sel, new_short_expr (index)); - sel->e.expr.type = &type_SEL; - return sel; -} - -expr_t * -protocol_expr (const char *protocol) -{ - return error (0, "not implemented"); -} - expr_t * encode_expr (type_t *type) { @@ -2689,137 +2699,6 @@ encode_expr (type_t *type) return e; } -expr_t * -super_expr (class_type_t *class_type) -{ - symbol_t *sym; - expr_t *super; - expr_t *e; - expr_t *super_block; - class_t *class; - - if (!class_type) - return error (0, "`super' used outside of class implementation"); - - class = extract_class (class_type); - - if (!class->super_class) - return error (0, "%s has no super class", class->name); - - sym = symtab_lookup (current_symtab, ".super"); - if (!sym || sym->table != current_symtab) { - sym = new_symbol_type (".super", &type_obj_super); - initialize_def (sym, 0, current_symtab->space, sc_local); - } - super = new_symbol_expr (sym); - - super_block = new_block_expr (); - - e = assign_expr (field_expr (super, new_name_expr ("self")), - new_name_expr ("self")); - append_expr (super_block, e); - - e = new_symbol_expr (class_pointer_symbol (class)); - e = assign_expr (field_expr (super, new_name_expr ("class")), - field_expr (e, new_name_expr ("super_class"))); - append_expr (super_block, e); - - e = address_expr (super, 0, 0); - super_block->e.block.result = e; - return super_block; -} - -expr_t * -message_expr (expr_t *receiver, keywordarg_t *message) -{ - expr_t *args = 0, **a = &args; - expr_t *selector = selector_expr (message); - expr_t *call; - keywordarg_t *m; - int self = 0, super = 0, class_msg = 0; - type_t *rec_type; - type_t *return_type; - type_t *method_type = &type_IMP; - class_t *class = 0; - method_t *method; - expr_t *send_msg; - - if (receiver->type == ex_symbol - && strcmp (receiver->e.symbol->name, "super") == 0) { - super = 1; - - receiver = super_expr (current_class); - - if (receiver->type == ex_error) - return receiver; - receiver = cast_expr (&type_id, receiver); //FIXME better way? - class = extract_class (current_class); - } else { - if (receiver->type == ex_symbol) { - if (strcmp (receiver->e.symbol->name, "self") == 0) - self = 1; - if (receiver->e.symbol->sy_type == sy_class) { - class = receiver->e.symbol->type->t.class; - class_msg = 1; - receiver = new_symbol_expr (class_pointer_symbol (class)); - } - } else if (receiver->type == ex_nil) { - convert_nil (receiver, &type_id); - } - rec_type = get_type (receiver); - - if (receiver->type == ex_error) - return receiver; - - if (rec_type == &type_id || rec_type == &type_Class) { - } else { - if (rec_type->type == ev_pointer) - rec_type = rec_type->t.fldptr.type; - if (!obj_is_class (rec_type)) - return error (receiver, "not a class/object"); - - if (self) { - if (!class) - class = extract_class (current_class); - if (rec_type == &type_obj_class) - class_msg = 1; - } else { - if (!class) - class = rec_type->t.class; - } - } - } - - return_type = &type_id; - method = class_message_response (class, class_msg, selector); - if (method) - return_type = method->type->t.func.type; - - for (m = message; m; m = m->next) { - *a = m->expr; - while ((*a)) - a = &(*a)->next; - } - *a = selector; - a = &(*a)->next; - *a = receiver; - - send_msg = send_message (super); - if (method) { - expr_t *err; - if ((err = method_check_params (method, args))) - return err; - method_type = method->type; - } - call = build_function_call (send_msg, method_type, args); - - if (call->type == ex_error) - return receiver; - - call->e.block.result = new_ret_expr (return_type); - return call; -} - expr_t * sizeof_expr (expr_t *expr, struct type_s *type) { diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 600c6140a..7d1f1aab9 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -81,16 +81,18 @@ check_assign_logic_precedence (expr_t *dst, expr_t *src) return 0; } -static expr_t * -check_valid_lvalue (expr_t *expr) +int +is_lvalue (const expr_t *expr) { switch (expr->type) { + case ex_def: + return !expr->e.def->constant; case ex_symbol: switch (expr->e.symbol->sy_type) { case sy_name: break; case sy_var: - return 0; + return 1; case sy_const: break; case sy_type: @@ -101,26 +103,30 @@ check_valid_lvalue (expr_t *expr) break; case sy_class: break; + case sy_convert: + break; } break; case ex_temp: - return 0; + return 1; case ex_expr: if (expr->e.expr.op == '.') { - return 0; + return 1; } if (expr->e.expr.op == 'A') { - return check_valid_lvalue (expr->e.expr.e1); + return is_lvalue (expr->e.expr.e1); } break; case ex_uexpr: if (expr->e.expr.op == '.') { - return 0; + return 1; } if (expr->e.expr.op == 'A') { - return check_valid_lvalue (expr->e.expr.e1); + return is_lvalue (expr->e.expr.e1); } break; + case ex_memset: + case ex_compound: case ex_state: case ex_bool: case ex_label: @@ -132,11 +138,20 @@ check_valid_lvalue (expr_t *expr) case ex_error: break; } - if (options.traditional) { - warning (expr, "invalid lvalue in assignment"); - return 0; + return 0; +} + +static expr_t * +check_valid_lvalue (expr_t *expr) +{ + if (!is_lvalue (expr)) { + if (options.traditional) { + warning (expr, "invalid lvalue in assignment"); + return 0; + } + return error (expr, "invalid lvalue in assignment"); } - return error (expr, "invalid lvalue in assignment"); + return 0; } static expr_t * @@ -151,9 +166,11 @@ check_types_compatible (expr_t *dst, expr_t *src) if (type_assignable (dst_type, src_type)) { if (is_scalar (dst_type) && is_scalar (src_type)) { - if (is_double (src_type)) { - warning (dst, "assignment of double to %s (use a cast)\n", - dst_type->name); + if (!src->implicit) { + if (is_double (src_type)) { + warning (dst, "assignment of double to %s (use a cast)\n", + dst_type->name); + } } // the types are different but cast-compatible expr_t *new = cast_expr (dst_type, src); @@ -258,26 +275,9 @@ assign_vector_expr (expr_t *dst, expr_t *src) } static __attribute__((pure)) int -is_const_ptr (expr_t *e) +is_memset (expr_t *e) { - if ((e->type != ex_value || e->e.value->lltype != ev_pointer) - || !(POINTER_VAL (e->e.value->v.pointer) >= 0 - && POINTER_VAL (e->e.value->v.pointer) < 65536)) { - return 1; - } - return 0; -} - -static __attribute__((pure)) int -is_indirect (expr_t *e) -{ - if (e->type == ex_block && e->e.block.result) - return is_indirect (e->e.block.result); - if (e->type == ex_expr && e->e.expr.op == '.') - return 1; - if (!(e->type == ex_uexpr && e->e.expr.op == '.')) - return 0; - return is_const_ptr (e->e.expr.e1); + return e->type == ex_memset; } expr_t * @@ -288,30 +288,40 @@ assign_expr (expr_t *dst, expr_t *src) type_t *dst_type, *src_type; convert_name (dst); - convert_name (src); - if (dst->type == ex_error) { return dst; } - if (src->type == ex_error) { - return src; - } - - if (options.traditional - && (expr = check_assign_logic_precedence (dst, src))) { - return expr; - } - - if ((expr = check_valid_lvalue (dst))) { return expr; } - dst_type = get_type (dst); - src_type = get_type (src); if (!dst_type) { internal_error (dst, "dst_type broke in assign_expr"); } + + if (src && !is_memset (src)) { + convert_name (src); + if (src->type == ex_error) { + return src; + } + + if (options.traditional + && (expr = check_assign_logic_precedence (dst, src))) { + return expr; + } + } else { + if (!src && is_scalar (dst_type)) { + return error (dst, "empty scalar initializer"); + } + src = new_nil_expr (); + } + if (src->type == ex_compound) { + src = initialized_temp_expr (dst_type, src); + if (src->type == ex_error) { + return src; + } + } + src_type = get_type (src); if (!src_type) { internal_error (src, "src_type broke in assign_expr"); } @@ -323,89 +333,26 @@ assign_expr (expr_t *dst, expr_t *src) src_type = get_type (src); } if (src->type == ex_bool) { + // boolean expressions are chains of tests, so extract the result + // of the tests src = convert_from_bool (src, dst_type); if (src->type == ex_error) { return src; } src_type = get_type (src); } - if (!is_void (dst_type) && src->type == ex_nil) { - // nil is a type-agnostic 0 - // FIXME: assignment to compound types? error or memset? - src_type = dst_type; - convert_nil (src, src_type); - } - if ((expr = check_types_compatible (dst, src))) { - // expr might be a valid expression, but if so, check_types_compatible - // will take care of everything - return expr; - } - - if ((expr = assign_vector_expr (dst, src))) { - return expr; - } - - if (is_indirect (dst) && is_indirect (src)) { - debug (dst, "here"); - if (is_struct (src_type)) { - dst = address_expr (dst, 0, 0); - src = address_expr (src, 0, 0); - expr = new_move_expr (dst, src, src_type, 1); - } else { - expr_t *temp = new_temp_def_expr (dst_type); - - expr = new_block_expr (); - append_expr (expr, assign_expr (temp, src)); - append_expr (expr, assign_expr (dst, temp)); - expr->e.block.result = temp; + if (!is_nil (src)) { + if ((expr = check_types_compatible (dst, src))) { + // expr might be a valid expression, but if so, + // check_types_compatible will take care of everything + return expr; } - return expr; - } else if (is_indirect (dst)) { - debug (dst, "here"); - if (is_struct (dst_type)) { - dst = address_expr (dst, 0, 0); - src = address_expr (src, 0, 0); - return new_move_expr (dst, src, dst_type, 1); + if ((expr = assign_vector_expr (dst, src))) { + return expr; } - if (dst->type == ex_expr) { - if (get_type (dst->e.expr.e1) == &type_entity) { - dst_type = dst->e.expr.type; - dst->e.expr.type = pointer_type (dst_type); - dst->e.expr.op = '&'; - } - op = PAS; - } else { - if (is_const_ptr (dst->e.expr.e1)) { - dst = dst->e.expr.e1; - op = PAS; - } - } - } else if (is_indirect (src)) { - debug (dst, "here"); - if (is_struct (dst_type)) { - dst = address_expr (dst, 0, 0); - src = address_expr (src, 0, 0); - src->rvalue = 1; - return new_move_expr (dst, src, src_type, 1); - } - if (src->type == ex_uexpr) { - expr = src->e.expr.e1; - if (is_const_ptr (expr)) { - if (expr->type == ex_expr && expr->e.expr.op == '&' - && expr->e.expr.type->type == ev_pointer - && !is_constant (expr)) { - src = expr; - src->e.expr.op = '.'; - src->e.expr.type = src_type; - src->rvalue = 1; - } - } - } - } - - if (is_struct (dst_type)) { - return new_move_expr (dst, src, dst_type, 0); + } else { + convert_nil (src, dst_type); } expr = new_binary_expr (op, dst, src); diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 2e31116f3..b7b526853 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -46,6 +46,7 @@ typedef struct { } expr_type_t; static expr_t *pointer_arithmetic (int op, expr_t *e1, expr_t *e2); +static expr_t *pointer_compare (int op, expr_t *e1, expr_t *e2); static expr_t *inverse_multiply (int op, expr_t *e1, expr_t *e2); static expr_t *double_compare (int op, expr_t *e1, expr_t *e2); @@ -72,6 +73,8 @@ static expr_type_t float_float[] = { {MOD, &type_float}, {SHL, &type_float}, {SHR, &type_float}, + {AND, &type_integer}, + {OR, &type_integer}, {EQ, &type_integer}, {NE, &type_integer}, {LE, &type_integer}, @@ -174,13 +177,13 @@ static expr_type_t func_func[] = { }; static expr_type_t pointer_pointer[] = { - {'-', &type_integer, &type_integer, &type_integer}, - {EQ, &type_integer}, - {NE, &type_integer}, - {LE, &type_integer}, - {GE, &type_integer}, - {LT, &type_integer}, - {GT, &type_integer}, + {'-', 0, 0, 0, pointer_arithmetic}, + {EQ, 0, 0, 0, pointer_compare}, + {NE, 0, 0, 0, pointer_compare}, + {LE, 0, 0, 0, pointer_compare}, + {GE, 0, 0, 0, pointer_compare}, + {LT, 0, 0, 0, pointer_compare}, + {GT, 0, 0, 0, pointer_compare}, {0, 0} }; @@ -253,7 +256,7 @@ static expr_type_t integer_vector[] = { }; static expr_type_t integer_pointer[] = { - {'+', &type_pointer, 0, &type_integer}, + {'+', 0, 0, 0, pointer_arithmetic}, {0, 0} }; @@ -274,6 +277,8 @@ static expr_type_t integer_integer[] = { {MOD, &type_integer}, {SHL, &type_integer}, {SHR, &type_integer}, + {AND, &type_integer}, + {OR, &type_integer}, {EQ, &type_integer}, {NE, &type_integer}, {LE, &type_integer}, @@ -731,21 +736,58 @@ static expr_t * pointer_arithmetic (int op, expr_t *e1, expr_t *e2) { expr_t *e; - type_t *ptype = get_type (e1); + type_t *t1 = get_type (e1); + type_t *t2 = get_type (e2); + expr_t *ptr; + expr_t *offset; + expr_t *psize; + type_t *ptype; - if (!is_pointer (ptype)) { - ptype = get_type (e2); - } - if (!is_pointer (ptype)) { + if (!is_pointer (t1) && !is_pointer (t2)) { internal_error (e1, "pointer arithmetic on non-pointers"); } - - e1 = cast_expr (&type_integer, e1); - e2 = cast_expr (&type_integer, e2); - e = binary_expr (op, e1, e2); + if (is_pointer (t1) && is_pointer (t2)) { + if (op != '-') { + return error (e2, "invalid pointer operation"); + } + if (t1 != t2) { + return error (e2, "cannot use %c on pointers of different types", + op); + } + e1 = cast_expr (&type_integer, e1); + e2 = cast_expr (&type_integer, e2); + psize = new_integer_expr (type_size (t1->t.fldptr.type)); + return binary_expr ('/', binary_expr ('-', e1, e2), psize); + } else if (is_pointer (t1)) { + offset = cast_expr (&type_integer, e2); + ptr = cast_expr (&type_integer, e1); + ptype = t1; + } else if (is_pointer (t2)) { + offset = cast_expr (&type_integer, e1); + ptr = cast_expr (&type_integer, e2); + ptype = t2; + } + psize = new_integer_expr (type_size (ptype->t.fldptr.type)); + e = binary_expr (op, ptr, binary_expr ('*', offset, psize)); return cast_expr (ptype, e); } +static expr_t * +pointer_compare (int op, expr_t *e1, expr_t *e2) +{ + type_t *t1 = get_type (e1); + type_t *t2 = get_type (e2); + expr_t *e; + + if (!type_assignable (t1, t2)) { + return error (e2, "cannot use %s on pointers of different types", + get_op_string (op)); + } + e = new_binary_expr (op, e1, e2); + e->e.expr.type = &type_integer; + return e; +} + static expr_t * inverse_multiply (int op, expr_t *e1, expr_t *e2) { @@ -762,8 +804,13 @@ double_compare (int op, expr_t *e1, expr_t *e2) type_t *t2 = get_type (e2); expr_t *e; - if ((is_double (t1) && is_float (t2)) - || (is_float (t1) && is_double (t2))) { + if (is_constant (e1) && e1->implicit && is_double (t1) && is_float (t2)) { + t1 = &type_float; + convert_double (e1); + } + if (is_float (t1) && is_constant (e2) && e2->implicit && is_double (t2)) { + t2 = &type_float; + convert_double (e2); } if (is_double (t1)) { if (is_float (t2)) { @@ -772,7 +819,7 @@ double_compare (int op, expr_t *e1, expr_t *e2) warning (e2, "comparison between double and integer"); } e2 = cast_expr (&type_double, e2); - } else { + } else if (is_double (t2)) { if (is_float (t1)) { warning (e1, "comparison between float and double"); } else if (!is_constant (e1)) { @@ -781,7 +828,7 @@ double_compare (int op, expr_t *e1, expr_t *e2) e1 = cast_expr (&type_double, e1); } e = new_binary_expr (op, e1, e2); - e->e.expr.type = &type_double; + e->e.expr.type = &type_integer; return e; } @@ -915,10 +962,14 @@ binary_expr (int op, expr_t *e1, expr_t *e2) convert_name (e1); e1 = convert_vector (e1); + // FIXME this is target-specific info and should not be in the + // expression tree if (e1->type == ex_block && e1->e.block.is_call && has_function_call (e2) && e1->e.block.result) { - e = new_temp_def_expr (get_type (e1->e.block.result)); - e1 = assign_expr (e, e1); + expr_t *tmp = new_temp_def_expr (get_type (e1->e.block.result)); + e = assign_expr (tmp, e1->e.block.result); + append_expr (e1, e); + e1->e.block.result = tmp; } if (e1->type == ex_error) return e1; @@ -951,6 +1002,15 @@ binary_expr (int op, expr_t *e1, expr_t *e2) } } + if (is_constant (e1) && is_double (t1) && e1->implicit && is_float (t2)) { + t1 = &type_float; + convert_double (e1); + } + if (is_constant (e2) && is_double (t2) && e2->implicit && is_float (t1)) { + t2 = &type_float; + convert_double (e2); + } + et1 = low_level_type (t1); et2 = low_level_type (t2); @@ -978,8 +1038,9 @@ binary_expr (int op, expr_t *e1, expr_t *e2) e = new_binary_expr (op, e1, e2); e->e.expr.type = expr_type->type; if (is_compare (op) || is_logic (op)) { - if (options.code.progsversion == PROG_ID_VERSION) + if (options.code.progsversion == PROG_ID_VERSION) { e->e.expr.type = &type_float; + } } return fold_constants (e); } diff --git a/tools/qfcc/source/expr_bool.c b/tools/qfcc/source/expr_bool.c new file mode 100644 index 000000000..74f8d24de --- /dev/null +++ b/tools/qfcc/source/expr_bool.c @@ -0,0 +1,310 @@ +/* + expr_bool.c + + short-circuit boolean expressions + + Copyright (C) 2001 Bill Currie + + Author: Bill Currie + Date: 2001/06/15 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/alloc.h" +#include "QF/dstring.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "qfcc.h" +#include "class.h" +#include "def.h" +#include "defspace.h" +#include "diagnostic.h" +#include "emit.h" +#include "expr.h" +#include "function.h" +#include "idstuff.h" +#include "method.h" +#include "options.h" +#include "reloc.h" +#include "shared.h" +#include "strpool.h" +#include "struct.h" +#include "symtab.h" +#include "type.h" +#include "value.h" +#include "qc-parse.h" + +expr_t * +test_expr (expr_t *e) +{ + static float zero[4] = {0, 0, 0, 0}; + expr_t *new = 0; + type_t *type; + + if (e->type == ex_error) + return e; + + type = get_type (e); + if (e->type == ex_error) + return e; + switch (type->type) { + case ev_type_count: + internal_error (e, 0); + case ev_void: + if (options.traditional) { + if (options.warnings.traditional) + warning (e, "void has no value"); + return e; + } + return error (e, "void has no value"); + case ev_string: + if (!options.code.ifstring) + return new_alias_expr (type_default, e); + new = new_string_expr (0); + break; + case ev_uinteger: + case ev_integer: + case ev_short: + if (type_default != &type_integer) { + if (is_constant (e)) { + return cast_expr (type_default, e); + } + return new_alias_expr (type_default, e); + } + return e; + case ev_float: + if (options.code.fast_float + || options.code.progsversion == PROG_ID_VERSION) { + if (type_default != &type_float) { + if (is_constant (e)) { + return cast_expr (type_default, e); + } + return new_alias_expr (type_default, e); + } + return e; + } + new = new_float_expr (0); + break; + case ev_double: + new = new_double_expr (0); + break; + case ev_vector: + new = new_vector_expr (zero); + break; + case ev_entity: + return new_alias_expr (type_default, e); + case ev_field: + return new_alias_expr (type_default, e); + case ev_func: + return new_alias_expr (type_default, e); + case ev_pointer: + return new_alias_expr (type_default, e); + case ev_quat: + new = new_quaternion_expr (zero); + break; + case ev_invalid: + if (is_enum (type)) { + new = new_nil_expr (); + break; + } + return test_error (e, get_type (e)); + } + new->line = e->line; + new->file = e->file; + new = binary_expr (NE, e, new); + new->line = e->line; + new->file = e->file; + return new; +} + +void +backpatch (ex_list_t *list, expr_t *label) +{ + int i; + expr_t *e; + + if (!list) + return; + if (!label || label->type != ex_label) + internal_error (label, "not a label"); + + for (i = 0; i < list->size; i++) { + e = list->e[i]; + if (e->type == ex_uexpr && e->e.expr.op == 'g') + e->e.expr.e1 = label; + else if (e->type == ex_expr && (e->e.expr.op == 'i' + || e->e.expr.op == 'n')) + e->e.expr.e2 = label; + else { + internal_error (e, 0); + } + label->e.label.used++; + } +} + +static ex_list_t * +merge (ex_list_t *l1, ex_list_t *l2) +{ + ex_list_t *m; + + if (!l1 && !l2) + internal_error (0, 0); + if (!l2) + return l1; + if (!l1) + return l2; + m = malloc ((size_t)&((ex_list_t *)0)->e[l1->size + l2->size]); + m->size = l1->size + l2->size; + memcpy (m->e, l1->e, l1->size * sizeof (expr_t *)); + memcpy (m->e + l1->size, l2->e, l2->size * sizeof (expr_t *)); + return m; +} + +static ex_list_t * +make_list (expr_t *e) +{ + ex_list_t *m; + + m = malloc ((size_t)&((ex_list_t *) 0)->e[1]); + m->size = 1; + m->e[0] = e; + return m; +} + +expr_t * +bool_expr (int op, expr_t *label, expr_t *e1, expr_t *e2) +{ + expr_t *block; + + if (!options.code.short_circuit) + return binary_expr (op, e1, e2); + + e1 = convert_bool (e1, 0); + if (e1->type == ex_error) + return e1; + + e2 = convert_bool (e2, 0); + if (e2->type == ex_error) + return e2; + + block = new_block_expr (); + append_expr (block, e1); + append_expr (block, label); + append_expr (block, e2); + + switch (op) { + case OR: + backpatch (e1->e.bool.false_list, label); + return new_bool_expr (merge (e1->e.bool.true_list, + e2->e.bool.true_list), + e2->e.bool.false_list, block); + break; + case AND: + backpatch (e1->e.bool.true_list, label); + return new_bool_expr (e2->e.bool.true_list, + merge (e1->e.bool.false_list, + e2->e.bool.false_list), block); + break; + } + internal_error (e1, 0); +} + +expr_t * +convert_bool (expr_t *e, int block) +{ + expr_t *b; + + if (e->type == ex_expr && e->e.expr.op == '=') { + expr_t *src; + if (!e->paren && options.warnings.precedence) + warning (e, "suggest parentheses around assignment " + "used as truth value"); + src = e->e.expr.e2; + if (src->type == ex_block) { + src = new_temp_def_expr (get_type (src)); + e = new_binary_expr (e->e.expr.op, e->e.expr.e1, + assign_expr (src, e->e.expr.e2)); + } + b = convert_bool (src, 1); + if (b->type == ex_error) + return b; + // insert the assignment into the bool's block + e->next = b->e.bool.e->e.block.head; + b->e.bool.e->e.block.head = e; + if (b->e.bool.e->e.block.tail == &b->e.bool.e->e.block.head) { + // shouldn't happen, but just in case + b->e.bool.e->e.block.tail = &e->next; + } + return b; + } + + if (e->type == ex_uexpr && e->e.expr.op == '!' + && get_type (e->e.expr.e1) != &type_string) { + e = convert_bool (e->e.expr.e1, 0); + if (e->type == ex_error) + return e; + e = unary_expr ('!', e); + } + if (e->type != ex_bool) { + e = test_expr (e); + if (e->type == ex_error) + return e; + if (is_constant (e)) { + int val; + + b = goto_expr (0); + if (is_integer_val (e)) { + val = expr_integer (e); + } else { + val = expr_float (e) != 0; + } + if (val) + e = new_bool_expr (make_list (b), 0, b); + else + e = new_bool_expr (0, make_list (b), b); + } else { + b = new_block_expr (); + append_expr (b, branch_expr ('i', e, 0)); + append_expr (b, goto_expr (0)); + e = new_bool_expr (make_list (b->e.block.head), + make_list (b->e.block.head->next), b); + } + } + if (block && e->e.bool.e->type != ex_block) { + expr_t *block = new_block_expr (); + append_expr (block, e->e.bool.e); + e->e.bool.e = block; + } + return e; +} diff --git a/tools/qfcc/source/expr_compound.c b/tools/qfcc/source/expr_compound.c new file mode 100644 index 000000000..5ead7de7a --- /dev/null +++ b/tools/qfcc/source/expr_compound.c @@ -0,0 +1,209 @@ +/* + expr_compound.c + + compound intializer expression construction and manipulations + + Copyright (C) 2020 Bill Currie + + Author: Bill Currie + Date: 2020/03/11 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/alloc.h" +#include "QF/dstring.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "diagnostic.h" +#include "expr.h" +#include "options.h" +#include "symtab.h" +#include "type.h" + +static element_t *elements_freelist; + +element_t * +new_element (expr_t *expr, symbol_t *symbol) +{ + element_t *element; + ALLOC (256, element_t, elements, element); + element->expr = expr; + element->symbol = symbol; + return element; +} + +static element_t * +append_init_element (element_chain_t *element_chain, element_t *element) +{ + element->next = 0; + *element_chain->tail = element; + element_chain->tail = &element->next; + return element; +} + +expr_t * +new_compound_init (void) +{ + expr_t *c = new_expr (); + c->type = ex_compound; + c->e.compound.head = 0; + c->e.compound.tail = &c->e.compound.head; + return c; +} + +void +build_element_chain (element_chain_t *element_chain, type_t *type, + expr_t *eles, int base_offset) +{ + element_t *ele = eles->e.compound.head; + + if (is_array (type)) { + type_t *array_type = type->t.array.type; + int array_size = type->t.array.size; + int i; + + for (i = 0; i < array_size; i++) { + int offset = base_offset + i * type_size (array_type); + if (ele && ele->expr && ele->expr->type == ex_compound) { + build_element_chain (element_chain, array_type, + ele->expr, offset); + } else { + element_t *element = new_element (0, 0); + element->type = array_type; + element->offset = offset; + element->expr = ele ? ele->expr : 0; // null -> nil + append_init_element (element_chain, element); + } + if (ele) { + ele = ele->next; + } + } + } else if (is_struct (type) || is_vector (type) || is_quaternion (type)) { + symtab_t *symtab = type->t.symtab; + symbol_t *field; + + for (field = symtab->symbols; field; field = field->next) { + int offset = base_offset + field->s.offset; + if (field->sy_type != sy_var + || field->visibility == vis_anonymous) { + continue; + } + if (ele && ele->expr && ele->expr->type == ex_compound) { + build_element_chain (element_chain, field->type, + ele->expr, offset); + } else { + element_t *element = new_element (0, 0); + element->type = field->type; + element->offset = offset; + element->expr = ele ? ele->expr : 0; // null -> nil + append_init_element (element_chain, element); + } + if (ele) { + ele = ele->next; + } + } + } else { + error (eles, "invalid initializer"); + } + if (ele && ele->next && options.warnings.initializer) { + warning (eles, "excessive elements in initializer"); + } +} + +void free_element_chain (element_chain_t *element_chain) +{ + *element_chain->tail = elements_freelist; + elements_freelist = element_chain->head; + element_chain->head = 0; + element_chain->tail = &element_chain->head; +} + +expr_t * +append_element (expr_t *compound, element_t *element) +{ + if (compound->type != ex_compound) { + internal_error (compound, "not a compound expression"); + } + + if (!element || (element->expr && element->expr->type == ex_error)) { + return compound; + } + + if (element->next) { + internal_error (compound, "append_element: element loop detected"); + } + append_init_element (&compound->e.compound, element); + return compound; +} + +void +assign_elements (expr_t *local_expr, expr_t *init, + element_chain_t *element_chain) +{ + element_t *element; + + for (element = element_chain->head; element; element = element->next) { + int offset = element->offset; + type_t *type = element->type; + expr_t *alias = new_offset_alias_expr (type, init, offset); + + expr_t *c; + + if (element->expr) { + c = constant_expr (element->expr); + } else { + c = new_nil_expr (); + } + if (c->type == ex_nil) { + c = convert_nil (c, type); + } + append_expr (local_expr, assign_expr (alias, c)); + } +} + +expr_t * +initialized_temp_expr (type_t *type, expr_t *compound) +{ + element_chain_t element_chain; + expr_t *temp = new_temp_def_expr (type); + expr_t *block = new_block_expr (); + + element_chain.head = 0; + element_chain.tail = &element_chain.head; + build_element_chain (&element_chain, type, compound, 0); + assign_elements (block, temp, &element_chain); + block->e.block.result = temp; + free_element_chain (&element_chain); + return block; +} diff --git a/tools/qfcc/source/expr_obj.c b/tools/qfcc/source/expr_obj.c new file mode 100644 index 000000000..6858adb54 --- /dev/null +++ b/tools/qfcc/source/expr_obj.c @@ -0,0 +1,249 @@ +/* + expr_obj.c + + Objective-QuakeC expression construction and manipulations + + Copyright (C) 2001 Bill Currie + + Author: Bill Currie + Date: 2001/06/15 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/alloc.h" +#include "QF/dstring.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "qfcc.h" +#include "class.h" +#include "def.h" +#include "defspace.h" +#include "diagnostic.h" +#include "emit.h" +#include "expr.h" +#include "function.h" +#include "idstuff.h" +#include "method.h" +#include "options.h" +#include "reloc.h" +#include "shared.h" +#include "strpool.h" +#include "struct.h" +#include "symtab.h" +#include "type.h" +#include "value.h" +#include "qc-parse.h" + +expr_t * +new_self_expr (void) +{ + symbol_t *sym; + + sym = make_symbol (".self", &type_entity, pr.near_data, sc_extern); + if (!sym->table) + symtab_addsymbol (pr.symtab, sym); + return new_symbol_expr (sym); +} + +expr_t * +new_this_expr (void) +{ + symbol_t *sym; + + sym = make_symbol (".this", field_type (&type_id), pr.near_data, sc_extern); + if (!sym->table) + symtab_addsymbol (pr.symtab, sym); + return new_symbol_expr (sym); +} + +expr_t * +selector_expr (keywordarg_t *selector) +{ + dstring_t *sel_id = dstring_newstr (); + expr_t *sel; + symbol_t *sel_sym; + symbol_t *sel_table; + int index; + + selector = copy_keywordargs (selector); + selector = (keywordarg_t *) reverse_params ((param_t *) selector); + selector_name (sel_id, selector); + index = selector_index (sel_id->str); + index *= type_size (type_SEL.t.fldptr.type); + sel_sym = make_symbol ("_OBJ_SELECTOR_TABLE_PTR", &type_SEL, + pr.near_data, sc_static); + if (!sel_sym->table) { + symtab_addsymbol (pr.symtab, sel_sym); + sel_table = make_symbol ("_OBJ_SELECTOR_TABLE", + array_type (type_SEL.t.fldptr.type, 0), + pr.far_data, sc_extern); + if (!sel_table->table) + symtab_addsymbol (pr.symtab, sel_table); + reloc_def_def (sel_table->s.def, sel_sym->s.def); + } + sel = new_symbol_expr (sel_sym); + dstring_delete (sel_id); + sel = new_binary_expr ('&', sel, new_short_expr (index)); + sel->e.expr.type = &type_SEL; + return sel; +} + +expr_t * +protocol_expr (const char *protocol_name) +{ + protocol_t *protocol = get_protocol (protocol_name, 0); + + if (!protocol) { + return error (0, "cannot find protocol declaration for `%s'", + protocol_name); + } + class_t *proto_class = get_class (new_symbol ("Protocol"), 1); + return new_pointer_expr (0, proto_class->type, protocol_def (protocol)); +} + +expr_t * +super_expr (class_type_t *class_type) +{ + symbol_t *sym; + expr_t *super; + expr_t *e; + expr_t *super_block; + class_t *class; + + if (!class_type) + return error (0, "`super' used outside of class implementation"); + + class = extract_class (class_type); + + if (!class->super_class) + return error (0, "%s has no super class", class->name); + + sym = symtab_lookup (current_symtab, ".super"); + if (!sym || sym->table != current_symtab) { + sym = new_symbol_type (".super", &type_obj_super); + initialize_def (sym, 0, current_symtab->space, sc_local); + } + super = new_symbol_expr (sym); + + super_block = new_block_expr (); + + e = assign_expr (field_expr (super, new_name_expr ("self")), + new_name_expr ("self")); + append_expr (super_block, e); + + e = new_symbol_expr (class_pointer_symbol (class)); + e = assign_expr (field_expr (super, new_name_expr ("class")), + field_expr (e, new_name_expr ("super_class"))); + append_expr (super_block, e); + + e = address_expr (super, 0, 0); + super_block->e.block.result = e; + return super_block; +} + +expr_t * +message_expr (expr_t *receiver, keywordarg_t *message) +{ + expr_t *args = 0, **a = &args; + expr_t *selector = selector_expr (message); + expr_t *call; + keywordarg_t *m; + int super = 0, class_msg = 0; + type_t *rec_type = 0; + type_t *return_type; + type_t *method_type = &type_IMP; + method_t *method; + expr_t *send_msg; + + if (receiver->type == ex_nil) { + rec_type = &type_id; + convert_nil (receiver, rec_type); + } else if (receiver->type == ex_symbol) { + if (strcmp (receiver->e.symbol->name, "self") == 0) { + rec_type = get_type (receiver); + } else if (strcmp (receiver->e.symbol->name, "super") == 0) { + super = 1; + + receiver = super_expr (current_class); + + if (receiver->type == ex_error) + return receiver; + receiver = cast_expr (&type_id, receiver); //FIXME better way? + rec_type = extract_class (current_class)->type; + } else if (receiver->e.symbol->sy_type == sy_class) { + class_t *class; + rec_type = receiver->e.symbol->type; + class = rec_type->t.class; + class_msg = 1; + receiver = new_symbol_expr (class_pointer_symbol (class)); + } + } + if (!rec_type) { + rec_type = get_type (receiver); + } + + if (receiver->type == ex_error) + return receiver; + + return_type = &type_id; + method = class_message_response (rec_type, class_msg, selector); + if (method) + return_type = method->type->t.func.type; + + for (m = message; m; m = m->next) { + *a = m->expr; + while ((*a)) { + expr_file_line (selector, *a); + a = &(*a)->next; + } + } + *a = selector; + a = &(*a)->next; + *a = receiver; + + send_msg = expr_file_line (send_message (super), receiver); + if (method) { + expr_t *err; + if ((err = method_check_params (method, args))) + return err; + method_type = method->type; + } + call = build_function_call (send_msg, method_type, args); + + if (call->type == ex_error) + return receiver; + + call->e.block.result = new_ret_expr (return_type); + return call; +} diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 995aa5b7d..438ece827 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -57,11 +57,11 @@ #include "symtab.h" #include "type.h" -static flowvar_t *vars_freelist; -static flowloop_t *loops_freelist; -static flownode_t *nodes_freelist; -static flowgraph_t *graphs_freelist; +/// \addtogroup qfcc_flow +///@{ +/** Static operand definitions for the ever present return and parameter slots. + */ static struct { const char *name; operand_t op; @@ -78,6 +78,17 @@ static struct { }; static const int num_flow_params = sizeof(flow_params)/sizeof(flow_params[0]); +/** \name Flow analysis memory management */ +///@{ +static flowvar_t *vars_freelist; ///< flowvar pool +static flowloop_t *loops_freelist; ///< flow loop pool +static flownode_t *nodes_freelist; ///< flow node pool +static flowgraph_t *graphs_freelist; ///< flow graph pool + +/** Allocate a new flow var. + * + * The var's use and define sets are initialized to empty. + */ static flowvar_t * new_flowvar (void) { @@ -88,6 +99,20 @@ new_flowvar (void) return var; } +/** Delete a flow var + */ +static void +delete_flowvar (flowvar_t *var) +{ + set_delete (var->use); + set_delete (var->define); + FREE (vars, var); +} + +/** Allocate a new flow loop. + * + * The loop's nodes set is initialized to the empty set. + */ static flowloop_t * new_loop (void) { @@ -97,6 +122,8 @@ new_loop (void) return loop; } +/** Free a flow loop and its nodes set. + */ static void delete_loop (flowloop_t *loop) { @@ -104,6 +131,10 @@ delete_loop (flowloop_t *loop) FREE (loops, loop); } +/** Allocate a new flow node. + * + * The node is completely empty. + */ static flownode_t * new_node (void) { @@ -112,6 +143,10 @@ new_node (void) return node; } +/** Free a flow node and its resources. + * + * \bug not global_vars or the vars and defs sets? + */ static void delete_node (flownode_t *node) { @@ -126,6 +161,10 @@ delete_node (flownode_t *node) FREE (nodes, node); } +/** Allocate a new flow graph. + * + * The graph is completely empty. + */ static flowgraph_t * new_graph (void) { @@ -134,6 +173,10 @@ new_graph (void) return graph; } +/** Return a flow graph and its resources to the pools. + * + * \bug except loops? + */ static void __attribute__((unused)) delete_graph (flowgraph_t *graph) { @@ -148,31 +191,23 @@ delete_graph (flowgraph_t *graph) free (graph->edges); if (graph->dfst) set_delete (graph->dfst); - if (graph->dfo) - free (graph->dfo); + if (graph->depth_first) + free (graph->depth_first); FREE (graphs, graph); } +///@} -static __attribute__((pure)) def_t * -flowvar_get_def (flowvar_t *var) -{ - operand_t *op = var->op; - - switch (op->op_type) { - case op_def: - return op->o.def; - case op_value: - case op_label: - return 0; - case op_temp: - return op->o.tempop.def; - case op_alias: - internal_error (0, "unexpected alias operand"); - } - internal_error (0, "oops, blue pill"); - return 0; -} - +/** \name Flowvar classification */ +///@{ +/** Check if the flowvar refers to a global variable. + * + * For the flowvar to refer to a global variable, the flowvar's operand + * must be a def operand (but the def itself may be an alias of the real def) + * and the rel def must not have its def_t::local flag set. This means that + * function-scope static variables are not considered local (ie, only + * non-static function-scope variables and function parameters are considered + * local (temp vars are local too, but are not represented by \a op_def)). + */ static int flowvar_is_global (flowvar_t *var) { @@ -188,6 +223,14 @@ flowvar_is_global (flowvar_t *var) return 1; } +/** Check if the flowvar refers to a function parameter. + * + * For the flowvar to refer to a function parameter, the flowvar's operand + * must be a def operand (but the def itself may be an alias of the real def) + * and the rel def must have both its def_t::local and def_t::param flags set. + * + * Temp vars are are not represented by op_def, so no mistake can be made. + */ static int flowvar_is_param (flowvar_t *var) { @@ -205,23 +248,53 @@ flowvar_is_param (flowvar_t *var) return 1; } +/** Check if the flowvar refers to a function parameter. + * + * As this is simply "neither global nor pamam", all other flowvars are + * considered local, in particular actual non-staic function scope variables + * and temp vars. + */ static int flowvar_is_local (flowvar_t *var) { return !(flowvar_is_global (var) || flowvar_is_param (var)); } -#if 0 -static int -flowvar_is_initialized (flowvar_t *var) -{ - def_t *def; +///@} - if (var->op->op_type != op_def) - return 0; - def = var->op->o.def; - return def->initialized; +/** Extract the def from a def or temp flowvar. + * + * It is an error for the operand referenced by the flowvar to be anything + * other than a real def or temp. + */ +static __attribute__((pure)) def_t * +flowvar_get_def (flowvar_t *var) +{ + operand_t *op = var->op; + + switch (op->op_type) { + case op_def: + return op->o.def; + case op_value: + case op_label: + return 0; + case op_temp: + return op->o.tempop.def; + case op_alias: + internal_error (op->expr, "unexpected alias operand"); + case op_nil: + internal_error (op->expr, "unexpected nil operand"); + } + internal_error (op->expr, "oops, blue pill"); + return 0; } -#endif + +/** Get a def or temp var operand's flowvar. + * + * Other operand types never have a flowvar. + * + * If the operand does not yet have a flowvar, one is created and assigned + * to the operand. + */ flowvar_t * flow_get_var (operand_t *op) { @@ -241,6 +314,12 @@ flow_get_var (operand_t *op) return 0; } +/** Indicate whether the operand should be counted. + * + * If the operand is a def or temp var operand, and it has not already been + * counted, then it is counted, otherwise it is not. + * \return 1 if the operand should be counted, 0 if not + */ static int count_operand (operand_t *op) { @@ -252,14 +331,15 @@ count_operand (operand_t *op) return 0; var = flow_get_var (op); - // flowvars are initialized with number == 0, and any global flowvar - // used by a function will always have a number >= 0 after flow analysis, - // and local flowvars will always be 0 before flow analysis, so use -1 - // to indicate the variable has been counted. - // - // Also, since this is the beginning of flow analysis for this function, - // ensure the define/use sets for global vars are empty. However, as - // checking if a var is global is too much trouble, just clear them all. + /** Flowvars are initialized with number == 0, and any global flowvar + * used by a function will always have a number >= 0 after flow analysis, + * and local flowvars will always be 0 before flow analysis, so use -1 + * to indicate the variable has been counted. + * + * Also, since this is the beginning of flow analysis for this function, + * ensure the define/use sets for global vars are empty. However, since + * checking if a var is global is too much trouble, just clear them all. + */ if (var && var->number != -1) { set_empty (var->use); set_empty (var->define); @@ -269,6 +349,22 @@ count_operand (operand_t *op) return 0; } +/** Allocate flow analysis pseudo address space to a temporary variable. + * + * If the operand already has an address allocated (flowvar_t::flowaddr is + * not 0), then the already allocated address is returned. + * + * If the operand refers to an alias, the alias chain is followed to the + * actual temp var operand and the real temp var is allocated space if it + * has not allready been alloced. + * + * The operand is given the address of the real temp var operand plus whatever + * offset the operand has. + * + * Real temp var operands must have a zero offset. + * + * The operand address is set in \a op and returned. + */ static int get_temp_address (function_t *func, operand_t *op) { @@ -283,10 +379,15 @@ get_temp_address (function_t *func, operand_t *op) top->o.tempop.flowaddr = func->tmpaddr; func->tmpaddr += top->size; } + if (top->o.tempop.offset) { + internal_error (top->expr, "real tempop with a non-zero offset"); + } op->o.tempop.flowaddr = top->o.tempop.flowaddr + op->o.tempop.offset; return op->o.tempop.flowaddr; } +/** Add an operand's flowvar to the function's list of variables. + */ static void add_operand (function_t *func, operand_t *op) { @@ -298,8 +399,15 @@ add_operand (function_t *func, operand_t *op) return; var = flow_get_var (op); - // If the flowvar number is still -1, then the flowvar has not yet been - // added to the list of variables referenced by the function. + /** If the flowvar number is still -1, then the flowvar has not yet been + * added to the list of variables referenced by the function. + * + * The flowvar's flowvar_t::number is set to its index in the function's + * list of flowvars. + * + * Also, temp and local flowvars are assigned addresses from the flow + * analysys pseudo address space so partial accesses can be analyzed. + */ if (var && var->number == -1) { var->number = func->num_vars++; var->op = op; @@ -312,6 +420,8 @@ add_operand (function_t *func, operand_t *op) } } +/** Create symbols and defs for params/return if not already available. + */ static symbol_t * param_symbol (const char *name) { @@ -322,6 +432,15 @@ param_symbol (const char *name) return sym; } +/** Build an array of all the statements in a function. + + The array exists so statements can be referenced by number and thus used + in sets. + + The statement references in the array (function_t::statements) are in the + same order as they are within the statement blocks (function_t::sblock) + and with the blocks in the same order as the linked list of blocks. +*/ static void flow_build_statements (function_t *func) { @@ -344,11 +463,53 @@ flow_build_statements (function_t *func) } } +/** Build an array of all the variables used by a function + * + * The array exists so variables can be referenced by number and thus used + * in sets. However, because larger variables may be aliased by smaller types, + * their representation is more complicated. + * + * # Local variable representation + * Defined local vars add their address in local space to the number of + * statements in the function. Thus their flow analysis address in in the + * range: + * + * ([num_statements ... num_statements+localsize]) + * + * with a set element in flowvar_t::define for each word used by the var. + * That is, single word types (int, float, pointer, etc) have one element, + * doubles have two adjacant elements, and vectors and quaternions have + * three and four elements respectively (also adjacant). Structural types + * (struct, union, array) have as many adjacant elements as their size + * dictates. + * + * Temporary vars are pseudo allocated and their addresses are added as + * for normal local vars. + * + * Note, however, that flowvar_t::define also includes real function + * statements that assign to the variable. + * + * # Pseudo Address Space + * Temporary variables are _effectively_ local variables and thus will + * be treated as such by the analizer in that their addresses and sizes + * will be used to determine which and how many set elements to use. + * + * However, at this stage, temporary variables do not have any address + * space assigned to them because their lifetimes are generally limited + * to a few statements and the memory used for the temp vars may be + * recycled. Thus, give temp vars a pseudo address space just past the + * address space used for source-defined local variables. As each temp + * var is added to the analyzer, get_temp_address() assigns the temp var + * an address using function_t::tmpaddr as a starting point. + * + * add_operand() takes care of setting flowvar_t::flowaddr for both locals + * and temps. + */ static void flow_build_vars (function_t *func) { statement_t *s; - operand_t *operands[4]; + operand_t *operands[FLOW_OPERANDS]; int num_vars = 0; int i, j; set_t *stuse; @@ -358,7 +519,16 @@ flow_build_vars (function_t *func) // first, count .return and .param_[0-7] as they are always needed for (i = 0; i < num_flow_params; i++) { - flow_params[i].op.o.def = param_symbol (flow_params[i].name)->s.def; + def_t *def = param_symbol (flow_params[i].name)->s.def; + def_t *a; + for (a = def->alias_defs; a; a = a->next) { + if (a->flowvar) { + delete_flowvar (a->flowvar); + a->flowvar = 0; + } + //free_def (def->alias_defs); + } + flow_params[i].op.o.def = def; num_vars += count_operand (&flow_params[i].op); } // then run through the statements in the function looking for accessed @@ -380,6 +550,7 @@ flow_build_vars (function_t *func) // set up pseudo address space for temp vars so accessing tmp vars // though aliases analyses correctly func->tmpaddr = func->num_statements + func->symtab->space->size; + func->num_vars = 0; // incremented by add_operand // first, add .return and .param_[0-7] as they are always needed for (i = 0; i < num_flow_params; i++) @@ -391,7 +562,12 @@ flow_build_vars (function_t *func) flow_analyze_statement (s, 0, 0, 0, operands); for (j = 0; j < 4; j++) add_operand (func, operands[j]); - + } + // and set the use/def sets for the vars (has to be a separate pass + // because the allias handling reqruires the flow address to be valid + // (ie, not -1) + for (i = 0; i < func->num_statements; i++) { + s = func->statements[i]; flow_analyze_statement (s, stuse, stdef, 0, 0); for (var_i = set_first (stdef); var_i; var_i = set_next (var_i)) { var = func->vars[var_i->element]; @@ -408,15 +584,8 @@ flow_build_vars (function_t *func) if (flowvar_is_global (func->vars[i])) set_add (func->global_vars, i); } - // create dummy defs for local vars - // defined local vars add their address in local space to the number of - // statements in the function: - // ([num_statements ... num_statements+localsize]) - // with a set element for each def used in the local space - // - // temporary vars are pseudo allocated and their addresses are added as for - // locals - // add_operand takes care of setting flowaddr for both locals and temps + // Put the local varibals in their place (set var->defined to the addresses + // spanned by the var) for (i = 0; i < func->num_vars; i++) { int j; @@ -433,8 +602,10 @@ flow_build_vars (function_t *func) set_delete (stdef); } +/** Add the tempop's spanned addresses to the kill set + */ static int -flow_tempop_kill_aliases_visit (tempop_t *tempop, void *_kill) +flow_tempop_kill_aliases (tempop_t *tempop, void *_kill) { set_t *kill = (set_t *) _kill; flowvar_t *var; @@ -444,8 +615,10 @@ flow_tempop_kill_aliases_visit (tempop_t *tempop, void *_kill) return 0; } +/** Add the def's spanned addresses to the kill set + */ static int -flow_def_kill_aliases_visit (def_t *def, void *_kill) +flow_def_kill_aliases (def_t *def, void *_kill) { set_t *kill = (set_t *) _kill; flowvar_t *var; @@ -455,6 +628,13 @@ flow_def_kill_aliases_visit (def_t *def, void *_kill) return 0; } +/** Add the flowvar's spanned addresses to the kill set + * + * If the flowvar refers to an alias, then the real def/tempop and any + * overlapping aliases are aslo killed. + * + * However, other aliases cannot kill anything in the uninitialized set. + */ static void flow_kill_aliases (set_t *kill, flowvar_t *var, const set_t *uninit) { @@ -464,19 +644,22 @@ flow_kill_aliases (set_t *kill, flowvar_t *var, const set_t *uninit) set_union (kill, var->define); op = var->op; tmp = set_new (); + // collect the kill sets from any aliases if (op->op_type == op_temp) { - tempop_visit_all (&op->o.tempop, 1, flow_tempop_kill_aliases_visit, - tmp); - set_difference (tmp, uninit); + tempop_visit_all (&op->o.tempop, 1, flow_tempop_kill_aliases, tmp); } else if (op->op_type == op_def) { - def_visit_all (op->o.def, 1, flow_def_kill_aliases_visit, tmp); - // don't allow aliases to kill definitions in the entry dummy block + def_visit_all (op->o.def, 1, flow_def_kill_aliases, tmp); + } + // don't allow aliases to kill definitions in the entry dummy block + if (uninit) { set_difference (tmp, uninit); } // merge the alias kills with the current def's kills set_union (kill, tmp); } +/** Compute reaching defs + */ static void flow_reaching_defs (flowgraph_t *graph) { @@ -494,15 +677,37 @@ flow_reaching_defs (flowgraph_t *graph) flowvar_t *var; // First, create out for the entry dummy node using fake statement numbers. + //\f[ \bigcup\limits_{i=1}^{\infty} F_{i} \f] + //\f[ \bigcap\limits_{i=1}^{\infty} F_{i} \f] + + /** The dummy entry node reaching defs \a out set is initialized to: + * \f[ out_{reaching}=[\bigcup\limits_{v \in \{locals\}} define_{v}] + * \setminus \{statements\} \f] + * where {\a locals} is the set of local def and tempop flowvars (does + * not include parameters), \a define is the set of addresses spanned + * by the flowvar (see flow_build_vars()) (XXX along with statement + * gens), and {\a statements} is the set of all statements in the + * function (ensures the \a out set does not include any initializers in + * the code nodes). + * + * All other entry node sets are initialized to empty. + */ + // kill represents the set of all statements in the function kill = set_new (); for (i = 0; i < graph->func->num_statements; i++) set_add (kill, i); + // uninit uninit = set_new (); for (i = 0; i < graph->func->num_vars; i++) { var = graph->func->vars[i]; set_union (uninit, var->define);// do not want alias handling here - set_difference (uninit, kill); // remove any gens from the function } + /** Any possible gens from the function code are removed from the + * \a uninit set (which becomes the \a out set of the entry node's + * reaching defs) in order to prevent them leaking into the real nodes. + */ + set_difference (uninit, kill); // remove any gens from the function + // initialize the reaching defs sets in the entry node graph->nodes[graph->num_nodes]->reaching_defs.out = uninit; graph->nodes[graph->num_nodes]->reaching_defs.in = set_new (); graph->nodes[graph->num_nodes]->reaching_defs.gen = set_new (); @@ -541,7 +746,7 @@ flow_reaching_defs (flowgraph_t *graph) changed = 0; // flow down the graph for (i = 0; i < graph->num_nodes; i++) { - node = graph->nodes[graph->dfo[i]]; + node = graph->nodes[graph->depth_first[i]]; in = node->reaching_defs.in; out = node->reaching_defs.out; gen = node->reaching_defs.gen; @@ -565,6 +770,8 @@ flow_reaching_defs (flowgraph_t *graph) set_delete (stkill); } +/** Update the node's \a use set from the statement's \a use set + */ static void live_set_use (set_t *stuse, set_t *use, set_t *def) { @@ -573,6 +780,8 @@ live_set_use (set_t *stuse, set_t *use, set_t *def) set_union (use, stuse); } +/** Update the node's \a def set from the statement's \a def set + */ static void live_set_def (set_t *stdef, set_t *use, set_t *def) { @@ -626,7 +835,7 @@ flow_live_vars (flowgraph_t *graph) // flow UP the graph because live variable analysis uses information // from a node's successors rather than its predecessors. for (j = graph->num_nodes - 1; j >= 0; j--) { - node = graph->nodes[graph->dfo[j]]; + node = graph->nodes[graph->depth_first[j]]; set_empty (tmp); for (succ = set_first (node->successors); succ; succ = set_next (succ)) @@ -718,7 +927,7 @@ flow_uninitialized (flowgraph_t *graph) defs = set_new (); for (i = 0; i < graph->num_nodes; i++) { - node = graph->nodes[graph->dfo[i]]; + node = graph->nodes[graph->depth_first[i]]; set_empty (defs); // collect definitions of all variables "used" in this node. use from // the live vars analysis is perfect for the job @@ -796,23 +1005,81 @@ flow_generate (flowgraph_t *graph) return code; } +static int +flow_tempop_add_aliases (tempop_t *tempop, void *_set) +{ + set_t *set = (set_t *) _set; + flowvar_t *var; + var = tempop->flowvar; + if (var) + set_add (set, var->number); + return 0; +} + +static int +flow_def_add_aliases (def_t *def, void *_set) +{ + set_t *set = (set_t *) _set; + flowvar_t *var; + var = def->flowvar; + if (var) + set_add (set, var->number); + return 0; +} + static void -flow_add_op_var (set_t *set, operand_t *op) +flow_add_op_var (set_t *set, operand_t *op, int is_use) { flowvar_t *var; + int ol = is_use ? 1 : 2; if (!set) return; if (!(var = flow_get_var (op))) return; set_add (set, var->number); + + // FIXME XXX I think the curent implementation will have problems + // for the def set when assigning to an alias as right now the real + // var is being treated as assigned as well. Want to handle partial + // defs properly, but I am as yet uncertain of how. + if (op->op_type == op_temp) { + tempop_visit_all (&op->o.tempop, ol, flow_tempop_add_aliases, set); + } else { + def_visit_all (op->o.def, ol, flow_def_add_aliases, set); + } +} + +static operand_t * +flow_analyze_pointer_operand (operand_t *ptrop, set_t *def) +{ + operand_t *op = 0; + + if (ptrop->op_type == op_value && ptrop->o.value->lltype == ev_pointer) { + ex_pointer_t *ptr = &ptrop->o.value->v.pointer; + if (ptrop->o.value->v.pointer.def) { + def_t *alias; + alias = alias_def (ptr->def, ptr->type, ptr->val); + op = def_operand (alias, ptr->type, ptrop->expr); + } + if (ptrop->o.value->v.pointer.tempop) { + op = ptrop->o.value->v.pointer.tempop; + } + if (op) { + flow_add_op_var (def, op, 0); + } + } + return op; } void flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, - operand_t *operands[4]) + operand_t *operands[FLOW_OPERANDS]) { int i, start, calln = -1; + operand_t *res_op = 0; + operand_t *aux_op1 = 0; + operand_t *aux_op2 = 0; if (use) set_empty (use); @@ -821,7 +1088,7 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, if (kill) set_empty (kill); if (operands) { - for (i = 0; i < 4; i++) + for (i = 0; i < FLOW_OPERANDS; i++) operands[i] = 0; } @@ -829,10 +1096,10 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, case st_none: internal_error (s->expr, "not a statement"); case st_expr: - flow_add_op_var (def, s->opc); - flow_add_op_var (use, s->opa); + flow_add_op_var (def, s->opc, 0); + flow_add_op_var (use, s->opa, 1); if (s->opb) - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opb, 1); if (operands) { operands[0] = s->opc; operands[1] = s->opa; @@ -840,8 +1107,8 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, } break; case st_assign: - flow_add_op_var (def, s->opb); - flow_add_op_var (use, s->opa); + flow_add_op_var (def, s->opb, 0); + flow_add_op_var (use, s->opa, 1); if (operands) { operands[0] = s->opb; operands[1] = s->opa; @@ -849,48 +1116,48 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, break; case st_ptrassign: case st_move: - flow_add_op_var (use, s->opa); - flow_add_op_var (use, s->opb); - if (!strcmp (s->opcode, "")) { - flow_add_op_var (def, s->opc); + case st_ptrmove: + case st_memset: + case st_ptrmemset: + flow_add_op_var (use, s->opa, 1); + flow_add_op_var (use, s->opb, 1); + if (!strcmp (s->opcode, "") + || !strcmp (s->opcode, "")) { + flow_add_op_var (def, s->opc, 0); + res_op = s->opc; } else if (!strcmp (s->opcode, "")) { - flow_add_op_var (use, s->opc); - if (s->opc->op_type == op_value - && s->opc->o.value->lltype == ev_pointer - && s->opc->o.value->v.pointer.def) { - operand_t *op; - ex_pointer_t *ptr = &s->opc->o.value->v.pointer; - op = def_operand (ptr->def, ptr->type); - flow_add_op_var (def, op); - if (operands) - operands[0] = op; - else - free_operand (op); - } else { - if (operands) - operands[3] = s->opc; - } + flow_add_op_var (use, s->opc, 0); + aux_op2 = flow_analyze_pointer_operand (s->opa, use); + res_op = flow_analyze_pointer_operand (s->opc, def); + aux_op1 = s->opc; + } else if (!strcmp (s->opcode, "")) { + flow_add_op_var (use, s->opc, 0); + res_op = flow_analyze_pointer_operand (s->opc, def); + aux_op1 = s->opc; + } else if (!strcmp (s->opcode, ".=")) { + flow_add_op_var (use, s->opc, 1); + res_op = flow_analyze_pointer_operand (s->opb, def); + aux_op1 = s->opc; } else { - if (s->opc) - flow_add_op_var (use, s->opc); + internal_error (s->expr, "unexpected opcode '%s' for %d", + s->opcode, s->type); } if (kill) { set_everything (kill); } if (operands) { - if (!strcmp (s->opcode, "")) - operands[0] = s->opc; + operands[0] = res_op; operands[1] = s->opa; operands[2] = s->opb; - if (strncmp (s->opcode, "opc; + operands[3] = aux_op1; + operands[4] = aux_op2; } break; case st_state: - flow_add_op_var (use, s->opa); - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opa, 1); + flow_add_op_var (use, s->opb, 1); if (s->opc) - flow_add_op_var (use, s->opc); + flow_add_op_var (use, s->opc, 1); //FIXME entity members if (operands) { operands[1] = s->opa; @@ -901,30 +1168,42 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, case st_func: if (strcmp (s->opcode, "") == 0 || strcmp (s->opcode, "") == 0) { - flow_add_op_var (use, s->opa); + flow_add_op_var (use, s->opa, 1); } else if (strcmp (s->opcode, "") == 0) { - if (use) - set_add (use, 0); //FIXME assumes .return location + if (use) { + flow_add_op_var (use, &flow_params[0].op, 1); + } } if (strncmp (s->opcode, "opcode[5] - '0'; - flow_add_op_var (use, s->opa); + flow_add_op_var (use, s->opa, 1); } else if (strncmp (s->opcode, "opcode[6] - '0'; - flow_add_op_var (use, s->opa); - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opa, 1); + flow_add_op_var (use, s->opb, 1); if (s->opc) - flow_add_op_var (use, s->opc); + flow_add_op_var (use, s->opc, 1); } if (calln >= 0) { if (use) { - for (i = start; i < calln; i++) - set_add (use, i + 1);//FIXME assumes .param_N locations + for (i = start; i < calln; i++) { + flow_add_op_var (use, &flow_params[i + 1].op, 1); + } + } + if (def) { + for (i = 0; i < num_flow_params; i++) { + flow_add_op_var (def, &flow_params[i].op, 0); + } + } + if (kill) { + for (i = 0; i < num_flow_params; i++) { + flow_kill_aliases (kill, + flow_get_var (&flow_params[i].op), + 0); + } } - if (kill) - set_add (kill, 0); //FIXME assumes .return location } if (operands) { operands[1] = s->opa; @@ -934,9 +1213,9 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, break; case st_flow: if (strcmp (s->opcode, "") != 0) { - flow_add_op_var (use, s->opa); + flow_add_op_var (use, s->opa, 1); if (strcmp (s->opcode, "") == 0) - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opb, 1); } if (operands) { operands[1] = s->opa; @@ -997,7 +1276,7 @@ flow_find_successors (flowgraph_t *graph) if (sb->next) { set_add (node->successors, sb->next->flownode->id); } else { - bug (0, "code drops off the end of the function"); + bug (st->expr, "code drops off the end of the function"); // this shouldn't happen // however, make the exit dummy block the node's successor set_add (node->successors, graph->num_nodes + 1); @@ -1175,7 +1454,7 @@ df_search (flowgraph_t *graph, set_t *visited, int *i, int n) } } node->dfn = --*i; - graph->dfo[node->dfn] = n; + graph->depth_first[node->dfn] = n; } static void @@ -1188,11 +1467,11 @@ flow_build_dfst (flowgraph_t *graph) set_add (visited, graph->num_nodes); set_add (visited, graph->num_nodes + 1); - if (graph->dfo) - free (graph->dfo); + if (graph->depth_first) + free (graph->depth_first); if (graph->dfst) set_delete (graph->dfst); - graph->dfo = calloc (graph->num_nodes, sizeof (int)); + graph->depth_first = calloc (graph->num_nodes, sizeof (int)); graph->dfst = set_new (); i = graph->num_nodes; df_search (graph, visited, &i, 0); @@ -1248,6 +1527,35 @@ flow_make_node (sblock_t *sblock, int id, function_t *func) return node; } +/** Build the flow graph for the function. + * + * In addition to the nodes create by the statement blocks, there are two + * dummy blocks: + * + * \dot + * digraph flow_build_graph { + * layout = dot; rankdir = TB; compound =true; nodesp = 1.0; + * dummy_entry [shape=box,label="entry"]; + * sblock0 [label="code"]; sblock1 [label="code"]; + * sblock2 [label="code"]; sblock3 [label="code"]; + * dummy_exit [shape=box,label="exit"]; + * dummy_entry -> sblock0; sblock0 -> sblock1; + * sblock1 -> sblock2; sblock2 -> sblock1; + * sblock2 -> dummy_exit; sblock1 -> sblock3; + * sblock3 -> dummy_exit; + * } + * \enddot + * + * The entry block is used for detecting use of uninitialized local variables + * and the exit block is used for ensuring global variables are treated as + * live at function exit. + * + * The exit block, which also is empty of statements, has its live vars + * \a use set initilized to the set of global defs, which are simply numbered + * by their index in the functions list of flowvars. All other exit node sets + * are initialized to empty. + * \f[ use_{live}=globals \f] + */ static flowgraph_t * flow_build_graph (function_t *func) { @@ -1311,3 +1619,5 @@ flow_data_flow (function_t *func) flow_cleanup_dags (graph); func->sblock = flow_generate (graph); } + +///@} diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 4d3a617e9..c9e5474a5 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -46,6 +46,7 @@ #include "qfcc.h" +#include "class.h" #include "codespace.h" #include "debug.h" #include "def.h" @@ -119,7 +120,7 @@ param_append_identifiers (param_t *params, symbol_t *idents, type_t *type) return params; } -param_t * +static param_t * _reverse_params (param_t *params, param_t *next) { param_t *p = params; @@ -137,6 +138,20 @@ reverse_params (param_t *params) return _reverse_params (params, 0); } +param_t * +append_params (param_t *params, param_t *more_params) +{ + if (params) { + param_t *p; + for (p = params; p->next; ) { + p = p->next; + } + p->next = more_params; + return params; + } + return more_params; +} + param_t * copy_params (param_t *params) { @@ -155,7 +170,12 @@ parse_params (type_t *type, param_t *parms) { param_t *p; type_t *new; - int count; + int count = 0; + + if (type && obj_is_class (type)) { + error (0, "cannot return an object (forgot *?)"); + type = &type_id; + } new = new_type (); new->type = ev_func; @@ -168,13 +188,19 @@ parse_params (type_t *type, param_t *parms) count++; } } - new->t.func.param_types = malloc (count * sizeof (type_t)); + if (count) { + new->t.func.param_types = malloc (count * sizeof (type_t)); + } for (p = parms; p; p = p->next) { if (!p->selector && !p->type && !p->name) { if (p->next) internal_error (0, 0); new->t.func.num_params = -(new->t.func.num_params + 1); } else if (p->type) { + if (obj_is_class (p->type)) { + error (0, "cannot use an object as a parameter (forgot *?)"); + p->type = &type_id; + } new->t.func.param_types[new->t.func.num_params] = p->type; new->t.func.num_params++; } @@ -467,6 +493,7 @@ build_scope (symbol_t *fsym, symtab_t *parent) symtab = new_symtab (parent, stab_local); fsym->s.func->symtab = symtab; + fsym->s.func->label_scope = new_symtab (0, stab_local); symtab->space = defspace_new (ds_virtual); current_symtab = symtab; @@ -638,12 +665,19 @@ build_builtin_function (symbol_t *sym, expr_t *bi_val, int far) if (sym->s.func->def->external) return 0; + sym->s.func->def->initialized = 1; + sym->s.func->def->constant = 1; + sym->s.func->def->nosave = 1; add_function (sym->s.func); if (is_integer_val (bi_val)) bi = expr_integer (bi_val); else bi = expr_float (bi_val); + if (bi < 0) { + error (bi_val, "builtin functions must be positive or 0"); + return 0; + } sym->s.func->builtin = bi; reloc_def_func (sym->s.func, sym->s.func->def); build_function (sym); diff --git a/tools/qfcc/source/idstuff.c b/tools/qfcc/source/idstuff.c index 629862003..2f195b7e2 100644 --- a/tools/qfcc/source/idstuff.c +++ b/tools/qfcc/source/idstuff.c @@ -295,7 +295,7 @@ WriteProgdefs (dprograms_t *progs, const char *filename) crc = CRC_Block ((byte *) dstr->str, dstr->size - 1); dasprintf (dstr, "#define PROGHEADER_CRC %u\n", crc); - dstring_insertstr (dstr, 0, "/* Actually, generated by qfcc, be one must " + dstring_insertstr (dstr, 0, "/* Actually, generated by qfcc, but one must " "maintain formalities */"); if (filename) { diff --git a/tools/qfcc/source/linker.c b/tools/qfcc/source/linker.c index 3f07ba7b0..de107d1b4 100644 --- a/tools/qfcc/source/linker.c +++ b/tools/qfcc/source/linker.c @@ -1119,15 +1119,12 @@ undefined_def (qfo_def_t *def) pr_lineno_t *line; while (func - work->funcs < work->num_funcs) { - if (func->code < 0) { - continue; - } - if ((pr_uint_t) func->code > reloc->offset) { - continue; - } - if (!best || reloc->offset - func->code < best_dist) { - best = func; - best_dist = reloc->offset - func->code; + if (func->code >= 0 + && (pr_uint_t) func->code <= reloc->offset) { + if (!best || reloc->offset - func->code < best_dist) { + best = func; + best_dist = reloc->offset - func->code; + } } func++; } @@ -1164,7 +1161,7 @@ check_defs (void) defref_t *_d = Hash_Find (defined_data_defs, "self"); if (_d) { qfo_def_t *d = REF (_d); - if (QFO_TYPEMETA (work, d->type) == ty_none + if (QFO_TYPEMETA (work, d->type) == ty_basic && QFO_TYPETYPE (work, d->type) == ev_entity) def_warning (d, "@self and self used together"); } diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 883133b64..e8e342c7a 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -89,8 +89,8 @@ new_method (type_t *ret_type, param_t *selector, param_t *opt_params) dstring_t *name = dstring_newstr (); dstring_t *types = dstring_newstr (); - opt_params = reverse_params (opt_params); - selector = _reverse_params (selector, opt_params); + selector = reverse_params (selector); + selector = append_params (selector, opt_params); cmd->next = selector; self->next = cmd; @@ -109,7 +109,7 @@ new_method (type_t *ret_type, param_t *selector, param_t *opt_params) free (name); free (types); - //print_type (meth->type); puts (""); + //print_type (meth->type); meth->def = 0; if (!known_methods) @@ -147,6 +147,12 @@ add_method (methodlist_t *methodlist, method_t *method) if (method->next) internal_error (0, "add_method: method loop detected"); + for (method_t *m = methodlist->head; m; m = m->next) { + if (method_compare (m, method)) { + debug (0, "dropping duplicate method: %s", method->name); + return; + } + } *methodlist->tail = method; methodlist->tail = &method->next; } @@ -199,16 +205,110 @@ new_methodlist (void) return l; } -void -copy_methods (methodlist_t *dst, methodlist_t *src) +static uintptr_t +methodset_get_hash (const void *_method, void *unused) { - method_t *s, *d; + method_t *method = (method_t *) _method; + uintptr_t hash; + + hash = Hash_String (method->name); + return hash ^ (method->instance << 3); +} + +static int +methodset_compare (const void *_m1, const void *_m2, void *unused) +{ + method_t *m1 = (method_t *) _m1; + method_t *m2 = (method_t *) _m2; + int cmp; + + cmp = strcmp (m1->name, m2->name) == 0; + return cmp && m1->instance == m2->instance; +} + +methodset_t * +new_methodset (void) +{ + methodset_t *s = malloc (sizeof (*s)); + s->tab = Hash_NewTable (31, 0, 0, 0); + Hash_SetHashCompare (s->tab, methodset_get_hash, methodset_compare); + return s; +} + +void +methodset_add_methods (methodset_t *methodset, methodlist_t *methods) +{ + method_t *m; + + for (m = methods->head; m; m = m->next) { + Hash_AddElement (methodset->tab, m); + } +} + +int +methodset_contains_method (methodset_t *methodset, method_t *method) +{ + return Hash_FindElement (methodset->tab, method) != 0; +} + +static int __attribute__((pure)) +method_in_list (methodlist_t *method_list, method_t *method) +{ + method_t *m; + + for (m = method_list->head; m; m = m->next) { + if (method_compare (m, method)) { + return 1; + } + } + return 0; +} + +void +merge_method_lists (methodlist_t *dst, methodlist_t *src) +{ + while (src->head) { + method_t *s = src->head; + src->head = s->next; + s->next = 0; + if (method_in_list (dst, s)) { + debug (0, "dropping duplicate method: %s", s->name); + free (s); + } else { + // add_method does the duplicate check + *dst->tail = s; + dst->tail = &s->next; + } + } + free (src); +} + +void +copy_methods (methodlist_t *dst, methodlist_t *src, methodset_t *except) +{ + method_t *s, *d; + param_t *self; for (s = src->head; s; s = s->next) { + if (methodset_contains_method (except, s) || method_in_list (dst, s)) { + debug (0, "skipping duplicate method: %s", s->name); + continue; + } d = malloc (sizeof (method_t)); *d = *s; + // The above is only a shallow copy and thus even though the methods + // are not shared between the source and destination lists, the + // parameters are. Thus, duplicate the self (first) parameter so + // changing its type to match the class into which it is inserted does + // not affect the source list. The rest of the parameters do not need + // to be copied as they will not be altered. + self = malloc (sizeof (param_t)); + *self = *d->params; + d->params = self; d->next = 0; - add_method (dst, d); + // add_method does the duplicate check + *dst->tail = d; + dst->tail = &d->next; } } @@ -275,6 +375,20 @@ find_method (const char *sel_name) return Hash_Find (known_methods, sel_name); } +method_t * +methodlist_find_method (methodlist_t *methodlist, selector_t *selector, + int instance) +{ + method_t *m; + + for (m = methodlist->head; m; m = m->next) { + if (m->instance == instance && strcmp (selector->name, m->name) == 0) { + return m; + } + } + return 0; +} + void selector_name (dstring_t *sel_id, keywordarg_t *selector) { @@ -474,7 +588,7 @@ emit_methods (methodlist_t *methods, const char *name, int instance) if (!methods) return 0; - for (count = 0, m = methods->head; m; m = m->next) + for (count = 0, m = methods->head; m; m = m->next) { if (!m->instance == !instance) { if (!m->def && options.warnings.unimplemented) { warning (0, "Method `%c%s' not implemented", @@ -483,6 +597,7 @@ emit_methods (methodlist_t *methods, const char *name, int instance) if (m->def) count++; } + } if (!count) return 0; methods->count = count; @@ -510,9 +625,11 @@ emit_method_list_item (def_t *def, void *data, int index) method_t *m; pr_method_description_t *desc; - if (def->type != &type_obj_method_description) - internal_error (0, "%s: expected method_description def", + if (!is_array (def->type) + || def->type->t.array.type != &type_obj_method_description) { + internal_error (0, "%s: expected array of method_description def", __FUNCTION__); + } if (index < 0 || index >= methods->count) internal_error (0, "%s: out of bounds index: %d %d", __FUNCTION__, index, methods->count); @@ -520,7 +637,7 @@ emit_method_list_item (def_t *def, void *data, int index) desc = D_POINTER (pr_method_description_t, def); for (m = methods->head; m; m = m->next) { - if (!m->instance != !methods->instance || !m->def) + if (!m->instance != !methods->instance) continue; if (!index--) break; @@ -546,7 +663,7 @@ emit_method_descriptions (methodlist_t *methods, const char *name, return 0; for (count = 0, m = methods->head; m; m = m->next) - if (!m->instance == !instance && m->def) + if (!m->instance == !instance) count++; if (!count) return 0; @@ -603,20 +720,27 @@ method_check_params (method_t *method, expr_t *args) arg_list[i--] = a; for (i = 2; i < count; i++) { expr_t *e = arg_list[i]; - type_t *t = get_type (e); + type_t *arg_type = mtype->t.func.param_types[i]; + type_t *t; - if (!t) + if (e->type == ex_compound) { + e = expr_file_line (initialized_temp_expr (arg_type, e), e); + } + t = get_type (e); + if (!t) { return e; + } if (i < param_count) { - if (e->type != ex_nil) - if (!type_assignable (mtype->t.func.param_types[i], t)) { - err = param_mismatch (e, i - 1, method->name, - mtype->t.func.param_types[i], t); + if (e->type != ex_nil) { + if (!type_assignable (arg_type, t)) { + err = param_mismatch (e, i - 1, method->name, arg_type, t); } + } } else { - if (is_integer_val (e) && options.warnings.vararg_integer) + if (is_integer_val (e) && options.warnings.vararg_integer) { warning (e, "passing integer consant into ... function"); + } } } free (arg_list); diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 44148eec8..45d01be47 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -31,6 +31,8 @@ # include "config.h" #endif +#define _GNU_SOURCE // for qsort_r + #ifdef HAVE_STRING_H # include #endif @@ -647,7 +649,7 @@ get_def_type (qfo_t *qfo, pointer_t type) return ev_void; type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); switch ((ty_meta_e)type_def->meta) { - case ty_none: + case ty_basic: // field, pointer and function types store their basic type in // the same location. return type_def->t.type; @@ -674,7 +676,7 @@ get_type_size (qfo_t *qfo, pointer_t type) return 1; type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); switch ((ty_meta_e)type_def->meta) { - case ty_none: + case ty_basic: // field, pointer and function types store their basic type in // the same location. return pr_type_size[type_def->t.type]; @@ -722,7 +724,7 @@ get_type_alignment_log (qfo_t *qfo, pointer_t type) return 0; type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); switch ((ty_meta_e)type_def->meta) { - case ty_none: + case ty_basic: // field, pointer and function types store their basic type in // the same location. return qfo_log2 (ev_types[type_def->t.type]->alignment); @@ -767,7 +769,7 @@ function_params (qfo_t *qfo, qfo_func_t *func, dfunction_t *df) if (func->type >= qfo->spaces[qfo_type_space].data_size) return; type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, func->type); - if (type->meta != ty_none && type->t.type != ev_func) + if (type->meta != ty_basic && type->t.type != ev_func) return; df->numparms = num_params = type->t.func.num_params; if (num_params < 0) @@ -860,6 +862,17 @@ align_globals_size (unsigned size) return RUP (size, 16 / sizeof (pr_type_t)); } +static int +qfo_def_compare (const void *i1, const void *i2, void *d) +{ + __auto_type defs = (const qfo_def_t *) d; + unsigned ind1 = *(unsigned *) i1; + unsigned ind2 = *(unsigned *) i2; + const qfo_def_t *def1 = defs + ind1; + const qfo_def_t *def2 = defs + ind2; + return def1->offset - def2->offset; +} + dprograms_t * qfo_to_progs (qfo_t *qfo, int *size) { @@ -873,21 +886,32 @@ qfo_to_progs (qfo_t *qfo, int *size) pr_type_t *locals; pr_type_t *far_data; pr_type_t *type_data; + pr_type_t *xdef_data; dprograms_t *progs; qfo_def_t *types_def = 0; + qfo_def_t *xdefs_def = 0; unsigned i, j; unsigned near_data_size = 0; unsigned locals_size = 0; int locals_start; + int type_encodings_start; + int xdefs_start; unsigned big_locals = 0; int big_func = 0; + pr_xdefs_t *xdefs = 0; + xdef_t *xdef; + unsigned *def_indices; + unsigned *far_def_indices; + unsigned *field_def_indices; *size = RUP (sizeof (dprograms_t), 16); progs = calloc (1, *size); progs->version = options.code.progsversion; progs->numstatements = qfo->spaces[qfo_code_space].data_size; progs->numglobaldefs = qfo->spaces[qfo_near_data_space].num_defs; - //FIXME ddef offsets are 16 bits + //ddef offsets are 16 bits so the ddef ofs will likely be invalid + //thus it will be forced invalid and the true offset written to the + //.xdefs array in the progs file progs->numglobaldefs += qfo->spaces[qfo_far_data_space].num_defs; progs->numfielddefs = qfo->spaces[qfo_entity_space].num_defs; progs->numfunctions = qfo->num_funcs + 1; @@ -909,7 +933,12 @@ qfo_to_progs (qfo_t *qfo, int *size) near_data_size = progs->numglobals; progs->numglobals = RUP (progs->numglobals, 16 / sizeof (pr_type_t)); progs->numglobals += qfo->spaces[qfo_far_data_space].data_size; + type_encodings_start = progs->numglobals; progs->numglobals += qfo->spaces[qfo_type_space].data_size; + progs->numglobals = RUP (progs->numglobals, type_xdef.alignment); + xdefs_start = progs->numglobals; + progs->numglobals += progs->numglobaldefs * type_size (&type_xdef); + progs->numglobals += progs->numfielddefs * type_size (&type_xdef); progs->entityfields = qfo->spaces[qfo_entity_space].data_size; *size += progs->numstatements * sizeof (dstatement_t); *size += progs->numglobaldefs * sizeof (ddef_t); @@ -923,6 +952,29 @@ qfo_to_progs (qfo_t *qfo, int *size) memset (progs + 1, 0, *size - sizeof (dprograms_t)); data += RUP (sizeof (dprograms_t), 16); + def_indices = alloca ((progs->numglobaldefs + progs->numfielddefs) + * sizeof (*def_indices)); + far_def_indices = def_indices + qfo->spaces[qfo_near_data_space].num_defs; + field_def_indices = def_indices + progs->numglobaldefs; + for (unsigned i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; i++) { + def_indices[i] = i; + } + for (unsigned i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; i++) { + far_def_indices[i] = i; + } + for (unsigned i = 0; i < qfo->spaces[qfo_entity_space].num_defs; i++) { + field_def_indices[i] = i; + } + qsort_r (def_indices, qfo->spaces[qfo_near_data_space].num_defs, + sizeof (unsigned), qfo_def_compare, + qfo->spaces[qfo_near_data_space].defs); + qsort_r (far_def_indices, qfo->spaces[qfo_far_data_space].num_defs, + sizeof (unsigned), qfo_def_compare, + qfo->spaces[qfo_far_data_space].defs); + qsort_r (field_def_indices, qfo->spaces[qfo_entity_space].num_defs, + sizeof (unsigned), qfo_def_compare, + qfo->spaces[qfo_entity_space].defs); + progs->ofs_strings = data - (byte *) progs; strings = (char *) data; data += RUP (progs->numstrings * sizeof (char), 16); @@ -948,7 +1000,8 @@ qfo_to_progs (qfo_t *qfo, int *size) globals = (pr_type_t*) data; locals = globals + locals_start; far_data = globals + near_data_size; - type_data = far_data + qfo->spaces[qfo_far_data_space].data_size; + type_data = globals + type_encodings_start; + xdef_data = globals + xdefs_start; memcpy (strings, qfo->spaces[qfo_strings_space].d.strings, qfo->spaces[qfo_strings_space].data_size * sizeof (char)); @@ -978,25 +1031,33 @@ qfo_to_progs (qfo_t *qfo, int *size) } for (i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; i++) { - qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + i; - if (!strcmp (QFO_GETSTR (qfo, def->name), ".type_encodings")) + unsigned ind = def_indices[i]; + qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + ind; + const char *defname = QFO_GETSTR (qfo, def->name); + if (!strcmp (defname, ".type_encodings")) types_def = def; + if (!strcmp (defname, ".xdefs")) + xdefs_def = def; convert_def (qfo, def, globaldefs++); } - //FIXME ddef offsets are 16 bits for (i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; i++) { - qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + i; + unsigned ind = far_def_indices[i]; + qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + ind; def->offset += far_data - globals; - convert_def (qfo, def, globaldefs++); + convert_def (qfo, def, globaldefs); + // the correct offset will be written to the far data space + globaldefs->ofs = -1; + globaldefs++; } for (i = 0; i < qfo->spaces[qfo_type_space].num_defs; i++) { - qfo->spaces[qfo_type_space].defs[i].offset += type_data - globals; + qfo->spaces[qfo_type_space].defs[i].offset += type_encodings_start; } for (i = 0; i < qfo->spaces[qfo_entity_space].num_defs; i++) { - convert_def (qfo, qfo->spaces[qfo_entity_space].defs + i, + unsigned ind = field_def_indices[i]; + convert_def (qfo, qfo->spaces[qfo_entity_space].defs + ind, fielddefs + i); } @@ -1019,9 +1080,33 @@ qfo_to_progs (qfo_t *qfo, int *size) if (types_def) { qfot_type_encodings_t *encodings; encodings = (qfot_type_encodings_t *) &globals[types_def->offset]; - encodings->types = type_data - globals; + encodings->types = type_encodings_start; encodings->size = qfo->spaces[qfo_type_space].data_size; } + if (xdefs_def) { + xdefs = (pr_xdefs_t *) &globals[xdefs_def->offset]; + xdef = (xdef_t *) xdef_data; + xdefs->xdefs = xdefs_start; + xdefs->num_xdefs = progs->numglobaldefs + progs->numfielddefs; + for (i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; + i++, xdef++) { + qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + i; + xdef->type = def->type + type_encodings_start; + xdef->ofs = def->offset; + } + for (i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; + i++, xdef++) { + qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + i; + xdef->type = def->type + type_encodings_start; + xdef->ofs = def->offset; + } + for (i = 0; i < qfo->spaces[qfo_entity_space].num_defs; + i++, xdef++) { + qfo_def_t *def = qfo->spaces[qfo_entity_space].defs + i; + xdef->type = def->type + type_encodings_start; + xdef->ofs = def->offset; + } + } // undo the relocation of the offsets of local defs so the local defs have // the correct offset in the debug info @@ -1044,7 +1129,7 @@ qfo_to_progs (qfo_t *qfo, int *size) printf ("%6i statements\n", progs->numstatements); printf ("%6i functions\n", progs->numfunctions); printf ("%6i global defs\n", progs->numglobaldefs); - printf ("%6i fielddefs\n", progs->numfielddefs); + printf ("%6i field defs\n", progs->numfielddefs); printf ("%6i globals\n", progs->numglobals); printf (" %6i near globals\n", near_data_size); printf (" %6i locals size%s\n", locals_size, big_function); @@ -1052,6 +1137,10 @@ qfo_to_progs (qfo_t *qfo, int *size) qfo->spaces[qfo_far_data_space].data_size); printf (" %6i type globals\n", qfo->spaces[qfo_type_space].data_size); + if (xdefs) { + printf (" %6i extended defs\n", + xdefs->num_xdefs * type_size (&type_xdef)); + } printf ("%6i entity fields\n", progs->entityfields); } @@ -1069,7 +1158,7 @@ qfo_to_sym (qfo_t *qfo, int *size) pr_auxfunction_t *auxfuncs; pr_auxfunction_t *aux; pr_lineno_t *linenos; - ddef_t *locals, *ld; + pr_def_t *locals, *ld; *size = sizeof (pr_debug_header_t); sym = calloc (1, *size); @@ -1090,12 +1179,12 @@ qfo_to_sym (qfo_t *qfo, int *size) *size += sym->num_auxfunctions * sizeof (pr_auxfunction_t); *size += sym->num_linenos * sizeof (pr_lineno_t); - *size += sym->num_locals * sizeof (ddef_t); + *size += sym->num_locals * sizeof (pr_def_t); sym = realloc (sym, *size); auxfuncs = (pr_auxfunction_t *)(sym + 1); linenos = (pr_lineno_t *)(auxfuncs + sym->num_auxfunctions); - locals = (ddef_t *)(linenos + sym->num_linenos); + locals = (pr_def_t *)(linenos + sym->num_linenos); sym->auxfunctions = (char *) auxfuncs - (char *) sym; sym->linenos = (char *) linenos - (char *) sym; @@ -1123,8 +1212,13 @@ qfo_to_sym (qfo_t *qfo, int *size) qfo->lines[func->line_info].fa.func = aux - auxfuncs; if (num_locals) { aux->local_defs = ld - locals; - for (j = 0; j < num_locals; j++) - convert_def (qfo, def++, ld++); + for (j = 0; j < num_locals; j++, def++, ld++) { + ld->type = get_def_type (qfo, def->type); + ld->size = get_type_size (qfo, def->type); + ld->ofs = def->offset; + ld->name = def->name; + ld->type_encoding = def->type; + } } aux->num_locals = num_locals; //FIXME check type diff --git a/tools/qfcc/source/obj_type.c b/tools/qfcc/source/obj_type.c index 55da5c137..c21e7e576 100644 --- a/tools/qfcc/source/obj_type.c +++ b/tools/qfcc/source/obj_type.c @@ -274,7 +274,7 @@ qfo_encode_type (type_t *type) } if (type->type_def) return type->type_def; - if (type->meta > ty_class) + if (type->meta > sizeof (funcs) / (sizeof (funcs[0]))) internal_error (0, "bad type meta type"); if (!type->encoding) type->encoding = type_get_encoding (type); diff --git a/tools/qfcc/source/opcodes.c b/tools/qfcc/source/opcodes.c index bf8b5b189..bbf10250a 100644 --- a/tools/qfcc/source/opcodes.c +++ b/tools/qfcc/source/opcodes.c @@ -131,7 +131,8 @@ opcode_free (void *_op, void *unused) void opcode_init (void) { - opcode_t *op, *mop; + const opcode_t *op; + opcode_t *mop; if (opcode_type_table) { Hash_FlushTable (opcode_void_table); diff --git a/tools/qfcc/source/options.c b/tools/qfcc/source/options.c index c3f283e89..6f972fd82 100644 --- a/tools/qfcc/source/options.c +++ b/tools/qfcc/source/options.c @@ -194,14 +194,16 @@ code_usage (void) printf ("%s - QuakeForge Code Compiler\n", this_program); printf ("Code generation options\n"); printf ( +" [no-]const-initializers Treat initialized globals as constants.\n" " [no-]cow Allow assignment to initialized globals.\n" " [no-]cpp Preprocess all input files with cpp.\n" " [no-]crc Write progdefs.h crc to progs.dat.\n" " [no-]debug Generate debug information.\n" " [no-]fast-float Use float values directly in \"if\" statements.\n" -" help Display his text.\n" +" help Display this text.\n" " [no-]local-merging Merge the local variable blocks into one.\n" " [no-]optimize Perform various optimizations on the code.\n" +" [no-]promote-float Promote float when passed through ...\n" " [no-]short-circuit Generate short circuit code for logical\n" " operators.\n" " [no-]single-cpp Convert progs.src to cpp input file.\n" @@ -309,6 +311,7 @@ DecodeArgs (int argc, char **argv) options.code.vector_components = -1; options.code.crc = -1; options.code.fast_float = true; + options.code.promote_float = true; options.warnings.uninited_variable = true; options.warnings.unused = true; options.warnings.executable = true; @@ -392,16 +395,19 @@ DecodeArgs (int argc, char **argv) options.traditional = 1; options.advanced = false; options.code.progsversion = PROG_ID_VERSION; + options.code.const_initializers = true; break; case OPT_TRADITIONAL: options.traditional = 2; options.advanced = false; options.code.progsversion = PROG_ID_VERSION; + options.code.const_initializers = true; break; case OPT_ADVANCED: options.traditional = 0; options.advanced = true; options.code.progsversion = PROG_VERSION; + options.code.const_initializers = false; break; case OPT_BLOCK_DOT: if (optarg) { @@ -485,6 +491,8 @@ DecodeArgs (int argc, char **argv) options.code.debug = flag; } else if (!(strcasecmp (temp, "fast-float"))) { options.code.fast_float = flag; + } else if (!(strcasecmp (temp, "promote-float"))) { + options.code.promote_float = flag; } else if (!strcasecmp (temp, "help")) { code_usage (); } else if (!(strcasecmp (temp, "local-merging"))) { @@ -506,6 +514,8 @@ DecodeArgs (int argc, char **argv) options.code.progsversion = PROG_ID_VERSION; else options.code.progsversion = PROG_VERSION; + } else if (!(strcasecmp (temp, "const-initializers"))) { + options.code.const_initializers = flag; } temp = strtok (NULL, ","); } @@ -710,8 +720,11 @@ DecodeArgs (int argc, char **argv) options.code.local_merging = true; if (options.code.vector_components == (qboolean) -1) options.code.vector_components = false; + } else { + options.code.promote_float = 0; } if (options.code.progsversion == PROG_ID_VERSION) { + options.code.promote_float = 0; add_cpp_def ("-D__VERSION6__=1"); if (options.code.crc == (qboolean) -1) options.code.crc = true; diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 58b661220..9d5c5a1b9 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -143,6 +143,7 @@ STRING \"(\\.|[^"\\])*\" if (options.traditional < 1) { double d = strtod (yytext, 0); qc_yylval.expr = new_double_expr (d); + qc_yylval.expr->implicit = 1; } else { float f = strtof (yytext, 0); qc_yylval.expr = new_float_expr (f); @@ -352,6 +353,7 @@ static keyword_t obj_keywords[] = { // make the language features available to traditional code. static keyword_t at_keywords[] = { {"for", FOR }, + {"goto", GOTO }, {"break", BREAK }, {"continue", CONTINUE}, {"switch", SWITCH }, diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index a2bbf1c03..4e49397bc 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -42,6 +42,7 @@ #include #include +#include #include "class.h" #include "debug.h" @@ -97,6 +98,7 @@ int yylex (void); void *pointer; // for ensuring pointer values are null struct type_s *type; struct expr_s *expr; + struct element_s *element; struct function_s *function; struct switch_block_s *switch_block; struct param_s *param; @@ -122,7 +124,7 @@ int yylex (void); %nonassoc STORAGEX %left COMMA -%right '=' ASX PAS /* pointer assign */ +%right '=' ASX %right '?' ':' %left OR %left AND @@ -144,8 +146,8 @@ int yylex (void); %token VALUE STRING %token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELLIPSIS -%token NIL IFBE IFB IFAE IFA SWITCH CASE DEFAULT ENUM TYPEDEF -%token ARGS EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT +%token NIL IFBE IFB IFAE IFA GOTO SWITCH CASE DEFAULT ENUM +%token ARGS TYPEDEF EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT %token STRUCT %token TYPE %token OBJECT TYPE_NAME @@ -153,7 +155,7 @@ int yylex (void); %token PROTECTED PROTOCOL PUBLIC SELECTOR REFERENCE SELF THIS %type optional_specifiers specifiers local_specifiers -%type storage_class save_storage +%type storage_class save_storage set_spec_storage %type type_specifier type_specifier_or_storage_class %type type @@ -180,19 +182,22 @@ int yylex (void); %type methoddef %type opt_initializer var_initializer local_def -%type opt_init opt_expr cexpr expr element_list element +%type opt_init opt_expr comma_expr expr +%type compound_init element_list +%type element %type optional_state_expr texpr vector_expr %type statement statements compound_statement -%type else label break_label continue_label -%type unary_expr cast_expr opt_arg_list arg_list +%type else bool_label break_label continue_label +%type unary_expr ident_expr cast_expr expr_list +%type opt_arg_list arg_list arg_expr %type init_var_decl_list init_var_decl %type switch_block -%type identifier +%type identifier label %type overloaded_identifier %type identifier_list -%type selector reserved_word +%type protocol_name_list selector reserved_word %type optional_param_list unaryselector keyworddecl %type keywordselector %type methodproto methoddecl @@ -264,6 +269,33 @@ default_type (specifier_t spec, symbol_t *sym) return spec; } +static int +is_anonymous_struct (specifier_t spec) +{ + if (spec.sym) { + return 0; + } + if (!is_struct (spec.type)) { + return 0; + } + if (!spec.type->t.symtab || spec.type->t.symtab->parent) { + return 0; + } + // struct and union type names always begin with "tag ". Untagged s/u + // are "tag ..". + if (spec.type->name[4] != '.') { + return 0; + } + return 1; +} + +static int +is_null_spec (specifier_t spec) +{ + static specifier_t null_spec; + return memcmp (&spec, &null_spec, sizeof (spec)) == 0; +} + %} %expect 0 @@ -312,7 +344,25 @@ external_def_list external_def : optional_specifiers external_decl_list ';' { } - | optional_specifiers ';' { } + | optional_specifiers ';' + { + if (!is_null_spec ($1)) { + if (!$1.type && !$1.sym) { + warning (0, "useless specifiers"); + } else if ($1.type && !$1.sym) { + if (is_anonymous_struct ($1)){ + warning (0, "unnamed struct/union that defines " + "no instances"); + } else if (!is_enum ($1.type) && !is_struct ($1.type)) { + warning (0, "useless type name in empty declaration"); + } + } else if (!$1.type && $1.sym) { + bug (0, "wha? %p %p", $1.type, $1.sym); + } else { + bug (0, "wha? %p %p", $1.type, $1.sym); + } + } + } | optional_specifiers qc_func_params { type_t **type; @@ -349,6 +399,14 @@ save_storage } ; +set_spec_storage + : /* emtpy */ + { + $$ = $0; + $$.storage = current_storage; + } + ; + function_body : optional_state_expr { @@ -473,6 +531,15 @@ specifiers type : type_specifier | type type_specifier + { + // deal with eg "int id" + $1.sym = $2.sym; + + if (!$1.sym) { + error (0, "two or more data types in declaration specifiers"); + } + $$ = $1; + } ; type_specifier_or_storage_class @@ -490,6 +557,7 @@ type_specifier | TYPE_NAME { $$ = make_spec ($1->type, 0, 0, 0); + $$.sym = $1; } | OBJECT protocolrefs { @@ -501,6 +569,7 @@ type_specifier } else { $$ = make_spec (&type_id, 0, 0, 0); } + $$.sym = $1; } | CLASS_NAME protocolrefs { @@ -512,6 +581,7 @@ type_specifier } else { $$ = make_spec ($1->type, 0, 0, 0); } + $$.sym = $1; } // NOTE: fields don't parse the way they should. This is not a problem // for basic types, but functions need special treatment @@ -590,9 +660,18 @@ struct_specifier if (!sym->table) { symtab_addsymbol (current_symtab, sym); } else { - error (0, "%s %s redefined", $1 == 's' ? "struct" : "union", - $2->name); - $1 = 0; + if (!sym->type) { + internal_error (0, "broken structure symbol?"); + } + if (sym->type->meta == ty_enum + || (sym->type->meta == ty_struct && sym->type->t.symtab)) { + error (0, "%s %s redefined", + $1 == 's' ? "struct" : "union", $2->name); + $1 = 0; + } else if (sym->type->meta != ty_struct) { + internal_error (0, "%s is not a struct or union", + $2->name); + } } current_symtab = new_symtab (current_symtab, stab_local); } @@ -645,6 +724,34 @@ struct_def_list struct_def : type struct_decl_list | type + { + if ($1.sym && $1.sym->type != $1.type) { + // a type name (id, typedef, etc) was used as a field name. + // this is allowed in C + $1.sym = new_symbol ($1.sym->name); + $1.sym->type = $1.type; + $1.sym->sy_type = sy_var; + symtab_addsymbol (current_symtab, $1.sym); + if (!$1.sym->table) { + error (0, "duplicate field `%s'", $1.sym->name); + } + } else if (is_anonymous_struct ($1)) { + // anonymous struct/union + // type->name always begins with "tag " + $1.sym = new_symbol (va (".anonymous.%s", $1.type->name + 4)); + $1.sym->type = $1.type; + $1.sym->sy_type = sy_var; + $1.sym->visibility = vis_anonymous; + symtab_addsymbol (current_symtab, $1.sym); + if (!$1.sym->table) { + error (0, "duplicate field `%s'", $1.sym->name); + } + } else { + // bare type + warning (0, "declaration does not declare anything"); + } + $$ = $1; + } ; struct_decl_list @@ -661,7 +768,11 @@ struct_decl $1->type = append_type ($1->type, $0.type); $1->type = find_type ($1->type); $1->sy_type = sy_var; + $1->visibility = current_visibility; symtab_addsymbol (current_symtab, $1); + if (!$1->table) { + error (0, "duplicate field `%s'", $1->name); + } } | var_decl { @@ -670,7 +781,11 @@ struct_decl $1->type = append_type ($1->type, $0.type); $1->type = find_type ($1->type); $1->sy_type = sy_var; + $1->visibility = current_visibility; symtab_addsymbol (current_symtab, $1); + if (!$1->table) { + error (0, "duplicate field `%s'", $1->name); + } } | var_decl ':' expr %prec COMMA {} | ':' expr %prec COMMA {} @@ -799,6 +914,7 @@ abstract_decl $1.type = type_default; $$->type = find_type (append_type ($$->type, $1.type)); } + | error { $$ = new_symbol (""); } ; qc_param_decl @@ -974,15 +1090,27 @@ overloaded_identifier non_code_func : '=' '#' expr { + if ($-1.storage == sc_extern) { + error (0, "initializing external variable"); + } build_builtin_function ($0, $3, 0); } | '=' expr { - symbol_t *sym = $0; - specifier_t spec = $-1; - initialize_def (sym, $2, current_symtab->space, spec.storage); - if (sym->s.def) - sym->s.def->nosave |= spec.nosave; + if (local_expr) { + symbol_t *sym = $0; + specifier_t spec = $-1; + initialize_def (sym, $2, current_symtab->space, spec.storage); + if (sym->s.def) + sym->s.def->nosave |= spec.nosave; + } else { + if (is_integer_val ($2) || is_float_val ($2)) { + error (0, "invalid function initializer." + " did you forget #?"); + } else { + error (0, "cannot create global function variables"); + } + } } | /* emtpy */ { @@ -1025,7 +1153,18 @@ opt_initializer var_initializer : '=' expr { $$ = $2; } - | '=' '{' element_list optional_comma '}' { $$ = $3; } + | '=' compound_init + { + if (!$2 && is_scalar ($-1.type)) { + error (0, "empty scalar initializer"); + } + $$ = $2 ? $2 : new_nil_expr (); + } + ; + +compound_init + : '{' element_list optional_comma '}' { $$ = $2; } + | '{' '}' { $$ = 0; } ; optional_state_expr @@ -1036,18 +1175,18 @@ optional_state_expr element_list : element { - $$ = new_block_expr (); - append_expr ($$, $1); + $$ = new_compound_init (); + append_element ($$, $1); } - | element_list ',' element + | element_list ',' element { - append_expr ($$, $3); + append_element ($$, $3); } ; element - : '{' element_list optional_comma '}' { $$ = $2; } - | expr { $$ = $1; } + : compound_init { $$ = new_element ($1, 0); } + | expr { $$ = new_element ($1, 0); } ; optional_comma @@ -1102,6 +1241,26 @@ local_def local_expr = 0; (void) ($2); } + | specifiers ';' + { + if (!is_null_spec ($1)) { + if (!$1.type && !$1.sym) { + warning (0, "useless specifiers"); + } else if ($1.type && !$1.sym) { + if (is_anonymous_struct ($1)){ + warning (0, "unnamed struct/union that defines " + "no instances"); + } else if (!is_enum ($1.type) && !is_struct ($1.type)) { + warning (0, "useless type name in empty declaration"); + } + } else if (!$1.type && $1.sym) { + bug (0, "wha? %p %p", $1.type, $1.sym); + } else { + bug (0, "wha? %p %p", $1.type, $1.sym); + } + } + $$ = 0; + } ; statement @@ -1109,10 +1268,8 @@ statement | error ';' { $$ = 0; yyerrok; } | compound_statement { $$ = $1; } | local_def { $$ = $1; } - | RETURN opt_expr ';' - { - $$ = return_expr (current_func, $2); - } + | RETURN opt_expr ';' { $$ = return_expr (current_func, $2); } + | RETURN compound_init ';' { $$ = return_expr (current_func, $2); } | BREAK ';' { $$ = 0; @@ -1129,6 +1286,10 @@ statement else error (0, "continue outside of loop"); } + | label + { + $$ = named_label_expr ($1); + } | CASE expr ':' { $$ = case_label_expr (switch_block, $2); @@ -1143,6 +1304,11 @@ statement switch_block = $5; break_label = $2; } + | GOTO NAME + { + expr_t *label = named_label_expr ($2); + $$ = goto_expr (label); + } | IF not '(' texpr ')' statement %prec IFX { $$ = build_if_statement ($2, $4, $6, 0, 0); @@ -1176,7 +1342,7 @@ statement break_label = $2; continue_label = $3; } - | cexpr ';' + | comma_expr ';' { $$ = $1; } @@ -1196,6 +1362,10 @@ else ; label + : NAME ':' + ; + +bool_label : /* empty */ { $$ = new_label_expr (); @@ -1228,8 +1398,8 @@ switch_block ; opt_init - : cexpr - | type init_var_decl_list { $$ = $2; } + : comma_expr + | type set_spec_storage init_var_decl_list { $$ = $3; } | /* empty */ { $$ = 0; @@ -1261,7 +1431,7 @@ init_var_decl ; opt_expr - : cexpr + : comma_expr | /* empty */ { $$ = 0; @@ -1277,6 +1447,7 @@ unary_expr | '(' expr ')' { $$ = $2; $$->paren = 1; } | unary_expr '(' opt_arg_list ')' { $$ = function_expr ($1, $3); } | unary_expr '[' expr ']' { $$ = array_expr ($1, $3); } + | unary_expr '.' ident_expr { $$ = field_expr ($1, $3); } | unary_expr '.' unary_expr { $$ = field_expr ($1, $3); } | INCOP unary_expr { $$ = incop_expr ($1, $2, 0); } | unary_expr INCOP { $$ = incop_expr ($2, $1, 1); } @@ -1295,8 +1466,14 @@ unary_expr | obj_expr { $$ = $1; } ; +ident_expr + : OBJECT { $$ = new_symbol_expr ($1); } + | CLASS_NAME { $$ = new_symbol_expr ($1); } + | TYPE_NAME { $$ = new_symbol_expr ($1); } + ; + vector_expr - : '[' expr ',' arg_list ']' + : '[' expr ',' expr_list ']' { expr_t *t = $4; while (t->next) @@ -1317,10 +1494,11 @@ cast_expr expr : cast_expr | expr '=' expr { $$ = assign_expr ($1, $3); } + | expr '=' compound_init { $$ = assign_expr ($1, $3); } | expr ASX expr { $$ = asx_expr ($2, $1, $3); } | expr '?' expr ':' expr { $$ = conditional_expr ($1, $3, $5); } - | expr AND label expr { $$ = bool_expr (AND, $3, $1, $4); } - | expr OR label expr { $$ = bool_expr (OR, $3, $1, $4); } + | expr AND bool_label expr { $$ = bool_expr (AND, $3, $1, $4); } + | expr OR bool_label expr { $$ = bool_expr (OR, $3, $1, $4); } | expr EQ expr { $$ = binary_expr (EQ, $1, $3); } | expr NE expr { $$ = binary_expr (NE, $1, $3); } | expr LE expr { $$ = binary_expr (LE, $1, $3); } @@ -1344,8 +1522,8 @@ texpr : expr { $$ = convert_bool ($1, 1); } ; -cexpr - : arg_list +comma_expr + : expr_list { if ($1->next) { expr_t *res = $1; @@ -1356,20 +1534,34 @@ cexpr } ; +expr_list + : expr + | expr_list ',' expr + { + $3->next = $1; + $$ = $3; + } + ; + opt_arg_list : /* emtpy */ { $$ = 0; } | arg_list { $$ = $1; } ; arg_list - : expr - | arg_list ',' expr + : arg_expr + | arg_list ',' arg_expr { $3->next = $1; $$ = $3; } ; +arg_expr + : expr + | compound_init + ; + const : VALUE | NIL { $$ = new_nil_expr (); } @@ -1393,6 +1585,7 @@ identifier obj_def : classdef { } | classdecl + | protocoldecl | protocoldef | { if (!current_class) PARSE_ERROR; } methoddef | END @@ -1431,9 +1624,13 @@ classdecl class_name : identifier %prec CLASS_NOT_CATEGORY { - $1 = check_undefined ($1); - if (!$1->type || !obj_is_class ($1->type)) { - error (0, "`%s' is not a class %p", $1->name, $1->type); + if (!$1->type) { + $$ = get_class ($1, 1); + if (!$1->table) { + symtab_addsymbol (current_symtab, $1); + } + } else if (!obj_is_class ($1->type)) { + error (0, "`%s' is not a class", $1->name); $$ = get_class (0, 1); } else { $$ = $1->type->t.class; @@ -1454,6 +1651,7 @@ new_class_name $1 = check_redefined ($1); $$ = get_class ($1, 1); } + $$->interface_declared = 1; current_class = &$$->class_type; if (!$1->table) symtab_addsymbol (current_symtab, $1); @@ -1472,6 +1670,12 @@ class_with_super new_class_with_super : new_class_name ':' class_name { + if (!$3->interface_declared) { + $3->interface_declared = 1; + error (0, "cannot find interface declaration for `%s', " + "superclass of `%s'", $3->name, $1->name); + } + $1->interface_declared = 1; $1->super_class = $3; $$ = $1; } @@ -1520,17 +1724,18 @@ category_reference } ; - protocol_name : identifier { $$ = get_protocol ($1->name, 0); - if ($$) { - error (0, "redefinition of %s", $1->name); + if ($$ && $$->methods) { + error (0, "redefinition of protocol %s", $1->name); $$ = get_protocol (0, 1); - } else { + } + if (!$$) { $$ = get_protocol ($1->name, 1); } + $$->methods = new_methodlist (); current_class = &$$->class_type; } ; @@ -1623,18 +1828,33 @@ classdef | REFERENCE category_reference ';' { } ; +protocoldecl + : protocol + protocol_name_list ';' + { + while ($2) { + get_protocol ($2->name, 1); + $2 = $2->next; + } + } + ; + protocoldef - : PROTOCOL { $$ = current_class; } + : protocol protocol_name - protocolrefs { protocol_add_protocols ($3, $4); $$ = 0; } - methodprotolist { protocol_add_methods ($3, $6); } + protocolrefs { protocol_add_protocols ($2, $3); $$ = 0; } + methodprotolist { protocol_add_methods ($2, $5); } END { - current_class = $2; - (void) ($5); + current_class = $1; + (void) ($4); } ; +protocol + : PROTOCOL { $$ = current_class; } + ; + protocolrefs : /* emtpy */ { $$ = 0; } | LT { $$ = new_protocol_list (); } @@ -1677,6 +1897,7 @@ ivar_decl_list tab = $$->parent; // preserve the ivars inheritance chain build_struct ('s', 0, $$, 0); $$->parent = tab; + current_visibility = vis_public; } ; @@ -1698,6 +1919,24 @@ ivar_decls ivar_decl : type ivars + | type + { + if (is_anonymous_struct ($1)) { + // anonymous struct/union + // type->name always begins with "tag " + $1.sym = new_symbol (va (".anonymous.%s", $1.type->name + 4)); + $1.sym->type = $1.type; + $1.sym->sy_type = sy_var; + $1.sym->visibility = vis_anonymous; + symtab_addsymbol (current_symtab, $1.sym); + if (!$1.sym->table) { + error (0, "duplicate field `%s'", $1.sym->name); + } + } else { + // bare type + warning (0, "declaration does not declare anything"); + } + } ; ivars @@ -1782,6 +2021,10 @@ methodproto $2->instance = 0; $$ = $2; } + | '-' error ';' + { $$ = new_method (&type_id, new_param ("", 0, 0), 0); } + | '+' error ';' + { $$ = new_method (&type_id, new_param ("", 0, 0), 0); } | '-' methoddecl ';' { $2->instance = 1; @@ -1806,8 +2049,7 @@ optional_param_list | ',' param_list { $$ = $2; } | ',' param_list ',' ELLIPSIS { - $$ = new_param (0, 0, 0); - $$->next = $2; + $$ = param_append_identifiers ($2, 0, 0); } ; @@ -1820,6 +2062,10 @@ keywordselector | keywordselector keyworddecl { $2->next = $1; $$ = $2; } ; +protocol_name_list + : identifier + | protocol_name_list ',' identifier { $3->next = $1; $$ = $3; } + selector : NAME { $$ = $1; } | CLASS_NAME { $$ = $1; } diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index 780db073a..7d0f8c800 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -148,6 +148,9 @@ InitData (void) pr.code = codespace_new (); memset (codespace_newstatement (pr.code), 0, sizeof (dstatement_t)); pr.strings = strpool_new (); + if (options.code.promote_float) { + ReuseString ("@float_promoted@"); + } pr.num_functions = 1; pr.num_linenos = 0; @@ -391,7 +394,9 @@ compile_to_obj (const char *file, const char *obj, lang_t lang) exit (1); } } - write_frame_macros (va ("%s.frame", file_basename (file))); + if (options.frames_files) { + write_frame_macros (va ("%s.frame", file_basename (file))); + } if (!err) { qfo_t *qfo; @@ -423,6 +428,7 @@ finish_link (void) ¶m_size); linker_add_def (".param_alignment", &type_integer, flags, ¶m_alignment); + linker_add_def (".xdefs", &type_xdefs, flags, 0); } if (options.code.debug) { @@ -442,7 +448,12 @@ finish_link (void) } else { int size; dprograms_t *progs; + pr_debug_header_t *sym = 0; + int sym_size = 0; + if (options.code.debug) { + sym = qfo_to_sym (qfo, &sym_size); + } progs = qfo_to_progs (qfo, &size); //finish_compilation (); @@ -456,9 +467,6 @@ finish_link (void) WriteProgs (progs, size); if (options.code.debug) { - pr_debug_header_t *sym; - int sym_size = 0; - sym = qfo_to_sym (qfo, &sym_size); sym->crc = CRC_Block ((byte *) progs, size); WriteSym (sym, sym_size); } @@ -749,8 +757,10 @@ progs_src_compile (void) } else { if (compile_file (qc_filename->str)) return 1; - write_frame_macros (va ("%s.frame", - file_basename (qc_filename->str))); + if (options.frames_files) { + write_frame_macros (va ("%s.frame", + file_basename (qc_filename->str))); + } } if (!Script_TokenAvailable (script, 0)) break; diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index 10ddf8abd..02f05bce9 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -128,7 +128,6 @@ static edict_t *edicts; static int num_edicts; static int reserved_edicts = 1; static progs_t pr; -static int need_progs; static qfo_t *qfo; static const char *source_path = ""; @@ -176,7 +175,7 @@ file_error (progs_t *pr, const char *name) } static void * -load_file (progs_t *pr, const char *name) +load_file (progs_t *pr, const char *name, off_t *_size) { QFile *file; int size; @@ -191,6 +190,7 @@ load_file (progs_t *pr, const char *name) sym = malloc (size + 1); sym[size] = 0; Qread (file, sym, size); + *_size = size; return sym; } @@ -233,10 +233,9 @@ init_qf (void) { Sys_Init (); - Cvar_Get ("pr_debug", va ("%d", verbosity), 0, 0, ""); + Cvar_Get ("pr_debug", va ("%d", 1+verbosity), 0, 0, ""); Cvar_Get ("pr_source_path", source_path, 0, 0, ""); PR_Init_Cvars (); - PR_Init (); pr.edicts = &edicts; pr.num_edicts = &num_edicts; @@ -246,58 +245,18 @@ init_qf (void) pr.allocate_progs_mem = allocate_progs_mem; pr.free_progs_mem = free_progs_mem; + PR_Init (&pr); + func_tab = Hash_NewTable (1021, 0, 0, 0); Hash_SetHashCompare (func_tab, func_hash, func_compare); } -static void -convert_qfo (void) -{ - int size; - int i; - - pr.progs = qfo_to_progs (qfo, &size); - -#define P(t,o) ((t *)((char *)pr.progs + pr.progs->o)) - pr.pr_statements = P (dstatement_t, ofs_statements); - pr.pr_strings = P (char, ofs_strings); - pr.pr_stringsize = pr.progs->numstrings; - pr.pr_functions = P (dfunction_t, ofs_functions); - pr.pr_globaldefs = P (ddef_t, ofs_globaldefs); - pr.pr_fielddefs = P (ddef_t, ofs_fielddefs); - pr.pr_globals = P (pr_type_t, ofs_globals); - pr.globals_size = pr.progs->numglobals; - pr.pr_edict_size = max (1, pr.progs->entityfields) * 4; - pr.pr_edictareasize = 1 * pr.pr_edict_size; -#undef P - - if (verbosity) { - pr.debug = qfo_to_sym (qfo, &size); -#define P(t,o) ((t *)((char *)pr.debug + pr.debug->o)) - pr.auxfunctions = P (pr_auxfunction_t, auxfunctions); - pr.linenos = P (pr_lineno_t, linenos); - pr.local_defs = P (ddef_t, locals); -#undef P - - pr.local_defs = calloc (qfo->num_defs, sizeof (ddef_t)); - - pr.auxfunction_map = calloc (pr.progs->numfunctions, - sizeof (pr_auxfunction_t *)); - for (i = 0; (int) i < pr.progs->numfunctions; i++) //FIXME (cast) - pr.auxfunction_map[i] = 0; - - for (i = 0; i < (int) pr.debug->num_auxfunctions; i++) { - pr_auxfunction_t *aux = pr.auxfunctions + i; - pr.auxfunction_map[aux->function] = aux; - } - } -} - static int load_progs (const char *name) { QFile *file; - int i, size; + int size; + pr_uint_t i; char buff[5]; Hash_FlushTable (func_tab); @@ -310,6 +269,7 @@ load_progs (const char *name) Qread (file, buff, 4); buff[4] = 0; Qseek (file, 0, SEEK_SET); + qfo = 0; if (!strcmp (buff, QFO)) { qfo = qfo_read (file); Qclose (file); @@ -317,9 +277,7 @@ load_progs (const char *name) if (!qfo) return 0; - if (!need_progs) - return 1; - convert_qfo (); + return 1; } else { pr.progs_name = name; pr.max_edicts = 1; @@ -330,7 +288,6 @@ load_progs (const char *name) if (!pr.progs) return 0; - PR_LoadStrings (&pr); PR_ResolveGlobals (&pr); PR_LoadDebug (&pr); } @@ -350,10 +307,10 @@ typedef struct { operation_t operations[] = { {disassemble_progs, 0}, // disassemble {dump_globals, qfo_globals}, // globals - {dump_strings, 0}, // strings - {dump_fields, 0}, // fields + {dump_strings, qfo_strings}, // strings + {dump_fields, qfo_fields}, // fields {dump_functions, qfo_functions}, // functions - {dump_lines, 0}, // lines + {dump_lines, qfo_lines}, // lines {dump_modules, 0}, // modules {0, qfo_relocs}, // relocs {dump_types, qfo_types}, // types @@ -412,12 +369,11 @@ main (int argc, char **argv) } init_qf (); while (optind < argc) { - need_progs = !func->qfo; if (!load_progs (argv[optind++])) return 1; if (qfo && func->qfo) func->qfo (qfo); - else if (func->progs) + else if (!qfo && func->progs) func->progs (&pr); else fprintf (stderr, "can't process %s\n", argv[optind - 1]); diff --git a/tools/qfcc/source/qp-parse.y b/tools/qfcc/source/qp-parse.y index 922068b02..730eab57a 100644 --- a/tools/qfcc/source/qp-parse.y +++ b/tools/qfcc/source/qp-parse.y @@ -105,7 +105,7 @@ int yylex (void); %nonassoc STORAGEX %left COMMA -%right '=' ASX PAS /* pointer assign */ +%right '=' ASX %right '?' ':' %left OR %left AND @@ -139,6 +139,29 @@ int yylex (void); %type sign %{ + +static void +build_dotmain (symbol_t *program) +{ + symbol_t *dotmain = new_symbol (".main"); + expr_t *code; + expr_t *exitcode; + + dotmain->params = 0; + dotmain->type = parse_params (&type_integer, 0); + dotmain->type = find_type (dotmain->type); + dotmain = function_symbol (dotmain, 0, 1); + + exitcode = new_symbol_expr (symtab_lookup (current_symtab, "ExitCode")); + + current_func = begin_function (dotmain, 0, current_symtab, 0); + current_symtab = current_func->symtab; + code = new_block_expr (); + append_expr (code, function_expr (new_symbol_expr (program), 0)); + append_expr (code, return_expr (current_func, exitcode)); + build_code_function (dotmain, 0, code); +} + %} %% @@ -159,15 +182,7 @@ program build_code_function ($1, 0, $4); current_symtab = st; - $4 = function_expr (new_symbol_expr ($1), 0); - $1 = new_symbol (".main"); - $1->params = 0; - $1->type = parse_params (&type_void, 0); - $1->type = find_type ($1->type); - $1 = function_symbol ($1, 0, 1); - current_func = begin_function ($1, 0, current_symtab, 0); - current_symtab = current_func->symtab; - build_code_function ($1, 0, $4); + build_dotmain ($1); current_symtab = st; } ; @@ -178,6 +193,15 @@ program_head { $$ = $3; + // FIXME need units and standard units + { + symbol_t *sym = new_symbol ("ExitCode"); + sym->type = &type_integer; + initialize_def (sym, 0, current_symtab->space, sc_global); + if (sym->s.def) { + sym->s.def->nosave = 1; + } + } $$->type = parse_params (&type_void, 0); $$->type = find_type ($$->type); $$ = function_symbol ($$, 0, 1); @@ -375,6 +399,7 @@ statement else : ELSE { + // this is only to get the the file and line number info $$ = new_nil_expr (); } ; diff --git a/tools/qfcc/source/reloc.c b/tools/qfcc/source/reloc.c index 29f1663d8..7c4ed3ce3 100644 --- a/tools/qfcc/source/reloc.c +++ b/tools/qfcc/source/reloc.c @@ -210,7 +210,7 @@ reloc_op_def_ofs (def_t *def, int offset, int field) } void -reloc_def_def (def_t *def, def_t *location) +reloc_def_def (def_t *def, const def_t *location) { reloc_t *ref; @@ -221,7 +221,7 @@ reloc_def_def (def_t *def, def_t *location) } void -reloc_def_def_ofs (def_t *def, def_t *location) +reloc_def_def_ofs (def_t *def, const def_t *location) { reloc_t *ref; @@ -232,7 +232,7 @@ reloc_def_def_ofs (def_t *def, def_t *location) } void -reloc_def_func (function_t *func, def_t *location) +reloc_def_func (function_t *func, const def_t *location) { reloc_t *ref; @@ -243,7 +243,7 @@ reloc_def_func (function_t *func, def_t *location) } void -reloc_def_string (def_t *location) +reloc_def_string (const def_t *location) { reloc_t *ref; @@ -254,7 +254,7 @@ reloc_def_string (def_t *location) } void -reloc_def_field (def_t *def, def_t *location) +reloc_def_field (def_t *def, const def_t *location) { reloc_t *ref; @@ -265,7 +265,7 @@ reloc_def_field (def_t *def, def_t *location) } void -reloc_def_field_ofs (def_t *def, def_t *location) +reloc_def_field_ofs (def_t *def, const def_t *location) { reloc_t *ref; @@ -276,7 +276,7 @@ reloc_def_field_ofs (def_t *def, def_t *location) } void -reloc_def_op (ex_label_t *label, def_t *location) +reloc_def_op (const ex_label_t *label, const def_t *location) { reloc_t *ref; diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 239c11f49..ba7af0765 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -42,6 +42,7 @@ #include "qfalloca.h" #include "QF/alloc.h" +#include "QF/mathlib.h" #include "QF/va.h" #include "dags.h" @@ -59,11 +60,27 @@ #include "value.h" #include "qc-parse.h" -static const char *op_type_names[] = { +const char *op_type_names[] = { "op_def", "op_value", "op_label", "op_temp", + "op_alias", + "op_nil", +}; + +const char *st_type_names[] = { + "st_none", + "st_expr", + "st_assign", + "st_ptrassign", + "st_move", + "st_ptrmove", + "st_memset", + "st_ptrmemset", + "st_state", + "st_func", + "st_flow", }; const char * @@ -74,6 +91,22 @@ optype_str (op_type_e type) return op_type_names[type]; } +static const char * +tempop_string (operand_t *tmpop) +{ + tempop_t *tempop = &tmpop->o.tempop; + if (tempop->alias) { + return va ("", + pr_type_name[tempop->type->type], + tmpop, tempop->users, + tempop->alias, + tempop->offset, + tempop->alias->o.tempop.users); + } + return va ("", pr_type_name[tempop->type->type], + tmpop, tempop->users); +} + const char * operand_string (operand_t *op) { @@ -103,7 +136,17 @@ operand_string (operand_t *op) op->o.value->v.quaternion_val[2], op->o.value->v.quaternion_val[3]); case ev_pointer: - return va ("ptr %d", op->o.value->v.pointer.val); + if (op->o.value->v.pointer.def) { + return va ("ptr %s+%d", + op->o.value->v.pointer.def->name, + op->o.value->v.pointer.val); + } else if(op->o.value->v.pointer.tempop) { + operand_t *tempop = op->o.value->v.pointer.tempop; + return va ("ptr %s+%d", tempop_string (tempop), + op->o.value->v.pointer.val); + } else { + return va ("ptr %d", op->o.value->v.pointer.val); + } case ev_field: return va ("field %d", op->o.value->v.pointer.val); case ev_entity: @@ -127,15 +170,7 @@ operand_string (operand_t *op) case op_label: return op->o.label->name; case op_temp: - if (op->o.tempop.alias) - return va ("", - pr_type_name[op->type->type], - op, op->o.tempop.users, - op->o.tempop.alias, - op->o.tempop.offset, - op->o.tempop.alias->o.tempop.users); - return va ("", pr_type_name[op->o.tempop.type->type], - op, op->o.tempop.users); + return tempop_string (op); case op_alias: { const char *alias = operand_string (op->o.alias); @@ -143,12 +178,14 @@ operand_string (operand_t *op) strcpy (buf, alias); return va ("alias(%s,%s)", pr_type_name[op->type->type], buf); } + case op_nil: + return va ("nil"); } return ("??"); } -void -print_operand (operand_t *op) +static void +_print_operand (operand_t *op) { switch (op->op_type) { case op_def: @@ -200,7 +237,7 @@ print_operand (operand_t *op) case ev_void: case ev_invalid: case ev_type_count: - internal_error (0, "weird value type"); + internal_error (op->expr, "weird value type"); } break; case op_label: @@ -213,23 +250,34 @@ print_operand (operand_t *op) break; case op_alias: printf ("alias(%s,", pr_type_name[op->type->type]); - print_operand (op->o.alias); + _print_operand (op->o.alias); printf (")"); + break; + case op_nil: + printf ("nil"); + break; } } +void +print_operand (operand_t *op) +{ + _print_operand (op); + puts (""); +} + void print_statement (statement_t *s) { printf ("(%s, ", s->opcode); if (s->opa) - print_operand (s->opa); + _print_operand (s->opa); printf (", "); if (s->opb) - print_operand (s->opb); + _print_operand (s->opb); printf (", "); if (s->opc) - print_operand (s->opc); + _print_operand (s->opc); printf (")\n"); } @@ -263,15 +311,18 @@ new_statement (st_type_t type, const char *opcode, expr_t *expr) statement->type = type; statement->opcode = save_string (opcode); statement->expr = expr; + statement->number = -1; // indicates flow analysis not done yet return statement; } static operand_t * -new_operand (op_type_e op) +new_operand (op_type_e op, expr_t *expr, void *return_addr) { operand_t *operand; ALLOC (256, operand_t, operands, operand); operand->op_type = op; + operand->expr = expr; + operand->return_addr = return_addr; return operand; } @@ -305,13 +356,23 @@ free_sblock (sblock_t *sblock) } operand_t * -def_operand (def_t *def, type_t *type) +nil_operand (type_t *type, expr_t *expr) +{ + operand_t *op; + op = new_operand (op_nil, expr, __builtin_return_address (0)); + op->type = type; + op->size = type_size (type); + return op; +} + +operand_t * +def_operand (def_t *def, type_t *type, expr_t *expr) { operand_t *op; if (!type) type = def->type; - op = new_operand (op_def); + op = new_operand (op_def, expr, __builtin_return_address (0)); op->type = type; op->size = type_size (type); op->o.def = def; @@ -319,28 +380,28 @@ def_operand (def_t *def, type_t *type) } operand_t * -return_operand (type_t *type) +return_operand (type_t *type, expr_t *expr) { symbol_t *return_symbol; return_symbol = make_symbol (".return", &type_param, pr.symtab->space, sc_extern); - return def_operand (return_symbol->s.def, type); + return def_operand (return_symbol->s.def, type, expr); } operand_t * -value_operand (ex_value_t *value) +value_operand (ex_value_t *value, expr_t *expr) { operand_t *op; - op = new_operand (op_value); + op = new_operand (op_value, expr, __builtin_return_address (0)); op->type = value->type; op->o.value = value; return op; } operand_t * -temp_operand (type_t *type) +temp_operand (type_t *type, expr_t *expr) { - operand_t *op = new_operand (op_temp); + operand_t *op = new_operand (op_temp, expr, __builtin_return_address (0)); op->o.tempop.type = type; op->type = type; @@ -356,6 +417,12 @@ tempop_overlap (tempop_t *t1, tempop_t *t2) int size1 = type_size (t1->type); int size2 = type_size (t2->type); + if (t1->alias) { + offs1 += t1->alias->o.tempop.offset; + } + if (t2->alias) { + offs2 += t2->alias->o.tempop.offset; + } if (offs1 <= offs2 && offs1 + size1 >= offs2 + size2) return 2; // t1 fully overlaps t2 if (offs1 < offs2 + size2 && offs2 < offs1 + size1) @@ -376,15 +443,17 @@ tempop_visit_all (tempop_t *tempop, int overlap, if (tempop->alias) { top = tempop->alias; if (top->op_type != op_temp) { - internal_error (0, "temp alias of non-temp operand"); + internal_error (top->expr, "temp alias of non-temp operand"); } tempop = &top->o.tempop; if ((ret = visit (tempop, data))) return ret; + } else { + overlap = 0; } for (top = tempop->alias_ops; top; top = top->next) { if (top->op_type != op_temp) { - internal_error (0, "temp alias of non-temp operand"); + internal_error (top->expr, "temp alias of non-temp operand"); } tempop = &top->o.tempop; if (tempop == start_tempop) @@ -398,33 +467,46 @@ tempop_visit_all (tempop_t *tempop, int overlap, } operand_t * -alias_operand (type_t *type, operand_t *op) +alias_operand (type_t *type, operand_t *op, expr_t *expr) { operand_t *aop; if (type_size (type) != type_size (op->type)) { - internal_error (0, "\naliasing operand with type of different size" - " (%d, %d)", type_size (type), type_size (op->type)); + internal_error (op->expr, + "aliasing operand with type of different size: %d, %d", + type_size (type), type_size (op->type)); } - aop = new_operand (op_alias); + aop = new_operand (op_alias, expr, __builtin_return_address (0)); aop->o.alias = op; aop->type = type; aop->size = type_size (type); return aop; } +operand_t * +label_operand (expr_t *label) +{ + operand_t *lop; + + if (label->type != ex_label) { + internal_error (label, "not a label expression"); + } + lop = new_operand (op_label, label, __builtin_return_address (0)); + lop->o.label = &label->e.label; + return lop; +} + static operand_t * -short_operand (short short_val) +short_operand (short short_val, expr_t *expr) { ex_value_t *val = new_short_val (short_val); - return value_operand (val); + return value_operand (val, expr); } static const char * convert_op (int op) { switch (op) { - case PAS: return ".="; case OR: return "||"; case AND: return "&&"; case EQ: return "=="; @@ -521,7 +603,7 @@ statement_get_targetlist (statement_t *s) sblock_t **target_list; int count = 0, i; def_t *table = 0; - expr_t *e; + element_t *e; if (statement_is_cond (s)) { count = 1; @@ -539,10 +621,10 @@ statement_get_targetlist (statement_t *s) target_list[0] = statement_get_target (s); } else if (statement_is_jumpb (s)) { if (table->alias) - internal_error (0, "aliased jump table"); - e = table->initializer->e.block.head; //FIXME check!!! + internal_error (s->opa->expr, "aliased jump table"); + e = table->initializer->e.compound.head; //FIXME check!!! for (i = 0; i < count; e = e->next, i++) - target_list[i] = e->e.labelref.label->dest; + target_list[i] = e->expr->e.labelref.label->dest; } return target_list; } @@ -579,8 +661,7 @@ statement_branch (sblock_t *sblock, expr_t *e) if (e->type == ex_uexpr && e->e.expr.op == 'g') { s = new_statement (st_flow, "", e); - s->opa = new_operand (op_label); - s->opa->o.label = &e->e.expr.e1->e.label; + s->opa = label_operand (e->e.expr.e1); } else { if (e->e.expr.op == 'g') { s = new_statement (st_flow, "", e); @@ -590,8 +671,7 @@ statement_branch (sblock_t *sblock, expr_t *e) opcode = convert_op (e->e.expr.op); s = new_statement (st_flow, opcode, e); sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); - s->opb = new_operand (op_label); - s->opb->o.label = &e->e.expr.e2->e.label; + s->opb = label_operand (e->e.expr.e2); } } @@ -600,45 +680,247 @@ statement_branch (sblock_t *sblock, expr_t *e) return sblock->next; } +static sblock_t * +expr_address (sblock_t *sblock, expr_t *e, operand_t **op) +{ + statement_t *s; + s = new_statement (st_expr, "&", e); + sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); + s->opc = temp_operand (e->e.expr.type, e); + sblock_add_statement (sblock, s); + *(op) = s->opc; + return sblock; +} + +static operand_t * +operand_address (operand_t *reference, expr_t *e) +{ + def_t *def; + type_t *type; + int offset = 0; + + type = reference->type; + switch (reference->op_type) { + case op_def: + // assumes aliasing is only one level deep which should be the + // case + def = reference->o.def; + if (def->alias) { + offset = def->offset; + def = def->alias; + } + return value_operand (new_pointer_val (offset, type, def, 0), e); + case op_temp: + // assumes aliasing is only one level deep which should be the + // case + if (reference->o.tempop.alias) { + offset = reference->o.tempop.offset; + reference = reference->o.tempop.alias; + } + return value_operand (new_pointer_val (offset, type, 0, + reference), e); + case op_alias: + //op_alias comes only from alias_operand and that is called + // by dags, so not expected + case op_value: + case op_label: + case op_nil: + break; + } + internal_error (e, "invalid operand type for operand address: %s", + op_type_names[reference->op_type]); +} + +static __attribute__((pure)) int +is_const_ptr (expr_t *e) +{ + if ((e->type != ex_value || e->e.value->lltype != ev_pointer) + || !(POINTER_VAL (e->e.value->v.pointer) >= 0 + && POINTER_VAL (e->e.value->v.pointer) < 65536)) { + return 0; + } + return 1; +} + +static __attribute__((pure)) int +is_indirect (expr_t *e) +{ + if ((e->type == ex_expr || e->type == ex_uexpr) + && e->e.expr.op == '.') { + return 1; + } + return 0; +} + +static sblock_t * +expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op, operand_t *src) +{ + statement_t *s; + expr_t *dst_expr = e->e.expr.e1; + expr_t *src_expr = e->e.expr.e2; + type_t *dst_type = get_type (dst_expr); + type_t *src_type = get_type (src_expr); + unsigned count; + expr_t *count_expr; + operand_t *dst = 0; + operand_t *size = 0; + static const char *opcode_sets[][2] = { + {"", ""}, + {"", ""}, + }; + const unsigned max_count = 1 << 16; + const char **opcode_set = opcode_sets[0]; + const char *opcode; + int need_ptr = 0; + st_type_t type = st_move; + + if ((src && src->op_type == op_nil) || src_expr->type == ex_nil) { + // switch to memset because nil is type agnostic 0 and structures + // can be any size + src_expr = new_integer_expr (0); + sblock = statement_subexpr (sblock, src_expr, &src); + opcode_set = opcode_sets[1]; + if (op) { + *op = nil_operand (dst_type, src_expr); + } + type = st_memset; + if (is_indirect (dst_expr)) { + goto dereference_dst; + } + } else { + if (!src) { + // This is the very right-hand node of a non-nil assignment chain + // (there may be more chains somwhere within src_expr, but they + // are not part of this chain as they are separated by another + // expression). + sblock = statement_subexpr (sblock, src_expr, &src); + } + // send the source operand back up through the assignment chain + // before modifying src if its address is needed + if (op) { + *op = src; + } + if (is_indirect (dst_expr) || is_indirect (src_expr)) { + src = operand_address (src, src_expr); + goto dereference_dst; + } + } + if (0) { +dereference_dst: + // dst_expr is a dereferenced pointer, so need to un-dereference it + // to get the pointer and switch to storep instructions. + dst_expr = expr_file_line (address_expr (dst_expr, 0, 0), e); + need_ptr = 1; + } + sblock = statement_subexpr (sblock, dst_expr, &dst); + + if (type_size (dst_type) != type_size (src_type)) { + bug (e, "dst and src sizes differ in expr_assign_copy: %d %d", + type_size (dst_type), type_size (src_type)); + } + count = min (type_size (dst_type), type_size (src_type)); + if (count < (1 << 16)) { + count_expr = expr_file_line (new_short_expr (count), e); + } else { + count_expr = expr_file_line (new_integer_expr (count), e); + } + sblock = statement_subexpr (sblock, count_expr, &size); + + if (count < max_count && !need_ptr) { + opcode = opcode_set[0]; + } else { + opcode = opcode_set[1]; + type++; // from st_move/st_memset to st_ptrmove/st_ptrmemset + } + + s = new_statement (type, opcode, e); + s->opa = src; + s->opb = size; + s->opc = dst; + sblock_add_statement (sblock, s); + return sblock; +} + static sblock_t * expr_assign (sblock_t *sblock, expr_t *e, operand_t **op) { statement_t *s; expr_t *src_expr = e->e.expr.e2; expr_t *dst_expr = e->e.expr.e1; + type_t *dst_type = get_type (dst_expr); operand_t *src = 0; operand_t *dst = 0; operand_t *ofs = 0; const char *opcode = convert_op (e->e.expr.op); st_type_t type; - if (e->e.expr.op == '=') { - sblock = statement_subexpr (sblock, dst_expr, &dst); - src = dst; + if (src_expr->type == ex_expr && src_expr->e.expr.op == '=') { sblock = statement_subexpr (sblock, src_expr, &src); - ofs = 0; - if (op) - *op = dst; - if (src == dst) - return sblock; - type = st_assign; + if (is_structural (dst_type)) { + return expr_assign_copy (sblock, e, op, src); + } + if (is_indirect (dst_expr)) { + goto dereference_dst; + } else { + sblock = statement_subexpr (sblock, dst_expr, &dst); + } } else { - //FIXME this sucks. find a better way to handle both pointer - //dereferences and pointer assignements - sblock = statement_subexpr (sblock, src_expr, &src); - if (dst_expr->type == ex_expr - && extract_type (dst_expr->e.expr.e1) == ev_pointer - && !is_constant (dst_expr->e.expr.e1)) { + if (is_structural (dst_type)) { + return expr_assign_copy (sblock, e, op, src); + } + + if (is_indirect (dst_expr)) { + // If both dst_expr and src_expr are indirect, then a staging temp + // is needed, but emitting src_expr first generates that temp + // because src is null. If src_expr is not indirect and is a simple + // variable reference, then just the ref will be generated and thus + // will be assigned to the dereferenced destination. If src_expr + // is not simple, then a temp will be generated, so all good. + sblock = statement_subexpr (sblock, src_expr, &src); + goto dereference_dst; + } else { + // dst_expr is direct and known to be an l-value, so emitting + // its expression will simply generate a reference to that l-value + // which will be used as the default location to store src_expr's + // result + sblock = statement_subexpr (sblock, dst_expr, &dst); + src = dst; + sblock = statement_subexpr (sblock, src_expr, &src); + } + } + type = st_assign; + + if (0) { +dereference_dst: + // dst_expr is a dereferenced pointer, so need to un-dereference it + // to get the pointer and switch to storep instructions. + dst_expr = expr_file_line (address_expr (dst_expr, 0, 0), e); + opcode = ".="; // FIXME find a nicer representation (lose strings?) + if (dst_expr->type == ex_expr && !is_const_ptr (dst_expr->e.expr.e1)) { sblock = statement_subexpr (sblock, dst_expr->e.expr.e1, &dst); sblock = statement_subexpr (sblock, dst_expr->e.expr.e2, &ofs); } else { sblock = statement_subexpr (sblock, dst_expr, &dst); ofs = 0; } - if (op) - *op = src; type = st_ptrassign; } + if (op) { + *op = src; + } + if (src == dst) { + return sblock; + } + + if (is_entity (dst->type) && ofs && is_field (ofs->type)) { + s = new_statement (st_expr, "&", dst_expr); + s->opa = dst; + s->opb = ofs; + s->opc = temp_operand (&type_pointer, dst_expr); + sblock_add_statement (sblock, s); + dst = s->opc; + ofs = 0; + } s = new_statement (type, opcode, e); s->opa = src; s->opb = dst; @@ -666,7 +948,8 @@ expr_move (sblock_t *sblock, expr_t *e, operand_t **op) dst = *op; sblock = statement_subexpr (sblock, src_expr, &src); sblock = statement_subexpr (sblock, size_expr, &size); - s = new_statement (st_move, convert_op (e->e.expr.op), e); + s = new_statement (e->e.expr.op == 'm' ? st_move : st_ptrmove, + convert_op (e->e.expr.op), e); s->opa = src; s->opb = size; s->opc = dst; @@ -729,7 +1012,6 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op) continue; } if (is_struct (get_type (param))) { - //FIXME this should be done in the expression tree expr_t *mov = assign_expr (param, a); mov->line = a->line; mov->file = a->file; @@ -763,34 +1045,13 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op) return sblock->next; } -static sblock_t * -expr_address (sblock_t *sblock, expr_t *e, operand_t **op) -{ - statement_t *s; - s = new_statement (st_expr, "&", e); - sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); - s->opc = temp_operand (e->e.expr.type); - sblock_add_statement (sblock, s); - *(op) = s->opc; - return sblock; -} - static statement_t * lea_statement (operand_t *pointer, operand_t *offset, expr_t *e) { statement_t *s = new_statement (st_expr, "&", e); s->opa = pointer; s->opb = offset; - s->opc = temp_operand (&type_pointer); - return s; -} - -static statement_t * -address_statement (operand_t *value, expr_t *e) -{ - statement_t *s = new_statement (st_expr, "&", e); - s->opa = value; - s->opc = temp_operand (&type_pointer); + s->opc = temp_operand (&type_pointer, e); return s; } @@ -805,7 +1066,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) && e->e.expr.e1->type == ex_symbol) { if (e->e.expr.e1->e.symbol->sy_type != sy_var) internal_error (e, "address of non-var"); - *op = def_operand (e->e.expr.e1->e.symbol->s.def, type); + *op = def_operand (e->e.expr.e1->e.symbol->s.def, type, e); } else if (e->type == ex_expr && e->e.expr.op == '&') { statement_t *s; operand_t *ptr = 0; @@ -813,7 +1074,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) sblock = statement_subexpr (sblock, e->e.expr.e1, &ptr); sblock = statement_subexpr (sblock, e->e.expr.e2, &offs); if (!*op) - *op = temp_operand (type); + *op = temp_operand (type, e); if (low_level_type (type) == ev_void) { operand_t *src_addr; operand_t *dst_addr; @@ -822,14 +1083,12 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) src_addr = s->opc; sblock_add_statement (sblock, s); - //FIXME an address immediate would be nice. - s = address_statement (*op, e); - dst_addr = s->opc; - sblock_add_statement (sblock, s); + dst_addr = operand_address (*op, e); - s = new_statement (st_move, "", deref); + s = new_statement (st_ptrmove, "", deref); s->opa = src_addr; - s->opb = short_operand (type_size (type)); + //FIXME large types + s->opb = short_operand (type_size (type), e); s->opc = dst_addr; sblock_add_statement (sblock, s); } else { @@ -842,17 +1101,17 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) } else if (e->type == ex_value && e->e.value->lltype == ev_pointer) { ex_pointer_t *ptr = &e->e.value->v.pointer; *op = def_operand (alias_def (ptr->def, ptr->type, ptr->val), - ptr->type); + ptr->type, e); } else { statement_t *s; operand_t *ptr = 0; sblock = statement_subexpr (sblock, e, &ptr); if (!*op) - *op = temp_operand (type); + *op = temp_operand (type, e); s = new_statement (st_expr, ".", deref); s->opa = ptr; - s->opb = short_operand (0); + s->opb = short_operand (0, e); s->opc = *op; sblock_add_statement (sblock, s); } @@ -884,6 +1143,7 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op) type = e->e.expr.type; sblock = statement_subexpr (sblock, e->e.expr.e1, &aop); if (type_compatible (aop->type, type)) { + //FIXME type_compatible??? shouldn't that be type_size ==? if (offset) { internal_error (e, "offset alias of same size type"); } @@ -904,7 +1164,7 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op) } } if (!top) { - top = temp_operand (type); + top = temp_operand (type, e); top->o.tempop.alias = aop; top->o.tempop.offset = offset; top->next = aop->o.tempop.alias_ops; @@ -915,9 +1175,10 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op) def = aop->o.def; while (def->alias) def = def->alias; - *op = def_operand (alias_def (def, type, offset), 0); + *op = def_operand (alias_def (def, type, offset), 0, e); } else if (aop->op_type == op_value) { - *op = value_operand (aop->o.value); + *op = value_operand (aop->o.value, e); + (*op)->type = type; } else { internal_error (e, "invalid alias target: %s: %s", optype_str (aop->op_type), operand_string (aop)); @@ -936,7 +1197,6 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op) sblock = expr_call (sblock, e, op); break; case '=': - case PAS: sblock = expr_assign (sblock, e, op); break; case 'm': @@ -954,7 +1214,7 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op) sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); sblock = statement_subexpr (sblock, e->e.expr.e2, &s->opb); if (!*op) - *op = temp_operand (e->e.expr.type); + *op = temp_operand (e->e.expr.type, e); s->opc = *op; sblock_add_statement (sblock, s); break; @@ -973,7 +1233,7 @@ expr_cast (sblock_t *sblock, expr_t *e, operand_t **op) if (is_scalar (src_type) && is_scalar (type)) { operand_t *src = 0; sblock = statement_subexpr (sblock, e->e.expr.e1, &src); - *op = temp_operand (e->e.expr.type); + *op = temp_operand (e->e.expr.type, e); s = new_statement (st_expr, "", e); s->opa = src; s->opc = *op; @@ -1030,24 +1290,31 @@ expr_uexpr (sblock_t *sblock, expr_t *e, operand_t **op) s = new_statement (st_expr, opcode, e); sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); if (!*op) - *op = temp_operand (e->e.expr.type); + *op = temp_operand (e->e.expr.type, e); s->opc = *op; sblock_add_statement (sblock, s); } return sblock; } +static sblock_t * +expr_def (sblock_t *sblock, expr_t *e, operand_t **op) +{ + *op = def_operand (e->e.def, e->e.def->type, e); + return sblock; +} + static sblock_t * expr_symbol (sblock_t *sblock, expr_t *e, operand_t **op) { symbol_t *sym = e->e.symbol; if (sym->sy_type == sy_var) { - *op = def_operand (sym->s.def, sym->type); + *op = def_operand (sym->s.def, sym->type, e); } else if (sym->sy_type == sy_const) { - *op = value_operand (sym->s.value); + *op = value_operand (sym->s.value, e); } else if (sym->sy_type == sy_func) { - *op = def_operand (sym->s.func->def, 0); + *op = def_operand (sym->s.func->def, 0, e); } else { internal_error (e, "unexpected symbol type: %s for %s", symtype_str (sym->sy_type), sym->name); @@ -1059,7 +1326,7 @@ static sblock_t * expr_temp (sblock_t *sblock, expr_t *e, operand_t **op) { if (!e->e.temp.op) - e->e.temp.op = temp_operand (e->e.temp.type); + e->e.temp.op = temp_operand (e->e.temp.type, e); *op = e->e.temp.op; return sblock; } @@ -1132,10 +1399,27 @@ expr_vector_e (sblock_t *sblock, expr_t *e, operand_t **op) return sblock; } +static sblock_t * +expr_nil (sblock_t *sblock, expr_t *e, operand_t **op) +{ + type_t *nil = e->e.nil; + expr_t *ptr; + if (!is_struct (nil) && !is_array (nil)) { + *op = value_operand (new_nil_val (nil), e); + return sblock; + } + ptr = expr_file_line (address_expr (new_temp_def_expr (nil), 0, 0), e); + expr_file_line (ptr, e); + sblock = statement_subexpr (sblock, ptr, op); + e = expr_file_line (new_memset_expr (ptr, new_integer_expr (0), nil), e); + sblock = statement_slist (sblock, e); + return sblock; +} + static sblock_t * expr_value (sblock_t *sblock, expr_t *e, operand_t **op) { - *op = value_operand (e->e.value); + *op = value_operand (e->e.value, e); return sblock; } @@ -1151,21 +1435,24 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op) expr_block, // ex_block expr_expr, expr_uexpr, + expr_def, expr_symbol, expr_temp, expr_vector_e, // ex_vector - 0, // ex_nil + expr_nil, expr_value, + 0, // ex_compound + 0, // ex_memset }; if (!e) { *op = 0; return sblock; } - if (e->type > ex_value) - internal_error (e, "bad expression type"); + if (e->type > ex_memset) + internal_error (e, "bad sub-expression type"); if (!sfuncs[e->type]) - internal_error (e, "unexpected expression type: %s", + internal_error (e, "unexpected sub-expression type: %s", expr_names[e->type]); sblock = sfuncs[e->type] (sblock, e, op); @@ -1327,7 +1614,11 @@ statement_label (sblock_t *sblock, expr_t *e) e->e.label.next = sblock->labels; sblock->labels = &e->e.label; } else { - debug (e, "dropping unused label %s", e->e.label.name); + if (e->e.label.symbol) { + warning (e, "unused label %s", e->e.label.symbol->name); + } else { + debug (e, "dropping unused label %s", e->e.label.name); + } } return sblock; } @@ -1360,7 +1651,6 @@ statement_expr (sblock_t *sblock, expr_t *e) sblock = statement_branch (sblock, e); break; case '=': - case PAS: sblock = expr_assign (sblock, e, 0); break; case 'm': @@ -1398,7 +1688,7 @@ statement_uexpr (sblock_t *sblock, expr_t *e) } s = new_statement (st_func, opcode, e); if (e->e.expr.e1) { - s->opa = return_operand (get_type (e->e.expr.e1)); + s->opa = return_operand (get_type (e->e.expr.e1), e); sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); } sblock_add_statement (sblock, s); @@ -1417,6 +1707,32 @@ statement_uexpr (sblock_t *sblock, expr_t *e) return sblock; } +static sblock_t * +statement_memset (sblock_t *sblock, expr_t *e) +{ + expr_t *dst = e->e.memset.dst; + expr_t *val = e->e.memset.val; + expr_t *count = e->e.memset.count; + const char *opcode = ""; + statement_t *s; + + if (is_constant (count)) { + if (is_integer (get_type (count)) + && (unsigned) expr_integer (count) < 0x10000) { + count = new_short_expr (expr_integer (count)); + } + if (is_uinteger (get_type (count)) && expr_integer (count) < 0x10000) { + count = new_short_expr (expr_uinteger (count)); + } + } + s = new_statement (st_move, opcode, e); + sblock = statement_subexpr (sblock, dst, &s->opc); + sblock = statement_subexpr (sblock, count, &s->opb); + sblock = statement_subexpr (sblock, val, &s->opa); + sblock_add_statement (sblock, s); + return sblock; +} + static sblock_t * statement_nonexec (sblock_t *sblock, expr_t *e) { @@ -1437,15 +1753,18 @@ statement_slist (sblock_t *sblock, expr_t *e) statement_block, statement_expr, statement_uexpr, + statement_nonexec, // ex_def statement_nonexec, // ex_symbol statement_nonexec, // ex_temp statement_nonexec, // ex_vector statement_nonexec, // ex_nil statement_nonexec, // ex_value + 0, // ex_compound + statement_memset, }; for (/**/; e; e = e->next) { - if (e->type > ex_value) + if (e->type > ex_memset) internal_error (e, "bad expression type"); sblock = sfuncs[e->type] (sblock, e); } @@ -1534,7 +1853,7 @@ remove_label_from_dest (ex_label_t *label) sblock_t *sblock; ex_label_t **l; - if (!label) + if (!label || !label->dest) return; debug (0, "dropping deceased label %s", label->name); @@ -1571,14 +1890,21 @@ thread_jumps (sblock_t *blocks) if (!sblock->statements) continue; s = (statement_t *) sblock->tail; - if (statement_is_goto (s)) + if (statement_is_goto (s)) { label = &s->opa->o.label; - else if (statement_is_cond (s)) + if (!(*label)->dest && (*label)->symbol) { + error (s->opa->expr, "undefined label `%s'", + (*label)->symbol->name); + (*label)->symbol = 0; + } + } else if (statement_is_cond (s)) { label = &s->opb->o.label; - else + } else { continue; + } for (l = *label; - l->dest->statements && statement_is_goto (l->dest->statements); + l->dest && l->dest->statements + && statement_is_goto (l->dest->statements); l = l->dest->statements->opa->o.label) { } if (l != *label) { @@ -1702,7 +2028,7 @@ check_final_block (sblock_t *sblock) s = new_statement (st_func, "", 0); if (options.traditional || options.code.progsversion == PROG_ID_VERSION) { s->opcode = save_string (""); - s->opa = return_operand (&type_void); + s->opa = return_operand (&type_void, 0); } sblock_add_statement (sblock, s); } diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 800a1aa66..85c8a85ba 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -47,6 +47,7 @@ #include #include +#include "class.h" #include "def.h" #include "defspace.h" #include "diagnostic.h" @@ -113,6 +114,7 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) symbol_t *sym = find_struct (su, tag, type); symbol_t *s; int alignment = 1; + symbol_t *as; symtab->parent = 0; // disconnect struct's symtab from parent scope @@ -123,7 +125,12 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) for (s = symtab->symbols; s; s = s->next) { if (s->sy_type != sy_var) continue; + if (obj_is_class (s->type)) { + error (0, "statically allocated instance of class %s", + s->type->t.class->name); + } if (su == 's') { + symtab->size = RUP (symtab->size, s->type->alignment); s->s.offset = symtab->size; symtab->size += type_size (s->type); } else { @@ -134,6 +141,32 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) if (s->type->alignment > alignment) { alignment = s->type->alignment; } + if (s->visibility == vis_anonymous) { + symtab_t *anonymous; + symbol_t *t = s->next; + int offset = s->s.offset; + + if (!is_struct (s->type)) { + internal_error (0, "non-struct/union anonymous field"); + } + anonymous = s->type->t.symtab; + for (as = anonymous->symbols; as; as = as->next) { + if (as->visibility == vis_anonymous || as->sy_type!= sy_var) { + continue; + } + if (Hash_Find (symtab->tab, as->name)) { + error (0, "ambiguous field `%s' in anonymous %s", + as->name, su == 's' ? "struct" : "union"); + } else { + s->next = copy_symbol (as); + s = s->next; + s->s.offset += offset; + s->table = symtab; + Hash_Add (symtab->tab, s); + } + } + s->next = t; + } } if (!type) sym->type = find_type (sym->type); // checks the tag, not the symtab diff --git a/tools/qfcc/source/switch.c b/tools/qfcc/source/switch.c index 7e76ef6f4..967a7b73f 100644 --- a/tools/qfcc/source/switch.c +++ b/tools/qfcc/source/switch.c @@ -337,11 +337,13 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val, const char *table_name = new_label_name (); int i; expr_t *range = binary_expr ('-', tree->high, tree->low); + expr_t *label; - table_init = new_block_expr (); + table_init = new_compound_init (); for (i = 0; i <= high - low; i++) { tree->labels[i]->e.label.used++; - append_expr (table_init, address_expr (tree->labels[i], 0, 0)); + label = address_expr (tree->labels[i], 0, 0); + append_element (table_init, new_element (label, 0)); } table_sym = new_symbol_type (table_name, array_type (&type_integer, diff --git a/tools/qfcc/source/symtab.c b/tools/qfcc/source/symtab.c index f26a690e7..353e29142 100644 --- a/tools/qfcc/source/symtab.c +++ b/tools/qfcc/source/symtab.c @@ -59,6 +59,7 @@ static const char *sy_type_names[] = { "sy_expr", "sy_func", "sy_class", + "sy_convert", }; const char * @@ -152,7 +153,7 @@ symtab_removesymbol (symtab_t *symtab, symbol_t *symbol) for (s = &symtab->symbols; *s && *s != symbol; s = & (*s)->next) ; if (!*s) - internal_error (0, "symtab_removesymbol"); + internal_error (0, "attempt to remove symbol not in symtab"); *s = (*s)->next; if (symtab->symtail == &symbol->next) symtab->symtail = s; @@ -165,6 +166,7 @@ symbol_t * copy_symbol (symbol_t *symbol) { symbol_t *sym = new_symbol (symbol->name); + sym->visibility = symbol->visibility; sym->type = symbol->type; sym->params = copy_params (symbol->params); sym->sy_type = symbol->sy_type; @@ -182,7 +184,8 @@ symtab_flat_copy (symtab_t *symtab, symtab_t *parent) newtab = new_symtab (parent, stab_local); do { for (symbol = symtab->symbols; symbol; symbol = symbol->next) { - if (Hash_Find (newtab->tab, symbol->name)) + if (symbol->visibility == vis_anonymous + || Hash_Find (newtab->tab, symbol->name)) continue; newsym = copy_symbol (symbol); symtab_addsymbol (newtab, newsym); diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 289b76563..4404f2ed0 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -62,16 +62,18 @@ // simple types. function types are dynamically allocated type_t type_invalid = { ev_invalid, "invalid" }; -type_t type_void = { ev_void, "void" }; +type_t type_void = { ev_void, "void", 1 }; type_t type_string = { ev_string, "string", 1 }; type_t type_float = { ev_float, "float", 1 }; type_t type_vector = { ev_vector, "vector", 1 }; type_t type_entity = { ev_entity, "entity", 1 }; -type_t type_field = {ev_field, "field", 1, ty_none, {{&type_void}} }; +type_t type_field = {ev_field, "field", 1, ty_basic, {{&type_void}} }; // type_function is a void() function used for state defs -type_t type_function = { ev_func, "function", 1, ty_none, {{&type_void}} }; -type_t type_pointer = { ev_pointer, "pointer", 1, ty_none, {{&type_void}} }; +type_t type_function = { ev_func, "function", 1, ty_basic, + {{&type_void}} }; +type_t type_pointer = { ev_pointer, "pointer", 1, ty_basic, + {{&type_void}} }; type_t type_quaternion = { ev_quat, "quaternion", 1 }; type_t type_integer = { ev_integer, "int", 1 }; type_t type_uinteger = { ev_uinteger, "uint", 1 }; @@ -87,8 +89,11 @@ type_t type_param = { ev_invalid, 0, 0, ty_struct }; type_t type_zero = { ev_invalid, 0, 0, ty_struct }; type_t type_type_encodings = { ev_invalid, "@type_encodings", 0, ty_struct }; +type_t type_xdef = { ev_invalid, "@xdef", 0, ty_struct }; +type_t type_xdef_pointer = { ev_pointer, 0, 1, ty_basic, {{&type_xdef}} }; +type_t type_xdefs = { ev_invalid, "@xdefs", 0, ty_struct }; -type_t type_floatfield = { ev_field, ".float", 1, ty_none, +type_t type_floatfield = { ev_field, ".float", 1, ty_basic, {{&type_float}} }; type_t *ev_types[ev_type_count] = { @@ -252,7 +257,7 @@ types_same (type_t *a, type_t *b) if (a->type != b->type || a->meta != b->meta) return 0; switch (a->meta) { - case ty_none: + case ty_basic: switch (a->type) { case ev_field: case ev_pointer: @@ -313,7 +318,7 @@ find_type (type_t *type) if (type->freeable) { switch (type->meta) { - case ty_none: + case ty_basic: switch (type->type) { case ev_field: case ev_pointer: @@ -447,79 +452,90 @@ print_type_str (dstring_t *str, const type_t *type) dasprintf (str, " (null)"); return; } - switch (type->type) { - case ev_field: - dasprintf (str, ".("); - print_type_str (str, type->t.fldptr.type); - dasprintf (str, ")"); - break; - case ev_func: - print_type_str (str, type->t.func.type); - if (type->t.func.num_params == -1) { - dasprintf (str, "(...)"); + switch (type->meta) { + case ty_class: + dasprintf (str, " %s", type->t.class->name); + if (type->protos) + print_protocollist (str, type->protos); + return; + case ty_enum: + dasprintf (str, " enum %s", type->name); + return; + case ty_struct: + dasprintf (str, " struct %s", type->name); + return; + case ty_union: + dasprintf (str, " union %s", type->name); + return; + case ty_array: + print_type_str (str, type->t.array.type); + if (type->t.array.base) { + dasprintf (str, "[%d..%d]", type->t.array.base, + type->t.array.base + type->t.array.size - 1); } else { - int c, i; - dasprintf (str, "("); - if ((c = type->t.func.num_params) < 0) - c = ~c; // num_params is one's compliment - for (i = 0; i < c; i++) { - if (i) - dasprintf (str, ", "); - print_type_str (str, type->t.func.param_types[i]); - } - if (type->t.func.num_params < 0) - dasprintf (str, ", ..."); - dasprintf (str, ")"); + dasprintf (str, "[%d]", type->t.array.size); } - break; - case ev_pointer: - if (obj_is_id (type)) { - dasprintf (str, "id"); - if (type->t.fldptr.type->protos) - print_protocollist (str, type->t.fldptr.type->protos); - break; - } - if (type == &type_SEL) { - dasprintf (str, "SEL"); - break; - } - dasprintf (str, "(*"); - print_type_str (str, type->t.fldptr.type); - dasprintf (str, ")"); - break; - case ev_invalid: - switch (type->meta) { - case ty_class: - dasprintf (str, " %s", type->t.class->name); - if (type->protos) - print_protocollist (str, type->protos); - break; - case ty_enum: - dasprintf (str, " enum %s", type->name); - break; - case ty_struct: - dasprintf (str, " struct %s", type->name); - break; - case ty_union: - dasprintf (str, " union %s", type->name); - break; - case ty_array: - print_type_str (str, type->t.array.type); - if (type->t.array.base) { - dasprintf (str, "[%d..%d]", type->t.array.base, - type->t.array.base + type->t.array.size - 1); + return; + case ty_basic: + switch (type->type) { + case ev_field: + dasprintf (str, ".("); + print_type_str (str, type->t.fldptr.type); + dasprintf (str, ")"); + return; + case ev_func: + print_type_str (str, type->t.func.type); + if (type->t.func.num_params == -1) { + dasprintf (str, "(...)"); } else { - dasprintf (str, "[%d]", type->t.array.size); + int c, i; + dasprintf (str, "("); + if ((c = type->t.func.num_params) < 0) + c = ~c; // num_params is one's compliment + for (i = 0; i < c; i++) { + if (i) + dasprintf (str, ", "); + print_type_str (str, type->t.func.param_types[i]); + } + if (type->t.func.num_params < 0) + dasprintf (str, ", ..."); + dasprintf (str, ")"); } - break; - case ty_none: + return; + case ev_pointer: + if (obj_is_id (type)) { + dasprintf (str, "id"); + if (type->t.fldptr.type->protos) + print_protocollist (str, type->t.fldptr.type->protos); + return; + } + if (type == &type_SEL) { + dasprintf (str, "SEL"); + return; + } + dasprintf (str, "(*"); + print_type_str (str, type->t.fldptr.type); + dasprintf (str, ")"); + return; + case ev_void: + case ev_string: + case ev_float: + case ev_vector: + case ev_entity: + case ev_quat: + case ev_integer: + case ev_uinteger: + case ev_short: + case ev_double: + dasprintf (str, " %s", pr_type_name[type->type]); + return; + case ev_invalid: + case ev_type_count: break; } break; - default: - dasprintf (str, " %s", pr_type_name[type->type]); - break; } + internal_error (0, "bad type meta:type %d:%d", type->meta, type->type); } void @@ -593,93 +609,91 @@ encode_type (dstring_t *encoding, const type_t *type) { if (!type) return; - switch (type->type) { - case ev_void: - dasprintf (encoding, "v"); - break; - case ev_string: - dasprintf (encoding, "*"); - break; - case ev_double: - dasprintf (encoding, "d"); - break; - case ev_float: - dasprintf (encoding, "f"); - break; - case ev_vector: - dasprintf (encoding, "V"); - break; - case ev_entity: - dasprintf (encoding, "E"); - break; - case ev_field: - dasprintf (encoding, "F"); - encode_type (encoding, type->t.fldptr.type); - break; - case ev_func: - dasprintf (encoding, "("); - encode_type (encoding, type->t.func.type); - dasprintf (encoding, "%s)", encode_params (type)); - break; - case ev_pointer: - if (type == &type_id) { - dasprintf (encoding, "@"); + switch (type->meta) { + case ty_class: + encode_class (encoding, type); + return; + case ty_enum: + encode_enum (encoding, type); + return; + case ty_struct: + case ty_union: + encode_struct (encoding, type); + return; + case ty_array: + dasprintf (encoding, "["); + dasprintf (encoding, "%d", type->t.array.size); + if (type->t.array.base) + dasprintf (encoding, ":%d", type->t.array.base); + dasprintf (encoding, "="); + encode_type (encoding, type->t.array.type); + dasprintf (encoding, "]"); + return; + case ty_basic: + switch (type->type) { + case ev_void: + dasprintf (encoding, "v"); + return; + case ev_string: + dasprintf (encoding, "*"); + return; + case ev_double: + dasprintf (encoding, "d"); + return; + case ev_float: + dasprintf (encoding, "f"); + return; + case ev_vector: + dasprintf (encoding, "V"); + return; + case ev_entity: + dasprintf (encoding, "E"); + return; + case ev_field: + dasprintf (encoding, "F"); + encode_type (encoding, type->t.fldptr.type); + return; + case ev_func: + dasprintf (encoding, "("); + encode_type (encoding, type->t.func.type); + dasprintf (encoding, "%s)", encode_params (type)); + return; + case ev_pointer: + if (type == &type_id) { + dasprintf (encoding, "@"); + return; + } + if (type == &type_SEL) { + dasprintf (encoding, ":"); + return; + } + if (type == &type_Class) { + dasprintf (encoding, "#"); + return; + } + type = type->t.fldptr.type; + dasprintf (encoding, "^"); + encode_type (encoding, type); + return; + case ev_quat: + dasprintf (encoding, "Q"); + return; + case ev_integer: + dasprintf (encoding, "i"); + return; + case ev_uinteger: + dasprintf (encoding, "I"); + return; + case ev_short: + dasprintf (encoding, "s"); + return; + case ev_invalid: + case ev_type_count: break; } - if (type == &type_SEL) { - dasprintf (encoding, ":"); - break; - } - if (type == &type_Class) { - dasprintf (encoding, "#"); - break; - } - type = type->t.fldptr.type; - dasprintf (encoding, "^"); - encode_type (encoding, type); - break; - case ev_quat: - dasprintf (encoding, "Q"); - break; - case ev_integer: - dasprintf (encoding, "i"); - break; - case ev_uinteger: - dasprintf (encoding, "I"); - break; - case ev_short: - dasprintf (encoding, "s"); - break; - case ev_invalid: - switch (type->meta) { - case ty_class: - encode_class (encoding, type); - break; - case ty_enum: - encode_enum (encoding, type); - break; - case ty_struct: - case ty_union: - encode_struct (encoding, type); - break; - case ty_array: - dasprintf (encoding, "["); - dasprintf (encoding, "%d", type->t.array.size); - if (type->t.array.base) - dasprintf (encoding, ":%d", type->t.array.base); - dasprintf (encoding, "="); - encode_type (encoding, type->t.array.type); - dasprintf (encoding, "]"); - break; - case ty_none: - dasprintf (encoding, "?"); - break; - } - break; - case ev_type_count: - dasprintf (encoding, "?"); break; } + internal_error (0, "bad type meta:type %d:%d", type->meta, type->type); } int @@ -697,11 +711,39 @@ is_enum (const type_t *type) } int -is_integral (const type_t *type) +is_integer (const type_t *type) { etype_t t = type->type; - if (t == ev_integer || t == ev_uinteger || t == ev_short) + if (t == ev_integer) + return 1; + return is_enum (type); +} + +int +is_uinteger (const type_t *type) +{ + etype_t t = type->type; + + if (t == ev_uinteger) + return 1; + return is_enum (type); +} + +int +is_short (const type_t *type) +{ + etype_t t = type->type; + + if (t == ev_short) + return 1; + return is_enum (type); +} + +int +is_integral (const type_t *type) +{ + if (is_integer (type) || is_uinteger (type) || is_short (type)) return 1; return is_enum (type); } @@ -769,6 +811,14 @@ is_field (const type_t *type) return 0; } +int +is_entity (const type_t *type) +{ + if (type->type == ev_entity) + return 1; + return 0; +} + int is_array (const type_t *type) { @@ -785,6 +835,20 @@ is_func (const type_t *type) return 0; } +int +is_structural (const type_t *type) +{ + return is_struct (type) || is_array (type); +} + +int +is_string (const type_t *type) +{ + if (type->type == ev_string) + return 1; + return 0; +} + int type_compatible (const type_t *dst, const type_t *src) { @@ -834,6 +898,9 @@ type_assignable (const type_t *dst, const type_t *src) dst = dst->t.fldptr.type; src = src->t.fldptr.type; + if (dst == src) { + return 1; + } if (is_void (dst)) return 1; if (is_void (src)) @@ -844,50 +911,31 @@ type_assignable (const type_t *dst, const type_t *src) int type_size (const type_t *type) { - switch (type->type) { - case ev_void: - case ev_string: - case ev_float: - case ev_vector: - case ev_entity: - case ev_field: - case ev_func: - case ev_pointer: - case ev_quat: - case ev_integer: - case ev_uinteger: - case ev_short: - case ev_double: - case ev_type_count: + switch (type->meta) { + case ty_basic: return pr_type_size[type->type]; - case ev_invalid: - switch (type->meta) { - case ty_enum: - if (!type->t.symtab) - return 0; - return type_size (&type_integer); - case ty_struct: - case ty_union: - if (!type->t.symtab) - return 0; - return type->t.symtab->size; - case ty_class: - { - class_t *class = type->t.class; - int size; - if (!class->ivars) - return 0; - size = class->ivars->size; - if (class->super_class) - size += type_size (class->super_class->type); - return size; - } - case ty_array: - return type->t.array.size * type_size (type->t.array.type); - case ty_none: + case ty_struct: + case ty_union: + if (!type->t.symtab) + return 0; + return type->t.symtab->size; + case ty_enum: + if (!type->t.symtab) + return 0; + return type_size (&type_integer); + case ty_array: + return type->t.array.size * type_size (type->t.array.type); + case ty_class: + { + class_t *class = type->t.class; + int size; + if (!class->ivars) return 0; + size = class->ivars->size; + if (class->super_class) + size += type_size (class->super_class->type); + return size; } - break; } return 0; } @@ -897,7 +945,6 @@ init_types (void) { static struct_def_t zero_struct[] = { {"string_val", &type_string}, - {"double_val", &type_double}, {"float_val", &type_float}, {"entity_val", &type_entity}, {"field_val", &type_field}, @@ -909,6 +956,7 @@ init_types (void) {"integer_val", &type_integer}, {"uinteger_val", &type_uinteger}, {"quaternion_val", &type_quaternion}, + {"double_val", &type_double}, {0, 0} }; static struct_def_t param_struct[] = { @@ -943,6 +991,16 @@ init_types (void) {"size", &type_integer}, {0, 0} }; + static struct_def_t xdef_struct[] = { + {"types", &type_pointer}, + {"offset", &type_pointer}, + {0, 0} + }; + static struct_def_t xdefs_struct[] = { + {"xdefs", &type_xdef_pointer}, + {"num_xdefs", &type_pointer}, + {0, 0} + }; type_nil = &type_quaternion; type_default = &type_integer; @@ -960,17 +1018,19 @@ init_types (void) make_structure ("@param", 'u', param_struct, &type_param); make_structure ("@vector", 's', vector_struct, &type_vector); type_vector.type = ev_vector; - type_vector.meta = ty_none; + type_vector.meta = ty_basic; make_structure ("@type_encodings", 's', type_encoding_struct, &type_type_encodings); + make_structure ("@xdef", 's', xdef_struct, &type_xdef); + make_structure ("@xdefs", 's', xdefs_struct, &type_xdefs); if (options.traditional) return; make_structure ("@quaternion", 's', quaternion_struct, &type_quaternion); type_quaternion.type = ev_quat; - type_quaternion.meta = ty_none; + type_quaternion.meta = ty_basic; { symbol_t *sym; sym = new_symbol_type ("x", &type_float); @@ -1018,6 +1078,9 @@ chain_initial_types (void) chain_type (&type_param); chain_type (&type_zero); chain_type (&type_type_encodings); + chain_type (&type_xdef); + chain_type (&type_xdef_pointer); + chain_type (&type_xdefs); va_list_struct[1].type = pointer_type (&type_param); make_structure ("@va_list", 's', va_list_struct, &type_va_list); diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index fc2024a57..2ee44db06 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -80,7 +80,7 @@ static uintptr_t value_get_hash (const void *_val, void *unused) { const ex_value_t *val = (const ex_value_t *) _val; - return Hash_Buffer (&val->v, sizeof (val->v)) + val->lltype; + return Hash_Buffer (&val->v, sizeof (val->v)) ^ (uintptr_t) val->type; } static int @@ -88,7 +88,7 @@ value_compare (const void *_val1, const void *_val2, void *unused) { const ex_value_t *val1 = (const ex_value_t *) _val1; const ex_value_t *val2 = (const ex_value_t *) _val2; - if (val1->lltype != val2->lltype) + if (val1->type != val2->type) return 0; return memcmp (&val1->v, &val2->v, sizeof (val1->v)) == 0; } @@ -197,7 +197,8 @@ new_func_val (int func_val, type_t *type) } ex_value_t * -new_pointer_val (int pointer_val, type_t *type, def_t *def) +new_pointer_val (int pointer_val, type_t *type, def_t *def, + struct operand_s *tempop) { ex_value_t val; if (!type) { @@ -208,6 +209,7 @@ new_pointer_val (int pointer_val, type_t *type, def_t *def) val.v.pointer.val = pointer_val; val.v.pointer.type = type; val.v.pointer.def = def; + val.v.pointer.tempop = tempop; return find_value (&val); } diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index d9d66090a..f6f0c6043 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -9,15 +9,19 @@ AM_CPPFLAGS= -I$(top_srcdir)/include $(QFCC_INCS) QFCC_DEP=$(builddir)/../source/qfcc$(EXEEXT) QFCC=$(QFCC_DEP) -QCFLAGS=-qq -O -g --no-default-paths -Werror -QCPPFLAGS= +QCFLAGS=-qq -O -g -Werror +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) -SUFFIXES=.qfo .r +SUFFIXES=.qfo .r .pas .r.qfo: $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -c -o $@ $< sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo +.pas.qfo: + $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -c -o $@ $< + sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo + $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo QFCC_TEST_LIBS=@QFCC_TEST_LIBS@ QFCC_TEST_DEPS=@QFCC_TEST_DEPS@ @@ -31,29 +35,37 @@ fail_bins= test_progs_dat=\ address-cast.dat \ alignment.dat \ + assignchain.dat \ + anonstruct.dat \ chewed-alias.dat \ chewed-return.dat \ comma-expr.dat \ + compound.dat \ deadbool.dat \ double.dat \ enum.dat \ fordecl.dat \ func-expr.dat \ func-static.dat \ + gcd.dat \ infloop.dat \ ivar-struct-return.dat \ + methodparams.dat \ modulo.dat \ paramret.dat \ quaternion.dat \ return-ivar.dat \ sendv.dat \ state.dat \ + struct-init-param.dat \ + struct-nil-init.dat \ structarray.dat \ structlive.dat \ structptr.dat \ structstruct.dat \ swap.dat \ triangle.dat \ + vecaddr.dat \ vecexpr.dat \ vecinit.dat \ voidfor.dat \ @@ -104,7 +116,7 @@ address_cast_obj=$(address_cast_dat_SOURCES:.r=.qfo) address-cast.dat$(EXEEXT): $(address_cast_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(address_cast_obj) address-cast.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/address-cast.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/address-cast.Qo @@ -113,16 +125,34 @@ alignment_obj=$(alignment_dat_SOURCES:.r=.qfo) alignment.dat$(EXEEXT): $(alignment_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(alignment_obj) alignment.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/alignment.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/alignment.Qo +anonstruct_dat_SOURCES=anonstruct.r +anonstruct_obj=$(anonstruct_dat_SOURCES:.r=.qfo) +anonstruct.dat$(EXEEXT): $(anonstruct_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(anonstruct_obj) +anonstruct.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/anonstruct.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/anonstruct.Qo + +assignchain_dat_SOURCES=assignchain.r +assignchain_obj=$(assignchain_dat_SOURCES:.r=.qfo) +assignchain.dat$(EXEEXT): $(assignchain_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(assignchain_obj) +assignchain.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/assignchain.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/assignchain.Qo + chewed_alias_dat_SOURCES=chewed-alias.r chewed_alias_obj=$(chewed_alias_dat_SOURCES:.r=.qfo) chewed-alias.dat$(EXEEXT): $(chewed_alias_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(chewed_alias_obj) chewed-alias.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/chewed-alias.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/chewed-alias.Qo @@ -131,7 +161,7 @@ chewed_return_obj=$(chewed_return_dat_SOURCES:.r=.qfo) chewed-return.dat$(EXEEXT): $(chewed_return_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(chewed_return_obj) chewed-return.run: Makefile build-run - TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ + @TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ include ./$(DEPDIR)/chewed-return.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/chewed-return.Qo @@ -140,16 +170,25 @@ comma_expr_obj=$(comma_expr_dat_SOURCES:.r=.qfo) comma-expr.dat$(EXEEXT): $(comma_expr_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(comma_expr_obj) comma-expr.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/comma-expr.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/comma-expr.Qo +compound_dat_SOURCES=compound.r +compound_obj=$(compound_dat_SOURCES:.r=.qfo) +compound.dat$(EXEEXT): $(compound_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(compound_obj) +compound.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/compound.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/compound.Qo + deadbool_dat_SOURCES=deadbool.r deadbool_obj=$(deadbool_dat_SOURCES:.r=.qfo) deadbool.dat$(EXEEXT): $(deadbool_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(deadbool_obj) deadbool.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/deadbool.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/deadbool.Qo @@ -158,46 +197,46 @@ double_obj=$(double_dat_SOURCES:.r=.qfo) double.dat$(EXEEXT): $(double_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(double_obj) double.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/double.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/double.Qo double-demote-int.run$(EXEEXT): double-demote-int.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-float.run$(EXEEXT): double-demote-float.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-int-ainit.run$(EXEEXT): double-demote-int-ainit.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-float-ainit.run$(EXEEXT): double-demote-float-ainit.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-int-ginit.run$(EXEEXT): double-demote-int-ginit.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-float-ginit.run$(EXEEXT): double-demote-float-ginit.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-int-linit.run$(EXEEXT): double-demote-int-linit.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-float-linit.run$(EXEEXT): double-demote-float-linit.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-int-compare.run$(EXEEXT): double-int-compare.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-float-compare.run$(EXEEXT): double-float-compare.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< enum_dat_SOURCES=enum.r enum_obj=$(enum_dat_SOURCES:.r=.qfo) enum.dat$(EXEEXT): $(enum_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(enum_obj) enum.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/enum.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/enum.Qo @@ -206,7 +245,7 @@ fordecl_obj=$(fordecl_dat_SOURCES:.r=.qfo) fordecl.dat$(EXEEXT): $(fordecl_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(fordecl_obj) fordecl.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/fordecl.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/fordecl.Qo @@ -215,7 +254,7 @@ func_expr_obj=$(func_expr_dat_SOURCES:.r=.qfo) func-expr.dat$(EXEEXT): $(func_expr_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(func_expr_obj) func-expr.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/func-expr.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/func-expr.Qo @@ -224,16 +263,25 @@ func_static_obj=$(func_static_dat_SOURCES:.r=.qfo) func-static.dat$(EXEEXT): $(func_static_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(func_static_obj) func-static.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/func-static.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/func-static.Qo +gcd_dat_SOURCES=gcd.pas +gcd_obj=$(gcd_dat_SOURCES:.pas=.qfo) +gcd.dat$(EXEEXT): $(gcd_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(gcd_obj) +gcd.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/gcd.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/gcd.Qo + infloop_dat_SOURCES=infloop.r infloop_obj=$(infloop_dat_SOURCES:.r=.qfo) infloop.dat$(EXEEXT): $(infloop_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(infloop_obj) infloop.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/infloop.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/infloop.Qo @@ -242,16 +290,25 @@ ivar_struct_return_obj=$(ivar_struct_return_dat_SOURCES:.r=.qfo) ivar-struct-return.dat$(EXEEXT): $(ivar_struct_return_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(ivar_struct_return_obj) ivar-struct-return.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/ivar-struct-return.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/ivar-struct-return.Qo +methodparams_dat_SOURCES=methodparams.r +methodparams_obj=$(methodparams_dat_SOURCES:.r=.qfo) +methodparams.dat$(EXEEXT): $(methodparams_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(methodparams_obj) +methodparams.run: Makefile build-run + @TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ +include ./$(DEPDIR)/methodparams.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/methodparams.Qo + modulo_dat_SOURCES=modulo.r modulo_obj=$(modulo_dat_SOURCES:.r=.qfo) modulo.dat$(EXEEXT): $(modulo_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(modulo_obj) modulo.run: Makefile build-run - TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ + @TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ include ./$(DEPDIR)/modulo.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/modulo.Qo @@ -260,7 +317,7 @@ paramret_obj=$(paramret_dat_SOURCES:.r=.qfo) paramret.dat$(EXEEXT): $(paramret_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(paramret_obj) paramret.run: Makefile build-run - TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ + @TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ include ./$(DEPDIR)/paramret.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/paramret.Qo @@ -269,7 +326,7 @@ quaternion_obj=$(quaternion_dat_SOURCES:.r=.qfo) quaternion.dat$(EXEEXT): $(quaternion_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(quaternion_obj) quaternion.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/quaternion.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/quaternion.Qo @@ -278,7 +335,7 @@ return_ivar_obj=$(return_ivar_dat_SOURCES:.r=.qfo) return-ivar.dat$(EXEEXT): $(return_ivar_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(return_ivar_obj) return-ivar.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/return-ivar.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/return-ivar.Qo @@ -287,7 +344,7 @@ sendv_obj=$(sendv_dat_SOURCES:.r=.qfo) sendv.dat$(EXEEXT): $(sendv_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(sendv_obj) sendv.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/sendv.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/sendv.Qo @@ -296,16 +353,34 @@ state_obj=$(state_dat_SOURCES:.r=.qfo) state.dat$(EXEEXT): $(state_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(state_obj) state.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/state.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/state.Qo +struct_init_param_dat_SOURCES=struct-init-param.r +struct_init_param_obj=$(struct_init_param_dat_SOURCES:.r=.qfo) +struct-init-param.dat$(EXEEXT): $(struct_init_param_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(struct_init_param_obj) +struct-init-param.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/struct-init-param.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/struct-init-param.Qo + +struct_nil_init_dat_SOURCES=struct-nil-init.r +struct_nil_init_obj=$(struct_nil_init_dat_SOURCES:.r=.qfo) +struct-nil-init.dat$(EXEEXT): $(struct_nil_init_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(struct_nil_init_obj) +struct-nil-init.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/struct-nil-init.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/struct-nil-init.Qo + structarray_dat_SOURCES=structarray.r structarray_obj=$(structarray_dat_SOURCES:.r=.qfo) structarray.dat$(EXEEXT): $(structarray_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(structarray_obj) structarray.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/structarray.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/structarray.Qo @@ -314,7 +389,7 @@ structlive_obj=$(structlive_dat_SOURCES:.r=.qfo) structlive.dat$(EXEEXT): $(structlive_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(structlive_obj) structlive.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/structlive.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/structlive.Qo @@ -323,7 +398,7 @@ structptr_obj=$(structptr_dat_SOURCES:.r=.qfo) structptr.dat$(EXEEXT): $(structptr_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(structptr_obj) structptr.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/structptr.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/structptr.Qo @@ -332,7 +407,7 @@ structstruct_obj=$(structstruct_dat_SOURCES:.r=.qfo) structstruct.dat$(EXEEXT): $(structstruct_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(structstruct_obj) structstruct.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/structstruct.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/structstruct.Qo @@ -341,7 +416,7 @@ swap_obj=$(swap_dat_SOURCES:.r=.qfo) swap.dat$(EXEEXT): $(swap_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(swap_obj) swap.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/swap.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/swap.Qo @@ -350,16 +425,34 @@ triangle_obj=$(triangle_dat_SOURCES:.r=.qfo) triangle.dat$(EXEEXT): $(triangle_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(triangle_obj) triangle.run: Makefile build-run - $(srcdir)/build-run $@ 100000 100000 1.00005 50002.4961 + @$(srcdir)/build-run $@ 100000 100000 1.00005 50002.4961 include ./$(DEPDIR)/triangle.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/triangle.Qo +#typedef_dat_SOURCES=typedef.r +#typedef_obj=$(typedef_dat_SOURCES:.r=.qfo) +#typedef.dat$(EXEEXT): $(typedef_obj) $(QFCC_DEP) +# $(QFCC) $(QCFLAGS) -o $@ $(typedef_obj) +#typedef.run: Makefile build-run +# @$(srcdir)/build-run $@ +#include ./$(DEPDIR)/typedef.Qo # am--include-marker +#r_depfiles_remade += ./$(DEPDIR)/typedef.Qo + +vecaddr_dat_SOURCES=vecaddr.r +vecaddr_obj=$(vecaddr_dat_SOURCES:.r=.qfo) +vecaddr.dat$(EXEEXT): $(vecaddr_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(vecaddr_obj) +vecaddr.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/vecaddr.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/vecaddr.Qo + vecexpr_dat_SOURCES=vecexpr.r vecexpr_obj=$(vecexpr_dat_SOURCES:.r=.qfo) vecexpr.dat$(EXEEXT): $(vecexpr_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(vecexpr_obj) vecexpr.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/vecexpr.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/vecexpr.Qo @@ -368,7 +461,7 @@ vecinit_obj=$(vecinit_dat_SOURCES:.r=.qfo) vecinit.dat$(EXEEXT): $(vecinit_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(vecinit_obj) vecinit.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/vecinit.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/vecinit.Qo @@ -377,7 +470,7 @@ voidfor_obj=$(voidfor_dat_SOURCES:.r=.qfo) voidfor.dat$(EXEEXT): $(voidfor_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(voidfor_obj) voidfor.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/voidfor.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/voidfor.Qo @@ -386,7 +479,7 @@ while_obj=$(while_dat_SOURCES:.r=.qfo) while.dat$(EXEEXT): $(while_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(while_obj) while.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/while.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/while.Qo diff --git a/tools/qfcc/test/anonstruct.r b/tools/qfcc/test/anonstruct.r new file mode 100644 index 000000000..3c025bb38 --- /dev/null +++ b/tools/qfcc/test/anonstruct.r @@ -0,0 +1,52 @@ +void printf (string fmt, ...) = #0; + +typedef struct xyzzy_s { + int magic; +} xyzzy_t; + +typedef struct anon_s { + int foo; + int id; + struct { + int bar; + int baz; + }; + union { + int snafu; + float fizzle; + }; +} anon_t; + +int foo (float f) +{ + anon_t anon; + anon.fizzle = f; + return anon.snafu; +} + +int main() +{ + anon_t anon; + int ret = 0; + if ((int)&anon.snafu != (int)&anon.fizzle) { + printf ("anon union broken: %p %p\n", + &anon.snafu, &anon.fizzle); + ret |= 1; + } + if ((int)&anon.snafu - (int)&anon.baz != 1) { + printf ("snafu and baz not adjacant: snafu:%p baz:%p\n", + &anon.snafu, &anon.baz); + ret |= 1; + } + if ((int)&anon.baz - (int)&anon.bar != 1) { + printf ("baz and bar not adjacant: baz:%p bar:%p\n", + &anon.baz, &anon.bar); + ret |= 1; + } + if ((int)&anon.bar - (int)&anon.id != 1) { + printf ("bar not after id: bar:%p id:%p\n", + &anon.bar, &anon.id); + ret |= 1; + } + return ret; +} diff --git a/tools/qfcc/test/assignchain.r b/tools/qfcc/test/assignchain.r new file mode 100644 index 000000000..7f08c0494 --- /dev/null +++ b/tools/qfcc/test/assignchain.r @@ -0,0 +1,92 @@ +#include "test-harness.h" + +typedef struct foo { + int x; + float y; +} foo; + +int x, y; +int z = 42; +foo bar, baz; +foo foo_init = { 5, 6.25 }; + +int test_simple_global (void) +{ + int ret = 0; + x = y = z; + if (x != z || y != z) { + printf ("test_simple_global: x=%d y=%d z=%d\n", x, y, z); + ret |= 1; + } + return ret; +} + +int test_struct_global (void) +{ + int ret = 0; + bar = baz = foo_init; + if (bar.x != foo_init.x || bar.y != foo_init.y) { + printf ("test_struct_global: bar={%d %g} foo_init={%d %g}\n", + bar.x, bar.y, foo_init.x, foo_init.y); + ret |= 1; + } + if (baz.x != foo_init.x || baz.y != foo_init.y) { + printf ("test_struct_global: baz={%d %g} foo_init={%d %g}\n", + baz.x, baz.y, foo_init.x, foo_init.y); + ret |= 1; + } + bar = baz = nil; + if (bar.x || baz.x || bar.y || baz.y) { + printf ("test_struct_global: bar={%d %g} baz={%d %g}\n", + bar.x, bar.y, baz.x, baz.y); + ret |= 1; + } + return ret; +} + +int test_simple_pointer (int *x, int *y) +{ + int ret = 0; + *x = *y = z; + if (*x != z || *y != z) { + printf ("test_simple_pointer: *x=%d *y=%d z=%d\n", *x, *y, z); + ret |= 1; + } + return ret; +} + +int test_struct_pointer (foo *bar, foo *baz) +{ + int ret = 0; + *bar = *baz = foo_init; + if (bar.x != foo_init.x || bar.y != foo_init.y) { + printf ("test_struct_pointer: bar={%d %g} foo_init={%d %g}\n", + bar.x, bar.y, foo_init.x, foo_init.y); + ret |= 1; + } + if (baz.x != foo_init.x || baz.y != foo_init.y) { + printf ("test_struct_pointer: baz={%d %g} foo_init={%d %g}\n", + baz.x, baz.y, foo_init.x, foo_init.y); + ret |= 1; + } + *bar = foo_init; + *baz = foo_init; + *bar = *baz = nil; + if (bar.x || baz.x || bar.y || baz.y) { + printf ("test_struct: bar={%d %g} baz={%d %g}\n", + bar.x, bar.y, baz.x, baz.y); + ret |= 1; + } + return ret; +} + +int main () +{ + int ret = 0; + ret |= test_simple_global (); + ret |= test_struct_global (); + x = 0; y = 0; + ret |= test_simple_pointer (&x, &y); + ret |= test_struct_pointer (&bar, &baz); + return ret; +} diff --git a/tools/qfcc/test/chewed-alias.r b/tools/qfcc/test/chewed-alias.r index 7f151bce5..08c060534 100644 --- a/tools/qfcc/test/chewed-alias.r +++ b/tools/qfcc/test/chewed-alias.r @@ -1,4 +1,9 @@ -@class Array,Object; +@interface Array +-count; +-lastObject; +@end +@interface Object +@end @static entity waypoint_thinker; @static Array *waypoint_queue; void foo (void) @@ -18,4 +23,6 @@ void __obj_exec_class (struct obj_module *msg) = #0; @implementation Object @end @implementation Array +-count { return self; } +-lastObject { return nil; } @end diff --git a/tools/qfcc/test/compound.r b/tools/qfcc/test/compound.r new file mode 100644 index 000000000..19a72d3fe --- /dev/null +++ b/tools/qfcc/test/compound.r @@ -0,0 +1,72 @@ +#include "test-harness.h" + +typedef struct Point { + int x; + int y; +} Point; + +typedef struct Size { + int width; + int height; +} Size; + +typedef struct Rect { + Point origin; + Size size; +} Rect; + +int test_simple_param (Point p, int x, int y) +{ + int ret = !(p.x == x && p.y == y); + if (ret) { + printf ("simple param: {%d, %d} != {%d, %d}\n", p.x, p.y, x, y); + } + return ret; +} + +int test_nested_param (Rect r, int x, int y, int w, int h) +{ + int ret = !(r.origin.x == x && r.origin.y == y + && r.size.width == w && r.size.height == h); + if (ret) { + printf ("nested param: {{%d, %d}, {%d, %d}} != ", + r.origin.x, r.origin.y, r.size.width, r.size.height); + printf ("{{%d, %d}, {%d, %d}}\n", x, y, w, h); + } + return ret; +} + +int test_simple_assign (int x, int y) +{ + Point p; + p = { x, y }; + int ret = !(p.x == x && p.y == y); + if (ret) { + printf ("simple assign: {%d, %d} != {%d, %d}\n", p.x, p.y, x, y); + } + return ret; +} + +int test_nested_assign (int x, int y, int w, int h) +{ + Rect r; + r = {{x, y}, {w, h}}; + int ret = !(r.origin.x == x && r.origin.y == y + && r.size.width == w && r.size.height == h); + if (ret) { + printf ("nested assign: {{%d, %d}, {%d, %d}} != ", + r.origin.x, r.origin.y, r.size.width, r.size.height); + printf ("{{%d, %d}, {%d, %d}}\n", x, y, w, h); + } + return ret; +} + +int main (void) +{ + int ret = 0; + ret |= test_simple_param ({1, 2}, 1, 2); + ret |= test_nested_param ({{1, 2}, {3, 4}}, 1, 2, 3, 4); + ret |= test_simple_assign (1, 2); + ret |= test_nested_assign (1, 2, 3, 4); + return ret; +} diff --git a/tools/qfcc/test/old/gcd.pas b/tools/qfcc/test/gcd.pas similarity index 73% rename from tools/qfcc/test/old/gcd.pas rename to tools/qfcc/test/gcd.pas index 04e193b26..3879a3d3d 100644 --- a/tools/qfcc/test/old/gcd.pas +++ b/tools/qfcc/test/gcd.pas @@ -1,5 +1,5 @@ program example (input, output); -var x, y: integer; +var x, y, g: integer; procedure printf (format:string; ...) := #0; function gcd (a, b: integer): integer; var c: quaternion; @@ -11,5 +11,7 @@ end; begin x := 130; y := 120; - printf ("%d\n", gcd (x, y)) + g := gcd (x, y); + printf ("%d\n", g); + ExitCode := g <> 10; end. diff --git a/tools/qfcc/test/ivar-struct-return.r b/tools/qfcc/test/ivar-struct-return.r index 5e212a5ba..8351293c8 100644 --- a/tools/qfcc/test/ivar-struct-return.r +++ b/tools/qfcc/test/ivar-struct-return.r @@ -1,4 +1,5 @@ #pragma bug die +#include "test-harness.h" struct Point { int x; @@ -11,17 +12,18 @@ typedef struct Point Point; int foo; Point origin; } --(Point) origin; ++(Point) origin; @end @implementation Object --(Point) origin ++(Point) origin { + origin = {1, 2}; return origin; } @end -void __obj_exec_class (struct obj_module *msg) = #0; int main() { - return 0; // to survive and prevail + Point p = [Object origin]; + return !(p.x == 1 && p.y == 2); } diff --git a/tools/qfcc/test/methodparams.r b/tools/qfcc/test/methodparams.r new file mode 100644 index 000000000..b29e6954b --- /dev/null +++ b/tools/qfcc/test/methodparams.r @@ -0,0 +1,29 @@ +typedef struct { int x, y; } Point; +@interface TextContext +- (void) mvvprintf: (Point) pos, string mft, @va_list args; +@end +@interface View +{ + TextContext *textContext; +} +- (void) mvprintf: (Point) pos, string mft, ...; +@end + +@implementation View +- (void) mvprintf: (Point) pos, string fmt, ... +{ + [textContext mvvprintf: pos, fmt, @args]; +} +@end +id obj_msgSend (id receiver, SEL op, ...) = #0; +void __obj_exec_class (struct obj_module *msg) = #0; +@interface Object +@end +@implementation Object +@end + +int +main (void) +{ + return 0; // to survive and prevail :) +} diff --git a/tools/qfcc/test/sendv.r b/tools/qfcc/test/sendv.r index 979a72c43..aa2cb6665 100644 --- a/tools/qfcc/test/sendv.r +++ b/tools/qfcc/test/sendv.r @@ -8,12 +8,13 @@ int obj_increment_retaincount (id object) = #0; void send (id obj, string cmd, string str) { - @static @param params[1]; - @va_list va_list = {1, params}; - SEL sel; + @static @param params[3]; + @va_list va_list = {3, params}; + SEL sel = sel_get_uid (cmd); - params[0].string_val = str; - sel = sel_get_uid (cmd); + params[0].pointer_val = obj; + params[1].pointer_val = sel; + params[2].string_val = str; obj_msg_sendv (obj, sel, va_list); } diff --git a/tools/qfcc/test/struct-init-param.r b/tools/qfcc/test/struct-init-param.r new file mode 100644 index 000000000..c3dd5927b --- /dev/null +++ b/tools/qfcc/test/struct-init-param.r @@ -0,0 +1,59 @@ +void printf (string fmt, ...) = #0; +typedef struct { + int x; + int y; +} Point; + +typedef struct { + int width; + int height; +} Extent; + +typedef struct Rect_s { + Point offset; + Extent extent; +} Rect; + +void *foo (Rect *obj, void *cmd, Rect *o, Point pos, Rect r); + +void *baz (Rect *obj, void *cmd, Rect *o, Point pos) +{ + Rect rect = { {1, 2}, {3, 4} }; + return foo (obj, cmd, o, pos, rect); +} + +void *bar (Rect *obj, void *cmd, Rect *o, Point pos) +{ + Rect rect = { {}, obj.extent }; + return foo (obj, cmd, o, pos, rect); +} + +void *foo (Rect *obj, void *cmd, Rect *o, Point pos, Rect r) +{ + *o = r; + return obj; +} + +Rect obj = { { 1, 2}, { 3, 4} }; +Rect o = { { 5, 6}, {7, 8} }; + +int main (void) +{ + int ret = 0; + int ok; + + bar(&obj, nil, &o, obj.offset); + ok = (o.offset.x == 0 && o.offset.y == 0 + && o.extent.width == 3 && o.extent.height == 4); + ret |= !ok; + printf ("%d %d %d %d %d\n", o.offset.x, o.offset.y, + o.extent.width, o.extent.height, ok); + + baz(&obj, nil, &o, obj.offset); + ok = (o.offset.x == 1 && o.offset.y == 2 + && o.extent.width == 3 && o.extent.height == 4); + ret |= !ok; + printf ("%d %d %d %d %d\n", o.offset.x, o.offset.y, + o.extent.width, o.extent.height, ok); + return ret; +} diff --git a/tools/qfcc/test/struct-nil-init.r b/tools/qfcc/test/struct-nil-init.r new file mode 100644 index 000000000..065a43b34 --- /dev/null +++ b/tools/qfcc/test/struct-nil-init.r @@ -0,0 +1,12 @@ +#pragma bug die + +struct foo { + quaternion x; + double y; +}; + +int main() +{ + struct foo bar = { }; + return bar.y; // to survive and prevail +} diff --git a/tools/qfcc/test/test-harness.c b/tools/qfcc/test/test-harness.c index a8f829cd9..934c02cb0 100644 --- a/tools/qfcc/test/test-harness.c +++ b/tools/qfcc/test/test-harness.c @@ -96,7 +96,7 @@ open_file (const char *path, int *len) } static void * -load_file (progs_t *pr, const char *name) +load_file (progs_t *pr, const char *name, off_t *_size) { QFile *file; int size; @@ -112,6 +112,7 @@ load_file (progs_t *pr, const char *name) sym = malloc (size + 1); sym[size] = 0; Qread (file, sym, size); + *_size = size; return sym; } @@ -137,6 +138,7 @@ init_qf (void) cvar_t *debug = Cvar_Get ("pr_debug", "2", 0, 0, 0); Cvar_Get ("pr_boundscheck", "2", 0, 0, 0); + Cvar_Get ("pr_deadbeef_locals", "1", 0, 0, 0); if (options.trace > 1) { Cvar_SetValue (debug, 4); @@ -149,10 +151,9 @@ init_qf (void) pr.allocate_progs_mem = allocate_progs_mem; pr.free_progs_mem = free_progs_mem; pr.no_exec_limit = 0; // absolutely want a limit! - pr.pr_trace = options.trace; PR_Init_Cvars (); - PR_Init (); + PR_Init (&pr); RUA_Init (&pr, 0); PR_Cmds_Init(&pr); BI_Init (&pr); @@ -176,6 +177,8 @@ load_progs (const char *name) Qclose (file); if (!PR_RunLoadFuncs (&pr)) PR_Error (&pr, "unable to load %s", pr.progs_name); + pr.pr_trace_depth = -1; + pr.pr_trace = options.trace; return 1; } @@ -264,6 +267,7 @@ main (int argc, char **argv) PR_RESET_PARAMS (&pr); P_INT (&pr, 0) = pr_argc; P_POINTER (&pr, 1) = PR_SetPointer (&pr, pr_argv); + pr.pr_argc = 2; PR_ExecuteProgram (&pr, main_func); PR_PopFrame (&pr); if (options.flote) diff --git a/tools/qfcc/test/test-harness.h b/tools/qfcc/test/test-harness.h index f350c7ec7..63f368416 100644 --- a/tools/qfcc/test/test-harness.h +++ b/tools/qfcc/test/test-harness.h @@ -5,3 +5,5 @@ string strerror (int err) = #0; void exit (int code) = #0; entity spawn (void) = #0; void remove (entity e) = #0; +id obj_msgSend (id receiver, SEL op, ...) = #0; +void __obj_exec_class (struct obj_module *msg) = #0; diff --git a/tools/qfcc/test/typedef.r b/tools/qfcc/test/typedef.r new file mode 100644 index 000000000..e6e80a92b --- /dev/null +++ b/tools/qfcc/test/typedef.r @@ -0,0 +1,66 @@ +#include + +// can't link against libr.a (may not be built) +void *PR_FindGlobal (string name) = #0; +void printf (string fmt, ...) = #0; + +qfot_type_encodings_t *encodings; + +typedef int *foo; +typedef int *bar; + +foo baz; +bar snafu; + +qfot_type_t * +next_type (qfot_type_t *type) +{ + int size = type.size; + if (!size) + size = 4; + return (qfot_type_t *) ((int *) type + size); +} + +int +check_alias (string name, qfot_type_t *alias) +{ + if (alias.meta != ty_basic || alias.t.type != ev_pointer + || alias.t.fldptr.aux_type.meta != ty_basic + || alias.t.fldptr.aux_type.t.type != ev_integer) { + printf ("%s is not a *int alias\n", name); + return 0; + } + return 1; +} + +int +main (void) +{ + baz = snafu; + + int found_foo = 0; + int found_bar = 0; + qfot_type_t *type; + + encodings = PR_FindGlobal (".type_encodings"); + + for (type = encodings.types; + ((int *)type - (int *) encodings.types) < encodings.size; + type = next_type (type)) { + if (type.meta == ty_alias) { + if (type.t.alias.name == "foo") { + found_foo = check_alias (type.t.alias.name, + type.t.alias.aux_type); + } + if (type.t.alias.name == "bar") { + found_bar = check_alias (type.t.alias.name, + type.t.alias.aux_type); + } + } + } + if (!(found_bar && found_foo)) { + printf ("missing typedef: foo: %d bar:%d\n", found_foo, found_bar); + return 1; + } + return 0; +} diff --git a/tools/qfcc/test/vecaddr.r b/tools/qfcc/test/vecaddr.r new file mode 100644 index 000000000..323d9205c --- /dev/null +++ b/tools/qfcc/test/vecaddr.r @@ -0,0 +1,16 @@ +void printf (string fmt, ...) = #0; + +float foo (vector v, float z) +{ + return v * *(vector*)(&v.y); +} + +int +main (int argc, string *argv) +{ + vector v = [1, 2, 3]; + vector w = [2, 3, 4]; + float f; + printf ("%v %g %g %g\n", v, v*v, v*w, f=foo (v, 4)); + return f != v*w; +} diff --git a/tools/qfcc/test/vecexpr.r b/tools/qfcc/test/vecexpr.r index 8667b0c93..0365ed589 100644 --- a/tools/qfcc/test/vecexpr.r +++ b/tools/qfcc/test/vecexpr.r @@ -1,4 +1,14 @@ #include "test-harness.h" + +vector t1(); +vector t2(float x); + +vector +t3(float x) +{ + return [x, t2(9).z, x] * 2; +} + vector t1() { @@ -11,12 +21,6 @@ t2(float x) return [x, x, x]; } -vector -t3(float x) -{ - return [x, t2(9).z, x] * 2; -} - int main () { diff --git a/tools/qwaq/Makefile.am b/tools/qwaq/Makefile.am deleted file mode 100644 index dd34fd9c5..000000000 --- a/tools/qwaq/Makefile.am +++ /dev/null @@ -1,50 +0,0 @@ -QWAQ_LIBS=@QWAQ_LIBS@ -QWAQ_DEPS=@QWAQ_DEPS@ -QWAQ_INCS=@QWAQ_INCS@ - -AM_CPPFLAGS= -I$(top_srcdir)/include $(QWAQ_INCS) - -QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) -QFCC=$(top_builddir)/tools/qfcc/source/qfcc -QCFLAGS=-qq -O -g -Werror --advanced --no-default-paths - -noinst_PROGRAMS=qwaq @QWAQ_TARGETS@ -noinst_DATA=qwaq.dat - -qwaq_dat_src= \ - defs.qc main.qc test.r types.r - -qwaq_SOURCES= main.c builtins.c -qwaq_LDADD= $(QWAQ_LIBS) -qwaq_DEPENDENCIES= $(QWAQ_DEPS) - -cl_plugin_libs= \ - @client_static_plugin_libs@ - -client_libs= \ - $(top_builddir)/libs/console/libQFconsole.la \ - $(top_builddir)/libs/video/targets/libQFjs.la \ - $(top_builddir)/libs/audio/libQFcd.la \ - $(top_builddir)/libs/audio/libQFsound.la \ - $(top_builddir)/libs/image/libQFimage.la - -qwaq_x11_libs= \ - $(cl_plugin_libs) \ - $(top_builddir)/libs/video/renderer/libQFrenderer.la \ - $(top_builddir)/libs/models/libQFmodels.la \ - $(top_builddir)/libs/video/targets/libQFx11.la \ - $(client_libs) \ - $(top_builddir)/libs/gib/libQFgib.la -qwaq_x11_SOURCES=qwaq.c qwaq-bi.c -qwaq_x11_LDADD= $(qwaq_x11_libs) $(QWAQ_LIBS) \ - $(VIDMODE_LIBS) $(DGA_LIBS) $(X_LIBS) -lX11 \ - $(X_EXTRA_LIBS) $(X_SHM_LIB) $(DL_LIBS) -qwaq_x11_LDFLAGS= -qwaq_x11_DEPENDENCIES= $(qwaq_x11_libs) $(QWAQ_DEPS) - -qwaq.dat: progs.src $(qwaq_dat_src) $(QFCC_DEP) $(top_srcdir)/ruamoko/lib/Object.r - $(QFCC) $(QCFLAGS) -I$(top_srcdir)/ruamoko/include - -EXTRA_PROGRAMS=qwaq-x11 -EXTRA_DIST=$(qwaq_dat_src) qwaq.h -CLEANFILES= *.dat *.sym diff --git a/tools/qwaq/defs.qc b/tools/qwaq/defs.qc deleted file mode 100644 index e872fb799..000000000 --- a/tools/qwaq/defs.qc +++ /dev/null @@ -1,22 +0,0 @@ -void (string str) print = #0; -int () errno = #0; -string (int err) strerror = #0; -int (...) open = #0; // string path, float flags[, float mode] -int (int handle) close = #0; -string read (int handle, int count, int *result) = #0; -int (int handle, string buffer, int count) write = #0; -int (int handle, int pos, int whence) seek = #0; - -//void() traceon = #0; // turns statment trace on -//void() traceoff = #0; - -void (...) printf = #0; - - -float time; -entity self; - -.float nextthink; -.void() think; -.float frame; -.vector origin; diff --git a/tools/qwaq/main.qc b/tools/qwaq/main.qc deleted file mode 100644 index 1014c1f4d..000000000 --- a/tools/qwaq/main.qc +++ /dev/null @@ -1,113 +0,0 @@ -string read_file (string filename) -{ - local QFile file; - local string data = nil, d; - file = Qopen (filename, "rtz"); - if (!file) { - printf ("Can't open %s for reading." - " Probably a bad hardcoded filename:)\n", filename); - return nil; - } - while ((d = Qgetline (file))) - data = data + d; - //FIXME can't read to a string, can't convert a pointer to a string ... - //Qread (file, data, 1023); - Qclose (file); - d = str_new (); - str_copy (d, data); - return d; -} - -void test_plist (void) -{ - local string data, l; - local plitem_t pl, item, i; - - data = read_file ("/home/bill/.quakeforge/gamedir.conf"); - pl = PL_GetPropertyList ("{" + data + "}"); - l = PL_WritePropertyList (pl); - printf ("%s", data); - printf ("%s", l); - i = PL_ObjectForKey (pl, "QF"); - item = PL_RemoveObjectForKey (pl, "QF"); - l = PL_WritePropertyList (item); - printf ("%s", l); - PL_Free (item); - //Because i and item both point to the same plitem, and item has been, - //freed, freeing i will generate an error - //l = PL_WritePropertyList (i); - PL_Free (pl); - str_free (data); -} - -void test_script (void) -{ - local script_t script; - local string token; - local string data; - - data = read_file ("progs.src"); - script = Script_New (); - token = Script_Start (script, "progs.src", data); - while (Script_GetToken (script, 1)) { - printf ("%s\n", token); - } - Script_Delete (script); - str_free (data); -} - -void () test_str = -{ - local string a,b,c,d; - a = "testing "; - b = "temp "; - c = "strings "; - d = "\n"; - print (a + b + c + d); - printf ("%i \"%.5s\" %3.4f %v\n", 14, "hi there", 3.1415926, '4 1 3'); -}; -void (...) dprint = #0; -int main (int argc, string *argv) -{ - local int i; - local SEL sel; - dprint ("foo", "bar\n"); - for (i = 0; i < argc; i++) { - print (argv[i]); - print ("\n"); - } - local id foo = [[Foo alloc] init]; - [foo run]; - sel = sel_get_uid ("run"); - if (sel) { - print ("found selector for `run'\n"); - if ([foo respondsToSelector:sel]) - print ("foo responds to `run'\n"); - else - print ("foo does not repond to `run'\n"); - } else - print ("did not find selector for `run'\n"); - sel = sel_get_uid ("alloc"); - if (sel) { - print ("found selector for `alloc'\n"); - if ([Object instancesRespondToSelector:sel]) - print ("Object instances respond to `alloc'\n"); - else - print ("Object instances do not repond to `alloc'\n"); - } else - print ("did not find selector for `alloc'\n"); - sel = sel_get_uid ("run:with:me:"); - if (sel) { - print ("found selector for `run:with:me:'\n"); - if ([Object instancesRespondToSelector:sel]) - print ("Object instances respond to `run:with:me:'\n"); - else - print ("Object instances do not repond to `run:with:me:'\n"); - } else - print ("did not find selector for `run:with:me:'\n"); - test_str (); - test_script (); - test_plist (); - test_types (); - return 0; -}; diff --git a/tools/qwaq/test.r b/tools/qwaq/test.r deleted file mode 100644 index 6e0afd6f2..000000000 --- a/tools/qwaq/test.r +++ /dev/null @@ -1,42 +0,0 @@ -@interface Foo : Object -{ - int x; -} --run; -@end - - -@implementation Foo - -+load -{ - print ("+load\n"); - return self; -} - -+alloc -{ - print ("+alloc\n"); - return class_create_instance (self); -} - --init -{ - print ("-init\n"); - return [super init]; -} - -+ (void) initialize -{ - print ("+initialize\n"); -} - --run -{ - print ("Hello world\n"); - printf ("%i %p [%s %s]\n", self, &self.x, [self description], - __PRETTY_FUNCTION__); - return self; -} - -@end diff --git a/tools/qwaq/types.r b/tools/qwaq/types.r deleted file mode 100644 index 82665e20a..000000000 --- a/tools/qwaq/types.r +++ /dev/null @@ -1,174 +0,0 @@ -#include "runtime.h" //FIXME for PR_FindGlobal -typedef enum { - ev_void, - ev_string, - ev_float, - ev_vector, - ev_entity, - ev_field, - ev_func, - ev_pointer, // end of v6 types - ev_quat, - ev_integer, - ev_uinteger, - ev_short, // value is embedded in the opcode - - ev_invalid, // invalid type. used for instruction checking - ev_type_count // not a type, gives number of types -} etype_t; - -typedef enum { - ty_none, ///< func/field/pointer or not used - ty_struct, - ty_union, - ty_enum, - ty_array, - ty_class, -} ty_meta_e; - - -typedef struct qfot_fldptr_s { - etype_t type; - struct qfot_type_s *aux_type; -} qfot_fldptr_t; - -typedef struct qfot_func_s { - etype_t type; - struct qfot_type_s *return_type; - int num_params; - struct qfot_type_s *param_types[1]; -} qfot_func_t; - -typedef struct qfot_var_s { - struct qfot_type_s *type; - string name; - int offset; // value for enum, 0 for union -} qfot_var_t; - -typedef struct qfot_struct_s { - string tag; - int num_fields; - qfot_var_t fields[1]; -} qfot_struct_t; - -typedef struct qfot_array_s { - struct qfot_type_s *type; - int base; - int size; -} qfot_array_t; - -typedef struct qfot_type_s { - ty_meta_e meta; - int size; - string encoding; - union { - etype_t type; - qfot_fldptr_t fldptr; - qfot_func_t func; - qfot_struct_t strct; - qfot_array_t array; - string class; - } t; -} qfot_type_t; - -typedef struct qfot_type_encodings_s { - qfot_type_t *types; - int size; -} qfot_type_encodings_t; - -qfot_type_t * -next_type (qfot_type_t *type) -{ - int size = type.size; - if (!size) - size = 4; - return (qfot_type_t *) ((int *) type + size); -} - -string ty_meta_name[6] = { - "basic", - "struct", - "union", - "enum", - "array", - "class", -}; - -string pr_type_name[ev_type_count] = { - "void", - "string", - "float", - "vector", - "entity", - "field", - "function", - "pointer", - "quaternion", - "integer", - "uinteger", - "short", - "invalid", -}; - -void -test_types (void) -{ - qfot_type_encodings_t *encodings; - qfot_type_t *type; - int i; - - encodings = PR_FindGlobal (".type_encodings"); - if (!encodings) { - printf ("Can't find encodings\n"); - return; - } - for (type = encodings.types; - ((int *)type - (int *) encodings.types) < encodings.size; - type = next_type (type)) { - printf ("%p %-6s %-20s", type, ty_meta_name[type.meta], - type.encoding); - if (!type.size) { - printf ("\n"); - continue; - } - switch (type.meta) { - case ty_none: - printf (" %-10s", pr_type_name[type.t.type]); - if (type.t.type == ev_func) { - int count = type.t.func.num_params; - printf ("%p %d", type.t.func.return_type, count); - if (count < 0) - count = ~count; - for (i = 0; i < count; i++) - printf (" %p", type.t.func.param_types[i]); - } else if (type.t.type == ev_pointer) { - printf (" *%p", type.t.fldptr.aux_type); - } else if (type.t.type == ev_field) { - printf (" .%p", type.t.fldptr.aux_type); - } else { - printf (" %p", type.t.fldptr.aux_type); - } - printf ("\n"); - break; - case ty_struct: - case ty_union: - case ty_enum: - printf (" %s\n", type.t.strct.tag); - for (i = 0; i < type.t.strct.num_fields; i++) { - printf (" %p %4x %s\n", - type.t.strct.fields[i].type, - type.t.strct.fields[i].offset, - type.t.strct.fields[i].name); - } - break; - case ty_array: - printf (" %p %d %d\n", type.t.array.type, - type.t.array.base, type.t.array.size); - break; - case ty_class: - printf (" %s %p\n", type.t.class, - obj_lookup_class (type.t.class)); - break; - } - } -}