Pawn 3.2.3664 code with samp_compatible patches applied
This commit is contained in:
commit
00f21e67d5
10
EXAMPLES/argument.p
Normal file
10
EXAMPLES/argument.p
Normal file
@ -0,0 +1,10 @@
|
||||
#include <args>
|
||||
|
||||
main()
|
||||
{
|
||||
printf "Argument count = %d\n", argcount()
|
||||
|
||||
new opt[100]
|
||||
for (new index = 0; argindex(index, opt); index++)
|
||||
printf "Argument %d = %s\n", index, opt
|
||||
}
|
14
EXAMPLES/c2f.p
Normal file
14
EXAMPLES/c2f.p
Normal file
@ -0,0 +1,14 @@
|
||||
#include <rational>
|
||||
|
||||
main()
|
||||
{
|
||||
new Rational: Celsius
|
||||
new Rational: Fahrenheit
|
||||
|
||||
print "Celsius\t Fahrenheit\n"
|
||||
for (Celsius = 5; Celsius <= 25; Celsius++)
|
||||
{
|
||||
Fahrenheit = (Celsius * 1.8) + 32
|
||||
printf "%r \t %r\n", Celsius, Fahrenheit
|
||||
}
|
||||
}
|
37
EXAMPLES/capt.p
Normal file
37
EXAMPLES/capt.p
Normal file
@ -0,0 +1,37 @@
|
||||
bool: ispacked(string[])
|
||||
return bool: (string[0] > charmax)
|
||||
|
||||
my_strlen(string[])
|
||||
{
|
||||
new len = 0
|
||||
if (ispacked(string))
|
||||
while (string{len} != EOS) /* get character from pack */
|
||||
++len
|
||||
else
|
||||
while (string[len] != EOS) /* get cell */
|
||||
++len
|
||||
return len
|
||||
}
|
||||
|
||||
strupper(string[])
|
||||
{
|
||||
assert ispacked(string)
|
||||
|
||||
for (new i=0; string{i} != EOS; ++i)
|
||||
string{i} = toupper(string{i})
|
||||
}
|
||||
|
||||
main()
|
||||
{
|
||||
new s[10]
|
||||
|
||||
for (new i = 0; i < 5; i++)
|
||||
s{i}=i+'a'
|
||||
s{5}=EOS
|
||||
|
||||
printf("String is %s\n", ispacked(s) ? "packed" : "unpacked")
|
||||
printf("String length is %d\n", my_strlen(s))
|
||||
printf("Original: %s\n", s)
|
||||
strupper(s)
|
||||
printf("Upper case: %s\n", s)
|
||||
}
|
65
EXAMPLES/cards.p
Normal file
65
EXAMPLES/cards.p
Normal file
@ -0,0 +1,65 @@
|
||||
enum _: CardSuits
|
||||
{
|
||||
Clubs,
|
||||
Diamonds,
|
||||
Hearts,
|
||||
Spades,
|
||||
}
|
||||
|
||||
const CardTypes = 13
|
||||
const TotalCards = CardSuits * CardTypes
|
||||
|
||||
enum CardDescription
|
||||
{
|
||||
CardName[10 char],
|
||||
CardSuit,
|
||||
CardValue,
|
||||
}
|
||||
|
||||
new CardNames[CardTypes][] = { !"Ace", !"Two", !"Three", !"Four", !"Five",
|
||||
!"Six", !"Seven", !"Eight", !"Nine", !"Ten",
|
||||
!"Jack", !"Queen", !"King" }
|
||||
new CardValues[CardTypes] = { 11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10 }
|
||||
|
||||
main()
|
||||
{
|
||||
new Cards[ TotalCards ][ CardDescription ]
|
||||
|
||||
/* fill in the cards */
|
||||
for (new suit = 0; suit < CardSuits; suit++)
|
||||
{
|
||||
for (new card = 0; card < CardTypes; card++)
|
||||
{
|
||||
new index = suit*CardTypes + card
|
||||
strpack Cards[ index ][CardName], CardNames[ card ]
|
||||
Cards[ index ][ CardSuit ] = suit
|
||||
Cards[ index ][ CardValue ] = CardValues[ card ]
|
||||
}
|
||||
}
|
||||
|
||||
/* shuffle the cards (swap an arbitrary number of randomly selected cards) */
|
||||
for (new iter = 0; iter < 200; iter++)
|
||||
{
|
||||
new first = random(TotalCards)
|
||||
new second = random(TotalCards)
|
||||
new TempCard[ CardDescription ]
|
||||
TempCard = Cards[first]
|
||||
Cards[ first ] = Cards[ second ]
|
||||
Cards[ second ] = TempCard
|
||||
}
|
||||
|
||||
/* print the cards with a subroutine */
|
||||
for (new card = 0; card < TotalCards; card++)
|
||||
PrintCard Cards[ card]
|
||||
}
|
||||
|
||||
PrintCard( TheCard[ CardDescription ] )
|
||||
{
|
||||
new SuitNames[ CardSuits ][] = { !"Clubs", !"Diamonds",
|
||||
!"Hearts", !"Spades" }
|
||||
|
||||
printf !"%s of %s (valued %d)\n",
|
||||
TheCard[ CardName ],
|
||||
SuitNames[ TheCard[ CardSuit ] ],
|
||||
TheCard[ CardValue ]
|
||||
}
|
31
EXAMPLES/chat.p
Normal file
31
EXAMPLES/chat.p
Normal file
@ -0,0 +1,31 @@
|
||||
#include <datagram>
|
||||
|
||||
@receivestring(const message[], const source[])
|
||||
printf "[%s] says: %s\n", source, message
|
||||
|
||||
@keypressed(key)
|
||||
{
|
||||
static string[100 char]
|
||||
static index
|
||||
|
||||
if (key == '\e')
|
||||
exit /* quit on 'Esc' key */
|
||||
|
||||
echo key
|
||||
if (key == '\r' || key == '\n' || index char == sizeof string)
|
||||
{
|
||||
string{index} = '\0' /* terminate string */
|
||||
sendstring string
|
||||
index = 0
|
||||
string[index] = '\0'
|
||||
}
|
||||
else
|
||||
string{index++} = key
|
||||
}
|
||||
|
||||
echo(key)
|
||||
{
|
||||
new string[2 char] = { 0 }
|
||||
string{0} = key == '\r' ? '\n' : key
|
||||
printf string
|
||||
}
|
45
EXAMPLES/comment.p
Normal file
45
EXAMPLES/comment.p
Normal file
@ -0,0 +1,45 @@
|
||||
/* parse C comments interactively, using events and a state machine */
|
||||
|
||||
main()
|
||||
state plain
|
||||
|
||||
@keypressed(key) <plain>
|
||||
{
|
||||
state (key == '/') slash
|
||||
if (key != '/')
|
||||
echo key
|
||||
}
|
||||
|
||||
@keypressed(key) <slash>
|
||||
{
|
||||
state (key != '/') plain
|
||||
state (key == '*') comment
|
||||
echo '/' /* print '/' held back from previous state */
|
||||
if (key != '/')
|
||||
echo key
|
||||
}
|
||||
|
||||
@keypressed(key) <comment>
|
||||
{
|
||||
echo key
|
||||
state (key == '*') star
|
||||
}
|
||||
|
||||
@keypressed(key) <star>
|
||||
{
|
||||
echo key
|
||||
state (key != '*') comment
|
||||
state (key == '/') plain
|
||||
}
|
||||
|
||||
echo(key) <plain, slash>
|
||||
printchar key, yellow
|
||||
|
||||
echo(key) <comment, star>
|
||||
printchar key, green
|
||||
|
||||
printchar(ch, colour)
|
||||
{
|
||||
setattr .foreground = colour
|
||||
printf "%c", ch
|
||||
}
|
20
EXAMPLES/faculty.p
Normal file
20
EXAMPLES/faculty.p
Normal file
@ -0,0 +1,20 @@
|
||||
/* Calculation of the faculty of a value */
|
||||
|
||||
main()
|
||||
{
|
||||
print "Enter a value: "
|
||||
new v = getvalue()
|
||||
new f = faculty(v)
|
||||
printf "The faculty of %d is %d\n", v, f
|
||||
}
|
||||
|
||||
faculty(n)
|
||||
{
|
||||
assert n >= 0
|
||||
|
||||
new result = 1
|
||||
while (n > 0)
|
||||
result *= n--
|
||||
|
||||
return result
|
||||
}
|
26
EXAMPLES/fib.p
Normal file
26
EXAMPLES/fib.p
Normal file
@ -0,0 +1,26 @@
|
||||
/* Calculation of Fibonacci numbers by iteration */
|
||||
|
||||
main()
|
||||
{
|
||||
print "Enter a value: "
|
||||
new v = getvalue()
|
||||
if (v > 0)
|
||||
printf "The value of Fibonacci number %d is %d\n",
|
||||
v, fibonacci(v)
|
||||
else
|
||||
printf "The Fibonacci number %d does not exist\n", v
|
||||
}
|
||||
|
||||
fibonacci(n)
|
||||
{
|
||||
assert n > 0
|
||||
|
||||
new a = 0, b = 1
|
||||
for (new i = 2; i < n; i++)
|
||||
{
|
||||
new c = a + b
|
||||
a = b
|
||||
b = c
|
||||
}
|
||||
return a + b
|
||||
}
|
17
EXAMPLES/gcd.p
Normal file
17
EXAMPLES/gcd.p
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
The greatest common divisor of two values,
|
||||
using Euclides' algorithm .
|
||||
*/
|
||||
|
||||
main()
|
||||
{
|
||||
print "Input two values\n"
|
||||
new a = getvalue()
|
||||
new b = getvalue()
|
||||
while (a != b)
|
||||
if (a > b)
|
||||
a = a - b
|
||||
else
|
||||
b = b - a
|
||||
printf "The greatest common divisor is %d\n", a
|
||||
}
|
297
EXAMPLES/gtkcalc.p
Normal file
297
EXAMPLES/gtkcalc.p
Normal file
@ -0,0 +1,297 @@
|
||||
/* A demo GTK application in Pawn, using gtk-server and the "process control"
|
||||
* module for Pawn. This example also illustrates the use of (communicating)
|
||||
* finite state machines.
|
||||
*/
|
||||
#include <process>
|
||||
#include <string>
|
||||
|
||||
enum Btn
|
||||
{
|
||||
Btn0, Btn1, Btn2,
|
||||
Btn3, Btn4, Btn5,
|
||||
Btn6, Btn7, Btn8,
|
||||
Btn9, BtnDot, BtnC,
|
||||
BtnCE, BtnPlus, BtnMin,
|
||||
BtnMul, BtnDiv, BtnEqual,
|
||||
BtnNone,
|
||||
}
|
||||
|
||||
static entry /* GTK "entry" widget */
|
||||
static numberstring[40 char]
|
||||
static accum
|
||||
static Btn:pending_op
|
||||
|
||||
adddigit(digit, bool:reset = false)
|
||||
{
|
||||
new command[80 char], charstr[2 char]
|
||||
charstr{0} = (0 <= digit <= 9) ? digit + '0' : digit
|
||||
if (reset)
|
||||
numberstring[0] = EOS
|
||||
strcat numberstring, charstr
|
||||
strformat command, _, true, "gtk_entry_set_text %d %s", entry, numberstring
|
||||
GTK(command)
|
||||
}
|
||||
|
||||
displayresult(value)
|
||||
{
|
||||
new command[80 char]
|
||||
valstr numberstring, value, true
|
||||
strformat command, _, true, "gtk_entry_set_text %d %s", entry, numberstring
|
||||
GTK(command)
|
||||
}
|
||||
|
||||
|
||||
resetentry(digit) <number:negated>
|
||||
{
|
||||
adddigit '-', .reset = true
|
||||
adddigit digit
|
||||
}
|
||||
|
||||
resetentry(digit) <>
|
||||
{
|
||||
adddigit digit, .reset = true
|
||||
}
|
||||
|
||||
|
||||
event_0() <number:zero, number:negated>
|
||||
{
|
||||
resetentry 0
|
||||
}
|
||||
|
||||
event_0() <number:int, number:frac>
|
||||
{
|
||||
adddigit 0
|
||||
}
|
||||
|
||||
event_1_9(Btn:idx) <number:zero, number:negated>
|
||||
{
|
||||
resetentry _:(idx - Btn0)
|
||||
state number:int
|
||||
}
|
||||
|
||||
event_1_9(Btn:idx) <number:int, number:frac>
|
||||
{
|
||||
adddigit _:(idx - Btn0)
|
||||
}
|
||||
|
||||
event_dot() <number:zero, number:negated>
|
||||
{
|
||||
resetentry 0
|
||||
adddigit '.'
|
||||
state number:frac
|
||||
}
|
||||
|
||||
event_dot() <number:int>
|
||||
{
|
||||
adddigit '.'
|
||||
state number:frac
|
||||
}
|
||||
|
||||
event_dot() <number:frac>
|
||||
{
|
||||
/* reject entry */
|
||||
}
|
||||
|
||||
event_minus() <number:zero, number:negated>
|
||||
{
|
||||
state number:negated
|
||||
resetentry 0
|
||||
}
|
||||
|
||||
event_minus() <>
|
||||
{
|
||||
event_oper BtnMin /* forward to the "calc" automaton */
|
||||
}
|
||||
|
||||
|
||||
/* helper function for the calculator automaton */
|
||||
performoperation()
|
||||
{
|
||||
/* get the other operand, perform the operation */
|
||||
new val = strval(numberstring)
|
||||
switch (pending_op)
|
||||
{
|
||||
case BtnPlus: accum += val
|
||||
case BtnMin: accum -= val
|
||||
case BtnMul: accum *= val
|
||||
case BtnDiv: accum = (val == 0) ? 0 : accum / val
|
||||
}
|
||||
displayresult accum
|
||||
}
|
||||
|
||||
event_oper(Btn:idx) <calc:idle>
|
||||
{
|
||||
/* save operand and operator */
|
||||
accum = strval(numberstring)
|
||||
pending_op = idx
|
||||
|
||||
state number:zero
|
||||
state calc:pending
|
||||
}
|
||||
|
||||
event_oper(Btn:idx) <calc:pending>
|
||||
{
|
||||
performoperation /* do the pending operation */
|
||||
pending_op = idx /* save the operator for the next operation */
|
||||
state number:zero
|
||||
}
|
||||
|
||||
event_equal() <calc:idle>
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
event_equal() <calc:pending>
|
||||
{
|
||||
performoperation /* do the pending operation */
|
||||
state calc:idle /* reset the calculator */
|
||||
state number:zero
|
||||
}
|
||||
|
||||
|
||||
event_C()
|
||||
{
|
||||
state calc:idle
|
||||
state number:zero
|
||||
resetentry 0
|
||||
}
|
||||
|
||||
event_CE()
|
||||
{
|
||||
state number:zero
|
||||
resetentry 0
|
||||
}
|
||||
|
||||
|
||||
main()
|
||||
{
|
||||
if (!procexec("gtk-server stdin") && !procexec("gtk-server.exe stdin"))
|
||||
fatal "unable to launch gtk-server"
|
||||
|
||||
/* make a window */
|
||||
GTK("gtk_init NULL NULL")
|
||||
new win = GTK("gtk_window_new 0")
|
||||
GTK("gtk_window_set_title %d \"Pawn calculator\"", win)
|
||||
GTK("gtk_widget_set_usize %d 200 200", win)
|
||||
|
||||
/* add a table (align the other controls) */
|
||||
new table = GTK("gtk_table_new 50 50 1")
|
||||
GTK("gtk_container_add %d %d", win, table)
|
||||
|
||||
/* the number entry */
|
||||
entry = GTK("gtk_entry_new")
|
||||
GTK("gtk_table_attach_defaults %d %d 1 49 1 9", table, entry)
|
||||
|
||||
/* the key pad */
|
||||
new buttons[Btn]
|
||||
buttons[BtnDot] = GTK("gtk_button_new_with_label .")
|
||||
GTK("gtk_table_attach_defaults %d %d 21 29 41 49", table, buttons[BtnDot])
|
||||
buttons[Btn0] = GTK("gtk_button_new_with_label 0")
|
||||
GTK("gtk_table_attach_defaults %d %d 1 19 41 49", table, buttons[Btn0])
|
||||
buttons[Btn1] = GTK("gtk_button_new_with_label 1")
|
||||
GTK("gtk_table_attach_defaults %d %d 1 9 31 39", table, buttons[Btn1])
|
||||
buttons[Btn2] = GTK("gtk_button_new_with_label 2")
|
||||
GTK("gtk_table_attach_defaults %d %d 11 19 31 39", table, buttons[Btn2])
|
||||
buttons[Btn3] = GTK("gtk_button_new_with_label 3")
|
||||
GTK("gtk_table_attach_defaults %d %d 21 29 31 39", table, buttons[Btn3])
|
||||
buttons[Btn4] = GTK("gtk_button_new_with_label 4")
|
||||
GTK("gtk_table_attach_defaults %d %d 1 9 21 29", table, buttons[Btn4])
|
||||
buttons[Btn5] = GTK("gtk_button_new_with_label 5")
|
||||
GTK("gtk_table_attach_defaults %d %d 11 19 21 29", table, buttons[Btn5])
|
||||
buttons[Btn6] = GTK("gtk_button_new_with_label 6")
|
||||
GTK("gtk_table_attach_defaults %d %d 21 29 21 29", table, buttons[Btn6])
|
||||
buttons[Btn7] = GTK("gtk_button_new_with_label 7")
|
||||
GTK("gtk_table_attach_defaults %d %d 1 9 11 19", table, buttons[Btn7])
|
||||
buttons[Btn8] = GTK("gtk_button_new_with_label 8")
|
||||
GTK("gtk_table_attach_defaults %d %d 11 19 11 19", table, buttons[Btn8])
|
||||
buttons[Btn9] = GTK("gtk_button_new_with_label 9")
|
||||
GTK("gtk_table_attach_defaults %d %d 21 29 11 19", table, buttons[Btn9])
|
||||
|
||||
buttons[BtnC] = GTK("gtk_button_new_with_label C")
|
||||
GTK("gtk_table_attach_defaults %d %d 31 39 11 19", table, buttons[BtnC])
|
||||
buttons[BtnCE] = GTK("gtk_button_new_with_label CE")
|
||||
GTK("gtk_table_attach_defaults %d %d 41 49 11 19", table, buttons[BtnCE])
|
||||
buttons[BtnPlus] = GTK("gtk_button_new_with_label +")
|
||||
GTK("gtk_table_attach_defaults %d %d 31 39 21 29", table, buttons[BtnPlus])
|
||||
buttons[BtnMin] = GTK("gtk_button_new_with_label -")
|
||||
GTK("gtk_table_attach_defaults %d %d 41 49 21 29", table, buttons[BtnMin])
|
||||
buttons[BtnMul] = GTK("gtk_button_new_with_label x")
|
||||
GTK("gtk_table_attach_defaults %d %d 31 39 31 39", table, buttons[BtnMul])
|
||||
buttons[BtnDiv] = GTK("gtk_button_new_with_label /")
|
||||
GTK("gtk_table_attach_defaults %d %d 41 49 31 39", table, buttons[BtnDiv])
|
||||
buttons[BtnEqual] = GTK("gtk_button_new_with_label =")
|
||||
GTK("gtk_table_attach_defaults %d %d 31 49 41 49", table, buttons[BtnEqual])
|
||||
|
||||
/* initialize automata */
|
||||
state number:zero
|
||||
state calc:idle
|
||||
|
||||
/* wait for events, and dispatch them */
|
||||
GTK("gtk_widget_show_all %d", win)
|
||||
|
||||
resetentry 0
|
||||
new event
|
||||
new Btn:idx
|
||||
do
|
||||
{
|
||||
event = GTK("gtk_server_callback wait")
|
||||
|
||||
/* find the button matching the event, generate the event */
|
||||
for (idx = Btn0; idx < BtnNone && buttons[idx] != event; idx++)
|
||||
{}
|
||||
switch (idx)
|
||||
{
|
||||
case Btn0:
|
||||
event_0
|
||||
case Btn1 .. Btn9:
|
||||
event_1_9 idx
|
||||
case BtnDot:
|
||||
event_dot
|
||||
case BtnMin:
|
||||
event_minus
|
||||
case BtnPlus, BtnMul, BtnDiv:
|
||||
event_oper idx
|
||||
case BtnEqual:
|
||||
event_equal
|
||||
case BtnC:
|
||||
event_C
|
||||
case BtnCE:
|
||||
event_CE
|
||||
}
|
||||
}
|
||||
while (event != win);
|
||||
|
||||
/* direct call, because we must not wait for a reply on this command */
|
||||
procwrite "gtk_exit 0", true
|
||||
}
|
||||
|
||||
GTK(const format[], ...)
|
||||
{
|
||||
new command[256 char]
|
||||
switch (numargs())
|
||||
{
|
||||
case 1:
|
||||
strpack command, format
|
||||
case 2:
|
||||
strformat command, _, true, format, getarg(1)
|
||||
case 3:
|
||||
strformat command, _, true, format, getarg(1), getarg(2)
|
||||
case 4:
|
||||
strformat command, _, true, format, getarg(1), getarg(2), getarg(3)
|
||||
case 5:
|
||||
strformat command, _, true, format, getarg(1), getarg(2), getarg(3), getarg(4)
|
||||
}
|
||||
procwrite command, true
|
||||
|
||||
new reply[30]
|
||||
procread reply, .striplf=true
|
||||
if (strcmp(reply, "ok") == 0)
|
||||
return true
|
||||
return strval(reply)
|
||||
}
|
||||
|
||||
fatal(const message[])
|
||||
{
|
||||
printf "FATAL: %s\n", message
|
||||
exit
|
||||
}
|
17
EXAMPLES/hanoi.p
Normal file
17
EXAMPLES/hanoi.p
Normal file
@ -0,0 +1,17 @@
|
||||
/* The Towers of Hanoi, a game solved through recursion */
|
||||
|
||||
main()
|
||||
{
|
||||
print "How many disks: "
|
||||
new disks = getvalue()
|
||||
move 1, 3, 2, disks
|
||||
}
|
||||
|
||||
move(from, to, spare, numdisks)
|
||||
{
|
||||
if (numdisks > 1)
|
||||
move from, spare, to, numdisks-1
|
||||
printf "Move disk from pillar %d to pillar %d\n", from, to
|
||||
if (numdisks > 1)
|
||||
move spare, to, from, numdisks-1
|
||||
}
|
2
EXAMPLES/hello.p
Normal file
2
EXAMPLES/hello.p
Normal file
@ -0,0 +1,2 @@
|
||||
main()
|
||||
printf "Hello world\n"
|
6
EXAMPLES/hello2.p
Normal file
6
EXAMPLES/hello2.p
Normal file
@ -0,0 +1,6 @@
|
||||
#include <console>
|
||||
|
||||
main()
|
||||
{
|
||||
printf("Hello world\n");
|
||||
}
|
61
EXAMPLES/julian.p
Normal file
61
EXAMPLES/julian.p
Normal file
@ -0,0 +1,61 @@
|
||||
/* calculate Julian Day number from a date, and vice versa */
|
||||
|
||||
main()
|
||||
{
|
||||
new d, m, y, jdn
|
||||
|
||||
print "Give a date (dd-mm-yyyy): "
|
||||
d = getvalue(_, '-', '/')
|
||||
m = getvalue(_, '-', '/')
|
||||
y = getvalue()
|
||||
|
||||
jdn = DateToJulian(d, m, y)
|
||||
printf("Date %d/%d/%d = %d JD\n", d, m, y, jdn)
|
||||
|
||||
print "Give a Julian Day Number: "
|
||||
jdn = getvalue()
|
||||
JulianToDate jdn, d, m, y
|
||||
printf "%d JD = %d/%d/%d\n", jdn, d, m, y
|
||||
}
|
||||
|
||||
DateToJulian(day, month, year)
|
||||
{
|
||||
/* The first year is 1. Year 0 does not exist: it is 1 BC (or -1) */
|
||||
assert year != 0
|
||||
if (year < 0)
|
||||
year++
|
||||
|
||||
/* move January and February to the end of the previous year */
|
||||
if (month <= 2)
|
||||
year--, month += 12
|
||||
new jdn = 365*year + year/4 - year/100 + year/400
|
||||
+ (153*month - 457) / 5
|
||||
+ day + 1721119
|
||||
return jdn
|
||||
}
|
||||
|
||||
JulianToDate(jdn, &day, &month, &year)
|
||||
{
|
||||
jdn -= 1721119
|
||||
|
||||
/* approximate year, then adjust in a loop */
|
||||
year = (400 * jdn) / 146097
|
||||
while (365*year + year/4 - year/100 + year/400 < jdn)
|
||||
year++
|
||||
year--
|
||||
|
||||
/* determine month */
|
||||
jdn -= 365*year + year/4 - year/100 + year/400
|
||||
month = (5*jdn + 457) / 153
|
||||
|
||||
/* determine day */
|
||||
day = jdn - (153*month - 457) / 5
|
||||
|
||||
/* move January and February to start of the year */
|
||||
if (month > 12)
|
||||
month -= 12, year++
|
||||
|
||||
/* adjust negative years (year 0 must become 1 BC, or -1) */
|
||||
if (year <= 0)
|
||||
year--
|
||||
}
|
62
EXAMPLES/ones.p
Normal file
62
EXAMPLES/ones.p
Normal file
@ -0,0 +1,62 @@
|
||||
forward ones: operator+(ones: a, ones: b)
|
||||
forward ones: operator-(ones: a, ones: b)
|
||||
forward ones: operator-(ones: a)
|
||||
|
||||
main()
|
||||
{
|
||||
new ones: chksum = ones: 0xffffffff
|
||||
print "Input values in hexadecimal, zero to exit\n"
|
||||
|
||||
new ones: value
|
||||
do
|
||||
{
|
||||
print ">> "
|
||||
value = ones: getvalue(.base=16)
|
||||
chksum = chksum + value
|
||||
printf "Checksum = %x\n", chksum
|
||||
}
|
||||
while (value)
|
||||
}
|
||||
|
||||
stock ones: operator+(ones: a, ones: b)
|
||||
{
|
||||
const ones: mask = ones: 0xffff /* word mask */
|
||||
const ones: shift = ones: 16 /* word shift */
|
||||
|
||||
/* add low words and high words separately */
|
||||
new ones: r1 = (a & mask) + (b & mask)
|
||||
new ones: r2 = (a >>> shift) + (b >>> shift)
|
||||
|
||||
new ones: carry
|
||||
restart: /* code label (goto target) */
|
||||
|
||||
/* add carry of the new low word to the high word, then
|
||||
* strip it from the low word
|
||||
*/
|
||||
carry = (r1 >>> shift)
|
||||
r2 += carry
|
||||
r1 &= mask
|
||||
|
||||
/* add the carry from the new high word back to the low
|
||||
* word, then strip it from the high word
|
||||
*/
|
||||
carry = (r2 >>> shift)
|
||||
r1 += carry
|
||||
r2 &= mask
|
||||
|
||||
/* a carry from the high word injected back into the low
|
||||
* word may cause the new low to overflow, so restart in
|
||||
* that case
|
||||
*/
|
||||
if (carry)
|
||||
goto restart
|
||||
|
||||
return (r2 << shift) | r1
|
||||
}
|
||||
|
||||
stock ones: operator-(ones: a)
|
||||
return (a == ones: 0xffffffff) ? a : ~a
|
||||
|
||||
stock ones: operator-(ones: a, ones: b)
|
||||
return a + -b
|
||||
|
78
EXAMPLES/queue.p
Normal file
78
EXAMPLES/queue.p
Normal file
@ -0,0 +1,78 @@
|
||||
/* Priority queue (for simple text strings) */
|
||||
|
||||
enum message
|
||||
{
|
||||
text[40 char],
|
||||
priority
|
||||
}
|
||||
|
||||
main()
|
||||
{
|
||||
new msg[message]
|
||||
|
||||
/* insert a few items (read from console input) */
|
||||
printf "Please insert a few messages and their priorities; \
|
||||
end with an empty string\n"
|
||||
for ( ;; )
|
||||
{
|
||||
printf "Message: "
|
||||
getstring .string = msg[text], .maxlength = 40, .pack = true
|
||||
if (strlen(msg[text]) == 0)
|
||||
break
|
||||
printf "Priority: "
|
||||
msg[priority] = getvalue()
|
||||
if (!insert(msg))
|
||||
{
|
||||
printf "Queue is full, cannot insert more items\n"
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/* now print the messages extracted from the queue */
|
||||
printf "\nContents of the queue:\n"
|
||||
while (extract(msg))
|
||||
printf "[%d] %s\n", msg[priority], msg[text]
|
||||
}
|
||||
|
||||
const queuesize = 10
|
||||
new queue[queuesize][message]
|
||||
new queueitems = 0
|
||||
|
||||
insert(const item[message])
|
||||
{
|
||||
/* check if the queue can hold one more message */
|
||||
if (queueitems == queuesize)
|
||||
return false /* queue is full */
|
||||
|
||||
/* find the position to insert it to */
|
||||
new pos = queueitems /* start at the bottom */
|
||||
while (pos > 0 && item[priority] > queue[pos-1][priority])
|
||||
--pos /* higher priority: move up a slot */
|
||||
|
||||
/* make place for the item at the insertion spot */
|
||||
for (new i = queueitems; i > pos; --i)
|
||||
queue[i] = queue[i-1]
|
||||
|
||||
/* add the message to the correct slot */
|
||||
queue[pos] = item
|
||||
queueitems++
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
extract(item[message])
|
||||
{
|
||||
/* check whether the queue has one more message */
|
||||
if (queueitems == 0)
|
||||
return false /* queue is empty */
|
||||
|
||||
/* copy the topmost item */
|
||||
item = queue[0]
|
||||
--queueitems
|
||||
|
||||
/* move the queue one position up */
|
||||
for (new i = 0; i < queueitems; ++i)
|
||||
queue[i] = queue[i+1]
|
||||
|
||||
return true
|
||||
}
|
1
EXAMPLES/quine.p
Normal file
1
EXAMPLES/quine.p
Normal file
@ -0,0 +1 @@
|
||||
new s[]="new s[]=%c%s%c; main() printf s,34,s,34"; main() printf s,34,s,34
|
39
EXAMPLES/randlist.p
Normal file
39
EXAMPLES/randlist.p
Normal file
@ -0,0 +1,39 @@
|
||||
main()
|
||||
{
|
||||
new HandOfCards[10]
|
||||
FillRandom(HandOfCards, 52)
|
||||
|
||||
print "A draw of 10 numbers from a range of 0 to 51 \
|
||||
(inclusive) without duplicates:\n"
|
||||
for (new i = 0; i < sizeof HandOfCards; i++)
|
||||
printf "%d ", HandOfCards[i]
|
||||
}
|
||||
|
||||
FillRandom(Series[], Range, Number = sizeof Series)
|
||||
{
|
||||
assert Range >= Number /* cannot select 50 values
|
||||
* without duplicates in the
|
||||
* range 0..40, for example */
|
||||
new Index = 0
|
||||
for (new Seq = Range - Number; Seq < Range; Seq++)
|
||||
{
|
||||
new Val = random(Seq + 1)
|
||||
new Pos = InSeries(Series, Val, Index)
|
||||
if (Pos >= 0)
|
||||
{
|
||||
Series[Index] = Series[Pos]
|
||||
Series[Pos] = Seq
|
||||
}
|
||||
else
|
||||
Series[Index] = Val
|
||||
Index++
|
||||
}
|
||||
}
|
||||
|
||||
InSeries(Series[], Value, Top = sizeof Series)
|
||||
{
|
||||
for (new i = 0; i < Top; i++)
|
||||
if (Series[i] == Value)
|
||||
return i
|
||||
return -1
|
||||
}
|
25
EXAMPLES/readfile.p
Normal file
25
EXAMPLES/readfile.p
Normal file
@ -0,0 +1,25 @@
|
||||
#include <file>
|
||||
|
||||
main()
|
||||
{
|
||||
/* ask for a filename */
|
||||
print "Please enter a filename: "
|
||||
new filename[128 char]
|
||||
getstring filename, .pack=true
|
||||
|
||||
/* try to open the file */
|
||||
new File: file = fopen(filename, io_read)
|
||||
if (!file)
|
||||
{
|
||||
printf "The file '%s' cannot be opened for reading\n", filename
|
||||
exit
|
||||
}
|
||||
|
||||
/* dump the file onto the console */
|
||||
new line[200]
|
||||
while (fread(file, line))
|
||||
print line, .highlight=true
|
||||
|
||||
/* done */
|
||||
fclose file
|
||||
}
|
21
EXAMPLES/rot13.p
Normal file
21
EXAMPLES/rot13.p
Normal file
@ -0,0 +1,21 @@
|
||||
/* Simple encryption, using ROT13 */
|
||||
|
||||
main()
|
||||
{
|
||||
printf "Please type the string to mangle: "
|
||||
|
||||
new str[100]
|
||||
getstring str, sizeof str
|
||||
rot13 str
|
||||
|
||||
printf "After mangling, the string is: \"%s\"\n", str
|
||||
}
|
||||
|
||||
rot13(string[])
|
||||
{
|
||||
for (new index = 0; string[index]; index++)
|
||||
if ('a' <= string[index] <= 'z')
|
||||
string[index] = (string[index] - 'a' + 13) % 26 + 'a'
|
||||
else if ('A' <= string[index] <= 'Z')
|
||||
string[index] = (string[index] - 'A' + 13) % 26 + 'A'
|
||||
}
|
12
EXAMPLES/rpn.p
Normal file
12
EXAMPLES/rpn.p
Normal file
@ -0,0 +1,12 @@
|
||||
/* a simple RPN calculator */
|
||||
#include strtok
|
||||
#include stack
|
||||
#include rpnparse
|
||||
|
||||
main()
|
||||
{
|
||||
print "Type an expression in Reverse Polish Notation: "
|
||||
new string[100]
|
||||
getstring string, sizeof string
|
||||
rpncalc string
|
||||
}
|
71
EXAMPLES/rpnparse.inc
Normal file
71
EXAMPLES/rpnparse.inc
Normal file
@ -0,0 +1,71 @@
|
||||
/* main rpn parser and lexical analysis, part of the RPN calculator */
|
||||
#include <rational>
|
||||
#include <string>
|
||||
|
||||
enum token
|
||||
{
|
||||
t_type, /* operator or token type */
|
||||
Rational: t_value, /* value, if t_type is "Number" */
|
||||
t_word[20], /* raw string */
|
||||
}
|
||||
|
||||
const Number = '0'
|
||||
const EndOfExpr = '#'
|
||||
|
||||
rpncalc(const string[])
|
||||
{
|
||||
new index
|
||||
new field[token]
|
||||
for ( ;; )
|
||||
{
|
||||
field = gettoken(string, index)
|
||||
switch (field[t_type])
|
||||
{
|
||||
case Number:
|
||||
push field[t_value]
|
||||
case '+':
|
||||
push pop() + pop()
|
||||
case '-':
|
||||
push - pop() + pop()
|
||||
case '*':
|
||||
push pop() * pop()
|
||||
case '/', ':':
|
||||
push 1.0 / pop() * pop()
|
||||
case EndOfExpr:
|
||||
break /* exit "for" loop */
|
||||
default:
|
||||
printf "Unknown operator '%s'\n", field[t_word]
|
||||
}
|
||||
}
|
||||
printf "Result = %r\n", pop()
|
||||
if (clearstack())
|
||||
print "Stack not empty\n", red
|
||||
}
|
||||
|
||||
gettoken(const string[], &index)
|
||||
{
|
||||
/* first get the next "word" from the string */
|
||||
new word[20]
|
||||
word = strtok(string, index)
|
||||
|
||||
/* then parse it */
|
||||
new field[token]
|
||||
field[t_word] = word
|
||||
if (strlen(word) == 0)
|
||||
{
|
||||
field[t_type] = EndOfExpr /* special "stop" symbol */
|
||||
field[t_value] = 0
|
||||
}
|
||||
else if ('0' <= word[0] <= '9')
|
||||
{
|
||||
field[t_type] = Number
|
||||
field[t_value] = rationalstr(word)
|
||||
}
|
||||
else
|
||||
{
|
||||
field[t_type] = word[0]
|
||||
field[t_value] = 0
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
46
EXAMPLES/set.p
Normal file
46
EXAMPLES/set.p
Normal file
@ -0,0 +1,46 @@
|
||||
/* Set operations, using bit arithmetic */
|
||||
|
||||
main()
|
||||
{
|
||||
enum (<<= 1) { A = 1, B, C, D, E, F, G }
|
||||
new nextstep[] =
|
||||
{ C | E, /* A can reach C and E */
|
||||
D | E, /* B " " D and E */
|
||||
G, /* C " " G */
|
||||
C | F, /* D " " C and F */
|
||||
0, /* E " " none */
|
||||
0, /* F " " none */
|
||||
E | F, /* G " " E and F */
|
||||
}
|
||||
#pragma unused A, B
|
||||
|
||||
print "The departure point: "
|
||||
new start = clamp( .value = toupper(getchar()) - 'A',
|
||||
.min = 0,
|
||||
.max = sizeof nextstep - 1
|
||||
)
|
||||
|
||||
print "\nThe number of steps: "
|
||||
new steps = getvalue()
|
||||
|
||||
/* make the set */
|
||||
new result = findtargets(start, steps, nextstep)
|
||||
printf "The points in range of %c in %d steps: ", start + 'A', steps
|
||||
for (new i = 0; i < sizeof nextstep; i++)
|
||||
if (result & 1 << i)
|
||||
printf "%c ", i + 'A'
|
||||
}
|
||||
|
||||
findtargets(start, steps, nextstep[], numpoints = sizeof nextstep)
|
||||
{
|
||||
new result = 0
|
||||
new addedpoints = nextstep[start]
|
||||
while (steps-- > 0 && result != addedpoints)
|
||||
{
|
||||
result = addedpoints
|
||||
for (new i = 0; i < numpoints; i++)
|
||||
if (result & 1 << i)
|
||||
addedpoints |= nextstep[i]
|
||||
}
|
||||
return result
|
||||
}
|
16
EXAMPLES/sieve.p
Normal file
16
EXAMPLES/sieve.p
Normal file
@ -0,0 +1,16 @@
|
||||
/* Print all primes below 100, using the "Sieve of Eratosthenes" */
|
||||
|
||||
main()
|
||||
{
|
||||
const max_primes = 100
|
||||
new series[max_primes] = { true, ... }
|
||||
|
||||
for (new i = 2; i < max_primes; ++i)
|
||||
if (series[i])
|
||||
{
|
||||
printf "%d ", i
|
||||
/* filter all multiples of this "prime" from the list */
|
||||
for (new j = 2 * i; j < max_primes; j += i)
|
||||
series[j] = false
|
||||
}
|
||||
}
|
26
EXAMPLES/stack.inc
Normal file
26
EXAMPLES/stack.inc
Normal file
@ -0,0 +1,26 @@
|
||||
/* stack functions, part of the RPN calculator */
|
||||
#include <rational>
|
||||
|
||||
static Rational: stack[50]
|
||||
static stackidx = 0
|
||||
|
||||
push(Rational: value)
|
||||
{
|
||||
assert stackidx < sizeof stack
|
||||
stack[stackidx++] = value
|
||||
}
|
||||
|
||||
Rational: pop()
|
||||
{
|
||||
assert stackidx > 0
|
||||
return stack[--stackidx]
|
||||
}
|
||||
|
||||
clearstack()
|
||||
{
|
||||
assert stackidx >= 0
|
||||
if (stackidx == 0)
|
||||
return false
|
||||
stackidx = 0
|
||||
return true
|
||||
}
|
25
EXAMPLES/strtok.inc
Normal file
25
EXAMPLES/strtok.inc
Normal file
@ -0,0 +1,25 @@
|
||||
/* extract words from a string (words are separated by white space) */
|
||||
#include <string>
|
||||
|
||||
strtok(const string[], &index)
|
||||
{
|
||||
new length = strlen(string)
|
||||
|
||||
/* skip leading white space */
|
||||
while (index < length && string[index] <= ' ')
|
||||
index++
|
||||
|
||||
/* store the word letter for letter */
|
||||
new offset = index /* save start position of token */
|
||||
new result[20] /* string to store the word in */
|
||||
while (index < length
|
||||
&& string[index] > ' '
|
||||
&& index - offset < sizeof result - 1)
|
||||
{
|
||||
result[index - offset] = string[index]
|
||||
index++
|
||||
}
|
||||
result[index - offset] = EOS /* zero-terminate the string */
|
||||
|
||||
return result
|
||||
}
|
35
EXAMPLES/traffic.p
Normal file
35
EXAMPLES/traffic.p
Normal file
@ -0,0 +1,35 @@
|
||||
/* traffic light synchronizer, using states in an event-driven model */
|
||||
#include <time>
|
||||
|
||||
main() state green_wait
|
||||
|
||||
@keypressed(key) <green_wait> state yellow_wait
|
||||
@keypressed(key) <red_walk, red_wait> state red_walk
|
||||
@keypressed(key) <> {} /* fallback */
|
||||
|
||||
@timer() <yellow_wait> state red_walk
|
||||
@timer() <red_walk> state red_wait
|
||||
@timer() <red_wait> state green_wait
|
||||
@timer() <> {} /* fallback */
|
||||
|
||||
|
||||
entry() <green_wait>
|
||||
print "Green / Don't walk\n"
|
||||
|
||||
entry() <yellow_wait>
|
||||
{
|
||||
print "Yellow / Don't walk\n"
|
||||
settimer 2000
|
||||
}
|
||||
|
||||
entry() <red_walk>
|
||||
{
|
||||
print "Red / Walk\n"
|
||||
settimer 5000
|
||||
}
|
||||
|
||||
entry() <red_wait>
|
||||
{
|
||||
print "Red / Don't walk\n"
|
||||
settimer 2000
|
||||
}
|
83
EXAMPLES/traffic2.p
Normal file
83
EXAMPLES/traffic2.p
Normal file
@ -0,0 +1,83 @@
|
||||
/* a more realistic traffic light synchronizer, including an
|
||||
* "override" for emergency vehicles
|
||||
*/
|
||||
#include <time>
|
||||
|
||||
main()
|
||||
state green_wait_interim
|
||||
|
||||
new bool: button_memo <red_wait, green_wait_interim, yellow_wait>
|
||||
|
||||
@keypressed(key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case ' ': button_press
|
||||
case '*': mirt_detect
|
||||
}
|
||||
}
|
||||
|
||||
button_press() <green_wait>
|
||||
state yellow_wait
|
||||
|
||||
button_press() <red_wait, green_wait_interim>
|
||||
button_memo = true
|
||||
|
||||
button_press() <> /* fallback */
|
||||
{}
|
||||
|
||||
mirt_detect()
|
||||
state mirt_override
|
||||
|
||||
@timer() <yellow_wait>
|
||||
state red_walk
|
||||
|
||||
@timer() <red_walk>
|
||||
state red_wait
|
||||
|
||||
@timer() <red_wait>
|
||||
state green_wait_interim
|
||||
|
||||
@timer() <green_wait_interim>
|
||||
{
|
||||
state (!button_memo) green_wait
|
||||
state (button_memo) yellow_wait
|
||||
}
|
||||
|
||||
@timer() <mirt_override>
|
||||
state green_wait
|
||||
|
||||
@timer() <> /* fallback */
|
||||
{}
|
||||
|
||||
|
||||
entry() <green_wait_interim>
|
||||
{
|
||||
print "Green / Don't walk\n"
|
||||
settimer 5000
|
||||
}
|
||||
|
||||
entry() <yellow_wait>
|
||||
{
|
||||
print "Yellow / Don't walk\n"
|
||||
button_memo = false
|
||||
settimer 2000
|
||||
}
|
||||
|
||||
entry() <red_walk>
|
||||
{
|
||||
print "Red / Walk\n"
|
||||
settimer 5000
|
||||
}
|
||||
|
||||
entry() <red_wait>
|
||||
{
|
||||
print "Red / Don't walk\n"
|
||||
settimer 2000
|
||||
}
|
||||
|
||||
entry() <mirt_override>
|
||||
{
|
||||
print "Green / Don't walk\n"
|
||||
settimer 5000
|
||||
}
|
26
EXAMPLES/turtle.p
Normal file
26
EXAMPLES/turtle.p
Normal file
@ -0,0 +1,26 @@
|
||||
@keypressed(key)
|
||||
{
|
||||
/* get current position */
|
||||
new x, y
|
||||
wherexy x, y
|
||||
|
||||
/* determine how the update the current position */
|
||||
switch (key)
|
||||
{
|
||||
case 'u': y-- /* up */
|
||||
case 'd': y++ /* down */
|
||||
case 'l': x-- /* left */
|
||||
case 'r': x++ /* right */
|
||||
case '\e': exit /* Escape = exit */
|
||||
}
|
||||
|
||||
/* adjust the cursor position and draw something */
|
||||
moveturtle x, y
|
||||
}
|
||||
|
||||
moveturtle(x, y)
|
||||
{
|
||||
gotoxy x, y
|
||||
print '*'
|
||||
gotoxy x, y
|
||||
}
|
46
EXAMPLES/wcount.p
Normal file
46
EXAMPLES/wcount.p
Normal file
@ -0,0 +1,46 @@
|
||||
/* word count: count words on a string that the user types */
|
||||
|
||||
main()
|
||||
{
|
||||
print "Please type a string: "
|
||||
new string[100]
|
||||
getstring string, sizeof string
|
||||
|
||||
new count = 0
|
||||
|
||||
new word[20]
|
||||
new index
|
||||
for ( ;; )
|
||||
{
|
||||
word = strtok(string, index)
|
||||
if (strlen(word) == 0)
|
||||
break
|
||||
count++
|
||||
printf "Word %d: '%s'\n", count, word
|
||||
}
|
||||
|
||||
printf "\nNumber of words: %d\n", count
|
||||
}
|
||||
|
||||
strtok(const string[], &index)
|
||||
{
|
||||
new length = strlen(string)
|
||||
|
||||
/* skip leading white space */
|
||||
while (index < length && string[index] <= ' ')
|
||||
index++
|
||||
|
||||
/* store the word letter for letter */
|
||||
new offset = index /* save start position of token */
|
||||
new result[20] /* string to store the word in */
|
||||
while (index < length
|
||||
&& string[index] > ' '
|
||||
&& index - offset < sizeof result - 1)
|
||||
{
|
||||
result[index - offset] = string[index]
|
||||
index++
|
||||
}
|
||||
result[index - offset] = EOS /* zero-terminate the string */
|
||||
|
||||
return result
|
||||
}
|
164
EXAMPLES/weekday.p
Normal file
164
EXAMPLES/weekday.p
Normal file
@ -0,0 +1,164 @@
|
||||
/**
|
||||
* This program illustrates Zeller's congruence algorithm to calculate
|
||||
* the day of the week given a date.
|
||||
*/
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* The main program: asks the user to input a date and prints on
|
||||
* what day of the week that date falls.
|
||||
* </summary>
|
||||
*/
|
||||
main()
|
||||
{
|
||||
new day, month, year
|
||||
if (readdate(day, month, year))
|
||||
{
|
||||
new wkday = weekday(day, month, year)
|
||||
printf "The date %d-%d-%d falls on a ", day, month, year
|
||||
switch (wkday)
|
||||
{
|
||||
case 0:
|
||||
print "Saturday"
|
||||
case 1:
|
||||
print "Sunday"
|
||||
case 2:
|
||||
print "Monday"
|
||||
case 3:
|
||||
print "Tuesday"
|
||||
case 4:
|
||||
print "Wednesday"
|
||||
case 5:
|
||||
print "Thursday"
|
||||
case 6:
|
||||
print "Friday"
|
||||
}
|
||||
}
|
||||
else
|
||||
print "Invalid date"
|
||||
|
||||
print "\n"
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* The core function of Zeller's congruence algorithm. The function
|
||||
* works for the Gregorian calender.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="day">
|
||||
* The day in the month, a value between 1 and 31.
|
||||
* </param>
|
||||
* <param name="month">
|
||||
* The month: a value between 1 and 12.
|
||||
* </param>
|
||||
* <param name="year">
|
||||
* The year in four digits.
|
||||
* </param>
|
||||
*
|
||||
* <returns>
|
||||
* The day of the week, where 0 is Saturday and 6 is Friday.
|
||||
* </returns>
|
||||
*
|
||||
* <remarks>
|
||||
* This function does not check the validity of the date; when the
|
||||
* date in the parameters is invalid, the returned "day of the week"
|
||||
* will hold an incorrect value.
|
||||
* <p/>
|
||||
* This equation fails in many programming languages, notably most
|
||||
* implementations of C, C++ and Pascal, because these languages have
|
||||
* a loosely defined "remainder" operator. Pawn, on the other hand,
|
||||
* provides the true modulus operator, as defined in mathematical
|
||||
* theory and as was intended by Zeller.
|
||||
* </remarks>
|
||||
*/
|
||||
weekday(day, month, year)
|
||||
{
|
||||
/**
|
||||
* <remarks>
|
||||
* For Zeller's congruence algorithm, the months January and
|
||||
* February are the 13th and 14th month of the <em>preceding</em>
|
||||
* year. The idea is that the "difficult month" February (which
|
||||
* has either 28 or 29 days) is moved to the end of the year.
|
||||
* </remarks>
|
||||
*/
|
||||
if (month <= 2)
|
||||
month += 12, --year
|
||||
|
||||
new j = year % 100
|
||||
new e = year / 100
|
||||
return (day + (month+1)*26/10 + j + j/4 + e/4 - 2*e) % 7
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Reads a date and stores it in three separate fields. tata
|
||||
* </summary>
|
||||
*
|
||||
* <param name="day">
|
||||
* Will hold the day number upon return.
|
||||
* </param>
|
||||
* <param name="month">
|
||||
* Will hold the month number upon return.
|
||||
* </param>
|
||||
* <param name="year">
|
||||
* Will hold the year number upon return.
|
||||
* </param>
|
||||
*
|
||||
* <returns>
|
||||
* <em>true</em> if the date is valid, <em>false</em> otherwise;
|
||||
* if the function returns <em>false</em>, the values of
|
||||
* <paramref name="day"/>, <paramref name="month"/> and
|
||||
* <paramref name="year"/> cannot be relied upon.
|
||||
* </returns>
|
||||
*/
|
||||
bool: readdate(&day, &month, &year)
|
||||
{
|
||||
print "Give a date (dd-mm-yyyy): "
|
||||
day = getvalue(_,'-','/')
|
||||
month = getvalue(_,'-','/')
|
||||
year = getvalue()
|
||||
return 1 <= month <= 12 && 1 <= day <= daysinmonth(month,year)
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns whether a year is a leap year.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="year">
|
||||
* The year in 4 digits.
|
||||
* </param>
|
||||
*
|
||||
* <remarks>
|
||||
* A year is a leap year:
|
||||
* <ul>
|
||||
* <li> if it is divisable by 4, </li>
|
||||
* <li> but <strong>not</strong> if it is divisable by 100, </li>
|
||||
* <li> but it <strong>is</strong> it is divisable by 400. </li>
|
||||
* </ul>
|
||||
* </remarks>
|
||||
*/
|
||||
bool: isleapyear(year)
|
||||
return year % 400 == 0 || year % 100 != 0 && year % 4 == 0
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the number of days in a month (the month is an integer
|
||||
* in the range 1 .. 12). One needs to pass in the year as well,
|
||||
* because the function takes leap years into account.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="month">
|
||||
* The month number, a value between 1 and 12.
|
||||
* </param>
|
||||
* <param name="year">
|
||||
* The year in 4 digits.
|
||||
* </param>
|
||||
*/
|
||||
daysinmonth(month, year)
|
||||
{
|
||||
static daylist[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||||
assert 1 <= month <= 12
|
||||
return daylist[month-1] + _:(month == 2 && isleapyear(year))
|
||||
}
|
78
INCLUDE/amxdll.inc
Normal file
78
INCLUDE/amxdll.inc
Normal file
@ -0,0 +1,78 @@
|
||||
/* An assortment of additional functions in the DLL version of the
|
||||
* Abstract Machine.
|
||||
*
|
||||
* (c) Copyright 2000-2005, ITB CompuPhase
|
||||
* This file is provided as is (no warranties).
|
||||
*/
|
||||
#if defined _amxdll_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _amxdll_included
|
||||
|
||||
enum
|
||||
{
|
||||
Ok,
|
||||
Okcancel,
|
||||
okCancel,
|
||||
Yesno,
|
||||
yesNo,
|
||||
Yesnocancel,
|
||||
yesNocancel,
|
||||
yesnoCancel,
|
||||
}
|
||||
enum
|
||||
{
|
||||
noicon,
|
||||
information,
|
||||
exclamation,
|
||||
question,
|
||||
stop
|
||||
}
|
||||
native messagebox(const message[], const caption[], buttons=Ok, icons=noicon, timeout=0);
|
||||
|
||||
/* Types:
|
||||
* i = integer (16/32 bit)
|
||||
* l = 32-bit integer
|
||||
* h = handle (16/32 bit)
|
||||
* p = packed string
|
||||
* s = (unpacked) string
|
||||
* w = 16-bit unsigned integer
|
||||
* lower case = by value, upper case = by reference
|
||||
*
|
||||
* The types noted as "16/32 bit" are converted to 16-bit in Win16 environments
|
||||
* prior to the call to the DLL.
|
||||
*
|
||||
* calldll() attaches "32" to the dll name if it cannot load the DLL as you
|
||||
* provide it. So it loads "user32" if you specify "user" and you are in Win32.
|
||||
* calldll() also appends a "A" to the function name if it cannot find the
|
||||
* function as specified. So it call "GetWindowTextA" if you ask for
|
||||
* "GetWindowText". By this means, the interface is more compatible between
|
||||
* 16-bit and 32-bit platforms.
|
||||
*/
|
||||
native calldll(const dllname[], const function[], const typestr[]="", ...);
|
||||
|
||||
native loaddll(const dllname[]);
|
||||
native freedll(const dllname[]);
|
||||
|
||||
native iswin32();
|
||||
|
||||
native balloon(&Balloon:handle, text[]="", x=0, y=0, timeout=-1);
|
||||
native balloonfont(&Balloon:handle, const font[]="", height=16, weight=400, italic=0);
|
||||
|
||||
stock wGetCursorPos(&x, &y)
|
||||
/* Get the current position of the mouse cursor relative to the upper
|
||||
* left corner of the screen
|
||||
*/
|
||||
{
|
||||
new point[2]
|
||||
calldll(!"user","GetCursorPos","I",point)
|
||||
if (!iswin32())
|
||||
{
|
||||
point[1] = point[0] >> 16
|
||||
point[0] &= 0xffff
|
||||
}
|
||||
x = point[0]
|
||||
y = point[1]
|
||||
}
|
||||
|
||||
|
15
INCLUDE/args.inc
Normal file
15
INCLUDE/args.inc
Normal file
@ -0,0 +1,15 @@
|
||||
/* Script Arguments support functions
|
||||
*
|
||||
* (c) Copyright 2005, ITB CompuPhase
|
||||
* This file is provided as is (no warranties).
|
||||
*/
|
||||
#if defined _args_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _args_included
|
||||
#pragma library Args
|
||||
|
||||
native argcount();
|
||||
native bool: argindex(index, value[], maxlength = sizeof value, bool: pack = false);
|
||||
native bool: argstr(index = 0, const option[] = "", value[] = "", maxlength = sizeof value, bool: pack = false);
|
||||
native bool: argvalue(index = 0, const option[] = "", &value = cellmin);
|
37
INCLUDE/console.inc
Normal file
37
INCLUDE/console.inc
Normal file
@ -0,0 +1,37 @@
|
||||
/* Console input/output functions
|
||||
*
|
||||
* (c) Copyright 1998-2005, ITB CompuPhase
|
||||
* This file is provided as is (no warranties).
|
||||
*/
|
||||
#if defined _console_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _console_included
|
||||
#pragma library Console
|
||||
|
||||
enum
|
||||
{
|
||||
black, /* colours as per the ANSI Escape sequences, ISO 6429 */
|
||||
red,
|
||||
green,
|
||||
yellow,
|
||||
blue,
|
||||
magenta,
|
||||
cyan,
|
||||
white,
|
||||
}
|
||||
|
||||
native getchar(echo=true);
|
||||
native getstring(string[], maxlength=sizeof string, bool:pack=false);
|
||||
native getvalue(base=10, term=0x0d, ...); /* 0x0d == '\r' */
|
||||
native print(const string[], foreground=-1, background=-1, highlight=-1);
|
||||
native printf(const format[], {Float,Fixed,_}:...);
|
||||
|
||||
native console(columns, lines);
|
||||
native clrscr(); /* also resets the cursor to (1,1) */
|
||||
native clreol();
|
||||
native gotoxy(x=1, y=1);
|
||||
native wherexy(&x, &y);
|
||||
native setattr(foreground=-1, background=-1, highlight=-1);
|
||||
|
||||
forward @keypressed(key);
|
34
INCLUDE/core.inc
Normal file
34
INCLUDE/core.inc
Normal file
@ -0,0 +1,34 @@
|
||||
/* Core functions
|
||||
*
|
||||
* (c) Copyright 1998-2005, ITB CompuPhase
|
||||
* This file is provided as is (no warranties).
|
||||
*/
|
||||
#if defined _core_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _core_included
|
||||
#pragma library Core
|
||||
|
||||
native heapspace();
|
||||
|
||||
native funcidx(const name[]);
|
||||
|
||||
native numargs();
|
||||
native getarg(arg, index=0);
|
||||
native setarg(arg, index=0, value);
|
||||
|
||||
native tolower(c);
|
||||
native toupper(c);
|
||||
native swapchars(c);
|
||||
|
||||
native random(max);
|
||||
|
||||
native min(value1, value2);
|
||||
native max(value1, value2);
|
||||
native clamp(value, min=cellmin, max=cellmax);
|
||||
|
||||
native getproperty(id=0, const name[]="", value=cellmin, string[]="");
|
||||
native setproperty(id=0, const name[]="", value=cellmin, const string[]="");
|
||||
native deleteproperty(id=0, const name[]="", value=cellmin);
|
||||
native existproperty(id=0, const name[]="", value=cellmin);
|
||||
|
18
INCLUDE/datagram.inc
Normal file
18
INCLUDE/datagram.inc
Normal file
@ -0,0 +1,18 @@
|
||||
/* Datagram sending/receiving
|
||||
*
|
||||
* (c) Copyright 2005, ITB CompuPhase
|
||||
* This file is provided as is (no warranties).
|
||||
*/
|
||||
#if defined _datagram_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _datagram_included
|
||||
#pragma library DGram
|
||||
|
||||
native sendstring(const message[], const destination[]="");
|
||||
native sendpacket(const packet[], size, const destination[]="");
|
||||
|
||||
native listenport(port);
|
||||
|
||||
forward @receivestring(const message[], const source[]);
|
||||
forward @receivepacket(const packet[], size, const source[]);
|
2
INCLUDE/default.inc
Normal file
2
INCLUDE/default.inc
Normal file
@ -0,0 +1,2 @@
|
||||
#include <core>
|
||||
#include <console>
|
44
INCLUDE/file.inc
Normal file
44
INCLUDE/file.inc
Normal file
@ -0,0 +1,44 @@
|
||||
/* File input/output functions
|
||||
*
|
||||
* (c) Copyright 2004-2005, ITB CompuPhase
|
||||
* This file is provided as is (no warranties).
|
||||
*/
|
||||
#if defined _file_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _file_included
|
||||
#pragma library File
|
||||
|
||||
enum filemode
|
||||
{
|
||||
io_read, /* file must exist */
|
||||
io_write, /* creates a new file */
|
||||
io_readwrite, /* opens an existing file, or creates a new file */
|
||||
io_append, /* appends to file (write-only) */
|
||||
}
|
||||
|
||||
enum seek_whence
|
||||
{
|
||||
seek_start,
|
||||
seek_current,
|
||||
seek_end,
|
||||
}
|
||||
|
||||
const EOF = -1;
|
||||
|
||||
native File: fopen(const name[], filemode: mode = io_readwrite);
|
||||
native bool: fclose(File: handle);
|
||||
native File: ftemp();
|
||||
native bool: fremove(const name[]);
|
||||
|
||||
native fwrite(File: handle, const string[]);
|
||||
native fread(File: handle, string[], size = sizeof string, bool: pack = false);
|
||||
native bool: fputchar(File: handle, value, bool: utf8 = true);
|
||||
native fgetchar(File: handle, bool: utf8 = true);
|
||||
native fblockwrite(File: handle, const buffer[], size = sizeof buffer);
|
||||
native fblockread(File: handle, buffer[], size = sizeof buffer);
|
||||
|
||||
native fseek(File: handle, position = 0, seek_whence: whence = seek_start);
|
||||
native flength(File: handle);
|
||||
native fexist(const pattern[]);
|
||||
native bool: fmatch(name[], const pattern[], index = 0, size = sizeof name);
|
95
INCLUDE/fixed.inc
Normal file
95
INCLUDE/fixed.inc
Normal file
@ -0,0 +1,95 @@
|
||||
/* Fixed point arithmetic
|
||||
*
|
||||
* (c) Copyright 1998-2005, ITB CompuPhase
|
||||
* This file is provided as is (no warranties).
|
||||
*/
|
||||
#if defined _Fixed_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _Fixed_included
|
||||
#pragma library Fixed
|
||||
|
||||
enum fround_method {
|
||||
fround_round,
|
||||
fround_floor,
|
||||
fround_ceil,
|
||||
fround_tozero,
|
||||
fround_unbiased
|
||||
}
|
||||
|
||||
native Fixed:fixed(value);
|
||||
native Fixed:strfixed(const string[]);
|
||||
native Fixed:fmul(Fixed:oper1, Fixed:oper2);
|
||||
native Fixed:fdiv(Fixed:dividend, Fixed:divisor);
|
||||
native Fixed:ffract(Fixed:value);
|
||||
native fround(Fixed:value, fround_method:method=fround_round);
|
||||
native Fixed:fpower(Fixed:value, exponent);
|
||||
native Fixed:fsqroot(Fixed:value);
|
||||
native Fixed:fabs(Fixed:value);
|
||||
|
||||
#pragma rational Fixed(3)
|
||||
|
||||
/* user defined operators */
|
||||
native Fixed:operator*(Fixed:oper1, Fixed:oper2) = fmul;
|
||||
native Fixed:operator/(Fixed:oper1, Fixed:oper2) = fdiv;
|
||||
native Fixed:operator=(oper) = fixed;
|
||||
|
||||
stock Fixed:operator++(Fixed:oper)
|
||||
return oper + fixed(1);
|
||||
|
||||
stock Fixed:operator--(Fixed:oper)
|
||||
return oper - fixed(1);
|
||||
|
||||
stock Fixed:operator*(Fixed:oper1, oper2)
|
||||
return Fixed: (_:oper1 * oper2); /* "*" is commutative */
|
||||
|
||||
stock Fixed:operator/(Fixed:oper1, oper2)
|
||||
return oper1 / fixed(oper2);
|
||||
|
||||
stock Fixed:operator/(oper1, Fixed:oper2)
|
||||
return fdiv(fixed(oper1), oper2);
|
||||
|
||||
stock Fixed:operator+(Fixed:oper1, oper2)
|
||||
return oper1 + fixed(oper2); /* "+" is commutative */
|
||||
|
||||
stock Fixed:operator-(Fixed:oper1, oper2)
|
||||
return oper1 - fixed(oper2);
|
||||
|
||||
stock Fixed:operator-(oper1, Fixed:oper2)
|
||||
return fixed(oper1) - oper2;
|
||||
|
||||
stock bool:operator>(Fixed:oper1, oper2)
|
||||
return oper1 > fixed(oper2);
|
||||
|
||||
stock bool:operator>(oper1, Fixed:oper2)
|
||||
return fixed(oper1) > oper2;
|
||||
|
||||
stock bool:operator>=(Fixed:oper1, oper2)
|
||||
return oper1 >= fixed(oper2);
|
||||
|
||||
stock bool:operator>=(oper1, Fixed:oper2)
|
||||
return fixed(oper1) >= oper2;
|
||||
|
||||
stock bool:operator<(Fixed:oper1, oper2)
|
||||
return oper1 < fixed(oper2);
|
||||
|
||||
stock bool:operator<(oper1, Fixed:oper2)
|
||||
return fixed(oper1) < oper2;
|
||||
|
||||
stock bool:operator<=(Fixed:oper1, oper2)
|
||||
return oper1 <= fixed(oper2);
|
||||
|
||||
stock bool:operator<=(oper1, Fixed:oper2)
|
||||
return fixed(oper1) <= oper2;
|
||||
|
||||
stock bool:operator==(Fixed:oper1, oper2) /* "==" is commutative */
|
||||
return oper1 == fixed(oper2);
|
||||
|
||||
stock bool:operator!=(Fixed:oper1, oper2) /* "!=" is commutative */
|
||||
return oper1 != fixed(oper2);
|
||||
|
||||
/* forbidden operations */
|
||||
forward operator%(Fixed:oper1, Fixed:oper2);
|
||||
forward operator%(Fixed:oper1, oper2);
|
||||
forward operator%(oper1, Fixed:oper2);
|
||||
|
184
INCLUDE/float.inc
Normal file
184
INCLUDE/float.inc
Normal file
@ -0,0 +1,184 @@
|
||||
/* Float arithmetic
|
||||
*
|
||||
* (c) Copyright 1999, Artran, Inc.
|
||||
* Written by Greg Garner (gmg@artran.com)
|
||||
* Modified in March 2001 to include user defined
|
||||
* operators for the floating point functions.
|
||||
*
|
||||
* This file is provided as is (no warranties).
|
||||
*/
|
||||
#if defined _Float_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _Float_included
|
||||
#pragma library Float
|
||||
|
||||
/* Different methods of rounding */
|
||||
enum floatround_method {
|
||||
floatround_round,
|
||||
floatround_floor,
|
||||
floatround_ceil,
|
||||
floatround_tozero,
|
||||
floatround_unbiased
|
||||
}
|
||||
enum anglemode {
|
||||
radian,
|
||||
degrees,
|
||||
grades
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
/* Convert an integer into a floating point value */
|
||||
native Float:float(value);
|
||||
|
||||
/**************************************************/
|
||||
/* Convert a string into a floating point value */
|
||||
native Float:strfloat(const string[]);
|
||||
|
||||
/**************************************************/
|
||||
/* Multiple two floats together */
|
||||
native Float:floatmul(Float:oper1, Float:oper2);
|
||||
|
||||
/**************************************************/
|
||||
/* Divide the dividend float by the divisor float */
|
||||
native Float:floatdiv(Float:dividend, Float:divisor);
|
||||
|
||||
/**************************************************/
|
||||
/* Add two floats together */
|
||||
native Float:floatadd(Float:oper1, Float:oper2);
|
||||
|
||||
/**************************************************/
|
||||
/* Subtract oper2 float from oper1 float */
|
||||
native Float:floatsub(Float:oper1, Float:oper2);
|
||||
|
||||
/**************************************************/
|
||||
/* Return the fractional part of a float */
|
||||
native Float:floatfract(Float:value);
|
||||
|
||||
/**************************************************/
|
||||
/* Round a float into a integer value */
|
||||
native floatround(Float:value, floatround_method:method=floatround_round);
|
||||
|
||||
/**************************************************/
|
||||
/* Compare two integers. If the two elements are equal, return 0.
|
||||
If the first argument is greater than the second argument, return 1,
|
||||
If the first argument is less than the second argument, return -1. */
|
||||
native floatcmp(Float:oper1, Float:oper2);
|
||||
|
||||
/**************************************************/
|
||||
/* Return the square root of the input value, same as floatpower(value, 0.5) */
|
||||
native Float:floatsqroot(Float:value);
|
||||
|
||||
/**************************************************/
|
||||
/* Return the value raised to the power of the exponent */
|
||||
native Float:floatpower(Float:value, Float:exponent);
|
||||
|
||||
/**************************************************/
|
||||
/* Return the logarithm */
|
||||
native Float:floatlog(Float:value, Float:base=10.0);
|
||||
|
||||
/**************************************************/
|
||||
/* Return the sine, cosine or tangent. The input angle may be in radian,
|
||||
degrees or grades. */
|
||||
native Float:floatsin(Float:value, anglemode:mode=radian);
|
||||
native Float:floatcos(Float:value, anglemode:mode=radian);
|
||||
native Float:floattan(Float:value, anglemode:mode=radian);
|
||||
|
||||
/**************************************************/
|
||||
/* Return the absolute value */
|
||||
native Float:floatabs(Float:value);
|
||||
|
||||
|
||||
/**************************************************/
|
||||
#pragma rational Float
|
||||
|
||||
/* user defined operators */
|
||||
native Float:operator*(Float:oper1, Float:oper2) = floatmul;
|
||||
native Float:operator/(Float:oper1, Float:oper2) = floatdiv;
|
||||
native Float:operator+(Float:oper1, Float:oper2) = floatadd;
|
||||
native Float:operator-(Float:oper1, Float:oper2) = floatsub;
|
||||
native Float:operator=(oper) = float;
|
||||
|
||||
stock Float:operator++(Float:oper)
|
||||
return oper+1.0;
|
||||
|
||||
stock Float:operator--(Float:oper)
|
||||
return oper-1.0;
|
||||
|
||||
stock Float:operator-(Float:oper)
|
||||
return oper^Float:cellmin; /* IEEE values are sign/magnitude */
|
||||
|
||||
stock Float:operator*(Float:oper1, oper2)
|
||||
return floatmul(oper1, float(oper2)); /* "*" is commutative */
|
||||
|
||||
stock Float:operator/(Float:oper1, oper2)
|
||||
return floatdiv(oper1, float(oper2));
|
||||
|
||||
stock Float:operator/(oper1, Float:oper2)
|
||||
return floatdiv(float(oper1), oper2);
|
||||
|
||||
stock Float:operator+(Float:oper1, oper2)
|
||||
return floatadd(oper1, float(oper2)); /* "+" is commutative */
|
||||
|
||||
stock Float:operator-(Float:oper1, oper2)
|
||||
return floatsub(oper1, float(oper2));
|
||||
|
||||
stock Float:operator-(oper1, Float:oper2)
|
||||
return floatsub(float(oper1), oper2);
|
||||
|
||||
stock bool:operator==(Float:oper1, Float:oper2)
|
||||
return floatcmp(oper1, oper2) == 0;
|
||||
|
||||
stock bool:operator==(Float:oper1, oper2)
|
||||
return floatcmp(oper1, float(oper2)) == 0; /* "==" is commutative */
|
||||
|
||||
stock bool:operator!=(Float:oper1, Float:oper2)
|
||||
return floatcmp(oper1, oper2) != 0;
|
||||
|
||||
stock bool:operator!=(Float:oper1, oper2)
|
||||
return floatcmp(oper1, float(oper2)) != 0; /* "!=" is commutative */
|
||||
|
||||
stock bool:operator>(Float:oper1, Float:oper2)
|
||||
return floatcmp(oper1, oper2) > 0;
|
||||
|
||||
stock bool:operator>(Float:oper1, oper2)
|
||||
return floatcmp(oper1, float(oper2)) > 0;
|
||||
|
||||
stock bool:operator>(oper1, Float:oper2)
|
||||
return floatcmp(float(oper1), oper2) > 0;
|
||||
|
||||
stock bool:operator>=(Float:oper1, Float:oper2)
|
||||
return floatcmp(oper1, oper2) >= 0;
|
||||
|
||||
stock bool:operator>=(Float:oper1, oper2)
|
||||
return floatcmp(oper1, float(oper2)) >= 0;
|
||||
|
||||
stock bool:operator>=(oper1, Float:oper2)
|
||||
return floatcmp(float(oper1), oper2) >= 0;
|
||||
|
||||
stock bool:operator<(Float:oper1, Float:oper2)
|
||||
return floatcmp(oper1, oper2) < 0;
|
||||
|
||||
stock bool:operator<(Float:oper1, oper2)
|
||||
return floatcmp(oper1, float(oper2)) < 0;
|
||||
|
||||
stock bool:operator<(oper1, Float:oper2)
|
||||
return floatcmp(float(oper1), oper2) < 0;
|
||||
|
||||
stock bool:operator<=(Float:oper1, Float:oper2)
|
||||
return floatcmp(oper1, oper2) <= 0;
|
||||
|
||||
stock bool:operator<=(Float:oper1, oper2)
|
||||
return floatcmp(oper1, float(oper2)) <= 0;
|
||||
|
||||
stock bool:operator<=(oper1, Float:oper2)
|
||||
return floatcmp(float(oper1), oper2) <= 0;
|
||||
|
||||
stock bool:operator!(Float:oper)
|
||||
return (_:oper & cellmax) == 0;
|
||||
|
||||
/* forbidden operations */
|
||||
forward operator%(Float:oper1, Float:oper2);
|
||||
forward operator%(Float:oper1, oper2);
|
||||
forward operator%(oper1, Float:oper2);
|
||||
|
19
INCLUDE/process.inc
Normal file
19
INCLUDE/process.inc
Normal file
@ -0,0 +1,19 @@
|
||||
/* Process control and Foreign Function Interface (calling functions
|
||||
* in DLLs or shared libraries)
|
||||
*
|
||||
* (c) Copyright 2006, ITB CompuPhase
|
||||
* This file is provided as is (no warranties).
|
||||
*/
|
||||
#if defined _process_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _process_included
|
||||
#pragma library Process
|
||||
|
||||
native libcall(const libname[], const funcname[], const typestring[], ...);
|
||||
native bool: libfree(const libname[]="");
|
||||
|
||||
native PID: procexec(const progname[]);
|
||||
native procwait(PID:pid);
|
||||
native bool: procwrite(const line[], bool:appendlf=false);
|
||||
native bool: procread(line[], size=sizeof line, bool:striplf=false, bool:packed=false);
|
53
INCLUDE/rational.inc
Normal file
53
INCLUDE/rational.inc
Normal file
@ -0,0 +1,53 @@
|
||||
/* Rational number support
|
||||
* Loads either Float.inc or Fixed.inc, depending on the configuration
|
||||
*
|
||||
* (c) Copyright 2004-2005, ITB CompuPhase
|
||||
* This file is provided as is (no warranties).
|
||||
*/
|
||||
#if defined _Rational_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _Rational_included
|
||||
|
||||
/* first try to include floating point support */
|
||||
#if !defined NOFLOAT
|
||||
#tryinclude <float>
|
||||
#endif
|
||||
#if defined _Float_included
|
||||
#define Rational: Float:
|
||||
#define rationalstr(%1) floatstr(%1)
|
||||
#define rround(%1, %2) floatround(%1, %2)
|
||||
#define rsqroot(%1) floatsqroot(%1)
|
||||
#define rpower(%1, %2) floatpower(%1, %2)
|
||||
#define rabs(%1) floatabs(%1)
|
||||
|
||||
#define rround_round floatround_round
|
||||
#define rround_floor floatround_floor
|
||||
#define rround_ceil floatround_ceil
|
||||
#define rround_tozero floatround_tozero
|
||||
#define rround_unbiased floatround_unbiased
|
||||
#endinput
|
||||
#endif
|
||||
|
||||
/* loading floating point support failed, try fixed point support */
|
||||
#if !defined NOFIXED
|
||||
#tryinclude <fixed>
|
||||
#endif
|
||||
#if defined _Fixed_included
|
||||
#define Rational: Fixed:
|
||||
#define rationalstr(%1) fixedstr(%1)
|
||||
#define rround(%1, %2) fround(%1, %2)
|
||||
#define rsqroot(%1) fsqroot(%1)
|
||||
#define rpower(%1, %2) fpower(%1, %2)
|
||||
#define rabs(%1) fabs(%1)
|
||||
|
||||
#define rround_round fround_round
|
||||
#define rround_floor fround_floor
|
||||
#define rround_ceil fround_ceil
|
||||
#define rround_tozero fround_tozero
|
||||
#define rround_unbiased fround_unbiased
|
||||
#endinput
|
||||
#endif
|
||||
|
||||
/* if arrived here, neither floating point, nor fixed point support is available */
|
||||
#error Rational number support is unavailable (disabled or not installed)
|
35
INCLUDE/string.inc
Normal file
35
INCLUDE/string.inc
Normal file
@ -0,0 +1,35 @@
|
||||
/* String functions
|
||||
*
|
||||
* (c) Copyright 2005, ITB CompuPhase
|
||||
* This file is provided as is (no warranties).
|
||||
*/
|
||||
#if defined _string_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _string_included
|
||||
#pragma library String
|
||||
|
||||
native strlen(const string[]);
|
||||
native strpack(dest[], const source[], maxlength=sizeof dest);
|
||||
native strunpack(dest[], const source[], maxlength=sizeof dest);
|
||||
native strcat(dest[], const source[], maxlength=sizeof dest);
|
||||
|
||||
native strmid(dest[], const source[], start=0, end=cellmax, maxlength=sizeof dest);
|
||||
native bool: strins(string[], const substr[], index, maxlength=sizeof string);
|
||||
native bool: strdel(string[], start, end);
|
||||
|
||||
native strcmp(const string1[], const string2[], bool:ignorecase=false, length=cellmax);
|
||||
native strfind(const string[], const sub[], bool:ignorecase=false, index=0);
|
||||
|
||||
native strval(const string[], index=0);
|
||||
native valstr(dest[], value, bool:pack=false);
|
||||
native bool: ispacked(const string[]);
|
||||
|
||||
native strformat(dest[], size=sizeof dest, bool:pack=false, const format[], {Fixed,Float,_}:...);
|
||||
|
||||
native uudecode(dest[], const source[], maxlength=sizeof dest);
|
||||
native uuencode(dest[], const source[], numbytes, maxlength=sizeof dest);
|
||||
native memcpy(dest[], const source[], index=0, numbytes, maxlength=sizeof dest);
|
||||
|
||||
stock bool: strequal(const string1[], const string2[], bool:ignorecase=false, length=cellmax)
|
||||
return strcmp(string1, string2, ignorecase, length) == 0
|
22
INCLUDE/time.inc
Normal file
22
INCLUDE/time.inc
Normal file
@ -0,0 +1,22 @@
|
||||
/* Date/time functions
|
||||
*
|
||||
* (c) Copyright 2001-2005, ITB CompuPhase
|
||||
* This file is provided as is (no warranties).
|
||||
*/
|
||||
#if defined _time_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _time_included
|
||||
#pragma library Time
|
||||
|
||||
native gettime(&hour=0, &minute=0, &second=0);
|
||||
native settime(hour=cellmin, minute=cellmin, second=cellmin);
|
||||
native getdate(&year=0, &month=0, &day=0);
|
||||
native setdate(year=cellmin, month=cellmin, day=cellmin);
|
||||
native settimestamp(seconds1970);
|
||||
|
||||
native settimer(milliseconds, bool: singleshot=false);
|
||||
native tickcount(&granularity=0);
|
||||
native delay(milliseconds);
|
||||
|
||||
forward @timer();
|
206
SOURCE/amx/CMakeLists.txt
Normal file
206
SOURCE/amx/CMakeLists.txt
Normal file
@ -0,0 +1,206 @@
|
||||
#build file for CMake, see http://www.cmake.org/
|
||||
|
||||
PROJECT(pawnamx)
|
||||
|
||||
# check for optional include files
|
||||
INCLUDE(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake)
|
||||
CHECK_INCLUDE_FILE("unistd.h" HAVE_UNISTD_H)
|
||||
IF(HAVE_UNISTD_H)
|
||||
ADD_DEFINITIONS(-DHAVE_UNISTD_H)
|
||||
ENDIF(HAVE_UNISTD_H)
|
||||
CHECK_INCLUDE_FILE("inttypes.h" HAVE_INTTYPES_H)
|
||||
IF(HAVE_INTTYPES_H)
|
||||
ADD_DEFINITIONS(-DHAVE_INTTYPES_H)
|
||||
ENDIF(HAVE_INTTYPES_H)
|
||||
CHECK_INCLUDE_FILE("stdint.h" HAVE_STDINT_H)
|
||||
IF(HAVE_STDINT_H)
|
||||
ADD_DEFINITIONS(-DHAVE_STDINT_H)
|
||||
ENDIF(HAVE_STDINT_H)
|
||||
CHECK_INCLUDE_FILE("alloca.h" HAVE_ALLOCA_H)
|
||||
IF(HAVE_ALLOCA_H)
|
||||
ADD_DEFINITIONS(-DHAVE_ALLOCA_H)
|
||||
ENDIF(HAVE_ALLOCA_H)
|
||||
|
||||
ADD_DEFINITIONS(-DFLOATPOINT -DFIXEDPOINT)
|
||||
IF (UNIX)
|
||||
ADD_DEFINITIONS(-DLINUX)
|
||||
CHECK_INCLUDE_FILE("ffi.h" HAVE_FFI_H)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../linux)
|
||||
ENDIF (UNIX)
|
||||
IF(WIN32)
|
||||
ADD_DEFINITIONS(-DAMXEXPORT=__stdcall -DAMX_NATIVE_CALL=__stdcall -DSTDECL)
|
||||
IF(NOT BORLAND)
|
||||
LINK_LIBRARIES(winmm)
|
||||
ENDIF(NOT BORLAND)
|
||||
ENDIF(WIN32)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Extension modules
|
||||
|
||||
# amxArgs
|
||||
SET(ARGS_SRCS amxargs.c amx.c)
|
||||
ADD_LIBRARY(amxArgs SHARED ${ARGS_SRCS})
|
||||
SET_TARGET_PROPERTIES(amxArgs PROPERTIES PREFIX "")
|
||||
IF(WIN32)
|
||||
SET(ARGS_SRCS ${ARGS_SRCS} dllmain.c amxargs.rc)
|
||||
IF(BORLAND)
|
||||
# Borland linker uses a DEF file if one is in the output directory
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/amxargs.def ${CMAKE_BINARY_DIR}/amxargs.def COPY_ONLY)
|
||||
ELSE(BORLAND)
|
||||
# For Microsoft Visual C/C++ we can set explicit flags for exports
|
||||
SET_TARGET_PROPERTIES(amxArgs PROPERTIES LINK_FLAGS "/export:amx_ArgsInit /export:amx_ArgsCleanup /export:amx_ArgsSetCmdLine")
|
||||
ENDIF(BORLAND)
|
||||
ENDIF(WIN32)
|
||||
IF(UNIX)
|
||||
ADD_CUSTOM_COMMAND(TARGET amxArgs POST_BUILD COMMAND strip ARGS -K amx_ArgsInit -K amx_ArgsCleanup -K amx_ArgsSetCmdLine ${CMAKE_BINARY_DIR}/amxArgs.so)
|
||||
ENDIF(UNIX)
|
||||
|
||||
# amxDGram
|
||||
SET(DGRAM_SRCS amxdgram.c amx.c)
|
||||
ADD_LIBRARY(amxDGram SHARED ${DGRAM_SRCS})
|
||||
SET_TARGET_PROPERTIES(amxDGram PROPERTIES PREFIX "")
|
||||
IF(WIN32)
|
||||
SET(DGRAM_SRCS ${DGRAM_SRCS} dllmain.c amxargs.rc)
|
||||
IF(BORLAND)
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/amxdgram.def ${CMAKE_BINARY_DIR}/amxdgram.def COPY_ONLY)
|
||||
ELSE(BORLAND)
|
||||
SET_TARGET_PROPERTIES(amxDGram PROPERTIES LINK_FLAGS "/export:amx_DGramInit /export:amx_DGramCleanup")
|
||||
ENDIF(BORLAND)
|
||||
ENDIF(WIN32)
|
||||
IF(UNIX)
|
||||
ADD_CUSTOM_COMMAND(TARGET amxDGram POST_BUILD COMMAND strip ARGS -K amx_DGramInit -K amx_DGramCleanup ${CMAKE_BINARY_DIR}/amxDGram.so)
|
||||
ENDIF(UNIX)
|
||||
|
||||
# amxFile
|
||||
SET(FILE_SRCS amxfile.c amx.c)
|
||||
ADD_LIBRARY(amxFile SHARED ${FILE_SRCS})
|
||||
SET_TARGET_PROPERTIES(amxFile PROPERTIES PREFIX "")
|
||||
IF(WIN32)
|
||||
SET(FILE_SRCS ${FILE_SRCS} dllmain.c amxfile.rc)
|
||||
IF(BORLAND)
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/amxfile.def ${CMAKE_BINARY_DIR}/amxfile.def COPY_ONLY)
|
||||
ELSE(BORLAND)
|
||||
SET_TARGET_PROPERTIES(amxFile PROPERTIES LINK_FLAGS "/export:amx_FileInit /export:amx_FileCleanup")
|
||||
ENDIF(BORLAND)
|
||||
ENDIF(WIN32)
|
||||
IF(UNIX)
|
||||
ADD_CUSTOM_COMMAND(TARGET amxFile POST_BUILD COMMAND strip ARGS -K amx_FileInit -K amx_FileCleanup ${CMAKE_BINARY_DIR}/amxFile.so)
|
||||
ENDIF(UNIX)
|
||||
|
||||
# amxFixed
|
||||
SET(FIXED_SRCS fixed.c amx.c)
|
||||
ADD_LIBRARY(amxFixed SHARED ${FIXED_SRCS})
|
||||
SET_TARGET_PROPERTIES(amxFixed PROPERTIES PREFIX "")
|
||||
IF(WIN32)
|
||||
SET(FIXED_SRCS ${FIXED_SRCS} dllmain.c amxfixed.rc)
|
||||
IF(BORLAND)
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/amxfixed.def ${CMAKE_BINARY_DIR}/amxfixed.def COPY_ONLY)
|
||||
ELSE(BORLAND)
|
||||
SET_TARGET_PROPERTIES(amxFixed PROPERTIES LINK_FLAGS "/export:amx_FixedInit /export:amx_FixedCleanup")
|
||||
ENDIF(BORLAND)
|
||||
ENDIF(WIN32)
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(amxFixed m)
|
||||
ADD_CUSTOM_COMMAND(TARGET amxFixed POST_BUILD COMMAND strip ARGS -K amx_FixedInit -K amx_FixedCleanup ${CMAKE_BINARY_DIR}/amxFixed.so)
|
||||
ENDIF(UNIX)
|
||||
|
||||
# amxFloat
|
||||
SET(FLOAT_SRCS float.c amx.c)
|
||||
ADD_LIBRARY(amxFloat SHARED ${FLOAT_SRCS})
|
||||
SET_TARGET_PROPERTIES(amxFloat PROPERTIES PREFIX "")
|
||||
IF(WIN32)
|
||||
SET(FLOAT_SRCS ${FLOAT_SRCS} dllmain.c amxfloat.rc)
|
||||
IF(BORLAND)
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/amxfloat.def ${CMAKE_BINARY_DIR}/amxfloat.def COPY_ONLY)
|
||||
ELSE(BORLAND)
|
||||
SET_TARGET_PROPERTIES(amxFloat PROPERTIES LINK_FLAGS "/export:amx_FloatInit /export:amx_FloatCleanup")
|
||||
ENDIF(BORLAND)
|
||||
ENDIF(WIN32)
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(amxFloat m)
|
||||
ADD_CUSTOM_COMMAND(TARGET amxFloat POST_BUILD COMMAND strip ARGS -K amx_FloatInit -K amx_FloatInit ${CMAKE_BINARY_DIR}/amxFloat.so)
|
||||
ENDIF(UNIX)
|
||||
|
||||
# amxProcess
|
||||
SET(PROCESS_SRCS amxprocess.c amx.c)
|
||||
IF(WIN32)
|
||||
ADD_LIBRARY(amxProcess SHARED ${PROCESS_SRCS})
|
||||
ELSE(WIN32)
|
||||
IF(HAVE_FFI_H)
|
||||
ADD_LIBRARY(amxProcess SHARED ${PROCESS_SRCS})
|
||||
ELSE(HAVE_FFI_H)
|
||||
MESSAGE(SEND_ERROR "amxProcess requires libffi; see http://sources.redhat.com/libffi/")
|
||||
MESSAGE(SEND_ERROR "libffi is not available (foreign function interface)")
|
||||
ENDIF(HAVE_FFI_H)
|
||||
ENDIF(WIN32)
|
||||
SET_TARGET_PROPERTIES(amxProcess PROPERTIES PREFIX "")
|
||||
IF(WIN32)
|
||||
SET(PROCESS_SRCS ${PROCESS_SRCS} dllmain.c amxprocess.rc)
|
||||
IF(BORLAND)
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/amxprocess.def ${CMAKE_BINARY_DIR}/amxprocess.def COPY_ONLY)
|
||||
ELSE(BORLAND)
|
||||
SET_TARGET_PROPERTIES(amxProcess PROPERTIES LINK_FLAGS "/export:amx_ProcessInit /export:amx_ProcessCleanup")
|
||||
ENDIF(BORLAND)
|
||||
ENDIF(WIN32)
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(amxProcess dl)
|
||||
ADD_CUSTOM_COMMAND(TARGET amxProcess POST_BUILD COMMAND strip ARGS -K amx_ProcessInit -K amx_ProcessCleanup ${CMAKE_BINARY_DIR}/amxProcess.so)
|
||||
ENDIF(UNIX)
|
||||
|
||||
# amxString
|
||||
SET(STRING_SRCS amxstring.c amx.c amxcons.c)
|
||||
ADD_LIBRARY(amxString SHARED ${STRING_SRCS})
|
||||
SET_TARGET_PROPERTIES(amxString PROPERTIES PREFIX "")
|
||||
IF(WIN32)
|
||||
SET(STRING_SRCS ${STRING_SRCS} dllmain.c amxstring.rc)
|
||||
IF(BORLAND)
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/amxstring.def ${CMAKE_BINARY_DIR}/amxstring.def COPY_ONLY)
|
||||
ELSE(BORLAND)
|
||||
SET_TARGET_PROPERTIES(amxString PROPERTIES LINK_FLAGS "/export:amx_StringInit /export:amx_StringCleanup")
|
||||
ENDIF(BORLAND)
|
||||
ENDIF(WIN32)
|
||||
IF(UNIX)
|
||||
ADD_CUSTOM_COMMAND(TARGET amxString POST_BUILD COMMAND strip ARGS -K amx_StringInit -K amx_StringCleanup ${CMAKE_BINARY_DIR}/amxString.so)
|
||||
ENDIF(UNIX)
|
||||
|
||||
# amxTime
|
||||
SET(TIME_SRCS amxtime.c amx.c)
|
||||
ADD_LIBRARY(amxTime SHARED ${TIME_SRCS})
|
||||
SET_TARGET_PROPERTIES(amxTime PROPERTIES PREFIX "")
|
||||
IF(WIN32)
|
||||
SET(TIME_SRCS ${TIME_SRCS} dllmain.c amxtime.rc)
|
||||
IF(BORLAND)
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/amxtime.def ${CMAKE_BINARY_DIR}/amxtime.def COPY_ONLY)
|
||||
ELSE(BORLAND)
|
||||
SET_TARGET_PROPERTIES(amxTime PROPERTIES LINK_FLAGS "/export:amx_TimeInit /export:amx_TimeCleanup")
|
||||
ENDIF(BORLAND)
|
||||
ENDIF(WIN32)
|
||||
IF(UNIX)
|
||||
ADD_CUSTOM_COMMAND(TARGET amxTime POST_BUILD COMMAND strip ARGS -K amx_TimeInit -K amx_TimeCleanup ${CMAKE_BINARY_DIR}/amxTime.so)
|
||||
ENDIF(UNIX)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Simple run-time (example program)
|
||||
|
||||
SET(PAWNRUN_SRCS pawnrun.c amx.c amxcore.c amxcons.c amxdbg.c)
|
||||
IF (UNIX)
|
||||
SET(PAWNRUN_SRCS ${PAWNRUN_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/../linux/getch.c ${CMAKE_CURRENT_SOURCE_DIR}/../linux/binreloc.c)
|
||||
ENDIF (UNIX)
|
||||
ADD_EXECUTABLE(pawnrun ${PAWNRUN_SRCS})
|
||||
SET_TARGET_PROPERTIES(pawnrun PROPERTIES COMPILE_FLAGS -DAMXDBG COMPILE_FLAGS -DENABLE_BINRELOC)
|
||||
IF (UNIX)
|
||||
TARGET_LINK_LIBRARIES(pawnrun dl)
|
||||
ENDIF (UNIX)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Simple console debugger
|
||||
|
||||
SET(PAWNDBG_SRCS pawndbg.c amx.c amxcore.c amxcons.c amxdbg.c)
|
||||
IF (UNIX)
|
||||
SET(PAWNDBG_SRCS ${PAWNDBG_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/../linux/getch.c ${CMAKE_CURRENT_SOURCE_DIR}/../linux/binreloc.c)
|
||||
ENDIF (UNIX)
|
||||
ADD_EXECUTABLE(pawndbg ${PAWNDBG_SRCS})
|
||||
SET_TARGET_PROPERTIES(pawndbg PROPERTIES COMPILE_FLAGS -DENABLE_BINRELOC)
|
||||
IF (UNIX)
|
||||
TARGET_LINK_LIBRARIES(pawndbg dl)
|
||||
ENDIF (UNIX)
|
4634
SOURCE/amx/amx.c
Normal file
4634
SOURCE/amx/amx.c
Normal file
File diff suppressed because it is too large
Load Diff
468
SOURCE/amx/amx.h
Normal file
468
SOURCE/amx/amx.h
Normal file
@ -0,0 +1,468 @@
|
||||
/* Pawn Abstract Machine (for the Pawn language)
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 1997-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amx.h 3648 2006-10-12 11:24:50Z thiadmer $
|
||||
*/
|
||||
|
||||
#ifndef AMX_H_INCLUDED
|
||||
#define AMX_H_INCLUDED
|
||||
|
||||
#include <stdlib.h> /* for size_t */
|
||||
#include <limits.h>
|
||||
|
||||
#if defined FREEBSD && !defined __FreeBSD__
|
||||
#define __FreeBSD__
|
||||
#endif
|
||||
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
#include <sclinux.h>
|
||||
#endif
|
||||
|
||||
#if defined HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#if defined __LCC__ || defined __DMC__ || defined LINUX || (defined __WATCOMC__ && __WATCOMC__ >= 1200)
|
||||
#if defined HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
||||
/* The ISO C99 defines the int16_t and int_32t types. If the compiler got
|
||||
* here, these types are probably undefined.
|
||||
*/
|
||||
#if defined __MACH__
|
||||
#include <ppc/types.h>
|
||||
typedef unsigned short int uint16_t;
|
||||
typedef unsigned long int uint32_t;
|
||||
#elif defined __FreeBSD__
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
typedef short int int16_t;
|
||||
typedef unsigned short int uint16_t;
|
||||
#if defined SN_TARGET_PS2
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef long int int32_t;
|
||||
typedef unsigned long int uint32_t;
|
||||
#endif
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#define HAVE_I64
|
||||
#elif defined __GNUC__
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#define HAVE_I64
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#define HAVE_STDINT_H
|
||||
#endif
|
||||
#if defined _LP64 || defined WIN64 || defined _WIN64
|
||||
#if !defined __64BIT__
|
||||
#define __64BIT__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAVE_ALLOCA_H
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 /* || defined __MSDOS__ */
|
||||
#if !defined alloca
|
||||
#define alloca(n) _alloca(n)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined arraysize
|
||||
#define arraysize(array) (sizeof(array) / sizeof((array)[0]))
|
||||
#endif
|
||||
#if !defined assert_static
|
||||
/* see "Compile-Time Assertions" by Ralf Holly,
|
||||
* C/C++ Users Journal, November 2004
|
||||
*/
|
||||
#define assert_static(e) \
|
||||
do { \
|
||||
enum { assert_static__ = 1/(e) }; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined PAWN_DLL
|
||||
#if !defined AMX_NATIVE_CALL
|
||||
#define AMX_NATIVE_CALL __stdcall
|
||||
#endif
|
||||
#if !defined AMXAPI
|
||||
#define AMXAPI __stdcall
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* calling convention for native functions */
|
||||
#if !defined AMX_NATIVE_CALL
|
||||
#define AMX_NATIVE_CALL
|
||||
#endif
|
||||
/* calling convention for all interface functions and callback functions */
|
||||
#if !defined AMXAPI
|
||||
#if defined STDECL
|
||||
#define AMXAPI __stdcall
|
||||
#elif defined CDECL
|
||||
#define AMXAPI __cdecl
|
||||
#elif defined GCC_HASCLASSVISIBILITY
|
||||
#define AMXAPI __attribute__ ((visibility("default")))
|
||||
#else
|
||||
#define AMXAPI
|
||||
#endif
|
||||
#endif
|
||||
#if !defined AMXEXPORT
|
||||
#define AMXEXPORT
|
||||
#endif
|
||||
|
||||
/* File format version (in CUR_FILE_VERSION)
|
||||
* 0 (original version)
|
||||
* 1 (opcodes JUMP.pri, SWITCH and CASETBL)
|
||||
* 2 (compressed files)
|
||||
* 3 (public variables)
|
||||
* 4 (opcodes SWAP.pri/alt and PUSHADDR)
|
||||
* 5 (tagnames table)
|
||||
* 6 (reformatted header)
|
||||
* 7 (name table, opcodes SYMTAG & SYSREQ.D)
|
||||
* 8 (opcode STMT, renewed debug interface)
|
||||
* 9 (macro opcodes)
|
||||
* MIN_FILE_VERSION is the lowest file version number that the current AMX
|
||||
* implementation supports. If the AMX file header gets new fields, this number
|
||||
* often needs to be incremented. MAX_AMX_VERSION is the lowest AMX version that
|
||||
* is needed to support the current file version. When there are new opcodes,
|
||||
* this number needs to be incremented.
|
||||
* The file version supported by the JIT may run behind MIN_AMX_VERSION. So
|
||||
* there is an extra constant for it: MAX_FILE_VER_JIT.
|
||||
*/
|
||||
#define CUR_FILE_VERSION 9 /* current file version; also the current AMX version */
|
||||
#define MIN_FILE_VERSION 6 /* lowest supported file format version for the current AMX version */
|
||||
#define MIN_AMX_VERSION 9 /* minimum AMX version needed to support the current file format */
|
||||
#define MAX_FILE_VER_JIT 8 /* file version supported by the JIT */
|
||||
#define MIN_AMX_VER_JIT 8 /* AMX version supported by the JIT */
|
||||
|
||||
#if !defined PAWN_CELL_SIZE
|
||||
#define PAWN_CELL_SIZE 32 /* by default, use 32-bit cells */
|
||||
#endif
|
||||
#if PAWN_CELL_SIZE==16
|
||||
typedef uint16_t ucell;
|
||||
typedef int16_t cell;
|
||||
#elif PAWN_CELL_SIZE==32
|
||||
typedef uint32_t ucell;
|
||||
typedef int32_t cell;
|
||||
#elif PAWN_CELL_SIZE==64
|
||||
typedef uint64_t ucell;
|
||||
typedef int64_t cell;
|
||||
#else
|
||||
#error Unsupported cell size (PAWN_CELL_SIZE)
|
||||
#endif
|
||||
|
||||
#define UNPACKEDMAX (((cell)1 << (sizeof(cell)-1)*8) - 1)
|
||||
#define UNLIMITED (~1u >> 1)
|
||||
|
||||
struct tagAMX;
|
||||
typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct tagAMX *amx, const cell *params);
|
||||
typedef int (AMXAPI *AMX_CALLBACK)(struct tagAMX *amx, cell index,
|
||||
cell *result, const cell *params);
|
||||
typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx);
|
||||
typedef int (AMXAPI *AMX_IDLE)(struct tagAMX *amx, int AMXAPI Exec(struct tagAMX *, cell *, int));
|
||||
#if !defined _FAR
|
||||
#define _FAR
|
||||
#endif
|
||||
|
||||
#if defined _MSC_VER
|
||||
#pragma warning(disable:4103) /* disable warning message 4103 that complains
|
||||
* about pragma pack in a header file */
|
||||
#pragma warning(disable:4100) /* "'%$S' : unreferenced formal parameter" */
|
||||
#endif
|
||||
|
||||
/* Some compilers do not support the #pragma align, which should be fine. Some
|
||||
* compilers give a warning on unknown #pragmas, which is not so fine...
|
||||
*/
|
||||
#if (defined SN_TARGET_PS2 || defined __GNUC__) && !defined AMX_NO_ALIGN
|
||||
#define AMX_NO_ALIGN
|
||||
#endif
|
||||
|
||||
#if defined __GNUC__
|
||||
#define PACKED __attribute__((packed))
|
||||
#else
|
||||
#define PACKED
|
||||
#endif
|
||||
|
||||
#if !defined AMX_NO_ALIGN
|
||||
#if defined LINUX || defined __FreeBSD__
|
||||
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
||||
#elif defined MACOS && defined __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#else
|
||||
#pragma pack(push)
|
||||
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
||||
#if defined __TURBOC__
|
||||
#pragma option -a- /* "pack" pragma for older Borland compilers */
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct tagAMX_NATIVE_INFO {
|
||||
const char _FAR *name PACKED;
|
||||
AMX_NATIVE func PACKED;
|
||||
} AMX_NATIVE_INFO;
|
||||
|
||||
#if !defined AMX_USERNUM
|
||||
#define AMX_USERNUM 4
|
||||
#endif
|
||||
#define sEXPMAX 19 /* maximum name length for file version <= 6 */
|
||||
#define sNAMEMAX 31 /* maximum name length of symbol name */
|
||||
|
||||
typedef struct tagAMX_FUNCSTUB {
|
||||
ucell address PACKED;
|
||||
char name[sEXPMAX+1];
|
||||
} AMX_FUNCSTUB;
|
||||
|
||||
typedef struct tagFUNCSTUBNT {
|
||||
ucell address PACKED;
|
||||
uint32_t nameofs PACKED;
|
||||
} AMX_FUNCSTUBNT;
|
||||
|
||||
/* The AMX structure is the internal structure for many functions. Not all
|
||||
* fields are valid at all times; many fields are cached in local variables.
|
||||
*/
|
||||
typedef struct tagAMX {
|
||||
unsigned char _FAR *base PACKED; /* points to the AMX header plus the code, optionally also the data */
|
||||
unsigned char _FAR *data PACKED; /* points to separate data+stack+heap, may be NULL */
|
||||
AMX_CALLBACK callback PACKED;
|
||||
AMX_DEBUG debug PACKED; /* debug callback */
|
||||
/* for external functions a few registers must be accessible from the outside */
|
||||
cell cip PACKED; /* instruction pointer: relative to base + amxhdr->cod */
|
||||
cell frm PACKED; /* stack frame base: relative to base + amxhdr->dat */
|
||||
cell hea PACKED; /* top of the heap: relative to base + amxhdr->dat */
|
||||
cell hlw PACKED; /* bottom of the heap: relative to base + amxhdr->dat */
|
||||
cell stk PACKED; /* stack pointer: relative to base + amxhdr->dat */
|
||||
cell stp PACKED; /* top of the stack: relative to base + amxhdr->dat */
|
||||
int flags PACKED; /* current status, see amx_Flags() */
|
||||
/* user data */
|
||||
#if AMX_USERNUM > 0
|
||||
long usertags[AMX_USERNUM] PACKED;
|
||||
void _FAR *userdata[AMX_USERNUM] PACKED;
|
||||
#endif
|
||||
/* native functions can raise an error */
|
||||
int error PACKED;
|
||||
/* passing parameters requires a "count" field */
|
||||
int paramcount;
|
||||
/* the sleep opcode needs to store the full AMX status */
|
||||
cell pri PACKED;
|
||||
cell alt PACKED;
|
||||
cell reset_stk PACKED;
|
||||
cell reset_hea PACKED;
|
||||
/* extra fields for increased performance */
|
||||
cell sysreq_d PACKED; /* relocated address/value for the SYSREQ.D opcode */
|
||||
#if defined JIT
|
||||
/* support variables for the JIT */
|
||||
int reloc_size PACKED; /* required temporary buffer for relocations */
|
||||
long code_size PACKED; /* estimated memory footprint of the native code */
|
||||
#endif
|
||||
} AMX;
|
||||
|
||||
/* The AMX_HEADER structure is both the memory format as the file format. The
|
||||
* structure is used internaly.
|
||||
*/
|
||||
typedef struct tagAMX_HEADER {
|
||||
int32_t size PACKED; /* size of the "file" */
|
||||
uint16_t magic PACKED; /* signature */
|
||||
char file_version; /* file format version */
|
||||
char amx_version; /* required version of the AMX */
|
||||
int16_t flags PACKED;
|
||||
int16_t defsize PACKED; /* size of a definition record */
|
||||
int32_t cod PACKED; /* initial value of COD - code block */
|
||||
int32_t dat PACKED; /* initial value of DAT - data block */
|
||||
int32_t hea PACKED; /* initial value of HEA - start of the heap */
|
||||
int32_t stp PACKED; /* initial value of STP - stack top */
|
||||
int32_t cip PACKED; /* initial value of CIP - the instruction pointer */
|
||||
int32_t publics PACKED; /* offset to the "public functions" table */
|
||||
int32_t natives PACKED; /* offset to the "native functions" table */
|
||||
int32_t libraries PACKED; /* offset to the table of libraries */
|
||||
int32_t pubvars PACKED; /* the "public variables" table */
|
||||
int32_t tags PACKED; /* the "public tagnames" table */
|
||||
int32_t nametable PACKED; /* name table */
|
||||
} AMX_HEADER;
|
||||
|
||||
#if PAWN_CELL_SIZE==16
|
||||
#define AMX_MAGIC 0xf1e2
|
||||
#elif PAWN_CELL_SIZE==32
|
||||
#define AMX_MAGIC 0xf1e0
|
||||
#elif PAWN_CELL_SIZE==64
|
||||
#define AMX_MAGIC 0xf1e1
|
||||
#endif
|
||||
|
||||
enum {
|
||||
AMX_ERR_NONE,
|
||||
/* reserve the first 15 error codes for exit codes of the abstract machine */
|
||||
AMX_ERR_EXIT, /* forced exit */
|
||||
AMX_ERR_ASSERT, /* assertion failed */
|
||||
AMX_ERR_STACKERR, /* stack/heap collision */
|
||||
AMX_ERR_BOUNDS, /* index out of bounds */
|
||||
AMX_ERR_MEMACCESS, /* invalid memory access */
|
||||
AMX_ERR_INVINSTR, /* invalid instruction */
|
||||
AMX_ERR_STACKLOW, /* stack underflow */
|
||||
AMX_ERR_HEAPLOW, /* heap underflow */
|
||||
AMX_ERR_CALLBACK, /* no callback, or invalid callback */
|
||||
AMX_ERR_NATIVE, /* native function failed */
|
||||
AMX_ERR_DIVIDE, /* divide by zero */
|
||||
AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */
|
||||
AMX_ERR_INVSTATE, /* invalid state for this access */
|
||||
|
||||
AMX_ERR_MEMORY = 16, /* out of memory */
|
||||
AMX_ERR_FORMAT, /* invalid file format */
|
||||
AMX_ERR_VERSION, /* file is for a newer version of the AMX */
|
||||
AMX_ERR_NOTFOUND, /* function not found */
|
||||
AMX_ERR_INDEX, /* invalid index parameter (bad entry point) */
|
||||
AMX_ERR_DEBUG, /* debugger cannot run */
|
||||
AMX_ERR_INIT, /* AMX not initialized (or doubly initialized) */
|
||||
AMX_ERR_USERDATA, /* unable to set user data field (table full) */
|
||||
AMX_ERR_INIT_JIT, /* cannot initialize the JIT */
|
||||
AMX_ERR_PARAMS, /* parameter error */
|
||||
AMX_ERR_DOMAIN, /* domain error, expression result does not fit in range */
|
||||
AMX_ERR_GENERAL, /* general error (unknown or unspecific error) */
|
||||
};
|
||||
|
||||
/* AMX_FLAG_CHAR16 0x01 no longer used */
|
||||
#define AMX_FLAG_DEBUG 0x02 /* symbolic info. available */
|
||||
#define AMX_FLAG_COMPACT 0x04 /* compact encoding */
|
||||
#define AMX_FLAG_SLEEP 0x08 /* script uses the sleep instruction (possible re-entry or power-down mode) */
|
||||
#define AMX_FLAG_NOCHECKS 0x10 /* no array bounds checking; no BREAK opcodes */
|
||||
#define AMX_FLAG_SYSREQN 0x800 /* script new (optimized) version of SYSREQ opcode */
|
||||
#define AMX_FLAG_NTVREG 0x1000 /* all native functions are registered */
|
||||
#define AMX_FLAG_JITC 0x2000 /* abstract machine is JIT compiled */
|
||||
#define AMX_FLAG_BROWSE 0x4000 /* busy browsing */
|
||||
#define AMX_FLAG_RELOC 0x8000 /* jump/call addresses relocated */
|
||||
|
||||
#define AMX_EXEC_MAIN (-1) /* start at program entry point */
|
||||
#define AMX_EXEC_CONT (-2) /* continue from last address */
|
||||
|
||||
#define AMX_USERTAG(a,b,c,d) ((a) | ((b)<<8) | ((long)(c)<<16) | ((long)(d)<<24))
|
||||
|
||||
#if !defined AMX_COMPACTMARGIN
|
||||
#define AMX_COMPACTMARGIN 64
|
||||
#endif
|
||||
|
||||
/* for native functions that use floating point parameters, the following
|
||||
* two macros are convenient for casting a "cell" into a "float" type _without_
|
||||
* changing the bit pattern
|
||||
*/
|
||||
#if PAWN_CELL_SIZE==32
|
||||
#define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */
|
||||
#define amx_ctof(c) ( * ((float*)&c) ) /* cell to float */
|
||||
#elif PAWN_CELL_SIZE==64
|
||||
#define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */
|
||||
#define amx_ctof(c) ( * ((double*)&c) ) /* cell to float */
|
||||
#else
|
||||
#error Unsupported cell size
|
||||
#endif
|
||||
|
||||
#define amx_StrParam(amx,param,result) \
|
||||
do { \
|
||||
cell *amx_cstr_; int amx_length_; \
|
||||
amx_GetAddr((amx), (param), &amx_cstr_); \
|
||||
amx_StrLen(amx_cstr_, &amx_length_); \
|
||||
if (amx_length_ > 0 && \
|
||||
((result) = (void*)alloca((amx_length_ + 1) * sizeof(*(result)))) != NULL) \
|
||||
amx_GetString((char*)(result), amx_cstr_, sizeof(*(result))>1, amx_length_ + 1); \
|
||||
else (result) = NULL; \
|
||||
} while (0)
|
||||
|
||||
uint16_t * AMXAPI amx_Align16(uint16_t *v);
|
||||
uint32_t * AMXAPI amx_Align32(uint32_t *v);
|
||||
#if defined _I64_MAX || defined HAVE_I64
|
||||
uint64_t * AMXAPI amx_Align64(uint64_t *v);
|
||||
#endif
|
||||
int AMXAPI amx_Allot(AMX *amx, int cells, cell *amx_addr, cell **phys_addr);
|
||||
int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, const cell *params);
|
||||
int AMXAPI amx_Cleanup(AMX *amx);
|
||||
int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data);
|
||||
int AMXAPI amx_Exec(AMX *amx, cell *retval, int index);
|
||||
int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index);
|
||||
int AMXAPI amx_FindPublic(AMX *amx, const char *funcname, int *index);
|
||||
int AMXAPI amx_FindPubVar(AMX *amx, const char *varname, cell *amx_addr);
|
||||
int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname);
|
||||
int AMXAPI amx_Flags(AMX *amx,uint16_t *flags);
|
||||
int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr);
|
||||
int AMXAPI amx_GetNative(AMX *amx, int index, char *funcname);
|
||||
int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname);
|
||||
int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr);
|
||||
int AMXAPI amx_GetString(char *dest,const cell *source, int use_wchar, size_t size);
|
||||
int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id);
|
||||
int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr);
|
||||
int AMXAPI amx_Init(AMX *amx, void *program);
|
||||
int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code);
|
||||
int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap);
|
||||
int AMXAPI amx_NameLength(AMX *amx, int *length);
|
||||
AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func);
|
||||
int AMXAPI amx_NumNatives(AMX *amx, int *number);
|
||||
int AMXAPI amx_NumPublics(AMX *amx, int *number);
|
||||
int AMXAPI amx_NumPubVars(AMX *amx, int *number);
|
||||
int AMXAPI amx_NumTags(AMX *amx, int *number);
|
||||
int AMXAPI amx_Push(AMX *amx, cell value);
|
||||
int AMXAPI amx_PushArray(AMX *amx, cell *amx_addr, cell **phys_addr, const cell array[], int numcells);
|
||||
int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar);
|
||||
int AMXAPI amx_RaiseError(AMX *amx, int error);
|
||||
int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number);
|
||||
int AMXAPI amx_Release(AMX *amx, cell amx_addr);
|
||||
int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback);
|
||||
int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug);
|
||||
int AMXAPI amx_SetString(cell *dest, const char *source, int pack, int use_wchar, size_t size);
|
||||
int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr);
|
||||
int AMXAPI amx_StrLen(const cell *cstring, int *length);
|
||||
int AMXAPI amx_UTF8Check(const char *string, int *length);
|
||||
int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value);
|
||||
int AMXAPI amx_UTF8Len(const cell *cstr, int *length);
|
||||
int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value);
|
||||
|
||||
#if PAWN_CELL_SIZE==16
|
||||
#define amx_AlignCell(v) amx_Align16(v)
|
||||
#elif PAWN_CELL_SIZE==32
|
||||
#define amx_AlignCell(v) amx_Align32(v)
|
||||
#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64)
|
||||
#define amx_AlignCell(v) amx_Align64(v)
|
||||
#else
|
||||
#error Unsupported cell size
|
||||
#endif
|
||||
|
||||
#define amx_RegisterFunc(amx, name, func) \
|
||||
amx_Register((amx), amx_NativeInfo((name),(func)), 1);
|
||||
|
||||
#if !defined AMX_NO_ALIGN
|
||||
#if defined LINUX || defined __FreeBSD__
|
||||
#pragma pack() /* reset default packing */
|
||||
#elif defined MACOS && defined __MWERKS__
|
||||
#pragma options align=reset
|
||||
#else
|
||||
#pragma pack(pop) /* reset previous packing */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AMX_H_INCLUDED */
|
6
SOURCE/amx/amxDGram.def
Normal file
6
SOURCE/amx/amxDGram.def
Normal file
@ -0,0 +1,6 @@
|
||||
NAME amxDGram
|
||||
DESCRIPTION 'Pawn AMX: network datagram'
|
||||
|
||||
EXPORTS
|
||||
amx_DGramInit
|
||||
amx_DGramCleanup
|
54
SOURCE/amx/amxDGram.rc
Normal file
54
SOURCE/amx/amxDGram.rc
Normal file
@ -0,0 +1,54 @@
|
||||
#include <windows.h>
|
||||
#if defined WIN32 || defined _WIN32 || defined __WIN32__
|
||||
# include <winver.h>
|
||||
#else
|
||||
# include <ver.h>
|
||||
#endif
|
||||
|
||||
/* Version information
|
||||
*
|
||||
* All strings MUST have an explicit \0. See the Windows SDK documentation
|
||||
* for details on version information and the VERSIONINFO structure.
|
||||
*/
|
||||
#define VERSION 1
|
||||
#define REVISION 0
|
||||
#define BUILD 0
|
||||
#define VERSIONSTR "1.0.0\0"
|
||||
#define VERSIONNAME "amxDGram.dll\0"
|
||||
#define VERSIONDESCRIPTION "Pawn AMX: network datagram\0"
|
||||
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
|
||||
#define VERSIONPRODUCTNAME "amxDGram\0"
|
||||
#define VERSIONCOPYRIGHT "Copyright \251 2006 ITB CompuPhase\0"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION, REVISION, BUILD, 0
|
||||
PRODUCTVERSION VERSION, REVISION, BUILD, 0
|
||||
FILEFLAGSMASK 0x0000003FL
|
||||
FILEFLAGS 0
|
||||
#if defined(WIN32)
|
||||
FILEOS VOS__WINDOWS32
|
||||
#else
|
||||
FILEOS VOS__WINDOWS16
|
||||
#endif
|
||||
FILETYPE VFT_DLL
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", VERSIONCOMPANYNAME
|
||||
VALUE "FileDescription", VERSIONDESCRIPTION
|
||||
VALUE "FileVersion", VERSIONSTR
|
||||
VALUE "InternalName", VERSIONNAME
|
||||
VALUE "LegalCopyright", VERSIONCOPYRIGHT
|
||||
VALUE "OriginalFilename", VERSIONNAME
|
||||
VALUE "ProductName", VERSIONPRODUCTNAME
|
||||
VALUE "ProductVersion", VERSIONSTR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
54
SOURCE/amx/amxFile.rc
Normal file
54
SOURCE/amx/amxFile.rc
Normal file
@ -0,0 +1,54 @@
|
||||
#include <windows.h>
|
||||
#if defined WIN32 || defined _WIN32 || defined __WIN32__
|
||||
# include <winver.h>
|
||||
#else
|
||||
# include <ver.h>
|
||||
#endif
|
||||
|
||||
/* Version information
|
||||
*
|
||||
* All strings MUST have an explicit \0. See the Windows SDK documentation
|
||||
* for details on version information and the VERSIONINFO structure.
|
||||
*/
|
||||
#define VERSION 1
|
||||
#define REVISION 1
|
||||
#define BUILD 0
|
||||
#define VERSIONSTR "1.1.0\0"
|
||||
#define VERSIONNAME "amxFile.dll\0"
|
||||
#define VERSIONDESCRIPTION "Pawn AMX: File I/O support\0"
|
||||
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
|
||||
#define VERSIONPRODUCTNAME "amxFile\0"
|
||||
#define VERSIONCOPYRIGHT "Copyright \251 2004-2006 ITB CompuPhase\0"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION, REVISION, BUILD, 0
|
||||
PRODUCTVERSION VERSION, REVISION, BUILD, 0
|
||||
FILEFLAGSMASK 0x0000003FL
|
||||
FILEFLAGS 0
|
||||
#if defined(WIN32)
|
||||
FILEOS VOS__WINDOWS32
|
||||
#else
|
||||
FILEOS VOS__WINDOWS16
|
||||
#endif
|
||||
FILETYPE VFT_DLL
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", VERSIONCOMPANYNAME
|
||||
VALUE "FileDescription", VERSIONDESCRIPTION
|
||||
VALUE "FileVersion", VERSIONSTR
|
||||
VALUE "InternalName", VERSIONNAME
|
||||
VALUE "LegalCopyright", VERSIONCOPYRIGHT
|
||||
VALUE "OriginalFilename", VERSIONNAME
|
||||
VALUE "ProductName", VERSIONPRODUCTNAME
|
||||
VALUE "ProductVersion", VERSIONSTR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
6
SOURCE/amx/amxFixed.def
Normal file
6
SOURCE/amx/amxFixed.def
Normal file
@ -0,0 +1,6 @@
|
||||
NAME amxFixed
|
||||
DESCRIPTION 'Pawn AMX: fixed-point arithmetic'
|
||||
|
||||
EXPORTS
|
||||
amx_FixedInit
|
||||
amx_FixedCleanup
|
54
SOURCE/amx/amxFixed.rc
Normal file
54
SOURCE/amx/amxFixed.rc
Normal file
@ -0,0 +1,54 @@
|
||||
#include <windows.h>
|
||||
#if defined WIN32 || defined _WIN32 || defined __WIN32__
|
||||
# include <winver.h>
|
||||
#else
|
||||
# include <ver.h>
|
||||
#endif
|
||||
|
||||
/* Version information
|
||||
*
|
||||
* All strings MUST have an explicit \0. See the Windows SDK documentation
|
||||
* for details on version information and the VERSIONINFO structure.
|
||||
*/
|
||||
#define VERSION 1
|
||||
#define REVISION 0
|
||||
#define BUILD 0
|
||||
#define VERSIONSTR "1.0.0\0"
|
||||
#define VERSIONNAME "amxFixed.dll\0"
|
||||
#define VERSIONDESCRIPTION "Pawn AMX: Fixed Point support\0"
|
||||
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
|
||||
#define VERSIONPRODUCTNAME "amxFixed\0"
|
||||
#define VERSIONCOPYRIGHT "Copyright \251 2003-2006 ITB CompuPhase\0"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION, REVISION, BUILD, 0
|
||||
PRODUCTVERSION VERSION, REVISION, BUILD, 0
|
||||
FILEFLAGSMASK 0x0000003FL
|
||||
FILEFLAGS 0
|
||||
#if defined(WIN32)
|
||||
FILEOS VOS__WINDOWS32
|
||||
#else
|
||||
FILEOS VOS__WINDOWS16
|
||||
#endif
|
||||
FILETYPE VFT_DLL
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", VERSIONCOMPANYNAME
|
||||
VALUE "FileDescription", VERSIONDESCRIPTION
|
||||
VALUE "FileVersion", VERSIONSTR
|
||||
VALUE "InternalName", VERSIONNAME
|
||||
VALUE "LegalCopyright", VERSIONCOPYRIGHT
|
||||
VALUE "OriginalFilename", VERSIONNAME
|
||||
VALUE "ProductName", VERSIONPRODUCTNAME
|
||||
VALUE "ProductVersion", VERSIONSTR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
6
SOURCE/amx/amxFloat.def
Normal file
6
SOURCE/amx/amxFloat.def
Normal file
@ -0,0 +1,6 @@
|
||||
NAME amxFloat
|
||||
DESCRIPTION 'Pawn AMX: floating-point arithmetic'
|
||||
|
||||
EXPORTS
|
||||
amx_FloatInit
|
||||
amx_FloatCleanup
|
54
SOURCE/amx/amxFloat.rc
Normal file
54
SOURCE/amx/amxFloat.rc
Normal file
@ -0,0 +1,54 @@
|
||||
#include <windows.h>
|
||||
#if defined WIN32 || defined _WIN32 || defined __WIN32__
|
||||
# include <winver.h>
|
||||
#else
|
||||
# include <ver.h>
|
||||
#endif
|
||||
|
||||
/* Version information
|
||||
*
|
||||
* All strings MUST have an explicit \0. See the Windows SDK documentation
|
||||
* for details on version information and the VERSIONINFO structure.
|
||||
*/
|
||||
#define VERSION 1
|
||||
#define REVISION 0
|
||||
#define BUILD 0
|
||||
#define VERSIONSTR "1.0.0\0"
|
||||
#define VERSIONNAME "amxFloat.dll\0"
|
||||
#define VERSIONDESCRIPTION "Pawn AMX: Floating Point support\0"
|
||||
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
|
||||
#define VERSIONPRODUCTNAME "amxFloat\0"
|
||||
#define VERSIONCOPYRIGHT "Copyright \251 2003-2006 ITB CompuPhase\0"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION, REVISION, BUILD, 0
|
||||
PRODUCTVERSION VERSION, REVISION, BUILD, 0
|
||||
FILEFLAGSMASK 0x0000003FL
|
||||
FILEFLAGS 0
|
||||
#if defined(WIN32)
|
||||
FILEOS VOS__WINDOWS32
|
||||
#else
|
||||
FILEOS VOS__WINDOWS16
|
||||
#endif
|
||||
FILETYPE VFT_DLL
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", VERSIONCOMPANYNAME
|
||||
VALUE "FileDescription", VERSIONDESCRIPTION
|
||||
VALUE "FileVersion", VERSIONSTR
|
||||
VALUE "InternalName", VERSIONNAME
|
||||
VALUE "LegalCopyright", VERSIONCOPYRIGHT
|
||||
VALUE "OriginalFilename", VERSIONNAME
|
||||
VALUE "ProductName", VERSIONPRODUCTNAME
|
||||
VALUE "ProductVersion", VERSIONSTR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
6
SOURCE/amx/amxProcess.def
Normal file
6
SOURCE/amx/amxProcess.def
Normal file
@ -0,0 +1,6 @@
|
||||
NAME amxProcess
|
||||
DESCRIPTION 'Pawn AMX: process control and foreign function interface'
|
||||
|
||||
EXPORTS
|
||||
amx_ProcessInit
|
||||
amx_ProcessCleanup
|
54
SOURCE/amx/amxProcess.rc
Normal file
54
SOURCE/amx/amxProcess.rc
Normal file
@ -0,0 +1,54 @@
|
||||
#include <windows.h>
|
||||
#if defined WIN32 || defined _WIN32 || defined __WIN32__
|
||||
# include <winver.h>
|
||||
#else
|
||||
# include <ver.h>
|
||||
#endif
|
||||
|
||||
/* Version information
|
||||
*
|
||||
* All strings MUST have an explicit \0. See the Windows SDK documentation
|
||||
* for details on version information and the VERSIONINFO structure.
|
||||
*/
|
||||
#define VERSION 1
|
||||
#define REVISION 0
|
||||
#define BUILD 0
|
||||
#define VERSIONSTR "1.0.0\0"
|
||||
#define VERSIONNAME "amxProcess.dll\0"
|
||||
#define VERSIONDESCRIPTION "Pawn AMX: process control and foreign function interface\0"
|
||||
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
|
||||
#define VERSIONPRODUCTNAME "amxProcess\0"
|
||||
#define VERSIONCOPYRIGHT "Copyright \251 2005-2006 ITB CompuPhase\0"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION, REVISION, BUILD, 0
|
||||
PRODUCTVERSION VERSION, REVISION, BUILD, 0
|
||||
FILEFLAGSMASK 0x0000003FL
|
||||
FILEFLAGS 0
|
||||
#if defined(WIN32)
|
||||
FILEOS VOS__WINDOWS32
|
||||
#else
|
||||
FILEOS VOS__WINDOWS16
|
||||
#endif
|
||||
FILETYPE VFT_DLL
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", VERSIONCOMPANYNAME
|
||||
VALUE "FileDescription", VERSIONDESCRIPTION
|
||||
VALUE "FileVersion", VERSIONSTR
|
||||
VALUE "InternalName", VERSIONNAME
|
||||
VALUE "LegalCopyright", VERSIONCOPYRIGHT
|
||||
VALUE "OriginalFilename", VERSIONNAME
|
||||
VALUE "ProductName", VERSIONPRODUCTNAME
|
||||
VALUE "ProductVersion", VERSIONSTR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
401
SOURCE/amx/amxargs.c
Normal file
401
SOURCE/amx/amxargs.c
Normal file
@ -0,0 +1,401 @@
|
||||
/* Script Arguments support module for the Pawn Abstract Machine
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2005-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxargs.c 3649 2006-10-12 13:13:57Z thiadmer $
|
||||
*/
|
||||
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
|
||||
# if !defined UNICODE /* for Windows */
|
||||
# define UNICODE
|
||||
# endif
|
||||
# if !defined _UNICODE /* for C library */
|
||||
# define _UNICODE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include "osdefs.h"
|
||||
#include "amx.h"
|
||||
|
||||
#if defined _UNICODE
|
||||
# include <tchar.h>
|
||||
#elif !defined __T
|
||||
typedef char TCHAR;
|
||||
# define __T(string) string
|
||||
# define _istdigit isdigit
|
||||
# define _tgetenv getenv
|
||||
# define _tcscat strcat
|
||||
# define _tcschr strchr
|
||||
# define _tcscpy strcpy
|
||||
# define _tcsdup strdup
|
||||
# define _tcslen strlen
|
||||
# define _tcsncmp strncmp
|
||||
# define _tcspbrk strpbrk
|
||||
# define _tcsrchr strrchr
|
||||
# define _tcstol strtol
|
||||
#endif
|
||||
|
||||
#if !defined AMXARGS_COLON
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
|
||||
/* A ':' is also a separator for filenames (the disk drive identifier), and
|
||||
* therefore it is better not to use it as an name/value seperator for
|
||||
* command line argiments as well. So, by default, the library uses only
|
||||
* the '=' as the name/value separator.
|
||||
*/
|
||||
#define AMXARGS_COLON 0
|
||||
#else
|
||||
#define AMXARGS_COLON 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined AMXARGS_SKIPARG
|
||||
/* The first option may be the name of the script (this is common if the
|
||||
* host application takes the name of the script as the first parameter).
|
||||
* This can optionally be ignored.
|
||||
*/
|
||||
#define AMXARGS_SKIPARG 0
|
||||
#endif
|
||||
|
||||
|
||||
static const TCHAR *tokenize(const TCHAR *string, int index, int *length);
|
||||
static const TCHAR *cmdline = NULL;
|
||||
|
||||
static const TCHAR *rawcmdline(void)
|
||||
{
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
#elif defined _Windows || defined __MSDOS__
|
||||
static char cmdbuffer[128];
|
||||
#elif defined LINUX
|
||||
static char cmdbuffer[1024]; /* some arbitrary maximum */
|
||||
#endif
|
||||
const TCHAR *ptr;
|
||||
int skip = 0;
|
||||
|
||||
if (cmdline == NULL) {
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
cmdline = GetCommandLine();
|
||||
skip++;
|
||||
#elif defined _Windows || defined __MSDOS__
|
||||
#if defined _Windows
|
||||
unsigned short _psp = GetCurrentPDB();
|
||||
#endif
|
||||
char _far *cmd = (char _far *)MK_FP(_psp, 128);
|
||||
unsigned char length = (unsigned char)*cmd++;
|
||||
assert(length < 128);
|
||||
assert(length < sizeof cmdbuffer);
|
||||
memcpy(cmdbuffer, cmd, length);
|
||||
cmdbuffer[length] = '\0';
|
||||
if ((cmd == strchr(cmdbuffer, '\r')) != NULL)
|
||||
*cmd = '\0'; /* also erase \r after the last option (if any) */
|
||||
cmdline = cmdbuffer;
|
||||
#elif defined LINUX
|
||||
/* Options in /proc/<pid>/cmdline are delimited with '\0' characters
|
||||
* rather than spaces.
|
||||
*/
|
||||
FILE *fp;
|
||||
size_t fsize;
|
||||
sprintf(cmdbuffer, "/proc/%d/cmdline", getpid());
|
||||
if ((fp = fopen(cmdbuffer, "r")) != NULL) {
|
||||
char *ptr;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fsize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
if (fsize >= sizeof cmdbuffer)
|
||||
fsize = sizeof cmdbuffer - 1;
|
||||
fread(cmdbuffer, 1, fsize, fp);
|
||||
fclose(fp);
|
||||
cmdbuffer[fsize] = '\0'; /* terminate with double-zero */
|
||||
// ??? convert to Unicode
|
||||
/* convert '\0' characters to spaces, for uniform parsing */
|
||||
for (ptr = cmdbuffer; *ptr != ' '; ptr = strchr(ptr, '\0') + 1)
|
||||
*ptr = ' ';
|
||||
cmdline = cmdbuffer;
|
||||
skip++;
|
||||
} /* if */
|
||||
#else
|
||||
#error Platform not supported
|
||||
#endif
|
||||
|
||||
/* skip leading white space */
|
||||
while (*cmdline <= __T(' ') && *cmdline != __T('\0'))
|
||||
cmdline++;
|
||||
|
||||
#if AMXARGS_SKIPARG
|
||||
skip++;
|
||||
#endif
|
||||
/* skip the first option(s), because it is the name of the host program
|
||||
* and the name of the script
|
||||
*/
|
||||
if ((ptr = tokenize(cmdline, skip, NULL)) != NULL)
|
||||
cmdline = ptr;
|
||||
else
|
||||
cmdline = _tcschr(cmdline, __T('\0'));
|
||||
|
||||
} /* if */
|
||||
|
||||
return cmdline;
|
||||
}
|
||||
|
||||
static const TCHAR *tokenize(const TCHAR *string, int index, int *length)
|
||||
{
|
||||
const TCHAR *start = string;
|
||||
TCHAR endchar;
|
||||
assert(index >= 0);
|
||||
assert(start != NULL);
|
||||
while (*start == __T(' ') || *start == __T('\t'))
|
||||
start++;
|
||||
if (*start == __T('\0'))
|
||||
return NULL;
|
||||
if (*start == __T('"'))
|
||||
endchar = *start++;
|
||||
else
|
||||
endchar = __T(' ');
|
||||
while (index > 0 && start != NULL) {
|
||||
start = _tcschr(start, endchar);
|
||||
if (start != NULL) {
|
||||
assert(*start == endchar);
|
||||
if (endchar != __T(' '))
|
||||
start++;
|
||||
while (*start == __T(' ') || *start == __T('\t'))
|
||||
start++;
|
||||
if (*start == __T('"'))
|
||||
endchar = *start++;
|
||||
else
|
||||
endchar = __T(' ');
|
||||
} /* if */
|
||||
index--;
|
||||
} /* while */
|
||||
if (start != NULL && length != NULL) {
|
||||
const TCHAR *end;
|
||||
if ((end = _tcschr(start, endchar)) == NULL)
|
||||
end = _tcschr(start, __T('\0'));
|
||||
assert(end != NULL);
|
||||
*length = (int)(end - start);
|
||||
} /* if */
|
||||
return start;
|
||||
}
|
||||
|
||||
static const TCHAR *matcharg(const TCHAR *key, int skip, int *length)
|
||||
{
|
||||
const TCHAR *cmdline = rawcmdline();
|
||||
int index, optlen, keylen;
|
||||
const TCHAR *option, *vptr;
|
||||
|
||||
keylen = (key != NULL) ? _tcslen(key) : 0;
|
||||
index = 0;
|
||||
while ((option = tokenize(cmdline, index, length)) != NULL) {
|
||||
/* check for a colon or an equal sign (':' or '=') */
|
||||
vptr = _tcschr(option, __T('='));
|
||||
#if AMXARGS_COLON
|
||||
if (vptr == NULL || (int)(vptr - option) > *length)
|
||||
vptr = _tcschr(option, __T(':'));
|
||||
#endif
|
||||
if (vptr != NULL && (int)(vptr - option) > *length)
|
||||
vptr = NULL;
|
||||
optlen = (vptr != NULL) ? (int)(vptr - option) : 0;
|
||||
if (keylen == 0 && vptr == NULL
|
||||
|| keylen > 0 && keylen == optlen && _tcsncmp(option, key, optlen) == 0)
|
||||
{
|
||||
if (vptr != NULL)
|
||||
optlen++; /* if ':' or '=' was found, skip it too */
|
||||
option += optlen; /* point behind option */
|
||||
*length -= optlen; /* length of the value, not of the option */
|
||||
assert(length >= 0);
|
||||
if (skip-- == 0)
|
||||
break;
|
||||
} /* if */
|
||||
index++;
|
||||
} /* while */
|
||||
return option;
|
||||
}
|
||||
|
||||
|
||||
/* bool: argindex(index, value[], maxlength=sizeof value, bool:pack=false)
|
||||
* returns true if the option was found and false on error or if the parameter "index" is out of range
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_argindex(AMX *amx, const cell *params)
|
||||
{
|
||||
const TCHAR *cmdline = rawcmdline();
|
||||
const TCHAR *option;
|
||||
int length, max;
|
||||
TCHAR *str;
|
||||
cell *cptr;
|
||||
|
||||
max = (int)params[3];
|
||||
if (max <= 0)
|
||||
return 0;
|
||||
amx_GetAddr(amx, params[2], &cptr);
|
||||
if (cptr == NULL) {
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
if ((option = tokenize(cmdline, params[1], &length)) == NULL) {
|
||||
/* option not found, return an empty string */
|
||||
*cptr = 0;
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
if (params[4])
|
||||
max *= sizeof(cell);
|
||||
if (max > length + 1)
|
||||
max = length + 1;
|
||||
str = (TCHAR *)alloca(max*sizeof(TCHAR));
|
||||
if (str == NULL) {
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
memcpy(str, option, (max - 1) * sizeof(TCHAR));
|
||||
str[max - 1] = __T('\0');
|
||||
amx_SetString(cptr, (char*)str, (int)params[4], sizeof(TCHAR)>1, max);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* bool: argstr(index=0, const option[]="", value[]="", maxlength=sizeof value, bool:pack=false)
|
||||
* returns true if the option was found and false otherwise
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_argstr(AMX *amx, const cell *params)
|
||||
{
|
||||
const TCHAR *option, *key;
|
||||
int length, max;
|
||||
TCHAR *str;
|
||||
cell *cptr;
|
||||
|
||||
max = (int)params[4];
|
||||
if (max <= 0)
|
||||
return 0;
|
||||
amx_StrParam(amx, params[2], key);
|
||||
amx_GetAddr(amx, params[3], &cptr);
|
||||
if (cptr == NULL) {
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
option = matcharg(key, (int)params[1], &length);
|
||||
if (option == NULL)
|
||||
return 0; /* option not found */
|
||||
|
||||
/* check whether we must write the value of the option at all; in case the
|
||||
* size is one cell and that cell is already zero, we do not write anything
|
||||
* back
|
||||
*/
|
||||
assert(params[4] > 0);
|
||||
if (params[4] > 1 || *cptr != 0) {
|
||||
if (params[5])
|
||||
max *= sizeof(cell);
|
||||
if (max > length + 1)
|
||||
max = length + 1;
|
||||
str = (TCHAR *)alloca(max*sizeof(TCHAR));
|
||||
if (str == NULL) {
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
memcpy(str, option, (max - 1) * sizeof(TCHAR));
|
||||
str[max - 1] = __T('\0');
|
||||
amx_SetString(cptr, (char*)str, (int)params[5], sizeof(TCHAR)>1, max);
|
||||
} /* if */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* bool: argvalue(index=0, const option[]="", &value=cellmin)
|
||||
* returns true if the option was found and false otherwise
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_argvalue(AMX *amx, const cell *params)
|
||||
{
|
||||
const TCHAR *option, *key;
|
||||
int length;
|
||||
cell *cptr;
|
||||
|
||||
amx_StrParam(amx, params[2], key);
|
||||
amx_GetAddr(amx, params[3], &cptr);
|
||||
if (cptr == NULL) {
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
option = matcharg(key, (int)params[1], &length);
|
||||
if (option == NULL)
|
||||
return 0;
|
||||
|
||||
/* check whether we must write the value of the option at all */
|
||||
if (length > 0 && (_istdigit(*option) || *option == __T('-')))
|
||||
*cptr = _tcstol(option, NULL, 10);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* argcount() */
|
||||
static cell AMX_NATIVE_CALL n_argcount(AMX *amx, const cell *params)
|
||||
{
|
||||
const TCHAR *cmdline = rawcmdline();
|
||||
cell count = 0;
|
||||
while (tokenize(cmdline, count, NULL) != NULL)
|
||||
count++;
|
||||
(void)amx;
|
||||
(void)params;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
const AMX_NATIVE_INFO args_Natives[] = {
|
||||
{ "argcount", n_argcount },
|
||||
{ "argindex", n_argindex },
|
||||
{ "argstr", n_argstr },
|
||||
{ "argvalue", n_argvalue },
|
||||
{ NULL, NULL } /* terminator */
|
||||
};
|
||||
|
||||
int AMXEXPORT amx_ArgsInit(AMX *amx)
|
||||
{
|
||||
return amx_Register(amx, args_Natives, -1);
|
||||
}
|
||||
|
||||
int AMXEXPORT amx_ArgsCleanup(AMX *amx)
|
||||
{
|
||||
(void)amx;
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
/* A host application calls this function to set the command line for the
|
||||
* script. If the host does not do this, the library will use the global
|
||||
* options for the application (provided that it can find these). The buffer
|
||||
* that is passed in to this function is NOT copied, so it may not be freed
|
||||
* after the call.
|
||||
*/
|
||||
int AMXEXPORT amx_ArgsSetCmdLine(const TCHAR *cmd)
|
||||
{
|
||||
cmdline = cmd;
|
||||
return AMX_ERR_NONE;
|
||||
}
|
54
SOURCE/amx/amxargs.rc
Normal file
54
SOURCE/amx/amxargs.rc
Normal file
@ -0,0 +1,54 @@
|
||||
#include <windows.h>
|
||||
#if defined WIN32 || defined _WIN32 || defined __WIN32__
|
||||
# include <winver.h>
|
||||
#else
|
||||
# include <ver.h>
|
||||
#endif
|
||||
|
||||
/* Version information
|
||||
*
|
||||
* All strings MUST have an explicit \0. See the Windows SDK documentation
|
||||
* for details on version information and the VERSIONINFO structure.
|
||||
*/
|
||||
#define VERSION 1
|
||||
#define REVISION 0
|
||||
#define BUILD 0
|
||||
#define VERSIONSTR "1.0.0\0"
|
||||
#define VERSIONNAME "amxArgs.dll\0"
|
||||
#define VERSIONDESCRIPTION "Pawn AMX: Script Arguments support\0"
|
||||
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
|
||||
#define VERSIONPRODUCTNAME "amxArgs\0"
|
||||
#define VERSIONCOPYRIGHT "Copyright \251 2005-2006 ITB CompuPhase\0"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION, REVISION, BUILD, 0
|
||||
PRODUCTVERSION VERSION, REVISION, BUILD, 0
|
||||
FILEFLAGSMASK 0x0000003FL
|
||||
FILEFLAGS 0
|
||||
#if defined(WIN32)
|
||||
FILEOS VOS__WINDOWS32
|
||||
#else
|
||||
FILEOS VOS__WINDOWS16
|
||||
#endif
|
||||
FILETYPE VFT_DLL
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", VERSIONCOMPANYNAME
|
||||
VALUE "FileDescription", VERSIONDESCRIPTION
|
||||
VALUE "FileVersion", VERSIONSTR
|
||||
VALUE "InternalName", VERSIONNAME
|
||||
VALUE "LegalCopyright", VERSIONCOPYRIGHT
|
||||
VALUE "OriginalFilename", VERSIONNAME
|
||||
VALUE "ProductName", VERSIONPRODUCTNAME
|
||||
VALUE "ProductVersion", VERSIONSTR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
167
SOURCE/amx/amxaux.c
Normal file
167
SOURCE/amx/amxaux.c
Normal file
@ -0,0 +1,167 @@
|
||||
/* Support routines for the Pawn Abstract Machine
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2003-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxaux.c 3612 2006-07-22 09:59:46Z thiadmer $
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "amx.h"
|
||||
#include "amxaux.h"
|
||||
|
||||
size_t AMXAPI aux_ProgramSize(char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
AMX_HEADER hdr;
|
||||
|
||||
if ((fp=fopen(filename,"rb")) == NULL)
|
||||
return 0;
|
||||
fread(&hdr, sizeof hdr, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
amx_Align16(&hdr.magic);
|
||||
amx_Align32((uint32_t *)&hdr.stp);
|
||||
return (hdr.magic==AMX_MAGIC) ? (size_t)hdr.stp : 0;
|
||||
}
|
||||
|
||||
int AMXAPI aux_LoadProgram(AMX *amx, char *filename, void *memblock)
|
||||
{
|
||||
FILE *fp;
|
||||
AMX_HEADER hdr;
|
||||
int result, didalloc;
|
||||
|
||||
/* open the file, read and check the header */
|
||||
if ((fp = fopen(filename, "rb")) == NULL)
|
||||
return AMX_ERR_NOTFOUND;
|
||||
fread(&hdr, sizeof hdr, 1, fp);
|
||||
amx_Align16(&hdr.magic);
|
||||
amx_Align32((uint32_t *)&hdr.size);
|
||||
amx_Align32((uint32_t *)&hdr.stp);
|
||||
if (hdr.magic != AMX_MAGIC) {
|
||||
fclose(fp);
|
||||
return AMX_ERR_FORMAT;
|
||||
} /* if */
|
||||
|
||||
/* allocate the memblock if it is NULL */
|
||||
didalloc = 0;
|
||||
if (memblock == NULL) {
|
||||
if ((memblock = malloc(hdr.stp)) == NULL) {
|
||||
fclose(fp);
|
||||
return AMX_ERR_MEMORY;
|
||||
} /* if */
|
||||
didalloc = 1;
|
||||
/* after amx_Init(), amx->base points to the memory block */
|
||||
} /* if */
|
||||
|
||||
/* read in the file */
|
||||
rewind(fp);
|
||||
fread(memblock, 1, (size_t)hdr.size, fp);
|
||||
fclose(fp);
|
||||
|
||||
/* initialize the abstract machine */
|
||||
memset(amx, 0, sizeof *amx);
|
||||
result = amx_Init(amx, memblock);
|
||||
|
||||
/* free the memory block on error, if it was allocated here */
|
||||
if (result != AMX_ERR_NONE && didalloc) {
|
||||
free(memblock);
|
||||
amx->base = NULL; /* avoid a double free */
|
||||
} /* if */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int AMXAPI aux_FreeProgram(AMX *amx)
|
||||
{
|
||||
if (amx->base!=NULL) {
|
||||
amx_Cleanup(amx);
|
||||
free(amx->base);
|
||||
memset(amx,0,sizeof(AMX));
|
||||
} /* if */
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
char * AMXAPI aux_StrError(int errnum)
|
||||
{
|
||||
static char *messages[] = {
|
||||
/* AMX_ERR_NONE */ "(none)",
|
||||
/* AMX_ERR_EXIT */ "Forced exit",
|
||||
/* AMX_ERR_ASSERT */ "Assertion failed",
|
||||
/* AMX_ERR_STACKERR */ "Stack/heap collision (insufficient stack size)",
|
||||
/* AMX_ERR_BOUNDS */ "Array index out of bounds",
|
||||
/* AMX_ERR_MEMACCESS */ "Invalid memory access",
|
||||
/* AMX_ERR_INVINSTR */ "Invalid instruction",
|
||||
/* AMX_ERR_STACKLOW */ "Stack underflow",
|
||||
/* AMX_ERR_HEAPLOW */ "Heap underflow",
|
||||
/* AMX_ERR_CALLBACK */ "No (valid) native function callback",
|
||||
/* AMX_ERR_NATIVE */ "Native function failed",
|
||||
/* AMX_ERR_DIVIDE */ "Divide by zero",
|
||||
/* AMX_ERR_SLEEP */ "(sleep mode)",
|
||||
/* 13 */ "(reserved)",
|
||||
/* 14 */ "(reserved)",
|
||||
/* 15 */ "(reserved)",
|
||||
/* AMX_ERR_MEMORY */ "Out of memory",
|
||||
/* AMX_ERR_FORMAT */ "Invalid/unsupported P-code file format",
|
||||
/* AMX_ERR_VERSION */ "File is for a newer version of the AMX",
|
||||
/* AMX_ERR_NOTFOUND */ "File or function is not found",
|
||||
/* AMX_ERR_INDEX */ "Invalid index parameter (bad entry point)",
|
||||
/* AMX_ERR_DEBUG */ "Debugger cannot run",
|
||||
/* AMX_ERR_INIT */ "AMX not initialized (or doubly initialized)",
|
||||
/* AMX_ERR_USERDATA */ "Unable to set user data field (table full)",
|
||||
/* AMX_ERR_INIT_JIT */ "Cannot initialize the JIT",
|
||||
/* AMX_ERR_PARAMS */ "Parameter error",
|
||||
/* AMX_ERR_DOMAIN */ "Domain error, expression result does not fit in range",
|
||||
/* AMX_ERR_GENERAL */ "General error (unknown or unspecific error)",
|
||||
};
|
||||
if (errnum < 0 || errnum >= sizeof messages / sizeof messages[0])
|
||||
return "(unknown)";
|
||||
return messages[errnum];
|
||||
}
|
||||
|
||||
int AMXAPI aux_GetSection(AMX *amx, int section, cell **start, size_t *size)
|
||||
{
|
||||
AMX_HEADER *hdr;
|
||||
|
||||
if (amx == NULL || start == NULL || size == NULL)
|
||||
return AMX_ERR_PARAMS;
|
||||
|
||||
hdr = (AMX_HEADER*)amx->base;
|
||||
switch(section) {
|
||||
case CODE_SECTION:
|
||||
*start = (cell *)(amx->base + hdr->cod);
|
||||
*size = hdr->dat - hdr->cod;
|
||||
break;
|
||||
case DATA_SECTION:
|
||||
*start = (cell *)(amx->data);
|
||||
*size = hdr->hea - hdr->dat;
|
||||
break;
|
||||
case HEAP_SECTION:
|
||||
*start = (cell *)(amx->data + hdr->hea);
|
||||
*size = amx->hea - hdr->hea;
|
||||
break;
|
||||
case STACK_SECTION:
|
||||
*start = (cell *)(amx->data + amx->stk);
|
||||
*size = amx->stp - amx->stk;
|
||||
break;
|
||||
default:
|
||||
return AMX_ERR_PARAMS;
|
||||
} /* switch */
|
||||
return AMX_ERR_NONE;
|
||||
}
|
54
SOURCE/amx/amxaux.h
Normal file
54
SOURCE/amx/amxaux.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* Support routines for the Pawn Abstract Machine
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2003-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxaux.h 3612 2006-07-22 09:59:46Z thiadmer $
|
||||
*/
|
||||
#ifndef AMXAUX_H_INCLUDED
|
||||
#define AMXAUX_H_INCLUDED
|
||||
|
||||
#include "amx.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* loading and freeing programs */
|
||||
size_t AMXAPI aux_ProgramSize(char *filename);
|
||||
int AMXAPI aux_LoadProgram(AMX *amx, char *filename, void *memblock);
|
||||
int AMXAPI aux_FreeProgram(AMX *amx);
|
||||
|
||||
/* a readable error message from an error code */
|
||||
char * AMXAPI aux_StrError(int errnum);
|
||||
|
||||
enum {
|
||||
CODE_SECTION,
|
||||
DATA_SECTION,
|
||||
HEAP_SECTION,
|
||||
STACK_SECTION,
|
||||
/* ----- */
|
||||
NUM_SECTIONS
|
||||
};
|
||||
int AMXAPI aux_GetSection(AMX *amx, int section, cell **start, size_t *size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AMXAUX_H_INCLUDED */
|
1266
SOURCE/amx/amxcons.c
Normal file
1266
SOURCE/amx/amxcons.c
Normal file
File diff suppressed because it is too large
Load Diff
17
SOURCE/amx/amxcons.h
Normal file
17
SOURCE/amx/amxcons.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef AMXCONS_H_INCLUDED
|
||||
#define AMXCONS_H_INCLUDED
|
||||
|
||||
typedef struct tagFMTINFO {
|
||||
const cell *params;
|
||||
int numparams;
|
||||
int skip; /* number of characters to skip from the beginning */
|
||||
int length; /* number of characters to print */
|
||||
/* helper functions */
|
||||
int (*f_putstr)(void *dest,const TCHAR *);
|
||||
int (*f_putchar)(void *dest,TCHAR);
|
||||
void *user; /* user data */
|
||||
} AMX_FMTINFO;
|
||||
|
||||
int amx_printstring(AMX *amx,cell *cstr,AMX_FMTINFO *info);
|
||||
|
||||
#endif /* AMXCONS_H_INCLUDED */
|
514
SOURCE/amx/amxcore.c
Normal file
514
SOURCE/amx/amxcore.c
Normal file
@ -0,0 +1,514 @@
|
||||
/* Core module for the Pawn AMX
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 1997-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxcore.c 3657 2006-10-24 20:09:50Z thiadmer $
|
||||
*/
|
||||
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
|
||||
# if !defined UNICODE /* for Windows */
|
||||
# define UNICODE
|
||||
# endif
|
||||
# if !defined _UNICODE /* for C library */
|
||||
# define _UNICODE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include "amx.h"
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* A few compilers do not provide the ANSI C standard "time" functions */
|
||||
#if !defined SN_TARGET_PS2 && !defined _WIN32_WCE && !defined __ICC430__
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined _UNICODE
|
||||
# include <tchar.h>
|
||||
#elif !defined __T
|
||||
typedef char TCHAR;
|
||||
# define __T(string) string
|
||||
# define _tcschr strchr
|
||||
# define _tcscpy strcpy
|
||||
# define _tcsdup strdup
|
||||
# define _tcslen strlen
|
||||
#endif
|
||||
|
||||
|
||||
#define CHARBITS (8*sizeof(char))
|
||||
typedef unsigned char uchar;
|
||||
|
||||
#if !defined AMX_NOPROPLIST
|
||||
typedef struct _property_list {
|
||||
struct _property_list *next;
|
||||
cell id;
|
||||
char *name;
|
||||
cell value;
|
||||
} proplist;
|
||||
|
||||
static proplist proproot = { NULL, 0, NULL, 0 };
|
||||
|
||||
static proplist *list_additem(proplist *root)
|
||||
{
|
||||
proplist *item;
|
||||
|
||||
assert(root!=NULL);
|
||||
if ((item=(proplist *)malloc(sizeof(proplist)))==NULL)
|
||||
return NULL;
|
||||
item->name=NULL;
|
||||
item->id=0;
|
||||
item->value=0;
|
||||
item->next=root->next;
|
||||
root->next=item;
|
||||
return item;
|
||||
}
|
||||
static void list_delete(proplist *pred,proplist *item)
|
||||
{
|
||||
assert(pred!=NULL);
|
||||
assert(item!=NULL);
|
||||
pred->next=item->next;
|
||||
assert(item->name!=NULL);
|
||||
free(item->name);
|
||||
free(item);
|
||||
}
|
||||
static void list_setitem(proplist *item,cell id,char *name,cell value)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
assert(item!=NULL);
|
||||
if ((ptr=(char *)malloc(strlen(name)+1))==NULL)
|
||||
return;
|
||||
if (item->name!=NULL)
|
||||
free(item->name);
|
||||
strcpy(ptr,name);
|
||||
item->name=ptr;
|
||||
item->id=id;
|
||||
item->value=value;
|
||||
}
|
||||
static proplist *list_finditem(proplist *root,cell id,char *name,cell value,
|
||||
proplist **pred)
|
||||
{
|
||||
proplist *item=root->next;
|
||||
proplist *prev=root;
|
||||
|
||||
/* check whether to find by name or by value */
|
||||
assert(name!=NULL);
|
||||
if (strlen(name)>0) {
|
||||
/* find by name */
|
||||
while (item!=NULL && (item->id!=id || stricmp(item->name,name)!=0)) {
|
||||
prev=item;
|
||||
item=item->next;
|
||||
} /* while */
|
||||
} else {
|
||||
/* find by value */
|
||||
while (item!=NULL && (item->id!=id || item->value!=value)) {
|
||||
prev=item;
|
||||
item=item->next;
|
||||
} /* while */
|
||||
} /* if */
|
||||
if (pred!=NULL)
|
||||
*pred=prev;
|
||||
return item;
|
||||
}
|
||||
#endif
|
||||
|
||||
static cell AMX_NATIVE_CALL numargs(AMX *amx,const cell *params)
|
||||
{
|
||||
AMX_HEADER *hdr;
|
||||
uchar *data;
|
||||
cell bytes;
|
||||
|
||||
(void)params;
|
||||
hdr=(AMX_HEADER *)amx->base;
|
||||
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
|
||||
/* the number of bytes is on the stack, at "frm + 2*cell" */
|
||||
bytes= * (cell *)(data+(int)amx->frm+2*sizeof(cell));
|
||||
/* the number of arguments is the number of bytes divided
|
||||
* by the size of a cell */
|
||||
return bytes/sizeof(cell);
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL getarg(AMX *amx,const cell *params)
|
||||
{
|
||||
AMX_HEADER *hdr;
|
||||
uchar *data;
|
||||
cell value;
|
||||
|
||||
hdr=(AMX_HEADER *)amx->base;
|
||||
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
|
||||
/* get the base value */
|
||||
value= * (cell *)(data+(int)amx->frm+((int)params[1]+3)*sizeof(cell));
|
||||
/* adjust the address in "value" in case of an array access */
|
||||
value+=params[2]*sizeof(cell);
|
||||
/* get the value indirectly */
|
||||
value= * (cell *)(data+(int)value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL setarg(AMX *amx,const cell *params)
|
||||
{
|
||||
AMX_HEADER *hdr;
|
||||
uchar *data;
|
||||
cell value;
|
||||
|
||||
hdr=(AMX_HEADER *)amx->base;
|
||||
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
|
||||
/* get the base value */
|
||||
value= * (cell *)(data+(int)amx->frm+((int)params[1]+3)*sizeof(cell));
|
||||
/* adjust the address in "value" in case of an array access */
|
||||
value+=params[2]*sizeof(cell);
|
||||
/* verify the address */
|
||||
if (value<0 || value>=amx->hea && value<amx->stk)
|
||||
return 0;
|
||||
/* set the value indirectly */
|
||||
* (cell *)(data+(int)value) = params[3];
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL heapspace(AMX *amx,const cell *params)
|
||||
{
|
||||
(void)params;
|
||||
return amx->stk - amx->hea;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL funcidx(AMX *amx,const cell *params)
|
||||
{
|
||||
char name[64];
|
||||
cell *cstr;
|
||||
int index,err,len;
|
||||
|
||||
amx_GetAddr(amx,params[1],&cstr);
|
||||
|
||||
/* verify string length */
|
||||
amx_StrLen(cstr,&len);
|
||||
if (len>=64) {
|
||||
amx_RaiseError(amx,AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
amx_GetString(name,cstr,0,UNLIMITED);
|
||||
err=amx_FindPublic(amx,name,&index);
|
||||
if (err!=AMX_ERR_NONE)
|
||||
index=-1; /* this is not considered a fatal error */
|
||||
return index;
|
||||
}
|
||||
|
||||
void amx_swapcell(cell *pc)
|
||||
{
|
||||
union {
|
||||
cell c;
|
||||
#if PAWN_CELL_SIZE==16
|
||||
uchar b[2];
|
||||
#elif PAWN_CELL_SIZE==32
|
||||
uchar b[4];
|
||||
#elif PAWN_CELL_SIZE==64
|
||||
uchar b[8];
|
||||
#else
|
||||
#error Unsupported cell size
|
||||
#endif
|
||||
} value;
|
||||
uchar t;
|
||||
|
||||
assert(pc!=NULL);
|
||||
value.c = *pc;
|
||||
#if PAWN_CELL_SIZE==16
|
||||
t = value.b[0];
|
||||
value.b[0] = value.b[1];
|
||||
value.b[1] = t;
|
||||
#elif PAWN_CELL_SIZE==32
|
||||
t = value.b[0];
|
||||
value.b[0] = value.b[3];
|
||||
value.b[3] = t;
|
||||
t = value.b[1];
|
||||
value.b[1] = value.b[2];
|
||||
value.b[2] = t;
|
||||
#elif PAWN_CELL_SIZE==64
|
||||
t = value.b[0];
|
||||
value.b[0] = value.b[7];
|
||||
value.b[7] = t;
|
||||
t = value.b[1];
|
||||
value.b[1] = value.b[6];
|
||||
value.b[6] = t;
|
||||
t = value.b[2];
|
||||
value.b[2] = value.b[5];
|
||||
value.b[5] = t;
|
||||
t = value.b[3];
|
||||
value.b[3] = value.b[4];
|
||||
value.b[4] = t;
|
||||
#else
|
||||
#error Unsupported cell size
|
||||
#endif
|
||||
*pc = value.c;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL swapchars(AMX *amx,const cell *params)
|
||||
{
|
||||
cell c;
|
||||
|
||||
(void)amx;
|
||||
assert((size_t)params[0]==sizeof(cell));
|
||||
|
||||
c=params[1];
|
||||
amx_swapcell(&c);
|
||||
return c;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL core_tolower(AMX *amx,const cell *params)
|
||||
{
|
||||
(void)amx;
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
return (cell)CharLower((LPTSTR)params[1]);
|
||||
#elif defined _Windows
|
||||
return (cell)AnsiLower((LPSTR)params[1]);
|
||||
#else
|
||||
if ((unsigned)(params[1]-'A')<26u)
|
||||
return params[1]+'a'-'A';
|
||||
return params[1];
|
||||
#endif
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL core_toupper(AMX *amx,const cell *params)
|
||||
{
|
||||
(void)amx;
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
return (cell)CharUpper((LPTSTR)params[1]);
|
||||
#elif defined _Windows
|
||||
return (cell)AnsiUpper((LPSTR)params[1]);
|
||||
#else
|
||||
if ((unsigned)(params[1]-'a')<26u)
|
||||
return params[1]+'A'-'a';
|
||||
return params[1];
|
||||
#endif
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL core_min(AMX *amx,const cell *params)
|
||||
{
|
||||
(void)amx;
|
||||
return params[1] <= params[2] ? params[1] : params[2];
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL core_max(AMX *amx,const cell *params)
|
||||
{
|
||||
(void)amx;
|
||||
return params[1] >= params[2] ? params[1] : params[2];
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL core_clamp(AMX *amx,const cell *params)
|
||||
{
|
||||
cell value = params[1];
|
||||
if (params[2] > params[3]) /* minimum value > maximum value ! */
|
||||
amx_RaiseError(amx,AMX_ERR_NATIVE);
|
||||
if (value < params[2])
|
||||
value = params[2];
|
||||
else if (value > params[3])
|
||||
value = params[3];
|
||||
return value;
|
||||
}
|
||||
|
||||
#if !defined AMX_NOPROPLIST
|
||||
static char *MakePackedString(cell *cptr)
|
||||
{
|
||||
int len;
|
||||
char *dest;
|
||||
|
||||
amx_StrLen(cptr,&len);
|
||||
dest=(char *)malloc(len+sizeof(cell));
|
||||
amx_GetString(dest,cptr,0,UNLIMITED);
|
||||
return dest;
|
||||
}
|
||||
|
||||
static int verify_addr(AMX *amx,cell addr)
|
||||
{
|
||||
int err;
|
||||
cell *cdest;
|
||||
|
||||
err=amx_GetAddr(amx,addr,&cdest);
|
||||
if (err!=AMX_ERR_NONE)
|
||||
amx_RaiseError(amx,err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL getproperty(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cstr;
|
||||
char *name;
|
||||
proplist *item;
|
||||
|
||||
amx_GetAddr(amx,params[2],&cstr);
|
||||
name=MakePackedString(cstr);
|
||||
item=list_finditem(&proproot,params[1],name,params[3],NULL);
|
||||
/* if list_finditem() found the value, store the name */
|
||||
if (item!=NULL && item->value==params[3] && strlen(name)==0) {
|
||||
int needed=(strlen(item->name)+sizeof(cell)-1)/sizeof(cell); /* # of cells needed */
|
||||
if (verify_addr(amx,(cell)(params[4]+needed))!=AMX_ERR_NONE) {
|
||||
free(name);
|
||||
return 0;
|
||||
} /* if */
|
||||
amx_GetAddr(amx,params[4],&cstr);
|
||||
amx_SetString(cstr,item->name,1,0,UNLIMITED);
|
||||
} /* if */
|
||||
free(name);
|
||||
return (item!=NULL) ? item->value : 0;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL setproperty(AMX *amx,const cell *params)
|
||||
{
|
||||
cell prev=0;
|
||||
cell *cstr;
|
||||
char *name;
|
||||
proplist *item;
|
||||
|
||||
amx_GetAddr(amx,params[2],&cstr);
|
||||
name=MakePackedString(cstr);
|
||||
item=list_finditem(&proproot,params[1],name,params[3],NULL);
|
||||
if (item==NULL)
|
||||
item=list_additem(&proproot);
|
||||
if (item==NULL) {
|
||||
amx_RaiseError(amx,AMX_ERR_MEMORY);
|
||||
} else {
|
||||
prev=item->value;
|
||||
if (strlen(name)==0) {
|
||||
free(name);
|
||||
amx_GetAddr(amx,params[4],&cstr);
|
||||
name=MakePackedString(cstr);
|
||||
} /* if */
|
||||
list_setitem(item,params[1],name,params[3]);
|
||||
} /* if */
|
||||
free(name);
|
||||
return prev;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL delproperty(AMX *amx,const cell *params)
|
||||
{
|
||||
cell prev=0;
|
||||
cell *cstr;
|
||||
char *name;
|
||||
proplist *item,*pred;
|
||||
|
||||
amx_GetAddr(amx,params[2],&cstr);
|
||||
name=MakePackedString(cstr);
|
||||
item=list_finditem(&proproot,params[1],name,params[3],&pred);
|
||||
if (item!=NULL) {
|
||||
prev=item->value;
|
||||
list_delete(pred,item);
|
||||
} /* if */
|
||||
free(name);
|
||||
return prev;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL existproperty(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cstr;
|
||||
char *name;
|
||||
proplist *item;
|
||||
|
||||
amx_GetAddr(amx,params[2],&cstr);
|
||||
name=MakePackedString(cstr);
|
||||
item=list_finditem(&proproot,params[1],name,params[3],NULL);
|
||||
free(name);
|
||||
return (item!=NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined AMX_NORANDOM
|
||||
/* This routine comes from the book "Inner Loops" by Rick Booth, Addison-Wesley
|
||||
* (ISBN 0-201-47960-5). This is a "multiplicative congruential random number
|
||||
* generator" that has been extended to 31-bits (the standard C version returns
|
||||
* only 15-bits).
|
||||
*/
|
||||
#define INITIAL_SEED 0xcaa938dbL
|
||||
static unsigned long IL_StandardRandom_seed = INITIAL_SEED; /* always use a non-zero seed */
|
||||
#define IL_RMULT 1103515245L
|
||||
#if defined __BORLANDC__ || defined __WATCOMC__
|
||||
#pragma argsused
|
||||
#endif
|
||||
static cell AMX_NATIVE_CALL core_random(AMX *amx,const cell *params)
|
||||
{
|
||||
unsigned long lo, hi, ll, lh, hh, hl;
|
||||
unsigned long result;
|
||||
|
||||
/* one-time initialization (or, mostly one-time) */
|
||||
#if !defined SN_TARGET_PS2 && !defined _WIN32_WCE && !defined __ICC430__
|
||||
if (IL_StandardRandom_seed == INITIAL_SEED)
|
||||
IL_StandardRandom_seed=(unsigned long)time(NULL);
|
||||
#endif
|
||||
|
||||
(void)amx;
|
||||
|
||||
lo = IL_StandardRandom_seed & 0xffff;
|
||||
hi = IL_StandardRandom_seed >> 16;
|
||||
IL_StandardRandom_seed = IL_StandardRandom_seed * IL_RMULT + 12345;
|
||||
ll = lo * (IL_RMULT & 0xffff);
|
||||
lh = lo * (IL_RMULT >> 16 );
|
||||
hl = hi * (IL_RMULT & 0xffff);
|
||||
hh = hi * (IL_RMULT >> 16 );
|
||||
result = ((ll + 12345) >> 16) + lh + hl + (hh << 16);
|
||||
result &= ~LONG_MIN; /* remove sign bit */
|
||||
if (params[1]!=0)
|
||||
result %= params[1];
|
||||
return (cell)result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
const AMX_NATIVE_INFO core_Natives[] = {
|
||||
{ "numargs", numargs },
|
||||
{ "getarg", getarg },
|
||||
{ "setarg", setarg },
|
||||
{ "heapspace", heapspace },
|
||||
{ "funcidx", funcidx },
|
||||
{ "swapchars", swapchars },
|
||||
{ "tolower", core_tolower },
|
||||
{ "toupper", core_toupper },
|
||||
{ "min", core_min },
|
||||
{ "max", core_max },
|
||||
{ "clamp", core_clamp },
|
||||
#if !defined AMX_NORANDOM
|
||||
{ "random", core_random },
|
||||
#endif
|
||||
#if !defined AMX_NOPROPLIST
|
||||
{ "getproperty", getproperty },
|
||||
{ "setproperty", setproperty },
|
||||
{ "deleteproperty",delproperty },
|
||||
{ "existproperty", existproperty },
|
||||
#endif
|
||||
{ NULL, NULL } /* terminator */
|
||||
};
|
||||
|
||||
int AMXEXPORT amx_CoreInit(AMX *amx)
|
||||
{
|
||||
return amx_Register(amx, core_Natives, -1);
|
||||
}
|
||||
|
||||
int AMXEXPORT amx_CoreCleanup(AMX *amx)
|
||||
{
|
||||
(void)amx;
|
||||
#if !defined AMX_NOPROPLIST
|
||||
while (proproot.next!=NULL)
|
||||
list_delete(&proproot,proproot.next);
|
||||
#endif
|
||||
return AMX_ERR_NONE;
|
||||
}
|
474
SOURCE/amx/amxdbg.c
Normal file
474
SOURCE/amx/amxdbg.c
Normal file
@ -0,0 +1,474 @@
|
||||
/* Pawn debugger interface
|
||||
*
|
||||
* Support functions for debugger applications
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2005-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxdbg.c 3612 2006-07-22 09:59:46Z thiadmer $
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "osdefs.h" /* for _MAX_PATH */
|
||||
#include "amx.h"
|
||||
#include "amxdbg.h"
|
||||
|
||||
|
||||
int AMXAPI dbg_FreeInfo(AMX_DBG *amxdbg)
|
||||
{
|
||||
assert(amxdbg != NULL);
|
||||
if (amxdbg->hdr != NULL)
|
||||
free(amxdbg->hdr);
|
||||
if (amxdbg->filetbl != NULL)
|
||||
free(amxdbg->filetbl);
|
||||
if (amxdbg->symboltbl != NULL)
|
||||
free(amxdbg->symboltbl);
|
||||
if (amxdbg->tagtbl != NULL)
|
||||
free(amxdbg->tagtbl);
|
||||
if (amxdbg->automatontbl != NULL)
|
||||
free(amxdbg->automatontbl);
|
||||
if (amxdbg->statetbl != NULL)
|
||||
free(amxdbg->statetbl);
|
||||
memset(amxdbg, 0, sizeof(AMX_DBG));
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
int AMXAPI dbg_LoadInfo(AMX_DBG *amxdbg, FILE *fp)
|
||||
{
|
||||
AMX_HEADER amxhdr;
|
||||
AMX_DBG_HDR dbghdr;
|
||||
unsigned char *ptr;
|
||||
int index, dim;
|
||||
AMX_DBG_SYMDIM *symdim;
|
||||
|
||||
assert(fp != NULL);
|
||||
assert(amxdbg != NULL);
|
||||
|
||||
memset(&amxhdr, 0, sizeof amxhdr);
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
fread(&amxhdr, sizeof amxhdr, 1, fp);
|
||||
#if BYTE_ORDER==BIG_ENDIAN
|
||||
amx_Align32((uint32_t*)&amxhdr.size);
|
||||
amx_Align16(&amxhdr.magic);
|
||||
#endif
|
||||
if (amxhdr.magic != AMX_MAGIC)
|
||||
return AMX_ERR_FORMAT;
|
||||
if ((amxhdr.flags & AMX_FLAG_DEBUG) == 0)
|
||||
return AMX_ERR_DEBUG;
|
||||
|
||||
fseek(fp, amxhdr.size, SEEK_SET);
|
||||
memset(&dbghdr, 0, sizeof(AMX_DBG_HDR));
|
||||
fread(&dbghdr, sizeof(AMX_DBG_HDR), 1, fp);
|
||||
|
||||
#if BYTE_ORDER==BIG_ENDIAN
|
||||
amx_Align32((uint32_t*)&dbghdr.size);
|
||||
amx_Align16(&dbghdr.magic);
|
||||
amx_Align16(&dbghdr.flags);
|
||||
amx_Align16(&dbghdr.files);
|
||||
amx_Align16(&dbghdr.lines);
|
||||
amx_Align16(&dbghdr.symbols);
|
||||
amx_Align16(&dbghdr.tags);
|
||||
amx_Align16(&dbghdr.automatons);
|
||||
amx_Align16(&dbghdr.states);
|
||||
#endif
|
||||
if (dbghdr.magic != AMX_DBG_MAGIC)
|
||||
return AMX_ERR_FORMAT;
|
||||
|
||||
/* allocate all memory */
|
||||
memset(amxdbg, 0, sizeof(AMX_DBG));
|
||||
amxdbg->hdr = malloc((size_t)dbghdr.size);
|
||||
if (dbghdr.files > 0)
|
||||
amxdbg->filetbl = malloc(dbghdr.files * sizeof(AMX_DBG_FILE *));
|
||||
if (dbghdr.symbols > 0)
|
||||
amxdbg->symboltbl = malloc(dbghdr.symbols * sizeof(AMX_DBG_SYMBOL *));
|
||||
if (dbghdr.tags > 0)
|
||||
amxdbg->tagtbl = malloc(dbghdr.tags * sizeof(AMX_DBG_TAG *));
|
||||
if (dbghdr.automatons > 0)
|
||||
amxdbg->automatontbl = malloc(dbghdr.automatons * sizeof(AMX_DBG_MACHINE *));
|
||||
if (dbghdr.states > 0)
|
||||
amxdbg->statetbl = malloc(dbghdr.states * sizeof(AMX_DBG_STATE *));
|
||||
if (amxdbg->hdr == NULL
|
||||
|| (dbghdr.files > 0 && amxdbg->filetbl == NULL)
|
||||
|| (dbghdr.symbols > 0 && amxdbg->symboltbl == NULL)
|
||||
|| (dbghdr.tags > 0 && amxdbg->tagtbl == NULL)
|
||||
|| (dbghdr.states > 0 && amxdbg->statetbl == NULL)
|
||||
|| (dbghdr.automatons > 0 && amxdbg->automatontbl == NULL))
|
||||
{
|
||||
dbg_FreeInfo(amxdbg);
|
||||
return AMX_ERR_MEMORY;
|
||||
} /* if */
|
||||
|
||||
/* load the entire symbolic information block into memory */
|
||||
memcpy(amxdbg->hdr, &dbghdr, sizeof dbghdr);
|
||||
fread(amxdbg->hdr + 1, 1, (size_t)(dbghdr.size - sizeof dbghdr), fp);
|
||||
|
||||
/* run through the file, fix alignment issues and set up table pointers */
|
||||
ptr = (unsigned char *)(amxdbg->hdr + 1);
|
||||
|
||||
/* file table */
|
||||
for (index = 0; index < dbghdr.files; index++) {
|
||||
assert(amxdbg->filetbl != NULL);
|
||||
amxdbg->filetbl[index] = (AMX_DBG_FILE *)ptr;
|
||||
#if BYTE_ORDER==BIG_ENDIAN
|
||||
amx_AlignCell(&amxdbg->filetbl[index]->address);
|
||||
#endif
|
||||
for (ptr = ptr + sizeof(AMX_DBG_FILE); *ptr != '\0'; ptr++)
|
||||
/* nothing */;
|
||||
ptr++; /* skip '\0' too */
|
||||
} /* for */
|
||||
|
||||
/* line table */
|
||||
amxdbg->linetbl = (AMX_DBG_LINE*)ptr;
|
||||
#if BYTE_ORDER==BIG_ENDIAN
|
||||
for (index = 0; index < dbghdr.lines; index++) {
|
||||
amx_AlignCell(&amxdbg->linetbl[index].address);
|
||||
amx_Align32((uint32_t*)&amxdbg->linetbl[index].line);
|
||||
} /* for */
|
||||
#endif
|
||||
ptr += dbghdr.lines * sizeof(AMX_DBG_LINE);
|
||||
|
||||
/* symbol table (plus index tags) */
|
||||
for (index = 0; index < dbghdr.symbols; index++) {
|
||||
assert(amxdbg->symboltbl != NULL);
|
||||
amxdbg->symboltbl[index] = (AMX_DBG_SYMBOL *)ptr;
|
||||
#if BYTE_ORDER==BIG_ENDIAN
|
||||
amx_AlignCell(&amxdbg->symboltbl[index]->address);
|
||||
amx_Align16((uint16_t*)&amxdbg->symboltbl[index]->tag);
|
||||
amx_AlignCell(&amxdbg->symboltbl[index]->codestart);
|
||||
amx_AlignCell(&amxdbg->symboltbl[index]->codeend);
|
||||
amx_Align16((uint16_t*)&amxdbg->symboltbl[index]->dim);
|
||||
#endif
|
||||
for (ptr = ptr + sizeof(AMX_DBG_SYMBOL); *ptr != '\0'; ptr++)
|
||||
/* nothing */;
|
||||
ptr++; /* skip '\0' too */
|
||||
for (dim = 0; dim < amxdbg->symboltbl[index]->dim; dim++) {
|
||||
symdim = (AMX_DBG_SYMDIM *)ptr;
|
||||
amx_Align16((uint16_t*)&symdim->tag);
|
||||
amx_AlignCell(&symdim->size);
|
||||
ptr += sizeof(AMX_DBG_SYMDIM);
|
||||
} /* for */
|
||||
} /* for */
|
||||
|
||||
/* tag name table */
|
||||
for (index = 0; index < dbghdr.tags; index++) {
|
||||
assert(amxdbg->tagtbl != NULL);
|
||||
amxdbg->tagtbl[index] = (AMX_DBG_TAG *)ptr;
|
||||
#if BYTE_ORDER==BIG_ENDIAN
|
||||
amx_Align16(&amxdbg->tagtbl[index]->tag);
|
||||
#endif
|
||||
for (ptr = ptr + sizeof(AMX_DBG_TAG) - 1; *ptr != '\0'; ptr++)
|
||||
/* nothing */;
|
||||
ptr++; /* skip '\0' too */
|
||||
} /* for */
|
||||
|
||||
/* automaton name table */
|
||||
for (index = 0; index < dbghdr.automatons; index++) {
|
||||
assert(amxdbg->automatontbl != NULL);
|
||||
amxdbg->automatontbl[index] = (AMX_DBG_MACHINE *)ptr;
|
||||
#if BYTE_ORDER==BIG_ENDIAN
|
||||
amx_Align16(&amxdbg->automatontbl[index]->automaton);
|
||||
amx_AlignCell(&amxdbg->automatontbl[index]->address);
|
||||
#endif
|
||||
for (ptr = ptr + sizeof(AMX_DBG_MACHINE) - 1; *ptr != '\0'; ptr++)
|
||||
/* nothing */;
|
||||
ptr++; /* skip '\0' too */
|
||||
} /* for */
|
||||
|
||||
/* state name table */
|
||||
for (index = 0; index < dbghdr.states; index++) {
|
||||
assert(amxdbg->statetbl != NULL);
|
||||
amxdbg->statetbl[index] = (AMX_DBG_STATE *)ptr;
|
||||
#if BYTE_ORDER==BIG_ENDIAN
|
||||
amx_Align16(&amxdbg->statetbl[index]->state);
|
||||
amx_Align16(&amxdbg->automatontbl[index]->automaton);
|
||||
#endif
|
||||
for (ptr = ptr + sizeof(AMX_DBG_STATE) - 1; *ptr != '\0'; ptr++)
|
||||
/* nothing */;
|
||||
ptr++; /* skip '\0' too */
|
||||
} /* for */
|
||||
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
int AMXAPI dbg_LookupFile(AMX_DBG *amxdbg, ucell address, const char **filename)
|
||||
{
|
||||
int index;
|
||||
|
||||
assert(amxdbg != NULL);
|
||||
assert(filename != NULL);
|
||||
*filename = NULL;
|
||||
/* this is a simple linear look-up; a binary search would be possible too */
|
||||
for (index = 0; index < amxdbg->hdr->files && amxdbg->filetbl[index]->address <= address; index++)
|
||||
/* nothing */;
|
||||
/* reset for overrun */
|
||||
if (--index < 0)
|
||||
return AMX_ERR_NOTFOUND;
|
||||
|
||||
*filename = amxdbg->filetbl[index]->name;
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
int AMXAPI dbg_LookupLine(AMX_DBG *amxdbg, ucell address, long *line)
|
||||
{
|
||||
int index;
|
||||
|
||||
assert(amxdbg != NULL);
|
||||
assert(line != NULL);
|
||||
*line = 0;
|
||||
/* this is a simple linear look-up; a binary search would be possible too */
|
||||
for (index = 0; index < amxdbg->hdr->lines && amxdbg->linetbl[index].address <= address; index++)
|
||||
/* nothing */;
|
||||
/* reset for overrun */
|
||||
if (--index < 0)
|
||||
return AMX_ERR_NOTFOUND;
|
||||
|
||||
*line = (long)amxdbg->linetbl[index].line;
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
int AMXAPI dbg_LookupFunction(AMX_DBG *amxdbg, ucell address, const char **funcname)
|
||||
{
|
||||
/* dbg_LookupFunction() finds the function a code address is in. It can be
|
||||
* used for stack walking, and for stepping through a function while stepping
|
||||
* over sub-functions
|
||||
*/
|
||||
int index;
|
||||
|
||||
assert(amxdbg != NULL);
|
||||
assert(funcname != NULL);
|
||||
*funcname = NULL;
|
||||
for (index = 0; index < amxdbg->hdr->symbols; index++) {
|
||||
if (amxdbg->symboltbl[index]->ident == iFUNCTN
|
||||
&& amxdbg->symboltbl[index]->codestart <= address
|
||||
&& amxdbg->symboltbl[index]->codeend > address)
|
||||
break;
|
||||
} /* for */
|
||||
if (index >= amxdbg->hdr->symbols)
|
||||
return AMX_ERR_NOTFOUND;
|
||||
|
||||
*funcname = amxdbg->symboltbl[index]->name;
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
int AMXAPI dbg_GetTagName(AMX_DBG *amxdbg, int tag, const char **name)
|
||||
{
|
||||
int index;
|
||||
|
||||
assert(amxdbg != NULL);
|
||||
assert(name != NULL);
|
||||
*name = NULL;
|
||||
for (index = 0; index < amxdbg->hdr->tags && amxdbg->tagtbl[index]->tag != tag; index++)
|
||||
/* nothing */;
|
||||
if (index >= amxdbg->hdr->tags)
|
||||
return AMX_ERR_NOTFOUND;
|
||||
|
||||
*name = amxdbg->tagtbl[index]->name;
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
int AMXAPI dbg_GetAutomatonName(AMX_DBG *amxdbg, int automaton, const char **name)
|
||||
{
|
||||
int index;
|
||||
|
||||
assert(amxdbg != NULL);
|
||||
assert(name != NULL);
|
||||
*name = NULL;
|
||||
for (index = 0; index < amxdbg->hdr->automatons && amxdbg->automatontbl[index]->automaton != automaton; index++)
|
||||
/* nothing */;
|
||||
if (index >= amxdbg->hdr->automatons)
|
||||
return AMX_ERR_NOTFOUND;
|
||||
|
||||
*name = amxdbg->automatontbl[index]->name;
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
int AMXAPI dbg_GetStateName(AMX_DBG *amxdbg, int state, const char **name)
|
||||
{
|
||||
int index;
|
||||
|
||||
assert(amxdbg != NULL);
|
||||
assert(name != NULL);
|
||||
*name = NULL;
|
||||
for (index = 0; index < amxdbg->hdr->states && amxdbg->statetbl[index]->state != state; index++)
|
||||
/* nothing */;
|
||||
if (index >= amxdbg->hdr->states)
|
||||
return AMX_ERR_NOTFOUND;
|
||||
|
||||
*name = amxdbg->statetbl[index]->name;
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
int AMXAPI dbg_GetLineAddress(AMX_DBG *amxdbg, long line, const char *filename, ucell *address)
|
||||
{
|
||||
/* Find a suitable "breakpoint address" close to the indicated line (and in
|
||||
* the specified file). The address is moved up to the next "breakable" line
|
||||
* if no "breakpoint" is available on the specified line. You can use function
|
||||
* dbg_LookupLine() to find out at which precise line the breakpoint was set.
|
||||
*
|
||||
* The filename comparison is strict (case sensitive and path sensitive); the
|
||||
* "filename" parameter should point into the "filetbl" of the AMX_DBG
|
||||
* structure.
|
||||
*/
|
||||
int file, index;
|
||||
ucell bottomaddr,topaddr;
|
||||
|
||||
assert(amxdbg != NULL);
|
||||
assert(filename != NULL);
|
||||
assert(address != NULL);
|
||||
*address = 0;
|
||||
|
||||
index = 0;
|
||||
for (file = 0; file < amxdbg->hdr->files; file++) {
|
||||
/* find the (next) mathing instance of the file */
|
||||
if (strcmp(amxdbg->filetbl[file]->name, filename) != 0)
|
||||
continue;
|
||||
/* get address range for the current file */
|
||||
bottomaddr = amxdbg->filetbl[file]->address;
|
||||
topaddr = (file + 1 < amxdbg->hdr->files) ? amxdbg->filetbl[file+1]->address : (ucell)(cell)-1;
|
||||
/* go to the starting address in the line table */
|
||||
while (index < amxdbg->hdr->lines && amxdbg->linetbl[index].address < bottomaddr)
|
||||
index++;
|
||||
/* browse until the line is found or until the top address is exceeded */
|
||||
while (index < amxdbg->hdr->lines
|
||||
&& amxdbg->linetbl[index].line < line
|
||||
&& amxdbg->linetbl[index].address < topaddr)
|
||||
index++;
|
||||
if (index >= amxdbg->hdr->lines)
|
||||
return AMX_ERR_NOTFOUND;
|
||||
if (amxdbg->linetbl[index].line >= line)
|
||||
break;
|
||||
/* if not found (and the line table is not yet exceeded) try the next
|
||||
* instance of the same file (a file may appear twice in the file table)
|
||||
*/
|
||||
} /* for */
|
||||
|
||||
if (strcmp(amxdbg->filetbl[file]->name, filename) != 0)
|
||||
return AMX_ERR_NOTFOUND;
|
||||
|
||||
assert(index < amxdbg->hdr->lines);
|
||||
*address = amxdbg->linetbl[index].address;
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
int AMXAPI dbg_GetFunctionAddress(AMX_DBG *amxdbg, const char *funcname, const char *filename, ucell *address)
|
||||
{
|
||||
/* Find a suitable "breakpoint address" close to the indicated line (and in
|
||||
* the specified file). The address is moved up to the first "breakable" line
|
||||
* in the function. You can use function dbg_LookupLine() to find out at which
|
||||
* precise line the breakpoint was set.
|
||||
*
|
||||
* The filename comparison is strict (case sensitive and path sensitive); the
|
||||
* "filename" parameter should point into the "filetbl" of the AMX_DBG
|
||||
* structure. The function name comparison is case sensitive too.
|
||||
*/
|
||||
int index, err;
|
||||
const char *tgtfile;
|
||||
ucell funcaddr;
|
||||
|
||||
assert(amxdbg != NULL);
|
||||
assert(funcname != NULL);
|
||||
assert(filename != NULL);
|
||||
assert(address != NULL);
|
||||
*address = 0;
|
||||
|
||||
index = 0;
|
||||
for ( ;; ) {
|
||||
/* find (next) matching function */
|
||||
while (index < amxdbg->hdr->symbols
|
||||
&& (amxdbg->symboltbl[index]->ident != iFUNCTN || strcmp(amxdbg->symboltbl[index]->name, funcname) != 0))
|
||||
index++;
|
||||
if (index >= amxdbg->hdr->symbols)
|
||||
return AMX_ERR_NOTFOUND;
|
||||
/* verify that this line falls in the appropriate file */
|
||||
err = dbg_LookupFile(amxdbg, amxdbg->symboltbl[index]->address, &tgtfile);
|
||||
if (err == AMX_ERR_NONE || strcmp(filename, tgtfile) == 0)
|
||||
break;
|
||||
index++; /* line is the wrong file, search further */
|
||||
} /* for */
|
||||
|
||||
/* now find the first line in the function where we can "break" on */
|
||||
assert(index < amxdbg->hdr->symbols);
|
||||
funcaddr = amxdbg->symboltbl[index]->address;
|
||||
for (index = 0; index < amxdbg->hdr->lines && amxdbg->linetbl[index].address < funcaddr; index++)
|
||||
/* nothing */;
|
||||
|
||||
if (index >= amxdbg->hdr->lines)
|
||||
return AMX_ERR_NOTFOUND;
|
||||
*address = amxdbg->linetbl[index].address;
|
||||
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
int AMXAPI dbg_GetVariable(AMX_DBG *amxdbg, const char *symname, ucell scopeaddr, const AMX_DBG_SYMBOL **sym)
|
||||
{
|
||||
ucell codestart,codeend;
|
||||
int index;
|
||||
|
||||
assert(amxdbg != NULL);
|
||||
assert(symname != NULL);
|
||||
assert(sym != NULL);
|
||||
*sym = NULL;
|
||||
|
||||
codestart = codeend = 0;
|
||||
index = 0;
|
||||
for ( ;; ) {
|
||||
/* find (next) matching variable */
|
||||
while (index < amxdbg->hdr->symbols
|
||||
&& (amxdbg->symboltbl[index]->ident == iFUNCTN || strcmp(amxdbg->symboltbl[index]->name, symname) != 0)
|
||||
&& (amxdbg->symboltbl[index]->codestart > scopeaddr || amxdbg->symboltbl[index]->codeend < scopeaddr))
|
||||
index++;
|
||||
if (index >= amxdbg->hdr->symbols)
|
||||
break;
|
||||
/* check the range, keep a pointer to the symbol with the smallest range */
|
||||
if (strcmp(amxdbg->symboltbl[index]->name, symname) == 0
|
||||
&& (codestart == 0 && codeend == 0
|
||||
|| amxdbg->symboltbl[index]->codestart >= codestart && amxdbg->symboltbl[index]->codeend <= codeend))
|
||||
{
|
||||
*sym = amxdbg->symboltbl[index];
|
||||
codestart = amxdbg->symboltbl[index]->codestart;
|
||||
codeend = amxdbg->symboltbl[index]->codeend;
|
||||
} /* if */
|
||||
index++;
|
||||
} /* for */
|
||||
|
||||
return (*sym == NULL) ? AMX_ERR_NOTFOUND : AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
int AMXAPI dbg_GetArrayDim(AMX_DBG *amxdbg, const AMX_DBG_SYMBOL *sym, const AMX_DBG_SYMDIM **symdim)
|
||||
{
|
||||
/* retrieves a pointer to the array dimensions structures of an array symbol */
|
||||
const char *ptr;
|
||||
|
||||
assert(amxdbg != NULL);
|
||||
assert(sym != NULL);
|
||||
assert(symdim != NULL);
|
||||
*symdim = NULL;
|
||||
|
||||
if (sym->ident != iARRAY && sym->ident != iREFARRAY)
|
||||
return AMX_ERR_PARAMS;
|
||||
assert(sym->dim > 0); /* array must have at least one dimension */
|
||||
|
||||
/* find the end of the symbol name */
|
||||
for (ptr = sym->name; *ptr != '\0'; ptr++)
|
||||
/* nothing */;
|
||||
*symdim = (AMX_DBG_SYMDIM *)(ptr + 1);/* skip '\0' too */
|
||||
|
||||
return AMX_ERR_NONE;
|
||||
}
|
172
SOURCE/amx/amxdbg.h
Normal file
172
SOURCE/amx/amxdbg.h
Normal file
@ -0,0 +1,172 @@
|
||||
/* Abstract Machine for the Pawn compiler, debugger support
|
||||
*
|
||||
* This file contains extra definitions that are convenient for debugger
|
||||
* support.
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2005-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxdbg.h 3612 2006-07-22 09:59:46Z thiadmer $
|
||||
*/
|
||||
|
||||
#ifndef AMXDBG_H_INCLUDED
|
||||
#define AMXDBG_H_INCLUDED
|
||||
|
||||
#ifndef AMX_H_INCLUDED
|
||||
#include "amx.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Some compilers do not support the #pragma align, which should be fine. Some
|
||||
* compilers give a warning on unknown #pragmas, which is not so fine...
|
||||
*/
|
||||
#if defined SN_TARGET_PS2 || defined __GNUC__
|
||||
#define AMX_NO_ALIGN
|
||||
#endif
|
||||
|
||||
#if defined __GNUC__
|
||||
#define PACKED __attribute__((packed))
|
||||
#else
|
||||
#define PACKED
|
||||
#endif
|
||||
|
||||
#if !defined AMX_NO_ALIGN
|
||||
#if defined LINUX || defined __FreeBSD__
|
||||
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
||||
#elif defined MACOS && defined __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#else
|
||||
#pragma pack(push)
|
||||
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
||||
#if defined __TURBOC__
|
||||
#pragma option -a- /* "pack" pragma for older Borland compilers */
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct tagAMX_DBG_HDR {
|
||||
int32_t size PACKED; /* size of the debug information chunk */
|
||||
uint16_t magic PACKED; /* signature, must be 0xf1ef */
|
||||
char file_version PACKED; /* file format version */
|
||||
char amx_version PACKED; /* required version of the AMX */
|
||||
int16_t flags PACKED; /* currently unused */
|
||||
int16_t files PACKED; /* number of entries in the "file" table */
|
||||
int32_t lines PACKED; /* number of entries in the "line" table */
|
||||
int16_t symbols PACKED; /* number of entries in the "symbol" table */
|
||||
int16_t tags PACKED; /* number of entries in the "tag" table */
|
||||
int16_t automatons PACKED; /* number of entries in the "automaton" table */
|
||||
int16_t states PACKED; /* number of entries in the "state" table */
|
||||
} PACKED AMX_DBG_HDR;
|
||||
#define AMX_DBG_MAGIC 0xf2ef
|
||||
|
||||
typedef struct tagAMX_DBG_FILE {
|
||||
ucell address PACKED; /* address in the code segment where generated code (for this file) starts */
|
||||
const char name[1] PACKED; /* ASCII string, zero-terminated */
|
||||
} PACKED AMX_DBG_FILE;
|
||||
|
||||
typedef struct tagAMX_DBG_LINE {
|
||||
ucell address PACKED; /* address in the code segment where generated code (for this line) starts */
|
||||
int32_t line PACKED; /* line number */
|
||||
} PACKED AMX_DBG_LINE;
|
||||
|
||||
typedef struct tagAMX_DBG_SYMBOL {
|
||||
ucell address PACKED; /* address in the data segment or relative to the frame */
|
||||
int16_t tag PACKED; /* tag for the symbol */
|
||||
ucell codestart PACKED; /* address in the code segment from which this symbol is valid (in scope) */
|
||||
ucell codeend PACKED; /* address in the code segment until which this symbol is valid (in scope) */
|
||||
char ident PACKED; /* kind of symbol (function/variable) */
|
||||
char vclass PACKED; /* class of symbol (global/local) */
|
||||
int16_t dim PACKED; /* number of dimensions */
|
||||
const char name[1] PACKED; /* ASCII string, zero-terminated */
|
||||
} PACKED AMX_DBG_SYMBOL;
|
||||
|
||||
typedef struct tagAMX_DBG_SYMDIM {
|
||||
int16_t tag PACKED; /* tag for the array dimension */
|
||||
ucell size PACKED; /* size of the array dimension */
|
||||
} PACKED AMX_DBG_SYMDIM;
|
||||
|
||||
typedef struct tagAMX_DBG_TAG {
|
||||
int16_t tag PACKED; /* tag id */
|
||||
const char name[1] PACKED; /* ASCII string, zero-terminated */
|
||||
} PACKED AMX_DBG_TAG;
|
||||
|
||||
typedef struct tagAMX_DBG_MACHINE {
|
||||
int16_t automaton PACKED; /* automaton id */
|
||||
ucell address PACKED; /* address of state variable */
|
||||
const char name[1] PACKED; /* ASCII string, zero-terminated */
|
||||
} PACKED AMX_DBG_MACHINE;
|
||||
|
||||
typedef struct tagAMX_DBG_STATE {
|
||||
int16_t state PACKED; /* state id */
|
||||
int16_t automaton PACKED; /* automaton id */
|
||||
const char name[1] PACKED; /* ASCII string, zero-terminated */
|
||||
} PACKED AMX_DBG_STATE;
|
||||
|
||||
typedef struct tagAMX_DBG {
|
||||
AMX_DBG_HDR *hdr PACKED; /* points to the AMX_DBG header */
|
||||
AMX_DBG_FILE **filetbl PACKED;
|
||||
AMX_DBG_LINE *linetbl PACKED;
|
||||
AMX_DBG_SYMBOL **symboltbl PACKED;
|
||||
AMX_DBG_TAG **tagtbl PACKED;
|
||||
AMX_DBG_MACHINE **automatontbl PACKED;
|
||||
AMX_DBG_STATE **statetbl PACKED;
|
||||
} PACKED AMX_DBG;
|
||||
|
||||
#if !defined iVARIABLE
|
||||
#define iVARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */
|
||||
#define iREFERENCE 2 /* iVARIABLE, but must be dereferenced */
|
||||
#define iARRAY 3
|
||||
#define iREFARRAY 4 /* an array passed by reference (i.e. a pointer) */
|
||||
#define iFUNCTN 9
|
||||
#endif
|
||||
|
||||
|
||||
int AMXAPI dbg_FreeInfo(AMX_DBG *amxdbg);
|
||||
int AMXAPI dbg_LoadInfo(AMX_DBG *amxdbg, FILE *fp);
|
||||
|
||||
int AMXAPI dbg_LookupFile(AMX_DBG *amxdbg, ucell address, const char **filename);
|
||||
int AMXAPI dbg_LookupFunction(AMX_DBG *amxdbg, ucell address, const char **funcname);
|
||||
int AMXAPI dbg_LookupLine(AMX_DBG *amxdbg, ucell address, long *line);
|
||||
|
||||
int AMXAPI dbg_GetFunctionAddress(AMX_DBG *amxdbg, const char *funcname, const char *filename, ucell *address);
|
||||
int AMXAPI dbg_GetLineAddress(AMX_DBG *amxdbg, long line, const char *filename, ucell *address);
|
||||
int AMXAPI dbg_GetAutomatonName(AMX_DBG *amxdbg, int automaton, const char **name);
|
||||
int AMXAPI dbg_GetStateName(AMX_DBG *amxdbg, int state, const char **name);
|
||||
int AMXAPI dbg_GetTagName(AMX_DBG *amxdbg, int tag, const char **name);
|
||||
int AMXAPI dbg_GetVariable(AMX_DBG *amxdbg, const char *symname, ucell scopeaddr, const AMX_DBG_SYMBOL **sym);
|
||||
int AMXAPI dbg_GetArrayDim(AMX_DBG *amxdbg, const AMX_DBG_SYMBOL *sym, const AMX_DBG_SYMDIM **symdim);
|
||||
|
||||
|
||||
#if !defined AMX_NO_ALIGN
|
||||
#if defined LINUX || defined __FreeBSD__
|
||||
#pragma pack() /* reset default packing */
|
||||
#elif defined MACOS && defined __MWERKS__
|
||||
#pragma options align=reset
|
||||
#else
|
||||
#pragma pack(pop) /* reset previous packing */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AMXDBG_H_INCLUDED */
|
86
SOURCE/amx/amxdef.asm
Normal file
86
SOURCE/amx/amxdef.asm
Normal file
@ -0,0 +1,86 @@
|
||||
; Definition of the AMX structure for assembler syntax (MASM/TASM/WASM)
|
||||
|
||||
amx_s STRUC
|
||||
_base DD ?
|
||||
_dataseg DD ?
|
||||
_callback DD ?
|
||||
_debug DD ?
|
||||
_cip DD ?
|
||||
_frm DD ?
|
||||
_hea DD ?
|
||||
_hlw DD ?
|
||||
_stk DD ?
|
||||
_stp DD ?
|
||||
_flags DD ?
|
||||
_usertags DD 4 DUP (?) ; 4 = AMX_USERNUM (#define'd in amx.h)
|
||||
_userdata DD 4 DUP (?) ; 4 = AMX_USERNUM (#define'd in amx.h)
|
||||
_error DD ?
|
||||
_paramcount DD ?
|
||||
_pri DD ?
|
||||
_alt DD ?
|
||||
_reset_stk DD ?
|
||||
_reset_hea DD ?
|
||||
_syscall_d DD ?
|
||||
IFDEF JIT
|
||||
; the two fields below are for the JIT; they do not exist in
|
||||
; the non-JIT version of the abstract machine
|
||||
_reloc_size DD ? ; memory block for relocations
|
||||
_code_size DD ? ; memory size of the native code
|
||||
ENDIF
|
||||
amx_s ENDS
|
||||
|
||||
amxhead_s STRUC
|
||||
_size DD ? ; size of the "file"
|
||||
_magic DW ? ; signature
|
||||
_file_version DB ? ;file format version
|
||||
_amx_version DB ? ; required version of the AMX
|
||||
_h_flags DW ?
|
||||
_defsize DW ? ; size of one public/native function entry
|
||||
_cod DD ? ; initial value of COD - code block
|
||||
_dat DD ? ; initial value of DAT - data block
|
||||
_h_hea DD ? ; initial value of HEA - start of the heap
|
||||
_h_stp DD ? ; initial value of STP - stack top
|
||||
_h_cip DD ? ; initial value of CIP - the instruction pointer
|
||||
_publics DD ? ; offset to the "public functions" table
|
||||
_natives DD ? ; offset to the "native functions" table
|
||||
_libraries DD ? ; offset to the "library" table
|
||||
_pubvars DD ? ; offset to the "public variables" table
|
||||
_tags DD ? ; offset to the "public tagnames" table
|
||||
_nametable DD ? ; offset to the name table, file version 7 only
|
||||
amxhead_s ENDS
|
||||
|
||||
|
||||
AMX_ERR_NONE EQU 0
|
||||
AMX_ERR_EXIT EQU 1
|
||||
AMX_ERR_ASSERT EQU 2
|
||||
AMX_ERR_STACKERR EQU 3
|
||||
AMX_ERR_BOUNDS EQU 4
|
||||
AMX_ERR_MEMACCESS EQU 5
|
||||
AMX_ERR_INVINSTR EQU 6
|
||||
AMX_ERR_STACKLOW EQU 7
|
||||
AMX_ERR_HEAPLOW EQU 8
|
||||
AMX_ERR_CALLBACK EQU 9
|
||||
AMX_ERR_NATIVE EQU 10
|
||||
AMX_ERR_DIVIDE EQU 11 ; for catching divide errors
|
||||
AMX_ERR_SLEEP EQU 12
|
||||
|
||||
AMX_ERR_MEMORY EQU 16
|
||||
AMX_ERR_FORMAT EQU 17
|
||||
AMX_ERR_VERSION EQU 18
|
||||
AMX_ERR_NOTFOUND EQU 19
|
||||
AMX_ERR_INDEX EQU 20
|
||||
AMX_ERR_DEBUG EQU 21
|
||||
AMX_ERR_INIT EQU 22
|
||||
AMX_ERR_USERDATA EQU 23
|
||||
AMX_ERR_INIT_JIT EQU 24
|
||||
AMX_ERR_PARAMS EQU 25
|
||||
AMX_ERR_DOMAIN EQU 26
|
||||
AMX_ERR_GENERAL EQU 27
|
||||
|
||||
AMX_FLAG_DEBUG EQU 0002h ; symbolic info. available
|
||||
AMX_FLAG_COMPACT EQU 0004h
|
||||
AMX_FLAG_BYTEOPC EQU 0008h
|
||||
AMX_FLAG_NOCHECKS EQU 0010h
|
||||
AMX_FLAG_BROWSE EQU 4000h
|
||||
AMX_FLAG_RELOC EQU 8000h ; jump/call addresses relocated
|
||||
|
86
SOURCE/amx/amxdefn.asm
Normal file
86
SOURCE/amx/amxdefn.asm
Normal file
@ -0,0 +1,86 @@
|
||||
; Definition of the AMX structure for assembler syntax (NASM)
|
||||
|
||||
struc amx_s
|
||||
_base: resd 1
|
||||
_dataseg: resd 1
|
||||
_callback: resd 1
|
||||
_debug: resd 1
|
||||
_cip: resd 1
|
||||
_frm: resd 1
|
||||
_hea: resd 1
|
||||
_hlw: resd 1
|
||||
_stk: resd 1
|
||||
_stp: resd 1
|
||||
_flags: resd 1
|
||||
_usertags: resd 4 ; 4 = AMX_USERNUM (#define'd in amx.h)
|
||||
_userdata: resd 4 ; 4 = AMX_USERNUM (#define'd in amx.h)
|
||||
_error: resd 1
|
||||
_paramcount: resd 1
|
||||
_pri: resd 1
|
||||
_alt: resd 1
|
||||
_reset_stk: resd 1
|
||||
_reset_hea: resd 1
|
||||
_syscall_d: resd 1
|
||||
%ifdef JIT
|
||||
; the two fields below are for the JIT; they do not exist in
|
||||
; the non-JIT version of the abstract machine
|
||||
_reloc_size: resd 1 ; memory block for relocations
|
||||
_code_size: resd 1 ; memory size of the native code
|
||||
%endif
|
||||
endstruc
|
||||
|
||||
struc amxhead_s
|
||||
_size: resd 1 ; size of the "file"
|
||||
_magic: resw 1 ; signature
|
||||
_file_version: resb 1; file format version
|
||||
_amx_version: resb 1 ; required version of the AMX
|
||||
_h_flags: resw 1
|
||||
_defsize: resw 1 ; size of one public/native function entry
|
||||
_cod: resd 1 ; initial value of COD - code block
|
||||
_dat: resd 1 ; initial value of DAT - data block
|
||||
_h_hea: resd 1 ; initial value of HEA - start of the heap
|
||||
_h_stp: resd 1 ; initial value of STP - stack top
|
||||
_h_cip: resd 1 ; initial value of CIP - the instruction pointer
|
||||
_publics: resd 1 ; offset to the "public functions" table
|
||||
_natives: resd 1 ; offset to the "native functions" table
|
||||
_libraries: resd 1 ; offset to the "library" table
|
||||
_pubvars: resd 1 ; offset to the "public variables" table
|
||||
_tags: resd 1 ; offset to the "public tagnames" table
|
||||
_nametable: resd 1 ; offset to the name table, file version 7 only
|
||||
endstruc
|
||||
|
||||
|
||||
AMX_ERR_NONE EQU 0
|
||||
AMX_ERR_EXIT EQU 1
|
||||
AMX_ERR_ASSERT EQU 2
|
||||
AMX_ERR_STACKERR EQU 3
|
||||
AMX_ERR_BOUNDS EQU 4
|
||||
AMX_ERR_MEMACCESS EQU 5
|
||||
AMX_ERR_INVINSTR EQU 6
|
||||
AMX_ERR_STACKLOW EQU 7
|
||||
AMX_ERR_HEAPLOW EQU 8
|
||||
AMX_ERR_CALLBACK EQU 9
|
||||
AMX_ERR_NATIVE EQU 10
|
||||
AMX_ERR_DIVIDE EQU 11 ; for catching divide errors
|
||||
AMX_ERR_SLEEP EQU 12
|
||||
|
||||
AMX_ERR_MEMORY EQU 16
|
||||
AMX_ERR_FORMAT EQU 17
|
||||
AMX_ERR_VERSION EQU 18
|
||||
AMX_ERR_NOTFOUND EQU 19
|
||||
AMX_ERR_INDEX EQU 20
|
||||
AMX_ERR_DEBUG EQU 21
|
||||
AMX_ERR_INIT EQU 22
|
||||
AMX_ERR_USERDATA EQU 23
|
||||
AMX_ERR_INIT_JIT EQU 24
|
||||
AMX_ERR_PARAMS EQU 25
|
||||
AMX_ERR_DOMAIN EQU 26
|
||||
AMX_ERR_GENERAL EQU 27
|
||||
|
||||
AMX_FLAG_DEBUG EQU 0002h ; symbolic info. available
|
||||
AMX_FLAG_COMPACT EQU 0004h
|
||||
AMX_FLAG_BYTEOPC EQU 0008h
|
||||
AMX_FLAG_NOCHECKS EQU 0010h
|
||||
AMX_FLAG_BROWSE EQU 4000h
|
||||
AMX_FLAG_RELOC EQU 8000h ; jump/call addresses relocated
|
||||
|
356
SOURCE/amx/amxdgram.c
Normal file
356
SOURCE/amx/amxdgram.c
Normal file
@ -0,0 +1,356 @@
|
||||
/* Datagram sending/receiving module for the Pawn Abstract Machine
|
||||
*
|
||||
* This module uses the UDP protocol (from the TCP/IP protocol suite).
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2005-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxdgram.c 3664 2006-11-08 12:09:25Z thiadmer $
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#if defined LINUX
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
#include "osdefs.h"
|
||||
#include "amx.h"
|
||||
|
||||
|
||||
#define SRC_BUFSIZE 22
|
||||
#define BUFLEN 512
|
||||
#define AMX_DGRAMPORT 9930 /* default port */
|
||||
|
||||
#if !defined SOCKET_ERROR
|
||||
#define SOCKET_ERROR -1
|
||||
#endif
|
||||
|
||||
static int sLocal;
|
||||
|
||||
static unsigned long udp_GetHostAddr(const char *host,int index)
|
||||
{
|
||||
unsigned long addr=inet_addr(host);
|
||||
if (addr==0xffffffffL) {
|
||||
struct hostent *phost=gethostbyname(host);
|
||||
if (phost!=NULL) {
|
||||
/* count the number of addresses in the list */
|
||||
int count;
|
||||
for (count=0; phost->h_addr_list[count]!=0; count++)
|
||||
/* nothing */;
|
||||
if (index<count)
|
||||
addr=*(unsigned long *)phost->h_addr_list[index];
|
||||
} /* if */
|
||||
} /* if */
|
||||
return addr;
|
||||
}
|
||||
|
||||
static int udp_Open(void)
|
||||
{
|
||||
#if defined __WIN32 || defined _WIN32 || defined WIN32
|
||||
WORD wVersionRequested = MAKEWORD(1,1);
|
||||
WSADATA wsaData;
|
||||
#endif
|
||||
int optval = 1;
|
||||
|
||||
#if defined __WIN32 || defined _WIN32 || defined WIN32
|
||||
WSAStartup(wVersionRequested, &wsaData);
|
||||
#endif
|
||||
|
||||
if ((sLocal=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||
return -1;
|
||||
|
||||
if (setsockopt(sLocal, SOL_SOCKET, SO_BROADCAST, (void*)&optval, sizeof optval) == -1)
|
||||
return -1;
|
||||
|
||||
return sLocal;
|
||||
}
|
||||
|
||||
static int udp_Close(void)
|
||||
{
|
||||
if (sLocal>=0) {
|
||||
#if defined __WIN32 || defined _WIN32 || defined WIN32
|
||||
closesocket(sLocal);
|
||||
#else
|
||||
close(sLocal);
|
||||
#endif
|
||||
} /* if */
|
||||
|
||||
#if defined __WIN32 || defined _WIN32 || defined WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int udp_Send(const char *host,short port,const char *message,int size)
|
||||
{
|
||||
struct sockaddr_in sRemote;
|
||||
|
||||
if (sLocal<0)
|
||||
return -1;
|
||||
|
||||
memset((void *)&sRemote,sizeof sRemote,0);
|
||||
sRemote.sin_family=AF_INET;
|
||||
sRemote.sin_port=htons(port);
|
||||
sRemote.sin_addr.s_addr= (host==NULL) ? htonl(INADDR_BROADCAST) : udp_GetHostAddr(host,0);
|
||||
|
||||
if (sendto(sLocal,message,size,0,(struct sockaddr *)&sRemote,sizeof sRemote)==-1)
|
||||
return -1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* This call is blocking
|
||||
* if source is not NULL, it must point to a buffer that can contain at least
|
||||
* 22 characters.
|
||||
*/
|
||||
static int udp_Receive(char *message,size_t maxmsg,char *source)
|
||||
{
|
||||
struct sockaddr_in sSource;
|
||||
int slen=sizeof(sSource);
|
||||
int size;
|
||||
|
||||
size=recvfrom(sLocal, message, maxmsg, 0, (struct sockaddr *)&sSource, &slen);
|
||||
if (size==-1)
|
||||
return -1;
|
||||
if (source!=NULL)
|
||||
sprintf(source, "%s:%d", inet_ntoa(sSource.sin_addr), ntohs(sSource.sin_port));
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int udp_IsPacket(void)
|
||||
{
|
||||
int result;
|
||||
fd_set rdset;
|
||||
struct timeval time;
|
||||
|
||||
/* the select() function waits until the socket can be read, or until a
|
||||
* time-out occurs; the time-out is set to 1 microsecond (the shortest
|
||||
* delay possible).
|
||||
*/
|
||||
time.tv_sec=0;
|
||||
time.tv_usec=1;
|
||||
FD_ZERO(&rdset);
|
||||
FD_SET(sLocal,&rdset);
|
||||
result=select(0,&rdset,NULL,NULL,&time);
|
||||
if (result==SOCKET_ERROR)
|
||||
return -1;
|
||||
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
static int udp_Listen(short port)
|
||||
{
|
||||
struct sockaddr_in sFrom;
|
||||
|
||||
memset((void *)&sFrom,sizeof sFrom,0);
|
||||
sFrom.sin_family=AF_INET;
|
||||
sFrom.sin_port=htons(port);
|
||||
sFrom.sin_addr.s_addr=htonl(INADDR_ANY);
|
||||
if (bind(sLocal,(struct sockaddr *)&sFrom,sizeof sFrom)==-1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static AMX_IDLE PrevIdle = NULL;
|
||||
static int idxReceiveString = -1;
|
||||
static int idxReceivePacket = -1;
|
||||
static short dgramPort = 0;
|
||||
static int dgramBound = 0;
|
||||
|
||||
/* sendstring(const message[], const destination[]="")
|
||||
* destination has the format "127.0.0.1:9930"; when set to an empty string,
|
||||
* a broadcast is sent.
|
||||
* To mark the text as a "string", the function inserts a "byte order mark" in
|
||||
* front of it. It does this for Extended ASCII strings too, although this is
|
||||
* not entirely correct.
|
||||
* Returns true on success, false on failure.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_sendstring(AMX *amx, const cell *params)
|
||||
{
|
||||
int r = 0, length;
|
||||
cell *cstr;
|
||||
char *host, *message, *ptr;
|
||||
short port=AMX_DGRAMPORT;
|
||||
|
||||
amx_GetAddr(amx, params[1], &cstr);
|
||||
amx_UTF8Len(cstr, &length);
|
||||
|
||||
if ((message = alloca(length + 3 + 1)) != NULL) {
|
||||
/* insert the byte order mark (BOM) */
|
||||
message[0]='\xef';
|
||||
message[1]='\xbb';
|
||||
message[2]='\xbf';
|
||||
/* if this is a wide string, convert it to UTF-8 */
|
||||
if ((ucell)*cstr<=UNPACKEDMAX) {
|
||||
ptr=message+3;
|
||||
while (*cstr!=0)
|
||||
amx_UTF8Put(ptr, &ptr, length - (ptr-message), *cstr++);
|
||||
*ptr='\0';
|
||||
} else {
|
||||
amx_GetString(message+3, cstr, 0, UNLIMITED);
|
||||
} /* if */
|
||||
|
||||
amx_StrParam(amx, params[2], host);
|
||||
if (host != NULL && (ptr=strchr(host,':'))!=NULL && isdigit(ptr[1])) {
|
||||
*ptr++='\0';
|
||||
port=(short)atoi(ptr);
|
||||
} /* if */
|
||||
r= (udp_Send(host,port,message,strlen(message)+1) > 0);
|
||||
} /* if */
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* sendpacket(const packet[], size, const destination[]="")
|
||||
* destination has the format "127.0.0.1:9930"; when set to an empty string,
|
||||
* a broadcast is sent.
|
||||
* Returns true on success, false on failure.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_sendpacket(AMX *amx, const cell *params)
|
||||
{
|
||||
cell *cstr;
|
||||
char *host, *ptr;
|
||||
short port=AMX_DGRAMPORT;
|
||||
|
||||
amx_GetAddr(amx, params[1], &cstr);
|
||||
amx_StrParam(amx, params[3], host);
|
||||
if (host != NULL && (ptr=strchr(host,':'))!=NULL && isdigit(ptr[1])) {
|
||||
*ptr++='\0';
|
||||
port=(short)atoi(ptr);
|
||||
} /* if */
|
||||
return (udp_Send(host,port,(const char *)cstr,params[2] * sizeof(cell)) > 0);
|
||||
}
|
||||
|
||||
/* listenport(port)
|
||||
* A program must call this function from main() or another start-up function
|
||||
* because the module will use the default port 9930 otherwise.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_listenport(AMX *amx, const cell *params)
|
||||
{
|
||||
(void)amx;
|
||||
dgramPort = (short)params[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int AMXAPI amx_DGramIdle(AMX *amx, int AMXAPI Exec(AMX *, cell *, int))
|
||||
{
|
||||
char message[BUFLEN], source[SRC_BUFSIZE];
|
||||
cell amx_addr_msg, amx_addr_src;
|
||||
int len, chars;
|
||||
int err=0;
|
||||
|
||||
assert(idxReceiveString >= 0 || idxReceivePacket >= 0);
|
||||
|
||||
if (PrevIdle != NULL)
|
||||
PrevIdle(amx, Exec);
|
||||
|
||||
/* set up listener (first call only) */
|
||||
if (!dgramBound) {
|
||||
if (dgramPort==0)
|
||||
dgramPort=AMX_DGRAMPORT; /* use default port if none was set */
|
||||
if (udp_Listen(dgramPort)==-1)
|
||||
return AMX_ERR_GENERAL;
|
||||
dgramBound=1;
|
||||
} /* if */
|
||||
|
||||
if (udp_IsPacket()) {
|
||||
len=udp_Receive(message, sizeof message / sizeof message[0], source);
|
||||
amx_PushString(amx,&amx_addr_src,NULL,source,1,0);
|
||||
/* check the presence of a byte order mark: if it is absent, the received
|
||||
* packet is no string; also check the packet size against string length
|
||||
*/
|
||||
if ((message[0]!='\xef' || message[1]!='\xbb' || message[2]!='\xbf'
|
||||
|| len!=(int)strlen(message)+1 || idxReceiveString<0) && idxReceivePacket>=0)
|
||||
{
|
||||
/* receive as "packet" */
|
||||
amx_Push(amx,len);
|
||||
amx_PushArray(amx,&amx_addr_msg,NULL,(cell*)message,len);
|
||||
err=Exec(amx,NULL,idxReceivePacket);
|
||||
} else {
|
||||
const char *msg=message;
|
||||
if (msg[0]=='\xef' && msg[1]=='\xbb' && msg[2]=='\xbf')
|
||||
msg+=3; /* skip BOM */
|
||||
/* optionally convert from UTF-8 to a wide string */
|
||||
if (amx_UTF8Check(msg,&chars)==AMX_ERR_NONE) {
|
||||
cell *array=alloca((chars+1)*sizeof(cell));
|
||||
cell *ptr=array;
|
||||
if (array!=NULL) {
|
||||
while (err==AMX_ERR_NONE && *msg!='\0')
|
||||
amx_UTF8Get(msg,&msg,ptr++);
|
||||
*ptr=0; /* zero-terminate */
|
||||
amx_PushArray(amx,&amx_addr_msg,NULL,array,chars+1);
|
||||
} /* if */
|
||||
} else {
|
||||
amx_PushString(amx,&amx_addr_msg,NULL,msg,1,0);
|
||||
} /* if */
|
||||
err=Exec(amx,NULL,idxReceiveString);
|
||||
} /* if */
|
||||
while (err==AMX_ERR_SLEEP)
|
||||
err=Exec(amx,NULL,AMX_EXEC_CONT);
|
||||
amx_Release(amx,amx_addr_msg);
|
||||
amx_Release(amx,amx_addr_src);
|
||||
} /* if */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
AMX_NATIVE_INFO dgram_Natives[] = {
|
||||
{ "sendstring", n_sendstring },
|
||||
{ "sendpacket", n_sendpacket },
|
||||
{ "listenport", n_listenport },
|
||||
{ NULL, NULL } /* terminator */
|
||||
};
|
||||
|
||||
int AMXEXPORT amx_DGramInit(AMX *amx)
|
||||
{
|
||||
dgramBound = 0;
|
||||
if (udp_Open()==-1)
|
||||
return AMX_ERR_GENERAL;
|
||||
|
||||
/* see whether there is an @receivestring() function */
|
||||
if (amx_FindPublic(amx,"@receivestring",&idxReceiveString)==AMX_ERR_NONE
|
||||
|| amx_FindPublic(amx,"@receivepacket",&idxReceivePacket)==AMX_ERR_NONE)
|
||||
{
|
||||
if (amx_GetUserData(amx,AMX_USERTAG('I','d','l','e'),(void**)&PrevIdle)!=AMX_ERR_NONE)
|
||||
PrevIdle=NULL;
|
||||
amx_SetUserData(amx,AMX_USERTAG('I','d','l','e'),amx_DGramIdle);
|
||||
} /* if */
|
||||
|
||||
return amx_Register(amx,dgram_Natives,-1);
|
||||
}
|
||||
|
||||
int AMXEXPORT amx_DGramCleanup(AMX *amx)
|
||||
{
|
||||
(void)amx;
|
||||
udp_Close();
|
||||
return AMX_ERR_NONE;
|
||||
}
|
2112
SOURCE/amx/amxexec.asm
Normal file
2112
SOURCE/amx/amxexec.asm
Normal file
File diff suppressed because it is too large
Load Diff
2021
SOURCE/amx/amxexecn.asm
Normal file
2021
SOURCE/amx/amxexecn.asm
Normal file
File diff suppressed because it is too large
Load Diff
796
SOURCE/amx/amxfile.c
Normal file
796
SOURCE/amx/amxfile.c
Normal file
@ -0,0 +1,796 @@
|
||||
/* Text file I/O module for the Pawn Abstract Machine
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2003-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxfile.c 3660 2006-11-05 13:05:09Z thiadmer $
|
||||
*/
|
||||
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
|
||||
# if !defined UNICODE /* for Windows */
|
||||
# define UNICODE
|
||||
# endif
|
||||
# if !defined _UNICODE /* for C library */
|
||||
# define _UNICODE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
|
||||
#include <io.h>
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined MACOS
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
#include "osdefs.h"
|
||||
#include "amx.h"
|
||||
|
||||
#include "fpattern.c"
|
||||
|
||||
#if !defined AMXFILE_VAR
|
||||
#define AMXFILE_VAR "AMXFILE"
|
||||
#elif AMXFILE_VAR==""
|
||||
#undef AMXFILE_VAR
|
||||
#endif
|
||||
|
||||
#if defined _UNICODE
|
||||
# include <tchar.h>
|
||||
#elif !defined __T
|
||||
typedef char TCHAR;
|
||||
# define __T(string) string
|
||||
# define _tfopen fopen
|
||||
# define _tgetenv getenv
|
||||
# define _tfputs fputs
|
||||
# define _tcscat strcat
|
||||
# define _tcschr strchr
|
||||
# define _tcscpy strcpy
|
||||
# define _tcsdup strdup
|
||||
# define _tcslen strlen
|
||||
# define _tcsncpy strncpy
|
||||
# define _tcspbrk strpbrk
|
||||
# define _tcsrchr strrchr
|
||||
#endif
|
||||
|
||||
#if !defined UNUSED_PARAM
|
||||
#define UNUSED_PARAM(p) ((void)(p))
|
||||
#endif
|
||||
|
||||
enum filemode {
|
||||
io_read, /* file must exist */
|
||||
io_write, /* creates a new file */
|
||||
io_readwrite, /* file must exist */
|
||||
io_append, /* file must exist, opened for writing only and seek to the end */
|
||||
};
|
||||
|
||||
enum seek_whence {
|
||||
seek_start,
|
||||
seek_current,
|
||||
seek_end,
|
||||
};
|
||||
|
||||
|
||||
/* This function only stores unpacked strings. UTF-8 is used for
|
||||
* Unicode, and packed strings can only store 7-bit and 8-bit
|
||||
* character sets (ASCII, Latin-1).
|
||||
*/
|
||||
static size_t fgets_cell(FILE *fp,cell *string,size_t max,int utf8mode)
|
||||
{
|
||||
size_t index;
|
||||
fpos_t pos;
|
||||
cell c;
|
||||
int follow,lastcr;
|
||||
cell lowmark;
|
||||
|
||||
assert(sizeof(cell)>=4);
|
||||
assert(fp!=NULL);
|
||||
assert(string!=NULL);
|
||||
if (max==0)
|
||||
return 0;
|
||||
|
||||
/* get the position, in case we have to back up */
|
||||
fgetpos(fp, &pos);
|
||||
|
||||
index=0;
|
||||
follow=0;
|
||||
lowmark=0;
|
||||
lastcr=0;
|
||||
for ( ;; ) {
|
||||
assert(index<max);
|
||||
if (index==max-1)
|
||||
break; /* string fully filled */
|
||||
if ((c=fgetc(fp))==EOF) {
|
||||
if (!utf8mode || follow==0)
|
||||
break; /* no more characters */
|
||||
/* If an EOF happened halfway an UTF-8 code, the string cannot be
|
||||
* UTF-8 mode, and we must restart.
|
||||
*/
|
||||
index=0;
|
||||
fsetpos(fp, &pos);
|
||||
continue;
|
||||
} /* if */
|
||||
|
||||
/* 8-bit characters are unsigned */
|
||||
if (c<0)
|
||||
c=-c;
|
||||
|
||||
if (utf8mode) {
|
||||
if (follow>0 && (c & 0xc0)==0x80) {
|
||||
/* leader code is active, combine with earlier code */
|
||||
string[index]=(string[index] << 6) | ((unsigned char)c & 0x3f);
|
||||
if (--follow==0) {
|
||||
/* encoding a character in more bytes than is strictly needed,
|
||||
* is not really valid UTF-8; we are strict here to increase
|
||||
* the chance of heuristic dectection of non-UTF-8 text
|
||||
* (JAVA writes zero bytes as a 2-byte code UTF-8, which is invalid)
|
||||
*/
|
||||
if (string[index]<lowmark)
|
||||
utf8mode=0;
|
||||
/* the code positions 0xd800--0xdfff and 0xfffe & 0xffff do not
|
||||
* exist in UCS-4 (and hence, they do not exist in Unicode)
|
||||
*/
|
||||
if (string[index]>=0xd800 && string[index]<=0xdfff
|
||||
|| string[index]==0xfffe || string[index]==0xffff)
|
||||
utf8mode=0;
|
||||
index++;
|
||||
} /* if */
|
||||
} else if (follow==0 && (c & 0x80)==0x80) {
|
||||
/* UTF-8 leader code */
|
||||
if ((c & 0xe0)==0xc0) {
|
||||
/* 110xxxxx 10xxxxxx */
|
||||
follow=1;
|
||||
lowmark=0x80;
|
||||
string[index]=c & 0x1f;
|
||||
} else if ((c & 0xf0)==0xe0) {
|
||||
/* 1110xxxx 10xxxxxx 10xxxxxx (16 bits, BMP plane) */
|
||||
follow=2;
|
||||
lowmark=0x800;
|
||||
string[index]=c & 0x0f;
|
||||
} else if ((c & 0xf8)==0xf0) {
|
||||
/* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
|
||||
follow=3;
|
||||
lowmark=0x10000;
|
||||
string[index]=c & 0x07;
|
||||
} else if ((c & 0xfc)==0xf8) {
|
||||
/* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
|
||||
follow=4;
|
||||
lowmark=0x200000;
|
||||
string[index]=c & 0x03;
|
||||
} else if ((c & 0xfe)==0xfc) {
|
||||
/* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (31 bits) */
|
||||
follow=5;
|
||||
lowmark=0x4000000;
|
||||
string[index]=c & 0x01;
|
||||
} else {
|
||||
/* this is invalid UTF-8 */
|
||||
utf8mode=0;
|
||||
} /* if */
|
||||
} else if (follow==0 && (c & 0x80)==0x00) {
|
||||
/* 0xxxxxxx (US-ASCII) */
|
||||
string[index++]=c;
|
||||
if (c==__T('\n'))
|
||||
break; /* read newline, done */
|
||||
} else {
|
||||
/* this is invalid UTF-8 */
|
||||
utf8mode=0;
|
||||
} /* if */
|
||||
if (!utf8mode) {
|
||||
/* UTF-8 mode was switched just off, which means that non-conforming
|
||||
* UTF-8 codes were found, which means in turn that the string is
|
||||
* probably not intended as UTF-8; start over again
|
||||
*/
|
||||
index=0;
|
||||
fsetpos(fp, &pos);
|
||||
} /* if */
|
||||
} else {
|
||||
string[index++]=c;
|
||||
if (c==__T('\n')) {
|
||||
break; /* read newline, done */
|
||||
} else if (lastcr) {
|
||||
ungetc(c,fp); /* carriage return was read, no newline follows */
|
||||
break;
|
||||
} /* if */
|
||||
lastcr=(c==__T('\r'));
|
||||
} /* if */
|
||||
} /* for */
|
||||
assert(index<max);
|
||||
string[index]=__T('\0');
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static size_t fputs_cell(FILE *fp,cell *string,int utf8mode)
|
||||
{
|
||||
size_t count=0;
|
||||
|
||||
assert(sizeof(cell)>=4);
|
||||
assert(fp!=NULL);
|
||||
assert(string!=NULL);
|
||||
|
||||
while (*string!=0) {
|
||||
if (utf8mode) {
|
||||
cell c=*string;
|
||||
if (c<0x80) {
|
||||
/* 0xxxxxxx */
|
||||
fputc((unsigned char)c,fp);
|
||||
} else if (c<0x800) {
|
||||
/* 110xxxxx 10xxxxxx */
|
||||
fputc((unsigned char)((c>>6) & 0x1f | 0xc0),fp);
|
||||
fputc((unsigned char)(c & 0x3f | 0x80),fp);
|
||||
} else if (c<0x10000) {
|
||||
/* 1110xxxx 10xxxxxx 10xxxxxx (16 bits, BMP plane) */
|
||||
fputc((unsigned char)((c>>12) & 0x0f | 0xe0),fp);
|
||||
fputc((unsigned char)((c>>6) & 0x3f | 0x80),fp);
|
||||
fputc((unsigned char)(c & 0x3f | 0x80),fp);
|
||||
} else if (c<0x200000) {
|
||||
/* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
|
||||
fputc((unsigned char)((c>>18) & 0x07 | 0xf0),fp);
|
||||
fputc((unsigned char)((c>>12) & 0x3f | 0x80),fp);
|
||||
fputc((unsigned char)((c>>6) & 0x3f | 0x80),fp);
|
||||
fputc((unsigned char)(c & 0x3f | 0x80),fp);
|
||||
} else if (c<0x4000000) {
|
||||
/* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
|
||||
fputc((unsigned char)((c>>24) & 0x03 | 0xf8),fp);
|
||||
fputc((unsigned char)((c>>18) & 0x3f | 0x80),fp);
|
||||
fputc((unsigned char)((c>>12) & 0x3f | 0x80),fp);
|
||||
fputc((unsigned char)((c>>6) & 0x3f | 0x80),fp);
|
||||
fputc((unsigned char)(c & 0x3f | 0x80),fp);
|
||||
} else {
|
||||
/* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (31 bits) */
|
||||
fputc((unsigned char)((c>>30) & 0x01 | 0xfc),fp);
|
||||
fputc((unsigned char)((c>>24) & 0x3f | 0x80),fp);
|
||||
fputc((unsigned char)((c>>18) & 0x3f | 0x80),fp);
|
||||
fputc((unsigned char)((c>>12) & 0x3f | 0x80),fp);
|
||||
fputc((unsigned char)((c>>6) & 0x3f | 0x80),fp);
|
||||
fputc((unsigned char)(c & 0x3f | 0x80),fp);
|
||||
} /* if */
|
||||
} else {
|
||||
/* not UTF-8 mode */
|
||||
fputc((unsigned char)*string,fp);
|
||||
} /* if */
|
||||
string++;
|
||||
count++;
|
||||
} /* while */
|
||||
return count;
|
||||
}
|
||||
|
||||
static size_t fgets_char(FILE *fp, char *string, size_t max)
|
||||
{
|
||||
size_t index;
|
||||
int c,lastcr;
|
||||
|
||||
index=0;
|
||||
lastcr=0;
|
||||
for ( ;; ) {
|
||||
assert(index<max);
|
||||
if (index==max-1)
|
||||
break; /* string fully filled */
|
||||
if ((c=fgetc(fp))==EOF)
|
||||
break; /* no more characters */
|
||||
string[index++]=(char)c;
|
||||
if (c==__T('\n')) {
|
||||
break; /* read newline, done */
|
||||
} else if (lastcr) {
|
||||
ungetc(c,fp); /* carriage return was read, no newline follows */
|
||||
break;
|
||||
} /* if */
|
||||
lastcr=(c==__T('\r'));
|
||||
} /* for */
|
||||
assert(index<max);
|
||||
string[index]=__T('\0');
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
#if defined _UNICODE
|
||||
wchar_t *_wgetenv(wchar_t *name)
|
||||
{
|
||||
static wchar_t buffer[_MAX_PATH];
|
||||
buffer[0]=L'\0';
|
||||
GetEnvironmentVariable(name,buffer,sizeof buffer/sizeof(wchar_t));
|
||||
return buffer[0]!=L'\0' ? buffer : NULL;
|
||||
}
|
||||
#else
|
||||
char *getenv(const char *name)
|
||||
{
|
||||
static char buffer[_MAX_PATH];
|
||||
buffer[0]='\0';
|
||||
GetEnvironmentVariable(name,buffer,sizeof buffer);
|
||||
return buffer[0]!='\0' ? buffer : NULL;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static char *completename(TCHAR *dest, TCHAR *src, size_t size)
|
||||
{
|
||||
#if defined AMXFILE_VAR
|
||||
TCHAR *prefix,*ptr;
|
||||
size_t len;
|
||||
|
||||
/* only files below a specific path are accessible */
|
||||
prefix=getenv(AMXFILE_VAR);
|
||||
|
||||
/* if no specific path for files is present, use the "temporary" path */
|
||||
if (prefix==NULL)
|
||||
prefix=getenv(__T("tmp")); /* common under Windows and Unix */
|
||||
if (prefix==NULL)
|
||||
prefix=getenv(__T("temp")); /* common under Windows */
|
||||
if (prefix==NULL)
|
||||
prefix=getenv(__T("tmpdir")); /* common under Unix */
|
||||
|
||||
/* if no path for files is defined, and no temporary directory exists,
|
||||
* fail the function; this is for security reasons.
|
||||
*/
|
||||
if (prefix==NULL)
|
||||
return NULL;
|
||||
|
||||
if (_tcslen(prefix)+1>=size) /* +1 because directory separator is appended */
|
||||
return NULL;
|
||||
_tcscpy(dest,prefix);
|
||||
/* append a directory separator (if not already present) */
|
||||
len=_tcslen(dest);
|
||||
if (len==0)
|
||||
return NULL; /* empty start directory is not allowed */
|
||||
if (dest[len-1]!=__T(DIRSEP_CHAR) && dest[len-1]!=__T('/') && len+1<size) {
|
||||
dest[len]=__T(DIRSEP_CHAR);
|
||||
dest[len+1]=__T('\0');
|
||||
} /* if */
|
||||
assert(_tcslen(dest)<size);
|
||||
|
||||
/* for DOS/Windows and Unix/Linux, skip everyting up to a comma, because
|
||||
* this is used to indicate a protocol (e.g. file://C:/myfile.txt)
|
||||
*/
|
||||
#if DIRSEP_CHAR!=':'
|
||||
if ((ptr=_tcsrchr(src,__T(':')))!=NULL) {
|
||||
src=ptr+1; /* skip protocol/drive and colon */
|
||||
/* a "drive" specifier is sometimes ended with a vertical bar instead
|
||||
* of a colon in URL specifications
|
||||
*/
|
||||
if ((ptr=_tcschr(src,__T('|')))!=NULL)
|
||||
src=ptr+1; /* skip drive and vertical bar */
|
||||
while (src[0]==__T(DIRSEP_CHAR) || src[0]==__T('/'))
|
||||
src++; /* skip slashes behind the protocol/drive letter */
|
||||
} /* if */
|
||||
#endif
|
||||
|
||||
/* skip an initial backslash or a drive specifier in the source */
|
||||
if ((src[0]==__T(DIRSEP_CHAR) || src[0]==__T('/')) && (src[1]==__T(DIRSEP_CHAR) || src[1]==__T('/'))) {
|
||||
/* UNC path */
|
||||
char separators[]={__T(DIRSEP_CHAR),__T('/'),__T('\0')};
|
||||
src+=2;
|
||||
ptr=_tcspbrk(src,separators);
|
||||
if (ptr!=NULL)
|
||||
src=ptr+1;
|
||||
} else if (src[0]==__T(DIRSEP_CHAR) || src[0]==__T('/')) {
|
||||
/* simple path starting from the root directory */
|
||||
src++;
|
||||
} /* if */
|
||||
|
||||
/* disallow any "../" specifications in the source path
|
||||
* (the check below should be stricter, but directory names with
|
||||
* trailing periods are rare anyway)
|
||||
*/
|
||||
for (ptr=src; *ptr!=__T('\0'); ptr++)
|
||||
if (ptr[0]==__T('.') && (ptr[1]==__T(DIRSEP_CHAR) || ptr[1]==__T('/')))
|
||||
return NULL; /* path name is not allowed */
|
||||
|
||||
/* concatenate the drive letter to the destination path */
|
||||
if (_tcslen(dest)+_tcslen(src)>=size)
|
||||
return NULL;
|
||||
_tcscat(dest,src);
|
||||
|
||||
/* change forward slashes into proper directory separators */
|
||||
#if DIRSEP_CHAR!='/'
|
||||
while ((ptr=_tcschr(dest,__T('/')))!=NULL)
|
||||
*ptr=__T(DIRSEP_CHAR);
|
||||
#endif
|
||||
return dest;
|
||||
|
||||
#else
|
||||
if (_tcslen(src)>=size)
|
||||
return NULL;
|
||||
_tcscpy(dest,src);
|
||||
/* change forward slashes into proper directory separators */
|
||||
#if DIRSEP_CHAR!='/'
|
||||
while ((ptr=_tcschr(dest,__T('/')))!=NULL)
|
||||
*ptr=__T(DIRSEP_CHAR);
|
||||
#endif
|
||||
return dest;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* File: fopen(const name[], filemode: mode) */
|
||||
static cell AMX_NATIVE_CALL n_fopen(AMX *amx, const cell *params)
|
||||
{
|
||||
TCHAR *attrib,*altattrib;
|
||||
TCHAR *name,fullname[_MAX_PATH];
|
||||
FILE *f = NULL;
|
||||
|
||||
altattrib=NULL;
|
||||
switch (params[2] & 0x7fff) {
|
||||
case io_read:
|
||||
attrib=__T("rb");
|
||||
break;
|
||||
case io_write:
|
||||
attrib=__T("wb");
|
||||
break;
|
||||
case io_readwrite:
|
||||
attrib=__T("r+b");
|
||||
altattrib=__T("w+b");
|
||||
break;
|
||||
case io_append:
|
||||
attrib=__T("ab");
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
} /* switch */
|
||||
|
||||
/* get the filename */
|
||||
amx_StrParam(amx,params[1],name);
|
||||
if (name!=NULL && completename(fullname,name,sizeof fullname)!=NULL) {
|
||||
f=_tfopen(fullname,attrib);
|
||||
if (f==NULL && altattrib!=NULL)
|
||||
f=_tfopen(fullname,altattrib);
|
||||
} /* if */
|
||||
return (cell)f;
|
||||
}
|
||||
|
||||
/* fclose(File: handle) */
|
||||
static cell AMX_NATIVE_CALL n_fclose(AMX *amx, const cell *params)
|
||||
{
|
||||
UNUSED_PARAM(amx);
|
||||
return fclose((FILE*)params[1]) == 0;
|
||||
}
|
||||
|
||||
/* fwrite(File: handle, const string[]) */
|
||||
static cell AMX_NATIVE_CALL n_fwrite(AMX *amx, const cell *params)
|
||||
{
|
||||
int r = 0;
|
||||
cell *cptr;
|
||||
char *str;
|
||||
int len;
|
||||
|
||||
amx_GetAddr(amx,params[2],&cptr);
|
||||
amx_StrLen(cptr,&len);
|
||||
if (len==0)
|
||||
return 0;
|
||||
|
||||
if ((ucell)*cptr>UNPACKEDMAX) {
|
||||
/* the string is packed, write it as an ASCII/ANSI string */
|
||||
if ((str=(char*)alloca(len + 1))!=NULL) {
|
||||
amx_GetString(str,cptr,0,len);
|
||||
r=fputs(str,(FILE*)params[1]);
|
||||
} /* if */
|
||||
} else {
|
||||
/* the string is unpacked, write it as UTF-8 */
|
||||
r=fputs_cell((FILE*)params[1],cptr,1);
|
||||
} /* if */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* fread(File: handle, string[], size=sizeof string, bool:pack=false) */
|
||||
static cell AMX_NATIVE_CALL n_fread(AMX *amx, const cell *params)
|
||||
{
|
||||
int chars,max;
|
||||
char *str;
|
||||
cell *cptr;
|
||||
|
||||
max=(int)params[3];
|
||||
if (max<=0)
|
||||
return 0;
|
||||
if (params[4])
|
||||
max*=sizeof(cell);
|
||||
|
||||
amx_GetAddr(amx,params[2],&cptr);
|
||||
str=(char *)alloca(max);
|
||||
if (str==NULL || cptr==NULL) {
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
if (params[4]) {
|
||||
/* store as packed string, read an ASCII/ANSI string */
|
||||
chars=fgets_char((FILE*)params[1],str,max);
|
||||
assert(chars<max);
|
||||
amx_SetString(cptr,str,(int)params[4],0,max);
|
||||
} else {
|
||||
/* store and unpacked string, interpret UTF-8 */
|
||||
chars=fgets_cell((FILE*)params[1],cptr,max,1);
|
||||
} /* if */
|
||||
|
||||
assert(chars<max);
|
||||
return chars;
|
||||
}
|
||||
|
||||
/* fputchar(File: handle, value, bool:utf8 = true) */
|
||||
static cell AMX_NATIVE_CALL n_fputchar(AMX *amx, const cell *params)
|
||||
{
|
||||
size_t result;
|
||||
|
||||
UNUSED_PARAM(amx);
|
||||
if (params[3]) {
|
||||
cell str[2];
|
||||
str[0]=params[2];
|
||||
str[1]=0;
|
||||
result=fputs_cell((FILE*)params[1],str,1);
|
||||
} else {
|
||||
fputc((int)params[2],(FILE*)params[1]);
|
||||
} /* if */
|
||||
assert(result==0 || result==1);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* fgetchar(File: handle, bool:utf8 = true) */
|
||||
static cell AMX_NATIVE_CALL n_fgetchar(AMX *amx, const cell *params)
|
||||
{
|
||||
cell str[2];
|
||||
size_t result;
|
||||
|
||||
UNUSED_PARAM(amx);
|
||||
if (params[2]) {
|
||||
result=fgets_cell((FILE*)params[1],str,2,1);
|
||||
} else {
|
||||
str[0]=fgetc((FILE*)params[1]);
|
||||
result= (str[0]!=EOF);
|
||||
} /* if */
|
||||
assert(result==0 || result==1);
|
||||
if (result==0)
|
||||
return EOF;
|
||||
else
|
||||
return str[0];
|
||||
}
|
||||
|
||||
#if PAWN_CELL_SIZE==16
|
||||
#define aligncell amx_Align16
|
||||
#elif PAWN_CELL_SIZE==32
|
||||
#define aligncell amx_Align32
|
||||
#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64)
|
||||
#define aligncell amx_Align64
|
||||
#else
|
||||
#error Unsupported cell size
|
||||
#endif
|
||||
|
||||
/* fblockwrite(File: handle, buffer[], size=sizeof buffer) */
|
||||
static cell AMX_NATIVE_CALL n_fblockwrite(AMX *amx, const cell *params)
|
||||
{
|
||||
cell *cptr;
|
||||
cell count;
|
||||
|
||||
amx_GetAddr(amx,params[2],&cptr);
|
||||
if (cptr!=NULL) {
|
||||
cell max=params[3];
|
||||
ucell v;
|
||||
for (count=0; count<max; count++) {
|
||||
v=(ucell)*cptr++;
|
||||
if (fwrite(aligncell(&v),sizeof(cell),1,(FILE*)params[1])!=1)
|
||||
break; /* write error */
|
||||
} /* for */
|
||||
} /* if */
|
||||
return count;
|
||||
}
|
||||
|
||||
/* fblockread(File: handle, buffer[], size=sizeof buffer) */
|
||||
static cell AMX_NATIVE_CALL n_fblockread(AMX *amx, const cell *params)
|
||||
{
|
||||
cell *cptr;
|
||||
cell count;
|
||||
|
||||
amx_GetAddr(amx,params[2],&cptr);
|
||||
if (cptr!=NULL) {
|
||||
cell max=params[3];
|
||||
ucell v;
|
||||
for (count=0; count<max; count++) {
|
||||
if (fread(&v,sizeof(cell),1,(FILE*)params[1])!=1)
|
||||
break; /* write error */
|
||||
*cptr++=(cell)*aligncell(&v);
|
||||
} /* for */
|
||||
} /* if */
|
||||
return count;
|
||||
}
|
||||
|
||||
/* File: ftemp() */
|
||||
static cell AMX_NATIVE_CALL n_ftemp(AMX *amx, const cell *params)
|
||||
{
|
||||
UNUSED_PARAM(amx);
|
||||
UNUSED_PARAM(params);
|
||||
return (cell)tmpfile();
|
||||
}
|
||||
|
||||
/* fseek(File: handle, position, seek_whence: whence=seek_start) */
|
||||
static cell AMX_NATIVE_CALL n_fseek(AMX *amx, const cell *params)
|
||||
{
|
||||
int whence;
|
||||
switch (params[3]) {
|
||||
case seek_start:
|
||||
whence=SEEK_SET;
|
||||
break;
|
||||
case seek_current:
|
||||
whence=SEEK_CUR;
|
||||
break;
|
||||
case seek_end:
|
||||
whence=SEEK_END;
|
||||
//if (params[2]>0)
|
||||
// params[2]=-params[2];
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
} /* switch */
|
||||
UNUSED_PARAM(amx);
|
||||
return lseek(fileno((FILE*)params[1]),params[2],whence);
|
||||
}
|
||||
|
||||
/* bool: fremove(const name[]) */
|
||||
static cell AMX_NATIVE_CALL n_fremove(AMX *amx, const cell *params)
|
||||
{
|
||||
int r=1;
|
||||
TCHAR *name,fullname[_MAX_PATH];
|
||||
|
||||
amx_StrParam(amx,params[1],name);
|
||||
if (name!=NULL && completename(fullname,name,sizeof fullname)!=NULL)
|
||||
r=remove(fullname);
|
||||
return r==0;
|
||||
}
|
||||
|
||||
/* flength(File: handle) */
|
||||
static cell AMX_NATIVE_CALL n_flength(AMX *amx, const cell *params)
|
||||
{
|
||||
long l,c;
|
||||
int fn=fileno((FILE*)params[1]);
|
||||
c=lseek(fn,0,SEEK_CUR); /* save the current position */
|
||||
l=lseek(fn,0,SEEK_END); /* return the file position at its end */
|
||||
lseek(fn,c,SEEK_SET); /* restore the file pointer */
|
||||
UNUSED_PARAM(amx);
|
||||
return l;
|
||||
}
|
||||
|
||||
static int match_optcopy(TCHAR *out,int outlen,const TCHAR *in,int skip)
|
||||
{
|
||||
if (out==NULL || skip!=0 || outlen<=0)
|
||||
return 0;
|
||||
_tcsncpy(out,in,outlen);
|
||||
out[outlen-1]='\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int matchfiles(const TCHAR *path,int skip,TCHAR *out,int outlen)
|
||||
{
|
||||
int count=0;
|
||||
const TCHAR *basename;
|
||||
#if DIRSEP_CHAR!='/'
|
||||
TCHAR *ptr;
|
||||
#endif
|
||||
#if defined __WIN32__
|
||||
HANDLE hfind;
|
||||
WIN32_FIND_DATA fd;
|
||||
#else
|
||||
/* assume LINUX, FreeBSD, OpenBSD, or some other variant */
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
TCHAR dirname[_MAX_PATH];
|
||||
#endif
|
||||
|
||||
basename=_tcsrchr(path,DIRSEP_CHAR);
|
||||
basename=(basename==NULL) ? path : basename+1;
|
||||
#if DIRSEP_CHAR!='/'
|
||||
ptr=_tcsrchr(basename,DIRSEP_CHAR);
|
||||
basename=(ptr==NULL) ? basename : ptr+1;
|
||||
#endif
|
||||
|
||||
#if defined __WIN32__
|
||||
if ((hfind=FindFirstFile(path,&fd))!=INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (fpattern_match(basename,fd.cFileName,-1,FALSE)) {
|
||||
count++;
|
||||
if (match_optcopy(out,outlen,fd.cFileName,skip--))
|
||||
break;
|
||||
} /* if */
|
||||
} while (FindNextFile(hfind,&fd));
|
||||
FindClose(hfind);
|
||||
} /* if */
|
||||
#else
|
||||
/* copy directory part only (zero-terminate) */
|
||||
if (basename==path) {
|
||||
strcpy(dirname,".");
|
||||
} else {
|
||||
strncpy(dirname,path,(int)(basename-path));
|
||||
dirname[(int)(basename-path)]=_T('\0');
|
||||
} /* if */
|
||||
if ((dir=opendir(dirname))!=NULL) {
|
||||
while ((entry=readdir(dir))!=NULL) {
|
||||
if (fpattern_match(basename,entry->d_name,-1,TRUE)) {
|
||||
count++;
|
||||
if (match_optcopy(out,outlen,entry->d_name,skip--))
|
||||
break;
|
||||
} /* if */
|
||||
} /* while */
|
||||
closedir(dir);
|
||||
} /* if */
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
/* fexist(const pattern[]) */
|
||||
static cell AMX_NATIVE_CALL n_fexist(AMX *amx, const cell *params)
|
||||
{
|
||||
int r=0;
|
||||
TCHAR *name,fullname[_MAX_PATH];
|
||||
|
||||
amx_StrParam(amx,params[1],name);
|
||||
if (name!=NULL && completename(fullname,name,sizeof fullname)!=NULL)
|
||||
r=matchfiles(fullname,0,NULL,0);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* bool: fmatch(filename[], const pattern[], index=0, maxlength=sizeof filename) */
|
||||
static cell AMX_NATIVE_CALL n_fmatch(AMX *amx, const cell *params)
|
||||
{
|
||||
TCHAR *name,fullname[_MAX_PATH]="";
|
||||
cell *cptr;
|
||||
|
||||
amx_StrParam(amx,params[2],name);
|
||||
if (name!=NULL && completename(fullname,name,sizeof fullname)!=NULL) {
|
||||
if (!matchfiles(fullname,params[3],fullname,sizeof fullname)) {
|
||||
fullname[0]='\0';
|
||||
} else {
|
||||
/* copy the string into the destination */
|
||||
amx_GetAddr(amx,params[1],&cptr);
|
||||
amx_SetString(cptr,fullname,1,0,params[4]);
|
||||
} /* if */
|
||||
} /* if */
|
||||
return fullname[0]!='\0';
|
||||
}
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
AMX_NATIVE_INFO file_Natives[] = {
|
||||
{ "fopen", n_fopen },
|
||||
{ "fclose", n_fclose },
|
||||
{ "fwrite", n_fwrite },
|
||||
{ "fread", n_fread },
|
||||
{ "fputchar", n_fputchar },
|
||||
{ "fgetchar", n_fgetchar },
|
||||
{ "fblockwrite", n_fblockwrite },
|
||||
{ "fblockread", n_fblockread },
|
||||
{ "ftemp", n_ftemp },
|
||||
{ "fseek", n_fseek },
|
||||
{ "flength", n_flength },
|
||||
{ "fremove", n_fremove },
|
||||
{ "fexist", n_fexist },
|
||||
{ "fmatch", n_fmatch },
|
||||
{ NULL, NULL } /* terminator */
|
||||
};
|
||||
|
||||
int AMXEXPORT amx_FileInit(AMX *amx)
|
||||
{
|
||||
return amx_Register(amx, file_Natives, -1);
|
||||
}
|
||||
|
||||
int AMXEXPORT amx_FileCleanup(AMX *amx)
|
||||
{
|
||||
UNUSED_PARAM(amx);
|
||||
return AMX_ERR_NONE;
|
||||
}
|
6
SOURCE/amx/amxfile.def
Normal file
6
SOURCE/amx/amxfile.def
Normal file
@ -0,0 +1,6 @@
|
||||
NAME amxFile
|
||||
DESCRIPTION 'File I/O support library'
|
||||
|
||||
EXPORTS
|
||||
amx_FileInit
|
||||
amx_FileCleanup
|
307
SOURCE/amx/amxgc.c
Normal file
307
SOURCE/amx/amxgc.c
Normal file
@ -0,0 +1,307 @@
|
||||
/* Simple garbage collector for the Pawn Abstract Machine
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2004-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxgc.c 3660 2006-11-05 13:05:09Z thiadmer $
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h> /* for malloc()/free() */
|
||||
#include <string.h> /* for memset() */
|
||||
#include "amx.h"
|
||||
#include "amxgc.h"
|
||||
|
||||
typedef struct tagGCPAIR {
|
||||
cell value;
|
||||
int count;
|
||||
} GCPAIR;
|
||||
|
||||
typedef struct tagGCINFO {
|
||||
GCPAIR *table;
|
||||
GC_FREE callback;
|
||||
int exponent;
|
||||
int flags;
|
||||
int count;
|
||||
} GCINFO;
|
||||
|
||||
#define SHIFT1 (sizeof(cell)*4)
|
||||
#define MASK1 (~(((cell)-1) << SHIFT1))
|
||||
#define FOLD1(p) ( ((p) & MASK1) ^ (((p) >> SHIFT1) & MASK1) )
|
||||
/* call FOLD1(c) if the table exponent < SHIFT1 */
|
||||
#define SHIFT2 (sizeof(cell)*2)
|
||||
#define MASK2 (~(((cell)-1) << SHIFT2))
|
||||
#define FOLD2(p) ( ((p) & MASK2) ^ (((p) >> SHIFT2) & MASK2) )
|
||||
/* call FOLD2(c) if the table size < MASK2 */
|
||||
#define SHIFT3 (sizeof(cell))
|
||||
#define MASK3 (~(((cell)-1)<<SHIFT3))
|
||||
#define FOLD3(p) ( ((p) & MASK3) ^ (((p) >> SHIFT3) & MASK3) )
|
||||
/* call FOLD3(c) if the table size < MASK3 */
|
||||
#define MASK(exp) (~(((cell)-1) << (exp)))
|
||||
|
||||
static unsigned increments[17] = { 1, 1, 1, 3, 5, 7, 17, 31, 67, 127, 257,
|
||||
509, 1021, 2053, 4099, 8191, 16381 };
|
||||
|
||||
static unsigned char inverse[256] = {
|
||||
255,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,
|
||||
239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,
|
||||
223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,
|
||||
207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,
|
||||
191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,
|
||||
175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,
|
||||
159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,
|
||||
143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,
|
||||
127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,
|
||||
111,110,109,108,107,106,105,104,103,102,101,100, 99, 98, 97, 96,
|
||||
95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80,
|
||||
79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64,
|
||||
63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48,
|
||||
47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32,
|
||||
31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
|
||||
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
};
|
||||
|
||||
static GCINFO SharedGC;
|
||||
|
||||
|
||||
int gc_setcallback(GC_FREE callback)
|
||||
{
|
||||
SharedGC.callback=callback;
|
||||
return GC_ERR_NONE;
|
||||
}
|
||||
|
||||
int gc_settable(int exponent, int flags)
|
||||
{
|
||||
if (exponent==0) {
|
||||
gc_clean(); /* delete all "live" objects first */
|
||||
if (SharedGC.table!=NULL) {
|
||||
free(SharedGC.table);
|
||||
SharedGC.table=NULL;
|
||||
} /* if */
|
||||
SharedGC.exponent=0;
|
||||
SharedGC.flags=0;
|
||||
SharedGC.count=0;
|
||||
} else {
|
||||
int size,oldsize;
|
||||
GCPAIR *table,*oldtable;
|
||||
|
||||
if (exponent<7 || (1L<<exponent)>INT_MAX)
|
||||
return GC_ERR_PARAMS;
|
||||
size=(1<<exponent);
|
||||
/* the hash table should not hold more elements than the new size */
|
||||
if (SharedGC.count>size)
|
||||
return GC_ERR_PARAMS;
|
||||
/* allocate the new table */
|
||||
table=malloc(size*sizeof(*table));
|
||||
if (table==NULL)
|
||||
return GC_ERR_MEMORY;
|
||||
/* save the statistics of the old table */
|
||||
oldtable=SharedGC.table;
|
||||
oldsize=(1<<SharedGC.exponent);
|
||||
/* clear and set the new table */
|
||||
memset(table,0,size*sizeof(*table));
|
||||
SharedGC.table=table;
|
||||
SharedGC.exponent=exponent;
|
||||
SharedGC.count=flags;
|
||||
SharedGC.count=0; /* old table in initially empty */
|
||||
/* re-mark all objects in the old table */
|
||||
if (oldtable!=NULL) {
|
||||
int index;
|
||||
for (index=0; index<oldsize; index++)
|
||||
if (oldtable[index].value!=0)
|
||||
gc_mark(oldtable[index].value);
|
||||
free(oldtable);
|
||||
} /* if */
|
||||
} /* if */
|
||||
return GC_ERR_NONE;
|
||||
}
|
||||
|
||||
int gc_tablestat(int *exponent,int *percentage)
|
||||
{
|
||||
if (exponent!=NULL)
|
||||
*exponent=SharedGC.exponent;
|
||||
if (*percentage!=NULL) {
|
||||
int size=(1L<<SharedGC.exponent);
|
||||
/* calculate with floating point to avoid integer overflow */
|
||||
double p=100.0*SharedGC.count/size;
|
||||
*percentage=(int)p;
|
||||
} /* if */
|
||||
return GC_ERR_NONE;
|
||||
}
|
||||
|
||||
int gc_mark(cell value)
|
||||
{
|
||||
int index,incr,incridx,mask;
|
||||
cell v,t;
|
||||
unsigned char *minorbyte;
|
||||
|
||||
if (SharedGC.table==NULL)
|
||||
return GC_ERR_INIT;
|
||||
if (SharedGC.count>=(1<<SharedGC.exponent)) {
|
||||
int err;
|
||||
if ((SharedGC.flags & GC_AUTOGROW)==0)
|
||||
return GC_ERR_TABLEFULL;
|
||||
err=gc_settable(SharedGC.exponent+1,SharedGC.flags);
|
||||
if (err!=GC_ERR_NONE)
|
||||
return err;
|
||||
} /* if */
|
||||
assert(SharedGC.count<(1<<SharedGC.exponent));
|
||||
|
||||
/* first "fold" the value, to make maximum use of all bits */
|
||||
v=value;
|
||||
if (SharedGC.exponent<SHIFT1)
|
||||
v=FOLD1(v);
|
||||
if (SharedGC.exponent<SHIFT2)
|
||||
v=FOLD2(v);
|
||||
if (SharedGC.exponent<SHIFT3)
|
||||
v=FOLD3(v);
|
||||
/* swap the bits of the minor byte */
|
||||
minorbyte=(unsigned char*)&v;
|
||||
*minorbyte=inverse[*minorbyte];
|
||||
/* truncate the value to the required number of bits */
|
||||
mask=MASK(SharedGC.exponent);
|
||||
index=(v & mask);
|
||||
|
||||
incridx= (SharedGC.exponent<sizeof increments / sizeof increments[0]) ?
|
||||
SharedGC.exponent :
|
||||
(sizeof increments / sizeof increments[0]) - 1;
|
||||
assert(incridx<sizeof increments / sizeof increments[0]);
|
||||
incr=increments[incridx];
|
||||
while ((t=SharedGC.table[index].value)!=0 && t!=value) {
|
||||
assert(incr>0);
|
||||
index=(index+incr) & mask;
|
||||
if (incridx>0)
|
||||
incr=increments[--incridx];
|
||||
} /* while */
|
||||
|
||||
if (t!=0) {
|
||||
assert(t==value);
|
||||
assert(SharedGC.table[index].value==value);
|
||||
return GC_ERR_DUPLICATE;
|
||||
} /* if */
|
||||
|
||||
SharedGC.table[index].value=value;
|
||||
assert(SharedGC.table[index].count==0);
|
||||
|
||||
return GC_ERR_NONE;
|
||||
}
|
||||
|
||||
static void scansection(cell *start,size_t size)
|
||||
{
|
||||
int index,incr,incridx,incridx_org,mask;
|
||||
cell v,t;
|
||||
unsigned char *minorbyte;
|
||||
|
||||
assert(SharedGC.table!=NULL);
|
||||
assert((size % sizeof(cell))==0);
|
||||
assert(start!=NULL);
|
||||
size/=sizeof(cell); /* from number of bytes to number of cells */
|
||||
|
||||
incridx_org= (SharedGC.exponent<sizeof increments / sizeof increments[0]) ?
|
||||
SharedGC.exponent :
|
||||
(sizeof increments / sizeof increments[0]) - 1;
|
||||
assert(incridx_org<sizeof increments / sizeof increments[0]);
|
||||
|
||||
minorbyte=(unsigned char*)&v;
|
||||
mask=MASK(SharedGC.exponent);
|
||||
|
||||
while (size>0) {
|
||||
v=*start;
|
||||
/* first "fold" the value, to make maximum use of all bits */
|
||||
if (SharedGC.exponent<SHIFT1)
|
||||
v=FOLD1(v);
|
||||
if (SharedGC.exponent<SHIFT2)
|
||||
v=FOLD2(v);
|
||||
if (SharedGC.exponent<SHIFT3)
|
||||
v=FOLD3(v);
|
||||
/* swap the bits of the minor byte */
|
||||
assert(minorbyte==(unsigned char*)&v);
|
||||
*minorbyte=inverse[*minorbyte];
|
||||
/* truncate the value to the required number of bits */
|
||||
index=(v & mask);
|
||||
|
||||
/* find it in the table */
|
||||
incridx=incridx_org;
|
||||
incr=increments[incridx];
|
||||
while ((t=SharedGC.table[index].value)!=*start && t!=0) {
|
||||
assert(incr>0);
|
||||
index=(index+incr) & mask;
|
||||
if (incridx>0)
|
||||
incr=increments[--incridx];
|
||||
} /* while */
|
||||
|
||||
/* if found, mark it */
|
||||
if (t!=0) {
|
||||
assert(t==*start);
|
||||
assert(SharedGC.table[index].value==*start);
|
||||
SharedGC.table[index].count+=1;
|
||||
} /* if */
|
||||
|
||||
size--;
|
||||
start++;
|
||||
} /* while */
|
||||
}
|
||||
|
||||
int gc_scan(AMX *amx)
|
||||
{
|
||||
AMX_HEADER *hdr;
|
||||
unsigned char *data;
|
||||
|
||||
if (amx==NULL)
|
||||
return GC_ERR_PARAMS;
|
||||
if (SharedGC.table==NULL)
|
||||
return GC_ERR_INIT;
|
||||
|
||||
hdr=(AMX_HEADER*)amx->base;
|
||||
|
||||
/* scan data segment */
|
||||
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
|
||||
scansection((cell *)data, hdr->hea - hdr->dat);
|
||||
/* scan stack */
|
||||
scansection((cell *)(data + amx->hlw), amx->hea - amx->hlw);
|
||||
/* scan heap */
|
||||
scansection((cell *)(data + amx->stk), amx->stp - amx->stk);
|
||||
|
||||
return GC_ERR_NONE;
|
||||
}
|
||||
|
||||
int gc_clean(void)
|
||||
{
|
||||
int size;
|
||||
GCPAIR *item;
|
||||
|
||||
if (SharedGC.table==NULL)
|
||||
return GC_ERR_INIT;
|
||||
if (SharedGC.callback==NULL)
|
||||
return GC_ERR_CALLBACK;
|
||||
|
||||
size=(1<<SharedGC.exponent);
|
||||
item=SharedGC.table;
|
||||
while (size>0) {
|
||||
if (item->value!=0) {
|
||||
if (item->count==0) {
|
||||
SharedGC.callback(item->value);
|
||||
item->value=0;
|
||||
} /* if */
|
||||
item->count=0;
|
||||
} /* if */
|
||||
size--;
|
||||
item++;
|
||||
} /* while */
|
||||
return GC_ERR_NONE;
|
||||
}
|
54
SOURCE/amx/amxgc.h
Normal file
54
SOURCE/amx/amxgc.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* Simple garbage collector for the Pawn Abstract Machine
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2004-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxgc.h 3612 2006-07-22 09:59:46Z thiadmer $
|
||||
*/
|
||||
|
||||
#ifndef AMXGC_H
|
||||
#define AMXGC_H
|
||||
|
||||
typedef void _FAR (* GC_FREE)(cell unreferenced);
|
||||
enum {
|
||||
GC_ERR_NONE,
|
||||
GC_ERR_CALLBACK, /* no callback, or invalid callback */
|
||||
GC_ERR_INIT, /* garbage collector not initialized (no table size) */
|
||||
GC_ERR_MEMORY, /* insufficient memory to set/resize the table */
|
||||
GC_ERR_PARAMS, /* parameter error */
|
||||
GC_ERR_TABLEFULL, /* domain error, expression result does not fit in range */
|
||||
GC_ERR_DUPLICATE, /* item is already in the table */
|
||||
};
|
||||
|
||||
/* flags */
|
||||
#define GC_AUTOGROW 1 /* gc_mark() may grow the hash table when it fills up */
|
||||
|
||||
int gc_setcallback(GC_FREE callback);
|
||||
|
||||
int gc_settable(int exponent,int flags);
|
||||
int gc_tablestat(int *exponent,int *percentage);
|
||||
/* Upon return, "exponent" will hold the values passed to gc_settable();
|
||||
* "percentage" is the level (in percent) that the hash table is filled
|
||||
* up. Either parameter may be set to NULL.
|
||||
*/
|
||||
|
||||
int gc_mark(cell value);
|
||||
int gc_scan(AMX *amx);
|
||||
int gc_clean(void);
|
||||
|
||||
#endif /* AMXGC_H */
|
2229
SOURCE/amx/amxjitr.asm
Normal file
2229
SOURCE/amx/amxjitr.asm
Normal file
File diff suppressed because it is too large
Load Diff
2261
SOURCE/amx/amxjits.asm
Normal file
2261
SOURCE/amx/amxjits.asm
Normal file
File diff suppressed because it is too large
Load Diff
2404
SOURCE/amx/amxjitsn.asm
Normal file
2404
SOURCE/amx/amxjitsn.asm
Normal file
File diff suppressed because it is too large
Load Diff
932
SOURCE/amx/amxprocess.c
Normal file
932
SOURCE/amx/amxprocess.c
Normal file
@ -0,0 +1,932 @@
|
||||
/* Process control and Foreign Function Interface module for the Pawn AMX
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2005-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxprocess.c 3664 2006-11-08 12:09:25Z thiadmer $
|
||||
*/
|
||||
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
|
||||
# if !defined UNICODE /* for Windows */
|
||||
# define UNICODE
|
||||
# endif
|
||||
# if !defined _UNICODE /* for C library */
|
||||
# define _UNICODE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
|
||||
#include <windows.h>
|
||||
#elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
/* The package libffi library (required for compiling this extension module
|
||||
* under Unix/Linux) is not included, because its license is more restrictive
|
||||
* than that of Pawn (even if ever so slightly). Recent versions of the GCC
|
||||
* compiler include libffi. A separate download of the libffi package is
|
||||
* available at http://sources.redhat.com/libffi/ and
|
||||
* http://sablevm.org/download/snapshot/.
|
||||
*/
|
||||
#include <ffi.h>
|
||||
#endif
|
||||
#include "osdefs.h"
|
||||
#include "amx.h"
|
||||
|
||||
#if defined _UNICODE
|
||||
# include <tchar.h>
|
||||
#elif !defined __T
|
||||
typedef char TCHAR;
|
||||
# define __T(string) string
|
||||
# define _istdigit isdigit
|
||||
# define _tgetenv getenv
|
||||
# define _tcscat strcat
|
||||
# define _tcschr strchr
|
||||
# define _tcscmp strcmp
|
||||
# define _tcscpy strcpy
|
||||
# define _tcsdup strdup
|
||||
# define _tcslen strlen
|
||||
# define _tcsncmp strncmp
|
||||
# define _tcspbrk strpbrk
|
||||
# define _tcsrchr strrchr
|
||||
# define _tcstol strtol
|
||||
#endif
|
||||
|
||||
|
||||
#define MAXPARAMS 32 /* maximum number of parameters to a called function */
|
||||
|
||||
|
||||
typedef struct tagMODlIST {
|
||||
struct tagMODlIST _FAR *next;
|
||||
TCHAR _FAR *name;
|
||||
unsigned long inst;
|
||||
AMX *amx;
|
||||
} MODLIST;
|
||||
|
||||
typedef struct tagPARAM {
|
||||
union {
|
||||
void *ptr;
|
||||
long val;
|
||||
} v;
|
||||
unsigned char type;
|
||||
unsigned char size;
|
||||
int range;
|
||||
} PARAM;
|
||||
|
||||
#define BYREF 0x80 /* stored in the "type" field fo the PARAM structure */
|
||||
|
||||
static MODLIST ModRoot = { NULL };
|
||||
|
||||
/* pipes for I/O redirection */
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
static HANDLE newstdin,newstdout,read_stdout,write_stdin;
|
||||
#elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
static int pipe_to[2]={-1,-1};
|
||||
static int pipe_from[2]={-1,-1};
|
||||
void *inst_ffi=NULL; /* open handle for libffi */
|
||||
#endif
|
||||
|
||||
|
||||
static const TCHAR *skippath(const TCHAR *name)
|
||||
{
|
||||
const TCHAR *ptr;
|
||||
|
||||
assert(name != NULL);
|
||||
if ((ptr = _tcsrchr(name, __T(DIRSEP_CHAR))) == NULL)
|
||||
ptr = name;
|
||||
else
|
||||
ptr++;
|
||||
assert(ptr != NULL);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static MODLIST _FAR *findlib(MODLIST *root, AMX *amx, const TCHAR *name)
|
||||
{
|
||||
MODLIST _FAR *item;
|
||||
const TCHAR *ptr = skippath(name);
|
||||
|
||||
for (item = root->next; item != NULL; item = item->next)
|
||||
if (_tcscmp(item->name, ptr) == 0 && item->amx == amx)
|
||||
return item;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static MODLIST _FAR *addlib(MODLIST *root, AMX *amx, const TCHAR *name)
|
||||
{
|
||||
MODLIST _FAR *item;
|
||||
const TCHAR *ptr = skippath(name);
|
||||
|
||||
assert(findlib(root, amx, name) == NULL); /* should not already be there */
|
||||
|
||||
if ((item = malloc(sizeof(MODLIST))) == NULL)
|
||||
goto error;
|
||||
memset(item, 0, sizeof(MODLIST));
|
||||
|
||||
assert(ptr != NULL);
|
||||
if ((item->name = malloc((_tcslen(ptr) + 1) * sizeof(TCHAR))) == NULL)
|
||||
goto error;
|
||||
_tcscpy(item->name, ptr);
|
||||
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
|
||||
item->inst = (unsigned long)LoadLibrary(name);
|
||||
#if !(defined __WIN32__ || defined _WIN32 || defined WIN32)
|
||||
if (item->inst <= 32)
|
||||
item->inst = 0;
|
||||
#endif
|
||||
#elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
/* also load the FFI library, if this is the first call */
|
||||
inst_ffi=dlopen("libffi.so",RTLD_NOW);
|
||||
if (inst_ffi==NULL)
|
||||
inst_ffi=dlopen("libffi-2.00-beta.so",RTLD_NOW);
|
||||
if (inst_ffi==NULL)
|
||||
goto error; /* failed to load either the old library or the new libbrary */
|
||||
item->inst = (unsigned long)dlopen(name,RTLD_NOW);
|
||||
#else
|
||||
#error Unsupported environment
|
||||
#endif
|
||||
if (item->inst == 0)
|
||||
goto error;
|
||||
|
||||
item->amx = amx;
|
||||
|
||||
item->next = root->next;
|
||||
root->next = item;
|
||||
return item;
|
||||
|
||||
error:
|
||||
if (item != NULL) {
|
||||
if (item->name != NULL)
|
||||
free(item->name);
|
||||
if (item->inst != 0) {
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
|
||||
FreeLibrary((HINSTANCE)item->inst);
|
||||
#elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
dlclose((void*)item->inst);
|
||||
#else
|
||||
#error Unsupported environment
|
||||
#endif
|
||||
} /* if */
|
||||
free(item);
|
||||
} /* if */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int freelib(MODLIST *root, AMX *amx, const TCHAR *name)
|
||||
{
|
||||
MODLIST _FAR *item, _FAR *prev;
|
||||
const TCHAR *ptr;
|
||||
int count = 0;
|
||||
|
||||
ptr = (name != NULL) ? skippath(name) : NULL;
|
||||
|
||||
for (prev = root, item = prev->next; item != NULL; prev = item, item = prev->next) {
|
||||
if ((amx == NULL || amx == item->amx) && (ptr == NULL || _tcscmp(item->name, ptr) == 0)) {
|
||||
prev->next = item->next; /* unlink first */
|
||||
assert(item->inst != 0);
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
|
||||
FreeLibrary((HINSTANCE)item->inst);
|
||||
#elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
dlclose((void*)item->inst);
|
||||
#else
|
||||
#error Unsupported environment
|
||||
#endif
|
||||
assert(item->name != NULL);
|
||||
free(item->name);
|
||||
free(item);
|
||||
count++;
|
||||
} /* if */
|
||||
} /* for */
|
||||
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
if (amx==NULL && name==NULL && inst_ffi!=NULL)
|
||||
dlclose(inst_ffi);
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
|
||||
|
||||
typedef long (CALLBACK* LIBFUNC)();
|
||||
|
||||
/* push()
|
||||
**
|
||||
** This function is the kind of programming trick that you don't even dare to
|
||||
** dream about! With the usual C calling convention, the caller cleans up the
|
||||
** stack after calling the function. This allows C functions to be flexible
|
||||
** with parameters, both in number and in type.
|
||||
** With the Pascal calling convention, used here, the callee (the function)
|
||||
** cleans up the stack. But here, function push() doesn't know about any
|
||||
** parameters. We neither declare any, nor indicate that the function has no
|
||||
** parameters (i.e. the function is not declared having 'void' parameters).
|
||||
** When we call function push(), the caller thinks the function cleans up the
|
||||
** stack (because of the Pascal calling convention), while the function does
|
||||
** not know that it has parameters, so it cannot clean them. As a result,
|
||||
** nobody cleans up the stack. Ergo, The parameter you pass to function push()
|
||||
** stays on the stack.
|
||||
*/
|
||||
static void PASCAL push() { }
|
||||
|
||||
LIBFUNC SearchProcAddress(unsigned long inst, const char *functionname)
|
||||
{
|
||||
FARPROC lpfn;
|
||||
|
||||
assert(inst!=0);
|
||||
lpfn=GetProcAddress((HINSTANCE)inst,functionname);
|
||||
#if defined __WIN32__
|
||||
if (lpfn==NULL && strlen(functionname)<128-1) {
|
||||
char str[128];
|
||||
strcpy(str,functionname);
|
||||
#if defined UNICODE
|
||||
strcat(str,"W");
|
||||
#else
|
||||
strcat(str,"A");
|
||||
#endif
|
||||
lpfn = GetProcAddress((HINSTANCE)inst,str);
|
||||
} /* if */
|
||||
#endif
|
||||
return (LIBFUNC)lpfn;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef long (* LIBFUNC)();
|
||||
|
||||
LIBFUNC SearchProcAddress(unsigned long inst, const char *functionname)
|
||||
{
|
||||
assert(inst!=0);
|
||||
return (LIBFUNC)dlsym((void*)inst, functionname);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void *fillarray(AMX *amx, PARAM *param, cell *cptr)
|
||||
{
|
||||
int i;
|
||||
void *vptr;
|
||||
|
||||
vptr = malloc(param->range * (param->size / 8));
|
||||
if (vptr == NULL) {
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return NULL;
|
||||
} /* if */
|
||||
|
||||
assert(param->range > 1);
|
||||
if (param->size == 8) {
|
||||
unsigned char *ptr = (unsigned char *)vptr;
|
||||
for (i = 0; i < param->range; i++)
|
||||
*ptr++ = (unsigned char)*cptr++;
|
||||
} else if (param->size == 16) {
|
||||
unsigned short *ptr = (unsigned short *)vptr;
|
||||
for (i = 0; i < param->range; i++)
|
||||
*ptr++ = (unsigned short)*cptr++;
|
||||
} else {
|
||||
unsigned long *ptr = (unsigned long *)vptr;
|
||||
for (i = 0; i < param->range; i++)
|
||||
*ptr++ = (unsigned long)*cptr++;
|
||||
} /* for */
|
||||
|
||||
return vptr;
|
||||
}
|
||||
|
||||
/* libcall(const libname[], const funcname[], const typestring[], ...)
|
||||
*
|
||||
* Loads the DLL or shared library if not yet loaded (the name comparison is
|
||||
* case sensitive).
|
||||
*
|
||||
* typestring format:
|
||||
* Whitespace is permitted between the types, but not inside the type
|
||||
* specification. The string "ii[4]&u16s" is equivalent to "i i[4] &u16 s",
|
||||
* but easier on the eye.
|
||||
*
|
||||
* types:
|
||||
* i = signed integer, 16-bit in Windows 3.x, else 32-bit in Win32 and Linux
|
||||
* u = unsigned integer, 16-bit in Windows 3.x, else 32-bit in Win32 and Linux
|
||||
* f = IEEE floating point, 32-bit
|
||||
* p = packed string
|
||||
* s = unpacked string
|
||||
* The difference between packed and unpacked strings is only relevant when
|
||||
* the parameter is passed by reference (see below).
|
||||
*
|
||||
* pass-by-value and pass-by-reference:
|
||||
* By default, parameters are passed by value. To pass a parameter by
|
||||
* reference, prefix the type letter with an "&":
|
||||
* &i = signed integer passed by reference
|
||||
* i = signed integer passed by value
|
||||
* Same for '&u' versus 'u' and '&f' versus 'f'.
|
||||
*
|
||||
* Arrays are passed by "copy & copy-back". That is, libcall() allocates a
|
||||
* block of dynamic memory to copy the array into. On return from the foreign
|
||||
* function, libcall() copies the array back to the abstract machine. The
|
||||
* net effect is similar to pass by reference, but the foreign function does
|
||||
* not work in the AMX stack directly. During the copy and the copy-back
|
||||
* operations, libcall() may also transform the array elements, for example
|
||||
* between 16-bit and 32-bit elements. This is done because Pawn only
|
||||
* supports a single cell size, which may not fit the required integer size
|
||||
* of the foreign function.
|
||||
*
|
||||
* See "element ranges" for the syntax of passing an array.
|
||||
*
|
||||
* Strings may either be passed by copy, or by "copy & copy-back". When the
|
||||
* string is an output parameter (for the foreign function), the size of the
|
||||
* array that will hold the return string must be indicated between square
|
||||
* brackets behind the type letter (see "element ranges"). When the string
|
||||
* is "input only", this is not needed --libcall() will determine the length
|
||||
* of the input string itself.
|
||||
*
|
||||
* The tokens 'p' and 's' are equivalent, but 'p[10]' and 's[10]' are not
|
||||
* equivalent: the latter syntaxes determine whether the output from the
|
||||
* foreign function will be stored as a packed or an unpacked string.
|
||||
*
|
||||
* element sizes:
|
||||
* Add an integer behind the type letter; for example, 'i16' refers to a
|
||||
* 16-bit signed integer. Note that the value behind the type letter must
|
||||
* be either 8, 16 or 32.
|
||||
*
|
||||
* You should only use element size specifiers on the 'i' and 'u' types. That
|
||||
* is, do not use these specifiers on 'f', 's' and 'p'.
|
||||
*
|
||||
* element ranges:
|
||||
* For passing arrays, the size of the array may be given behind the type
|
||||
* letter and optional element size. The token 'u[4]' indicates an array of
|
||||
* four unsigned integers, which are typically 32-bit. The token 'i16[8]'
|
||||
* is an array of 8 signed 16-bit integers. Arrays are always passed by
|
||||
* "copy & copy-back"
|
||||
*
|
||||
* When compiled as Unicode, this library converts all strings to Unicode
|
||||
* strings.
|
||||
*
|
||||
* The calling convention for the foreign functions is assumed:
|
||||
* - "__stdcall" for Win32,
|
||||
* - "far pascal" for Win16
|
||||
* - and the GCC default for Unix/Linux (_cdecl)
|
||||
*
|
||||
* C++ name mangling of the called function is not handled (there is no standard
|
||||
* convention for name mangling, so there is no portable way to convert C++
|
||||
* function names to mangled names). Win32 name mangling (used by default by
|
||||
* Microsoft compilers on functions declared as __stdcall) is also not handled.
|
||||
*
|
||||
* Returns the value of the called function.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_libcall(AMX *amx, const cell *params)
|
||||
{
|
||||
const TCHAR *libname, *funcname, *typestring;
|
||||
MODLIST *item;
|
||||
int paramidx, typeidx, idx;
|
||||
PARAM ps[MAXPARAMS];
|
||||
cell *cptr,result;
|
||||
LIBFUNC LibFunc;
|
||||
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
ffi_cif cif;
|
||||
ffi_type *ptypes[MAXPARAMS];
|
||||
void *pvalues[MAXPARAMS];
|
||||
#endif
|
||||
|
||||
amx_StrParam(amx, params[1], libname);
|
||||
item = findlib(&ModRoot, amx, libname);
|
||||
if (item == NULL)
|
||||
item = addlib(&ModRoot, amx, libname);
|
||||
if (item == NULL) {
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
/* library is loaded, get the function */
|
||||
amx_StrParam(amx, params[2], funcname);
|
||||
LibFunc=(LIBFUNC)SearchProcAddress(item->inst, funcname);
|
||||
if (LibFunc==NULL) {
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
/* decode the parameters */
|
||||
paramidx=typeidx=0;
|
||||
amx_StrParam(amx, params[3], typestring);
|
||||
while (paramidx < MAXPARAMS && typestring[typeidx]!=__T('\0')) {
|
||||
/* skip white space */
|
||||
while (typestring[typeidx]!=__T('\0') && typestring[typeidx]<=__T(' '))
|
||||
typeidx++;
|
||||
if (typestring[typeidx]==__T('\0'))
|
||||
break;
|
||||
/* save "pass-by-reference" token */
|
||||
ps[paramidx].type=0;
|
||||
if (typestring[typeidx]==__T('&')) {
|
||||
ps[paramidx].type=BYREF;
|
||||
typeidx++;
|
||||
} /* if */
|
||||
/* store type character */
|
||||
ps[paramidx].type |= (unsigned char)typestring[typeidx];
|
||||
typeidx++;
|
||||
/* set default size, then check for an explicit size */
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
ps[paramidx].size=32;
|
||||
#elif defined _Windows
|
||||
ps[paramidx].size=16;
|
||||
#endif
|
||||
if (_istdigit(typestring[typeidx])) {
|
||||
ps[paramidx].size=(unsigned char)_tcstol(&typestring[typeidx],NULL,10);
|
||||
while (_istdigit(typestring[typeidx]))
|
||||
typeidx++;
|
||||
} /* if */
|
||||
/* set default range, then check for an explicit range */
|
||||
ps[paramidx].range=1;
|
||||
if (typestring[typeidx]=='[') {
|
||||
ps[paramidx].range=_tcstol(&typestring[typeidx+1],NULL,10);
|
||||
while (typestring[typeidx]!=']' && typestring[typeidx]!='\0')
|
||||
typeidx++;
|
||||
ps[paramidx].type |= BYREF; /* arrays are always passed by reference */
|
||||
typeidx++; /* skip closing ']' too */
|
||||
} /* if */
|
||||
/* get pointer to parameter */
|
||||
amx_GetAddr(amx,params[paramidx+4],&cptr);
|
||||
switch (ps[paramidx].type) {
|
||||
case 'i': /* signed integer */
|
||||
case 'u': /* unsigned integer */
|
||||
case 'f': /* floating point */
|
||||
assert(ps[paramidx].range==1);
|
||||
ps[paramidx].v.val=(int)*cptr;
|
||||
break;
|
||||
case 'i' | BYREF:
|
||||
case 'u' | BYREF:
|
||||
case 'f' | BYREF:
|
||||
ps[paramidx].v.ptr=cptr;
|
||||
if (ps[paramidx].range>1) {
|
||||
/* convert array and pass by address */
|
||||
ps[paramidx].v.ptr = fillarray(amx, &ps[paramidx], cptr);
|
||||
} /* if */
|
||||
break;
|
||||
case 'p':
|
||||
case 's':
|
||||
case 'p' | BYREF:
|
||||
case 's' | BYREF:
|
||||
if (ps[paramidx].type=='s' || ps[paramidx].type=='p') {
|
||||
int len;
|
||||
/* get length of input string */
|
||||
amx_StrLen(cptr,&len);
|
||||
len++; /* include '\0' */
|
||||
/* check max. size */
|
||||
if (len<ps[paramidx].range)
|
||||
len=ps[paramidx].range;
|
||||
ps[paramidx].range=len;
|
||||
} /* if */
|
||||
ps[paramidx].v.ptr=malloc(ps[paramidx].range*sizeof(TCHAR));
|
||||
if (ps[paramidx].v.ptr==NULL)
|
||||
return amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
amx_GetString((char *)ps[paramidx].v.ptr,cptr,sizeof(TCHAR)>1,UNLIMITED);
|
||||
break;
|
||||
default:
|
||||
/* invalid parameter type */
|
||||
return amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
} /* switch */
|
||||
paramidx++;
|
||||
} /* while */
|
||||
if ((params[0]/sizeof(cell)) - 3 != (size_t)paramidx)
|
||||
return amx_RaiseError(amx, AMX_ERR_NATIVE); /* format string does not match number of parameters */
|
||||
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
|
||||
/* push the parameters to the stack (left-to-right in 16-bit; right-to-left
|
||||
* in 32-bit)
|
||||
*/
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
for (idx=paramidx-1; idx>=0; idx--) {
|
||||
#else
|
||||
for (idx=0; idx<paramidx; idx++) {
|
||||
#endif
|
||||
if ((ps[idx].type=='i' || ps[idx].type=='u' || ps[idx].type=='f') && ps[idx].range==1) {
|
||||
switch (ps[idx].size) {
|
||||
case 8:
|
||||
push((unsigned char)(ps[idx].v.val & 0xff));
|
||||
break;
|
||||
case 16:
|
||||
push((unsigned short)(ps[idx].v.val & 0xffff));
|
||||
break;
|
||||
default:
|
||||
push(ps[idx].v.val);
|
||||
} /* switch */
|
||||
} else {
|
||||
push(ps[idx].v.ptr);
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
/* call the function; all parameters are already pushed to the stack (the
|
||||
* function should remove the parameters from the stack)
|
||||
*/
|
||||
result=LibFunc();
|
||||
#elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
/* use libffi (foreign function interface) */
|
||||
for (idx = 0; idx < paramidx; idx++) {
|
||||
/* copy parameter types */
|
||||
switch (ps[idx].type) {
|
||||
case 'i': /* signed integer */
|
||||
assert(ps[idx].range==1);
|
||||
switch (ps[idx].size) {
|
||||
case 8:
|
||||
ptypes[idx] = &ffi_type_sint8;
|
||||
break;
|
||||
case 16:
|
||||
ptypes[idx] = &ffi_type_sint16;
|
||||
break;
|
||||
default:
|
||||
ptypes[idx] = &ffi_type_sint32;
|
||||
} /* switch */
|
||||
break;
|
||||
case 'u': /* unsigned integer */
|
||||
assert(ps[idx].range==1);
|
||||
switch (ps[idx].size) {
|
||||
case 8:
|
||||
ptypes[idx] = &ffi_type_uint8;
|
||||
break;
|
||||
case 16:
|
||||
ptypes[idx] = &ffi_type_uint16;
|
||||
break;
|
||||
default:
|
||||
ptypes[idx] = &ffi_type_uint32;
|
||||
} /* switch */
|
||||
break;
|
||||
case 'f': /* floating point */
|
||||
assert(ps[idx].range==1);
|
||||
ptypes[idx] = &ffi_type_float;
|
||||
break;
|
||||
default: /* strings, arrays, fields passed by reference */
|
||||
ptypes[idx] = &ffi_type_pointer;
|
||||
break;
|
||||
/* switch */
|
||||
} /* if */
|
||||
/* copy pointer to parameter values */
|
||||
pvalues[idx] = &ps[idx].v;
|
||||
} /* for */
|
||||
ffi_prep_cif(&cif, FFI_DEFAULT_ABI, paramidx, &ffi_type_slong, ptypes);
|
||||
ffi_call(&cif, FFI_FN(LibFunc), (void*)&result, pvalues);
|
||||
#endif
|
||||
|
||||
/* store return values and free allocated memory */
|
||||
for (idx=0; idx<paramidx; idx++) {
|
||||
switch (ps[idx].type) {
|
||||
case 'p':
|
||||
case 's':
|
||||
free(ps[idx].v.ptr);
|
||||
break;
|
||||
case 'p' | BYREF:
|
||||
case 's' | BYREF:
|
||||
amx_GetAddr(amx,params[idx+4],&cptr);
|
||||
amx_SetString(cptr,(char *)ps[idx].v.ptr,ps[idx].type==('p'|BYREF),sizeof(TCHAR)>1,UNLIMITED);
|
||||
free(ps[idx].v.ptr);
|
||||
break;
|
||||
case 'i':
|
||||
case 'u':
|
||||
case 'f':
|
||||
assert(ps[idx].range==1);
|
||||
break;
|
||||
case 'i' | BYREF:
|
||||
case 'u' | BYREF:
|
||||
case 'f' | BYREF:
|
||||
amx_GetAddr(amx,params[idx+4],&cptr);
|
||||
if (ps[idx].range==1) {
|
||||
/* modify directly in the AMX (no memory block was allocated */
|
||||
switch (ps[idx].size) {
|
||||
case 8:
|
||||
*cptr= (ps[idx].type==('i' | BYREF)) ? (long)((signed char)*cptr) : (*cptr & 0xff);
|
||||
break;
|
||||
case 16:
|
||||
*cptr= (ps[idx].type==('i' | BYREF)) ? (long)((short)*cptr) : (*cptr & 0xffff);
|
||||
break;
|
||||
} /* switch */
|
||||
} else {
|
||||
int i;
|
||||
for (i=0; i<ps[idx].range; i++) {
|
||||
switch (ps[idx].size) {
|
||||
case 8:
|
||||
*cptr= (ps[idx].type==('i' | BYREF)) ? ((signed char*)ps[idx].v.ptr)[i] : ((unsigned char*)ps[idx].v.ptr)[i];
|
||||
break;
|
||||
case 16:
|
||||
*cptr= (ps[idx].type==('i' | BYREF)) ? ((short*)ps[idx].v.ptr)[i] : ((unsigned short*)ps[idx].v.ptr)[i];
|
||||
break;
|
||||
default:
|
||||
*cptr= (ps[idx].type==('i' | BYREF)) ? ((long*)ps[idx].v.ptr)[i] : ((unsigned long*)ps[idx].v.ptr)[i];
|
||||
} /* switch */
|
||||
} /* for */
|
||||
free((char *)ps[idx].v.ptr);
|
||||
} /* if */
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
} /* switch */
|
||||
} /* for */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* bool: libfree(const libname[]="")
|
||||
* When the name is an empty string, this function frees all libraries (for this
|
||||
* abstract machine). The name comparison is case sensitive.
|
||||
* Returns true if one or more libraries were freed.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_libfree(AMX *amx, const cell *params)
|
||||
{
|
||||
const TCHAR *libname;
|
||||
amx_StrParam(amx,params[1],libname);
|
||||
return freelib(&ModRoot,amx,libname) > 0;
|
||||
}
|
||||
|
||||
static void closepipe(void)
|
||||
{
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
if (newstdin!=NULL) {
|
||||
CloseHandle(newstdin);
|
||||
newstdin=NULL;
|
||||
} /* if */
|
||||
if (newstdout!=NULL) {
|
||||
CloseHandle(newstdout);
|
||||
newstdout=NULL;
|
||||
} /* if */
|
||||
if (read_stdout!=NULL) {
|
||||
CloseHandle(read_stdout);
|
||||
read_stdout=NULL;
|
||||
} /* if */
|
||||
if (write_stdin!=NULL) {
|
||||
CloseHandle(write_stdin);
|
||||
write_stdin=NULL;
|
||||
} /* if */
|
||||
#elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
if (pipe_to[0]>=0) {
|
||||
close(pipe_to[0]);
|
||||
pipe_to[0]=-1;
|
||||
} /* if */
|
||||
if (pipe_to[1]>=0) {
|
||||
close(pipe_to[1]);
|
||||
pipe_to[1]=-1;
|
||||
} /* if */
|
||||
if (pipe_from[0]>=0) {
|
||||
close(pipe_from[0]);
|
||||
pipe_from[0]=-1;
|
||||
} /* if */
|
||||
if (pipe_from[1]>=0) {
|
||||
close(pipe_from[1]);
|
||||
pipe_from[1]=-1;
|
||||
} /* if */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* PID: procexec(const commandline[])
|
||||
* Executes a program. Returns an "id" representing the new process (or 0 on
|
||||
* failure).
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_procexec(AMX *amx, const cell *params)
|
||||
{
|
||||
TCHAR *pgmname;
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
BOOL IsWinNT;
|
||||
OSVERSIONINFO VerInfo;
|
||||
STARTUPINFO si;
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
PROCESS_INFORMATION pi;
|
||||
#elif defined _Windows
|
||||
HINSTANCE hinst;
|
||||
#elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
pid_t pid;
|
||||
#endif
|
||||
|
||||
amx_StrParam(amx,params[1],pgmname);
|
||||
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
/* most of this code comes from a "Borland Network" article, combined
|
||||
* with some knowledge gained from a CodeProject article
|
||||
*/
|
||||
closepipe();
|
||||
|
||||
VerInfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
|
||||
GetVersionEx(&VerInfo);
|
||||
IsWinNT = VerInfo.dwPlatformId==VER_PLATFORM_WIN32_NT;
|
||||
|
||||
if (IsWinNT) { //initialize security descriptor (Windows NT)
|
||||
InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
|
||||
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
} else {
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
} /* if */
|
||||
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
sa.bInheritHandle = TRUE; //allow inheritable handles
|
||||
|
||||
if (!CreatePipe(&newstdin,&write_stdin,&sa,0)) { //create stdin pipe
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
if (!CreatePipe(&read_stdout,&newstdout,&sa,0)) { //create stdout pipe
|
||||
closepipe();
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
GetStartupInfo(&si); //set startupinfo for the spawned process
|
||||
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_SHOWNORMAL;
|
||||
si.hStdOutput = newstdout;
|
||||
si.hStdError = newstdout; //set the new handles for the child process
|
||||
si.hStdInput = newstdin;
|
||||
|
||||
/* spawn the child process */
|
||||
if (!CreateProcess(NULL,(TCHAR*)pgmname,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi)) {
|
||||
closepipe();
|
||||
return 0;
|
||||
} /* if */
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
Sleep(100);
|
||||
return pi.dwProcessId;
|
||||
#elif defined _Windows
|
||||
hinst=WinExec(pgmname,SW_SHOW);
|
||||
if (hinst<=32)
|
||||
hinst=0;
|
||||
return (cell)hinst;
|
||||
#elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
/* set up communication pipes first */
|
||||
closepipe();
|
||||
if (pipe(pipe_to)!=0 || pipe(pipe_from)!=0) {
|
||||
closepipe();
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
/* attempt to fork */
|
||||
if ((pid=fork())<0) {
|
||||
closepipe();
|
||||
amx_RaiseError(amx, AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
if (pid==0) {
|
||||
/* this is the child process */
|
||||
#define MAX_ARGS 10
|
||||
TCHAR *args[MAX_ARGS];
|
||||
int i;
|
||||
dup2(pipe_to[0],STDIN_FILENO); /* replace stdin with the in side of the pipe */
|
||||
dup2(pipe_from[1],STDOUT_FILENO); /* replace stdout with the out side of the pipe */
|
||||
close(pipe_to[0]); /* the pipes are no longer needed */
|
||||
close(pipe_to[1]);
|
||||
close(pipe_from[0]);
|
||||
close(pipe_from[1]);
|
||||
pipe_to[0]=-1;
|
||||
pipe_to[1]=-1;
|
||||
pipe_from[0]=-1;
|
||||
pipe_from[1]=-1;
|
||||
/* split off the option(s) */
|
||||
assert(MAX_ARGS>=2); /* args[0] is reserved */
|
||||
memset(args,0,MAX_ARGS*sizeof(TCHAR*));
|
||||
args[0]=pgmname;
|
||||
for (i=1; i<MAX_ARGS && args[i-1]!=NULL; i++) {
|
||||
if ((args[i]=strchr(args[i-1],' '))!=NULL) {
|
||||
args[i][0]='\0';
|
||||
args[i]+=1;
|
||||
} /* if */
|
||||
} /* for */
|
||||
/* replace the child fork with a new process */
|
||||
if(execvp(pgmname,args)<0)
|
||||
return 0;
|
||||
} else {
|
||||
close(pipe_to[0]); /* close unused pipes */
|
||||
close(pipe_from[1]);
|
||||
pipe_to[0]=-1;
|
||||
pipe_from[1]=-1;
|
||||
} /* if */
|
||||
return pid;
|
||||
#else
|
||||
return (system(pgmname)==0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* bool: procwrite(const line[], bool:appendlf=false)
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_procwrite(AMX *amx, const cell *params)
|
||||
{
|
||||
const TCHAR *line;
|
||||
unsigned long num;
|
||||
|
||||
amx_StrParam(amx,params[1],line);
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
if (write_stdin==NULL)
|
||||
return 0;
|
||||
WriteFile(write_stdin,line,_tcslen(line),&num,NULL); //send it to stdin
|
||||
if (params[2])
|
||||
WriteFile(write_stdin,__T("\n"),1,&num,NULL);
|
||||
#elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
if (pipe_to[1]<0)
|
||||
return 0;
|
||||
write(pipe_to[1],line,_tcslen(line));
|
||||
if (params[2])
|
||||
write(pipe_to[1],__T("\n"),1);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* bool: procread(line[], size=sizeof line, bool:striplf=false, bool:packed=false)
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_procread(AMX *amx, const cell *params)
|
||||
{
|
||||
TCHAR line[128];
|
||||
cell *cptr;
|
||||
unsigned long num;
|
||||
int index;
|
||||
|
||||
index=0;
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
if (read_stdout==NULL)
|
||||
return 0;
|
||||
do {
|
||||
if (!ReadFile(read_stdout,line+index,1,&num,NULL))
|
||||
break;
|
||||
index++;
|
||||
} while (index<sizeof(line)/sizeof(line[0])-1 && line[index-1]!=__T('\n'));
|
||||
#elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
if (pipe_from[0]<0)
|
||||
return 0;
|
||||
do {
|
||||
if (read(pipe_from[0],line+index,1)<0)
|
||||
break;
|
||||
index++;
|
||||
} while (index<sizeof(line)/sizeof(line[0])-1 && line[index-1]!=__T('\n'));
|
||||
#endif
|
||||
|
||||
if (params[3])
|
||||
while (index>0 && (line[index-1]==__T('\r') || line[index-1]==__T('\n')))
|
||||
index--;
|
||||
line[index]=__T('\0');
|
||||
|
||||
amx_GetAddr(amx,params[1],&cptr);
|
||||
amx_SetString(cptr,line,params[4],sizeof(TCHAR)>1,params[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* procwait(PID:pid)
|
||||
* Waits until the process has terminated.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_procwait(AMX *amx, const cell *params)
|
||||
{
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
HANDLE hProcess;
|
||||
DWORD exitcode;
|
||||
#endif
|
||||
|
||||
(void)amx;
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)params[1]);
|
||||
if (hProcess != NULL) {
|
||||
while (GetExitCodeProcess(hProcess,&exitcode) && exitcode==STILL_ACTIVE)
|
||||
Sleep(100);
|
||||
CloseHandle(hProcess);
|
||||
} /* if */
|
||||
#elif defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
waitpid((pid_t)params[1],NULL,WNOHANG);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
AMX_NATIVE_INFO ffi_Natives[] = {
|
||||
{ "libcall", n_libcall },
|
||||
{ "libfree", n_libfree },
|
||||
{ "procexec", n_procexec },
|
||||
{ "procread", n_procread },
|
||||
{ "procwrite", n_procwrite },
|
||||
{ "procwait", n_procwait },
|
||||
{ NULL, NULL } /* terminator */
|
||||
};
|
||||
|
||||
int AMXEXPORT amx_ProcessInit(AMX *amx)
|
||||
{
|
||||
return amx_Register(amx, ffi_Natives, -1);
|
||||
}
|
||||
|
||||
int AMXEXPORT amx_ProcessCleanup(AMX *amx)
|
||||
{
|
||||
freelib(&ModRoot, amx, NULL);
|
||||
closepipe();
|
||||
return AMX_ERR_NONE;
|
||||
}
|
883
SOURCE/amx/amxstring.c
Normal file
883
SOURCE/amx/amxstring.c
Normal file
@ -0,0 +1,883 @@
|
||||
/* String functions for the Pawn Abstract Machine
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2005-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxstring.c 3656 2006-10-24 07:20:26Z thiadmer $
|
||||
*/
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include "osdefs.h"
|
||||
#include "amx.h"
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#define MAX_FORMATSTR 256
|
||||
|
||||
#define CHARBITS (8*sizeof(char))
|
||||
|
||||
#if defined _UNICODE
|
||||
# include <tchar.h>
|
||||
#elif !defined __T
|
||||
typedef char TCHAR;
|
||||
# define __T(string) string
|
||||
# define _tcscat strcat
|
||||
# define _tcschr strchr
|
||||
# define _tcscpy strcpy
|
||||
# define _tcslen strlen
|
||||
#endif
|
||||
#include "amxcons.h"
|
||||
|
||||
#if !defined isdigit
|
||||
# define isdigit(c) ((unsigned)((c)-'0')<10u)
|
||||
#endif
|
||||
|
||||
|
||||
/* dest the destination buffer; the buffer must point to the start of a cell
|
||||
* source the source buffer, this must be aligned to a cell edge
|
||||
* len the number of characters (bytes) to copy
|
||||
* offs the offset in dest, in characters (bytes)
|
||||
*/
|
||||
static int amx_StrPack(cell *dest,cell *source,int len,int offs)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((ucell)*source>UNPACKEDMAX && offs%sizeof(cell)==0) {
|
||||
/* source string is already packed and the destination is cell-aligned */
|
||||
unsigned char* pdest=(unsigned char*)dest+offs;
|
||||
i=(len+sizeof(cell)-1)/sizeof(cell);
|
||||
memmove(pdest,source,i*sizeof(cell));
|
||||
/* zero-terminate */
|
||||
#if BYTE_ORDER==BIG_ENDIAN
|
||||
pdest+=len;
|
||||
for (i=len; i==len || i%sizeof(cell)!=0; i++)
|
||||
*pdest++='\0';
|
||||
#else
|
||||
i=(len/sizeof(cell))*sizeof(cell);
|
||||
pdest+=i;
|
||||
len=(len==i) ? sizeof(cell) : sizeof(cell)-(len-i);
|
||||
assert(len>0 && len<=sizeof(cell));
|
||||
for (i=0; i<len; i++)
|
||||
*pdest++='\0';
|
||||
#endif
|
||||
} else if ((ucell)*source>UNPACKEDMAX) {
|
||||
/* source string is packed, destination is not aligned */
|
||||
cell mask,c;
|
||||
dest+=offs/sizeof(cell); /* increment whole number of cells */
|
||||
offs%=sizeof(cell); /* get remainder */
|
||||
mask=(~(ucell)0) >> (offs*CHARBITS);
|
||||
c=*dest & ~mask;
|
||||
for (i=0; i<len+offs+1; i+=sizeof(cell)) {
|
||||
*dest=c | ((*source >> (offs*CHARBITS)) & mask);
|
||||
c=(*source << ((sizeof(cell)-offs)*CHARBITS)) & ~mask;
|
||||
dest++;
|
||||
source++;
|
||||
} /* for */
|
||||
/* set the zero byte in the last cell */
|
||||
mask=(~(ucell)0) >> (((offs+len)%sizeof(cell))*CHARBITS);
|
||||
*(dest-1) &= ~mask;
|
||||
} else {
|
||||
/* source string is unpacked: pack string, from top-down */
|
||||
cell c=0;
|
||||
if (offs!=0) {
|
||||
/* get the last cell in "dest" and mask of the characters that must be changed */
|
||||
cell mask;
|
||||
dest+=offs/sizeof(cell); /* increment whole number of cells */
|
||||
offs%=sizeof(cell); /* get remainder */
|
||||
mask=(~(ucell)0) >> (offs*CHARBITS);
|
||||
c=(*dest & ~mask) >> ((sizeof(cell)-offs)*CHARBITS);
|
||||
} /* if */
|
||||
/* for proper alignement, add the offset to both the starting and the ending
|
||||
* criterion (so that the number of iterations stays the same)
|
||||
*/
|
||||
assert(offs>=0 && offs<sizeof(cell));
|
||||
for (i=offs; i<len+offs; i++) {
|
||||
c=(c<<CHARBITS) | (*source++ & 0xff);
|
||||
if (i%sizeof(cell)==sizeof(cell)-1) {
|
||||
*dest++=c;
|
||||
c=0;
|
||||
} /* if */
|
||||
} /* for */
|
||||
if (i%sizeof(cell) != 0) /* store remaining packed characters */
|
||||
*dest=c << (sizeof(cell)-i%sizeof(cell))*CHARBITS;
|
||||
else
|
||||
*dest=0; /* store full cell of zeros */
|
||||
} /* if */
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
static int amx_StrUnpack(cell *dest,cell *source,int len)
|
||||
{
|
||||
/* len excludes the terminating '\0' byte */
|
||||
if ((ucell)*source>UNPACKEDMAX) {
|
||||
/* unpack string, from bottom up (so string can be unpacked in place) */
|
||||
cell c;
|
||||
int i;
|
||||
for (i=len-1; i>=0; i--) {
|
||||
c=source[i/sizeof(cell)] >> (sizeof(cell)-i%sizeof(cell)-1)*CHARBITS;
|
||||
dest[i]=c & UCHAR_MAX;
|
||||
} /* for */
|
||||
dest[len]=0; /* zero-terminate */
|
||||
} else {
|
||||
/* source string is already unpacked */
|
||||
while (len-->0)
|
||||
*dest++=*source++;
|
||||
*dest=0;
|
||||
} /* if */
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
static unsigned char *packedptr(cell *string,int index)
|
||||
{
|
||||
unsigned char *ptr=(unsigned char *)(string+index/sizeof(cell));
|
||||
#if BYTE_ORDER==BIG_ENDIAN
|
||||
ptr+=index & (sizeof(cell)-1);
|
||||
#else
|
||||
ptr+=(sizeof(cell)-1) - (index & (sizeof(cell)-1));
|
||||
#endif
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static cell extractchar(cell *string,int index,int mklower)
|
||||
{
|
||||
cell c;
|
||||
|
||||
if ((ucell)*string>UNPACKEDMAX)
|
||||
c=*packedptr(string,index);
|
||||
else
|
||||
c=string[index];
|
||||
if (mklower) {
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
c=(cell)CharLower((LPTSTR)c);
|
||||
#elif defined _Windows
|
||||
c=(cell)AnsiLower((LPSTR)c);
|
||||
#else
|
||||
if ((unsigned int)(c-'A')<26u)
|
||||
c+='a'-'A';
|
||||
#endif
|
||||
} /* if */
|
||||
return c;
|
||||
}
|
||||
|
||||
static int verify_addr(AMX *amx,cell addr)
|
||||
{
|
||||
int err;
|
||||
cell *cdest;
|
||||
|
||||
err=amx_GetAddr(amx,addr,&cdest);
|
||||
if (err!=AMX_ERR_NONE)
|
||||
amx_RaiseError(amx,err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* strlen(const string[])
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_strlen(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cptr;
|
||||
int len = 0;
|
||||
|
||||
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
|
||||
amx_StrLen(cptr,&len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* strpack(dest[], const source[], maxlength=sizeof dest)
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_strpack(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cdest,*csrc;
|
||||
int len,needed,err;
|
||||
size_t lastaddr;
|
||||
|
||||
/* calculate number of cells needed for (packed) destination */
|
||||
amx_GetAddr(amx,params[2],&csrc);
|
||||
amx_StrLen(csrc,&len);
|
||||
if ((unsigned)len>params[3]*sizeof(cell)-1)
|
||||
len=params[3]*sizeof(cell)-1;
|
||||
needed=(len+sizeof(cell))/sizeof(cell); /* # of cells needed */
|
||||
assert(needed>0);
|
||||
lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1);
|
||||
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
|
||||
return amx_RaiseError(amx,AMX_ERR_NATIVE);
|
||||
|
||||
amx_GetAddr(amx,params[1],&cdest);
|
||||
err=amx_StrPack(cdest,csrc,len,0);
|
||||
if (err!=AMX_ERR_NONE)
|
||||
return amx_RaiseError(amx,err);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* strunpack(dest[], const source[], maxlength=sizeof dest)
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_strunpack(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cdest,*csrc;
|
||||
int len,err;
|
||||
size_t lastaddr;
|
||||
|
||||
/* calculate number of cells needed for (unpacked) destination */
|
||||
amx_GetAddr(amx,params[2],&csrc);
|
||||
amx_StrLen(csrc,&len);
|
||||
assert(len>=0);
|
||||
if (len>=params[3])
|
||||
len=params[3]-1;
|
||||
lastaddr=(size_t)(params[1]+sizeof(cell)*(len+1)-1);
|
||||
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
|
||||
return amx_RaiseError(amx,AMX_ERR_NATIVE);
|
||||
|
||||
amx_GetAddr(amx,params[1],&cdest);
|
||||
err=amx_StrUnpack(cdest,csrc,len);
|
||||
if (err!=AMX_ERR_NONE)
|
||||
return amx_RaiseError(amx,err);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* strcat(dest[], const source[], maxlength=sizeof dest)
|
||||
* packed/unpacked attribute is taken from dest[], or from source[] if dest[]
|
||||
* is an empty string.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_strcat(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cdest,*csrc;
|
||||
int len,len2,needed;
|
||||
int packed,err;
|
||||
size_t lastaddr;
|
||||
|
||||
/* calculate number of cells needed for (packed) destination */
|
||||
amx_GetAddr(amx,params[2],&csrc);
|
||||
amx_GetAddr(amx,params[1],&cdest);
|
||||
amx_StrLen(csrc,&len);
|
||||
amx_StrLen(cdest,&len2);
|
||||
packed=(*cdest==0) ? ((ucell)*csrc>UNPACKEDMAX) : ((ucell)*cdest>UNPACKEDMAX);
|
||||
if (packed) {
|
||||
if ((unsigned)(len+len2)>params[3]*sizeof(cell)-1)
|
||||
len=params[3]*sizeof(cell)-len2-1;
|
||||
needed=(len+len2+sizeof(cell))/sizeof(cell); /* # of cells needed */
|
||||
assert(needed>0);
|
||||
lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1);
|
||||
} else {
|
||||
if (len+len2>params[3]-1)
|
||||
len=params[3]-len2-1;
|
||||
lastaddr=(size_t)(params[1]+sizeof(cell)*(len+len2+1)-1);
|
||||
} /* if */
|
||||
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
|
||||
return amx_RaiseError(amx,AMX_ERR_NATIVE);
|
||||
|
||||
if (packed) {
|
||||
err=amx_StrPack(cdest,csrc,len,len2);
|
||||
} else {
|
||||
/* destination string must either be unpacked, or empty */
|
||||
assert((ucell)*cdest<=UNPACKEDMAX || len2==0);
|
||||
err=amx_StrUnpack(cdest+len2,csrc,len);
|
||||
} /* if */
|
||||
if (err!=AMX_ERR_NONE)
|
||||
return amx_RaiseError(amx,err);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int compare(cell *cstr1,cell *cstr2,int ignorecase,int length,int offs1)
|
||||
{
|
||||
int index;
|
||||
cell c1=0,c2=0;
|
||||
|
||||
for (index=0; index<length; index++) {
|
||||
c1=extractchar(cstr1,index+offs1,ignorecase);
|
||||
c2=extractchar(cstr2,index,ignorecase);
|
||||
assert(c1!=0 && c2!=0); /* string lengths are already checked, so zero-bytes should not occur */
|
||||
if (c1!=c2)
|
||||
break;
|
||||
} /* for */
|
||||
|
||||
if (c1<c2)
|
||||
return -1;
|
||||
if (c1>c2)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* strcmp(const string1[], const string2[], bool:ignorecase=false, length=cellmax)
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_strcmp(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cstr1,*cstr2;
|
||||
int len1,len2,len;
|
||||
cell result;
|
||||
|
||||
amx_GetAddr(amx,params[1],&cstr1);
|
||||
amx_GetAddr(amx,params[2],&cstr2);
|
||||
|
||||
/* get the maximum length to compare */
|
||||
amx_StrLen(cstr1,&len1);
|
||||
amx_StrLen(cstr2,&len2);
|
||||
len=len1;
|
||||
if (len>len2)
|
||||
len=len2;
|
||||
if (len>params[4])
|
||||
len=params[4];
|
||||
if (len==0)
|
||||
return 0;
|
||||
|
||||
result=compare(cstr1,cstr2,params[3],len,0);
|
||||
if (result==0 && len!=params[4])
|
||||
result=len1-len2;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* strfind(const string[], const sub[], bool:ignorecase=false, offset=0)
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_strfind(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cstr,*csub;
|
||||
int lenstr,lensub,offs;
|
||||
cell c,f;
|
||||
|
||||
amx_GetAddr(amx,params[1],&cstr);
|
||||
amx_GetAddr(amx,params[2],&csub);
|
||||
|
||||
/* get the maximum length to compare */
|
||||
amx_StrLen(cstr,&lenstr);
|
||||
amx_StrLen(csub,&lensub);
|
||||
if (lensub==0)
|
||||
return -1;
|
||||
|
||||
/* get the start character of the substring, for quicker searching */
|
||||
f=extractchar(csub,0,params[3]);
|
||||
assert(f!=0); /* string length is already checked */
|
||||
|
||||
for (offs=(int)params[4]; offs+lensub<=lenstr; offs++) {
|
||||
/* find the initial character */
|
||||
c=extractchar(csub,0,params[3]);
|
||||
assert(c!=0); /* string length is already checked */
|
||||
if (c!=f)
|
||||
continue;
|
||||
if (compare(cstr,csub,params[3],lensub,offs)==0)
|
||||
return offs;
|
||||
} /* for */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* strmid(dest[], const source[], start, end, maxlength=sizeof dest)
|
||||
* packed/unpacked attribute is taken from source[]
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_strmid(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cdest,*csrc;
|
||||
int len,needed,err;
|
||||
int soffs,doffs;
|
||||
size_t lastaddr;
|
||||
unsigned char *ptr;
|
||||
unsigned char c;
|
||||
int start=params[3];
|
||||
int end=params[4];
|
||||
|
||||
/* calculate number of cells needed for (packed) destination */
|
||||
amx_GetAddr(amx,params[2],&csrc);
|
||||
amx_GetAddr(amx,params[1],&cdest);
|
||||
amx_StrLen(csrc,&len);
|
||||
|
||||
/* clamp the start/end parameters */
|
||||
if (start<0)
|
||||
start=0;
|
||||
else if (start>len)
|
||||
start=len;
|
||||
if (end<start)
|
||||
end=start;
|
||||
else if (end>len)
|
||||
end=len;
|
||||
|
||||
len=end-start;
|
||||
if ((ucell)*csrc>UNPACKEDMAX) {
|
||||
if ((unsigned)len>params[5]*sizeof(cell)-1)
|
||||
len=params[5]*sizeof(cell)-1;
|
||||
needed=(len+sizeof(cell))/sizeof(cell); /* # of cells needed */
|
||||
assert(needed>0);
|
||||
lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1);
|
||||
} else {
|
||||
if (len>params[5]-1)
|
||||
len=params[5]-1;
|
||||
lastaddr=(size_t)(params[1]+sizeof(cell)*(len+1)-1);
|
||||
} /* if */
|
||||
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
|
||||
return amx_RaiseError(amx,AMX_ERR_NATIVE);
|
||||
|
||||
if ((ucell)*csrc>UNPACKEDMAX) {
|
||||
/* first align the source to a cell boundary */
|
||||
for (doffs=0,soffs=start; (soffs & (sizeof(cell)-1))!=0 && len>0; soffs++,doffs++,len--) {
|
||||
ptr=packedptr(csrc,soffs);
|
||||
c=*ptr;
|
||||
ptr=packedptr(cdest,doffs);
|
||||
*ptr=c;
|
||||
} /* for */
|
||||
if (len==0) {
|
||||
/* nothing left to do, zero-terminate */
|
||||
ptr=packedptr(cdest,doffs);
|
||||
*ptr='\0';
|
||||
err=AMX_ERR_NONE;
|
||||
} else {
|
||||
err=amx_StrPack(cdest,csrc+soffs/sizeof(cell),len,doffs);
|
||||
} /* if */
|
||||
} else {
|
||||
err=amx_StrUnpack(cdest,csrc+start,len);
|
||||
} /* if */
|
||||
if (err!=AMX_ERR_NONE)
|
||||
return amx_RaiseError(amx,err);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* strdel(string[], start, end)
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_strdel(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cstr;
|
||||
int index,offs,length;
|
||||
unsigned char *ptr;
|
||||
unsigned char c;
|
||||
|
||||
/* calculate number of cells needed for (packed) destination */
|
||||
amx_GetAddr(amx,params[1],&cstr);
|
||||
amx_StrLen(cstr,&length);
|
||||
index=(int)params[2];
|
||||
offs=(int)params[3]-index;
|
||||
if (index>=length || offs<=0)
|
||||
return 0;
|
||||
if (index+offs>length)
|
||||
offs=length-index;
|
||||
|
||||
index--; /* prepare for increment in the top of the loop */
|
||||
if (((ucell)*cstr>UNPACKEDMAX)) {
|
||||
do {
|
||||
index++;
|
||||
ptr=packedptr(cstr,index+offs);
|
||||
c=*ptr;
|
||||
ptr=packedptr(cstr,index);
|
||||
*ptr=c;
|
||||
} while (c!='\0');
|
||||
if (index==0)
|
||||
*cstr=0;
|
||||
} else {
|
||||
do {
|
||||
index++;
|
||||
cstr[index]=cstr[index+offs];
|
||||
} while (cstr[index]!=0);
|
||||
} /* if */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* strins(string[], const substr[], offset, maxlength=sizeof string)
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_strins(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cstr,*csub;
|
||||
int index,lenstr,lensub,count;
|
||||
int needed;
|
||||
size_t lastaddr;
|
||||
unsigned char *ptr;
|
||||
cell c;
|
||||
|
||||
/* calculate number of cells needed for (packed) destination */
|
||||
amx_GetAddr(amx,params[1],&cstr);
|
||||
amx_GetAddr(amx,params[2],&csub);
|
||||
amx_StrLen(cstr,&lenstr);
|
||||
amx_StrLen(csub,&lensub);
|
||||
index=(int)params[3];
|
||||
if (index>lenstr)
|
||||
return amx_RaiseError(amx,AMX_ERR_NATIVE);
|
||||
|
||||
if (((ucell)*cstr>UNPACKEDMAX)) {
|
||||
needed=(lenstr+lensub+sizeof(cell))/sizeof(cell); /* # of cells needed */
|
||||
assert(needed>0);
|
||||
lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1);
|
||||
} else {
|
||||
lastaddr=(size_t)(params[1]+sizeof(cell)*(lenstr+lensub+1)-1);
|
||||
} /* if */
|
||||
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
|
||||
return amx_RaiseError(amx,AMX_ERR_NATIVE);
|
||||
|
||||
if (*cstr==0) {
|
||||
/* current string is empty (and the insertion point is zero), just make a copy */
|
||||
assert(index==0);
|
||||
if ((ucell)*csub>UNPACKEDMAX)
|
||||
amx_StrPack(cstr,csub,lensub,0);
|
||||
else
|
||||
amx_StrUnpack(cstr,csub,lensub);
|
||||
return 1;
|
||||
} /* if */
|
||||
|
||||
if (((ucell)*cstr>UNPACKEDMAX)) {
|
||||
/* make room for the new characters */
|
||||
for (count=lenstr+lensub; count>index; count--) {
|
||||
ptr=packedptr(cstr,count-lensub);
|
||||
c=*ptr;
|
||||
ptr=packedptr(cstr,count);
|
||||
*ptr=(unsigned char)c;
|
||||
} /* for */
|
||||
/* copy in the new characters */
|
||||
for (count=0; count<lensub; count++) {
|
||||
c=extractchar(csub,count,0);
|
||||
ptr=packedptr(cstr,index+count);
|
||||
*ptr=(unsigned char)c;
|
||||
} /* for */
|
||||
} else {
|
||||
/* make room for the new characters */
|
||||
for (count=lenstr+lensub; count>index; count--)
|
||||
cstr[count]=cstr[count-lensub];
|
||||
/* copy in the new characters */
|
||||
for (count=0; count<lensub; count++) {
|
||||
c=extractchar(csub,count,0);
|
||||
cstr[index+count]=c;
|
||||
} /* for */
|
||||
} /* if */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* strval(const string[], index=0)
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_strval(AMX *amx,const cell *params)
|
||||
{
|
||||
TCHAR str[50],*ptr;
|
||||
cell *cstr,result;
|
||||
int len,negate=0;
|
||||
int offset=0;
|
||||
|
||||
/* get parameters */
|
||||
amx_GetAddr(amx,params[1],&cstr);
|
||||
amx_StrLen(cstr,&len);
|
||||
if ((unsigned)params[0]>=2*sizeof(cell))
|
||||
offset=params[2];
|
||||
if (offset<0)
|
||||
offset=0;
|
||||
else if (offset>=len)
|
||||
offset=len-1;
|
||||
|
||||
/* skip a number of cells */
|
||||
while (offset>=(int)sizeof(cell)) {
|
||||
cstr++;
|
||||
offset-=sizeof(cell);
|
||||
len-=sizeof(cell);
|
||||
} /* while */
|
||||
|
||||
if (len>=(int)sizeof str) {
|
||||
amx_RaiseError(amx,AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
amx_GetString(str,cstr,sizeof(TCHAR)>1,sizeof str);
|
||||
assert(offset<(int)sizeof(cell) && offset>=0);
|
||||
ptr=str+offset;
|
||||
result=0;
|
||||
while (*ptr!='\0' && *ptr<=' ')
|
||||
ptr++; /* skip whitespace */
|
||||
if (*ptr=='-') { /* handle sign */
|
||||
negate=1;
|
||||
ptr++;
|
||||
} else if (*ptr=='+') {
|
||||
ptr++;
|
||||
} /* if */
|
||||
while (isdigit(*ptr)) {
|
||||
result=result*10 + (*ptr-'0');
|
||||
ptr++;
|
||||
} /* while */
|
||||
if (negate)
|
||||
result=-result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* valstr(dest[], value, bool:pack=false) */
|
||||
static cell AMX_NATIVE_CALL n_valstr(AMX *amx,const cell *params)
|
||||
{
|
||||
TCHAR str[50];
|
||||
cell value,mult;
|
||||
cell *cstr;
|
||||
int len,result,negate=0;
|
||||
|
||||
/* find out how many digits are needed */
|
||||
mult=10;
|
||||
len=1;
|
||||
value=params[2];
|
||||
if (value<0) {
|
||||
negate=1;
|
||||
len++;
|
||||
value=-value;
|
||||
} /* if */
|
||||
while (value>=mult) {
|
||||
len++;
|
||||
mult*=10;
|
||||
} /* while */
|
||||
|
||||
/* put in the string */
|
||||
result=len;
|
||||
str[len--]='\0';
|
||||
while (len>=negate) {
|
||||
str[len--]=(char)((value % 10)+'0');
|
||||
value/=10;
|
||||
} /* while */
|
||||
if (negate)
|
||||
str[0]='-';
|
||||
amx_GetAddr(amx,params[1],&cstr);
|
||||
amx_SetString(cstr,str,params[3],sizeof(TCHAR)>1,UNLIMITED);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ispacked(const string[]) */
|
||||
static cell AMX_NATIVE_CALL n_ispacked(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cstr;
|
||||
amx_GetAddr(amx,params[1],&cstr);
|
||||
return *cstr>=UNPACKEDMAX;
|
||||
}
|
||||
|
||||
|
||||
/* single character decode and encode */
|
||||
#define BITMASK 0x3f
|
||||
#define DEC(c) (((c) - ' ') & BITMASK)
|
||||
#define ENC(c) (char)(((c) & BITMASK) == 0 ? 0x60 : ((c) & BITMASK) + ' ')
|
||||
|
||||
static int uudecode(unsigned char *target, char *source)
|
||||
{
|
||||
int len, retval;
|
||||
|
||||
len = DEC(*source++);
|
||||
retval = len;
|
||||
while (len > 0) {
|
||||
if (len-- > 0)
|
||||
*target++ = (unsigned char)(( DEC(source[0]) << 2 ) | ( DEC(source[1]) >> 4 ));
|
||||
if (len-- > 0)
|
||||
*target++ = (unsigned char)(( DEC(source[1]) << 4 ) | ( DEC(source[2]) >> 2 ));
|
||||
if (len-- > 0)
|
||||
*target++ = (unsigned char)(( DEC(source[2]) << 6 ) | DEC(source[3]) );
|
||||
source += 4;
|
||||
} /* while */
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int uuencode(char *target, unsigned char *source, int length)
|
||||
{
|
||||
int split[4]={0,0,0,0};
|
||||
|
||||
if (length > BITMASK)
|
||||
return 0; /* can encode up to 64 bytes */
|
||||
|
||||
*target++ = ENC(length);
|
||||
while (length > 0) {
|
||||
split[0] = source[0] >> 2; /* split first byte to char. 0 & 1 */
|
||||
split[1] = source[0] << 4;
|
||||
if (length > 1) {
|
||||
split[1] |= source[1] >> 4; /* split 2nd byte to char. 1 & 2 */
|
||||
split[2] = source[1] << 2;
|
||||
if (length > 2) {
|
||||
split[2] |= source[2] >> 6; /* split 3th byte to char. 2 & 3 */
|
||||
split[3] = source[2];
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
*target++ = ENC(split[0]);
|
||||
*target++ = ENC(split[1]);
|
||||
if (length > 1)
|
||||
*target++ = ENC(split[2]);
|
||||
if (length > 2)
|
||||
*target++ = ENC(split[3]);
|
||||
source += 3;
|
||||
length -= 3;
|
||||
} /* while */
|
||||
|
||||
*target = '\0'; /* end string */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* uudecode(dest[], const source[], maxlength=sizeof dest)
|
||||
* Returns the number of bytes (not cells) decoded; if the dest buffer is
|
||||
* too small, not all bytes are stored.
|
||||
* Always creates a (packed) array (not a string; the array is not
|
||||
* zero-terminated).
|
||||
* A buffer may be decoded "in-place"; the destination size is always smaller
|
||||
* than the source size.
|
||||
* Endian issues (for multi-byte values in the data stream) are not handled.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_uudecode(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cstr;
|
||||
unsigned char dst[BITMASK+2];
|
||||
char src[BITMASK+BITMASK/3+2];
|
||||
int len;
|
||||
size_t size;
|
||||
|
||||
/* get the source */
|
||||
amx_GetAddr(amx,params[2],&cstr);
|
||||
amx_GetString(src,cstr,0,sizeof src);
|
||||
/* decode */
|
||||
len=uudecode(dst,src);
|
||||
/* store */
|
||||
amx_GetAddr(amx,params[1],&cstr);
|
||||
size=len;
|
||||
if (size>params[3]*sizeof(cell))
|
||||
size=params[3]*sizeof(cell);
|
||||
memcpy(cstr,dst,size);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* uuencode(dest[], const source[], numbytes, maxlength=sizeof dest)
|
||||
* Returns the number of characters encoded, excluding the zero string
|
||||
* terminator; if the dest buffer is too small, not all bytes are stored.
|
||||
* Always creates a packed string. This string has a newline character at the
|
||||
* end. A buffer may be encoded "in-place" if the destination is large enough.
|
||||
* Endian issues (for multi-byte values in the data stream) are not handled.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_uuencode(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cstr;
|
||||
unsigned char src[BITMASK+2];
|
||||
char dst[BITMASK+BITMASK/3+2];
|
||||
|
||||
/* get the source */
|
||||
amx_GetAddr(amx,params[2],&cstr);
|
||||
/* encode (and check for errors) */
|
||||
if (uuencode(dst,src,params[3])) {
|
||||
if (params[4]>0) {
|
||||
amx_GetAddr(amx,params[1],&cstr);
|
||||
*cstr=0;
|
||||
} /* if */
|
||||
return 0;
|
||||
} /* if */
|
||||
/* always add a \n */
|
||||
assert(strlen(dst)+1<sizeof dst);
|
||||
strcat(dst,"\n");
|
||||
/* store */
|
||||
amx_GetAddr(amx,params[1],&cstr);
|
||||
amx_SetString(cstr,dst,1,0,params[4]);
|
||||
return (((params[3]+2)/3) << 2)+2;
|
||||
}
|
||||
|
||||
/* memcpy(dest[], const source[], index=0, numbytes, maxlength=sizeof dest)
|
||||
* This function can align byte strings in cell arrays, or concatenate two
|
||||
* byte strings in two arrays. The parameter "index" is a byte offset; "numbytes"
|
||||
* is the number of bytes to copy. Parameter "maxlength", however, is in cells.
|
||||
* This function allows copying in-place, for aligning memory buffers.
|
||||
* Endian issues (for multi-byte values in the data stream) are not handled.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_memcpy(AMX *amx,const cell *params)
|
||||
{
|
||||
cell *cdest,*csrc;
|
||||
unsigned char *pdest,*psrc;
|
||||
|
||||
if (params[3]<0 || params[4]<0 || (params[3]+params[4])>params[5]*(int)sizeof(cell))
|
||||
return 0;
|
||||
amx_GetAddr(amx,params[1],&cdest);
|
||||
amx_GetAddr(amx,params[2],&csrc);
|
||||
pdest=(unsigned char*)cdest+params[3];
|
||||
psrc=(unsigned char*)csrc;
|
||||
memmove(pdest,psrc,params[4]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !defined AMX_NOSTRFMT
|
||||
static int str_putstr(void *dest,const TCHAR *str)
|
||||
{
|
||||
if (_tcslen((TCHAR*)dest)+_tcslen(str)<MAX_FORMATSTR)
|
||||
_tcscat((TCHAR*)dest,str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int str_putchar(void *dest,TCHAR ch)
|
||||
{
|
||||
int len=_tcslen((TCHAR*)dest);
|
||||
if (len<MAX_FORMATSTR-1) {
|
||||
((TCHAR*)dest)[len]=ch;
|
||||
((TCHAR*)dest)[len+1]='\0';
|
||||
} /* if */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* strformat(dest[], size=sizeof dest, bool:pack=false, const format[], {Fixed,_}:...)
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_strformat(AMX *amx,const cell *params)
|
||||
{
|
||||
#if defined AMX_NOSTRFMT
|
||||
(void)amx;
|
||||
(void)params;
|
||||
return 0;
|
||||
#else
|
||||
cell *cstr;
|
||||
AMX_FMTINFO info;
|
||||
TCHAR output[MAX_FORMATSTR];
|
||||
|
||||
memset(&info,0,sizeof info);
|
||||
info.params=params+5;
|
||||
info.numparams=(int)(params[0]/sizeof(cell))-4;
|
||||
info.skip=0;
|
||||
info.length=MAX_FORMATSTR; /* max. length of the string */
|
||||
info.f_putstr=str_putstr;
|
||||
info.f_putchar=str_putchar;
|
||||
info.user=output;
|
||||
output[0] = __T('\0');
|
||||
|
||||
amx_GetAddr(amx,params[4],&cstr);
|
||||
amx_printstring(amx,cstr,&info);
|
||||
|
||||
/* store the output string */
|
||||
amx_GetAddr(amx,params[1],&cstr);
|
||||
amx_SetString(cstr,(char*)output,(int)params[3],sizeof(TCHAR)>1,(int)params[2]);
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
const AMX_NATIVE_INFO string_Natives[] = {
|
||||
{ "ispacked", n_ispacked },
|
||||
{ "memcpy", n_memcpy },
|
||||
{ "strcat", n_strcat },
|
||||
{ "strcmp", n_strcmp },
|
||||
{ "strdel", n_strdel },
|
||||
{ "strfind", n_strfind },
|
||||
{ "strformat", n_strformat },
|
||||
{ "strins", n_strins },
|
||||
{ "strlen", n_strlen },
|
||||
{ "strmid", n_strmid },
|
||||
{ "strpack", n_strpack },
|
||||
{ "strunpack", n_strunpack },
|
||||
{ "strval", n_strval },
|
||||
{ "uudecode", n_uudecode },
|
||||
{ "uuencode", n_uuencode },
|
||||
{ "valstr", n_valstr },
|
||||
{ NULL, NULL } /* terminator */
|
||||
};
|
||||
|
||||
int AMXEXPORT amx_StringInit(AMX *amx)
|
||||
{
|
||||
return amx_Register(amx, string_Natives, -1);
|
||||
}
|
||||
|
||||
int AMXEXPORT amx_StringCleanup(AMX *amx)
|
||||
{
|
||||
(void)amx;
|
||||
return AMX_ERR_NONE;
|
||||
}
|
6
SOURCE/amx/amxstring.def
Normal file
6
SOURCE/amx/amxstring.def
Normal file
@ -0,0 +1,6 @@
|
||||
NAME amxString
|
||||
DESCRIPTION 'Pawn AMX: string manipulation routines'
|
||||
|
||||
EXPORTS
|
||||
amx_StringInit
|
||||
amx_StringCleanup
|
54
SOURCE/amx/amxstring.rc
Normal file
54
SOURCE/amx/amxstring.rc
Normal file
@ -0,0 +1,54 @@
|
||||
#include <windows.h>
|
||||
#if defined WIN32 || defined _WIN32 || defined __WIN32__
|
||||
# include <winver.h>
|
||||
#else
|
||||
# include <ver.h>
|
||||
#endif
|
||||
|
||||
/* Version information
|
||||
*
|
||||
* All strings MUST have an explicit \0. See the Windows SDK documentation
|
||||
* for details on version information and the VERSIONINFO structure.
|
||||
*/
|
||||
#define VERSION 1
|
||||
#define REVISION 1
|
||||
#define BUILD 0
|
||||
#define VERSIONSTR "1.1.0\0"
|
||||
#define VERSIONNAME "amxString.dll\0"
|
||||
#define VERSIONDESCRIPTION "Pawn AMX: String manipulation routines\0"
|
||||
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
|
||||
#define VERSIONPRODUCTNAME "amxString\0"
|
||||
#define VERSIONCOPYRIGHT "Copyright \251 2005-2006 ITB CompuPhase\0"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION, REVISION, BUILD, 0
|
||||
PRODUCTVERSION VERSION, REVISION, BUILD, 0
|
||||
FILEFLAGSMASK 0x0000003FL
|
||||
FILEFLAGS 0
|
||||
#if defined(WIN32)
|
||||
FILEOS VOS__WINDOWS32
|
||||
#else
|
||||
FILEOS VOS__WINDOWS16
|
||||
#endif
|
||||
FILETYPE VFT_DLL
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", VERSIONCOMPANYNAME
|
||||
VALUE "FileDescription", VERSIONDESCRIPTION
|
||||
VALUE "FileVersion", VERSIONSTR
|
||||
VALUE "InternalName", VERSIONNAME
|
||||
VALUE "LegalCopyright", VERSIONCOPYRIGHT
|
||||
VALUE "OriginalFilename", VERSIONNAME
|
||||
VALUE "ProductName", VERSIONPRODUCTNAME
|
||||
VALUE "ProductVersion", VERSIONSTR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
350
SOURCE/amx/amxtime.c
Normal file
350
SOURCE/amx/amxtime.c
Normal file
@ -0,0 +1,350 @@
|
||||
/* Date/time module for the Pawn Abstract Machine
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2001-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: amxtime.c 3649 2006-10-12 13:13:57Z thiadmer $
|
||||
*/
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include "amx.h"
|
||||
#if defined __WIN32__ || defined _WIN32
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#endif
|
||||
|
||||
#define CELLMIN (-1 << (8*sizeof(cell) - 1))
|
||||
|
||||
#if !defined CLOCKS_PER_SEC
|
||||
#define CLOCKS_PER_SEC CLK_TCK
|
||||
#endif
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
static int timerset = 0;
|
||||
/* timeGetTime() is more accurate on WindowsNT if timeBeginPeriod(1) is set */
|
||||
#define INIT_TIMER() \
|
||||
if (!timerset) { \
|
||||
timeBeginPeriod(1); \
|
||||
timerset=1; \
|
||||
}
|
||||
#else
|
||||
#define INIT_TIMER()
|
||||
#endif
|
||||
static unsigned long timestamp;
|
||||
static unsigned long timelimit;
|
||||
static int timerepeat;
|
||||
|
||||
static const unsigned char monthdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
static int wrap(int value, int min, int max)
|
||||
{
|
||||
if (value<min)
|
||||
value=max;
|
||||
else if (value>max)
|
||||
value=min;
|
||||
return value;
|
||||
}
|
||||
|
||||
static unsigned long gettimestamp(void)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
value=timeGetTime(); /* this value is already in milliseconds */
|
||||
#else
|
||||
value=(cell)clock();
|
||||
#if CLOCKS_PER_SEC!=1000
|
||||
/* convert to milliseconds */
|
||||
value=(cell)((1000L * (value+CLOCKS_PER_SEC/2)) / CLOCKS_PER_SEC);
|
||||
#endif
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
|
||||
/* settime(hour, minute, second)
|
||||
* Always returns 0
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_settime(AMX *amx, const cell *params)
|
||||
{
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
SYSTEMTIME systim;
|
||||
|
||||
GetLocalTime(&systim);
|
||||
if (params[1]!=CELLMIN)
|
||||
systim.wHour=(WORD)wrap((int)params[1],0,23);
|
||||
if (params[2]!=CELLMIN)
|
||||
systim.wMinute=(WORD)wrap((int)params[2],0,59);
|
||||
if (params[3]!=CELLMIN)
|
||||
systim.wSecond=(WORD)wrap((int)params[3],0,59);
|
||||
SetLocalTime(&systim);
|
||||
#else
|
||||
/* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
|
||||
* must have "root" permission to call stime()
|
||||
*/
|
||||
time_t sec1970;
|
||||
struct tm gtm;
|
||||
|
||||
(void)amx;
|
||||
time(&sec1970);
|
||||
gtm=*localtime(&sec1970);
|
||||
if (params[1]!=CELLMIN)
|
||||
gtm.tm_hour=wrap((int)params[1],0,23);
|
||||
if (params[2]!=CELLMIN)
|
||||
gtm.tm_min=wrap((int)params[2],0,59);
|
||||
if (params[3]!=CELLMIN)
|
||||
gtm.tm_sec=wrap((int)params[3],0,59);
|
||||
sec1970=mktime(>m);
|
||||
stime(&sec1970);
|
||||
#endif
|
||||
(void)amx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* gettime(&hour, &minute, &second)
|
||||
* The return value is the number of seconds since 1 January 1970 (Unix system
|
||||
* time).
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_gettime(AMX *amx, const cell *params)
|
||||
{
|
||||
time_t sec1970;
|
||||
struct tm gtm;
|
||||
cell *cptr;
|
||||
|
||||
assert(params[0]==(int)(3*sizeof(cell)));
|
||||
|
||||
time(&sec1970);
|
||||
|
||||
/* on DOS/Windows, the timezone is usually not set for the C run-time
|
||||
* library; in that case gmtime() and localtime() return the same value
|
||||
*/
|
||||
gtm=*localtime(&sec1970);
|
||||
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
|
||||
*cptr=gtm.tm_hour;
|
||||
if (amx_GetAddr(amx,params[2],&cptr)==AMX_ERR_NONE)
|
||||
*cptr=gtm.tm_min;
|
||||
if (amx_GetAddr(amx,params[3],&cptr)==AMX_ERR_NONE)
|
||||
*cptr=gtm.tm_sec;
|
||||
|
||||
/* the time() function returns the number of seconds since January 1 1970
|
||||
* in Universal Coordinated Time (the successor to Greenwich Mean Time)
|
||||
*/
|
||||
return sec1970;
|
||||
}
|
||||
|
||||
/* setdate(year, month, day)
|
||||
* Always returns 0
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_setdate(AMX *amx, const cell *params)
|
||||
{
|
||||
int maxday;
|
||||
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
SYSTEMTIME systim;
|
||||
|
||||
GetLocalTime(&systim);
|
||||
if (params[1]!=CELLMIN)
|
||||
systim.wYear=(WORD)wrap((int)params[1],1970,2099);
|
||||
if (params[2]!=CELLMIN)
|
||||
systim.wMonth=(WORD)wrap((int)params[2],1,12);
|
||||
maxday=monthdays[systim.wMonth - 1];
|
||||
if (systim.wMonth==2 && ((systim.wYear % 4)==0 && ((systim.wYear % 100)!=0 || (systim.wYear % 400)==0)))
|
||||
maxday++;
|
||||
if (params[3]!=CELLMIN)
|
||||
systim.wDay=(WORD)wrap((int)params[3],1,maxday);
|
||||
SetLocalTime(&systim);
|
||||
#else
|
||||
/* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
|
||||
* must have "root" permission to call stime()
|
||||
*/
|
||||
time_t sec1970;
|
||||
struct tm gtm;
|
||||
|
||||
(void)amx;
|
||||
time(&sec1970);
|
||||
gtm=*localtime(&sec1970);
|
||||
if (params[1]!=CELLMIN)
|
||||
gtm.tm_year=params[1]-1900;
|
||||
if (params[2]!=CELLMIN)
|
||||
gtm.tm_mon=params[2]-1;
|
||||
if (params[3]!=CELLMIN)
|
||||
gtm.tm_mday=params[3];
|
||||
sec1970=mktime(>m);
|
||||
stime(&sec1970);
|
||||
#endif
|
||||
(void)amx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* getdate(&year, &month, &day)
|
||||
* The return value is the number of days since the start of the year. January
|
||||
* 1 is day 1 of the year.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_getdate(AMX *amx, const cell *params)
|
||||
{
|
||||
time_t sec1970;
|
||||
struct tm gtm;
|
||||
cell *cptr;
|
||||
|
||||
assert(params[0]==(int)(3*sizeof(cell)));
|
||||
|
||||
time(&sec1970);
|
||||
|
||||
gtm=*localtime(&sec1970);
|
||||
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
|
||||
*cptr=gtm.tm_year+1900;
|
||||
if (amx_GetAddr(amx,params[2],&cptr)==AMX_ERR_NONE)
|
||||
*cptr=gtm.tm_mon+1;
|
||||
if (amx_GetAddr(amx,params[3],&cptr)==AMX_ERR_NONE)
|
||||
*cptr=gtm.tm_mday;
|
||||
|
||||
return gtm.tm_yday+1;
|
||||
}
|
||||
|
||||
/* tickcount(&granularity)
|
||||
* Returns the number of milliseconds since start-up. For a 32-bit cell, this
|
||||
* count overflows after approximately 24 days of continuous operation.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_tickcount(AMX *amx, const cell *params)
|
||||
{
|
||||
cell *cptr;
|
||||
|
||||
assert(params[0]==(int)sizeof(cell));
|
||||
|
||||
INIT_TIMER();
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
|
||||
*cptr=1000; /* granularity = 1 ms */
|
||||
#else
|
||||
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
|
||||
*cptr=(cell)CLOCKS_PER_SEC; /* in Unix/Linux, this is often 100 */
|
||||
#endif
|
||||
return gettimestamp() & 0x7fffffff;
|
||||
}
|
||||
|
||||
/* delay(milliseconds)
|
||||
* Pauses for (at least) the requested number of milliseconds.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_delay(AMX *amx, const cell *params)
|
||||
{
|
||||
unsigned long stamp;
|
||||
|
||||
(void)amx;
|
||||
assert(params[0]==(int)sizeof(cell));
|
||||
|
||||
INIT_TIMER();
|
||||
stamp=gettimestamp();
|
||||
while (gettimestamp()-stamp < (unsigned long)params[1])
|
||||
/* nothing */;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* settimer(milliseconds, bool: singleshot = false)
|
||||
* Sets the delay until the @timer() callback is called. The timer may either
|
||||
* be single-shot or repetitive.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_settimer(AMX *amx, const cell *params)
|
||||
{
|
||||
(void)amx;
|
||||
assert(params[0]==(int)(2*sizeof(cell)));
|
||||
timestamp=gettimestamp();
|
||||
timelimit=params[1];
|
||||
timerepeat=(int)(params[2]==0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* bool: gettimer(&milliseconds, bool: &singleshot = false)
|
||||
* Retrieves the timer set with settimer(); returns true if a timer
|
||||
* was set up, or false otherwise.
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_gettimer(AMX *amx, const cell *params)
|
||||
{
|
||||
cell *cptr;
|
||||
|
||||
assert(params[0]==(int)(2*sizeof(cell)));
|
||||
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
|
||||
*cptr=timelimit;
|
||||
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
|
||||
*cptr=timerepeat;
|
||||
return timelimit>0;
|
||||
}
|
||||
|
||||
|
||||
#if !defined AMXTIME_NOIDLE
|
||||
static AMX_IDLE PrevIdle = NULL;
|
||||
static int idxTimer = -1;
|
||||
|
||||
static int AMXAPI amx_TimeIdle(AMX *amx, int AMXAPI Exec(AMX *, cell *, int))
|
||||
{
|
||||
int err=0;
|
||||
|
||||
assert(idxTimer >= 0);
|
||||
|
||||
if (PrevIdle != NULL)
|
||||
PrevIdle(amx, Exec);
|
||||
|
||||
if (timelimit>0 && (gettimestamp()-timestamp)>=timelimit) {
|
||||
if (timerepeat)
|
||||
timestamp+=timelimit;
|
||||
else
|
||||
timelimit=0; /* do not repeat single-shot timer */
|
||||
err = Exec(amx, NULL, idxTimer);
|
||||
while (err == AMX_ERR_SLEEP)
|
||||
err = Exec(amx, NULL, AMX_EXEC_CONT);
|
||||
} /* if */
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
const AMX_NATIVE_INFO time_Natives[] = {
|
||||
{ "gettime", n_gettime },
|
||||
{ "settime", n_settime },
|
||||
{ "getdate", n_getdate },
|
||||
{ "setdate", n_setdate },
|
||||
{ "tickcount", n_tickcount },
|
||||
{ "settimer", n_settimer },
|
||||
{ "gettimer", n_gettimer },
|
||||
{ "delay", n_delay },
|
||||
{ NULL, NULL } /* terminator */
|
||||
};
|
||||
|
||||
int AMXEXPORT amx_TimeInit(AMX *amx)
|
||||
{
|
||||
#if !defined AMXTIME_NOIDLE
|
||||
/* see whether there is a @timer() function */
|
||||
if (amx_FindPublic(amx,"@timer",&idxTimer) == AMX_ERR_NONE) {
|
||||
if (amx_GetUserData(amx, AMX_USERTAG('I','d','l','e'), (void**)&PrevIdle) != AMX_ERR_NONE)
|
||||
PrevIdle = NULL;
|
||||
amx_SetUserData(amx, AMX_USERTAG('I','d','l','e'), amx_TimeIdle);
|
||||
} /* if */
|
||||
#endif
|
||||
|
||||
return amx_Register(amx, time_Natives, -1);
|
||||
}
|
||||
|
||||
int AMXEXPORT amx_TimeCleanup(AMX *amx)
|
||||
{
|
||||
(void)amx;
|
||||
#if !defined AMXTIME_NOIDLE
|
||||
PrevIdle = NULL;
|
||||
#endif
|
||||
return AMX_ERR_NONE;
|
||||
}
|
6
SOURCE/amx/amxtime.def
Normal file
6
SOURCE/amx/amxtime.def
Normal file
@ -0,0 +1,6 @@
|
||||
NAME amxTime
|
||||
DESCRIPTION 'Pawn AMX: time routines'
|
||||
|
||||
EXPORTS
|
||||
amx_TimeInit
|
||||
amx_TimeCleanup
|
54
SOURCE/amx/amxtime.rc
Normal file
54
SOURCE/amx/amxtime.rc
Normal file
@ -0,0 +1,54 @@
|
||||
#include <windows.h>
|
||||
#if defined WIN32 || defined _WIN32 || defined __WIN32__
|
||||
# include <winver.h>
|
||||
#else
|
||||
# include <ver.h>
|
||||
#endif
|
||||
|
||||
/* Version information
|
||||
*
|
||||
* All strings MUST have an explicit \0. See the Windows SDK documentation
|
||||
* for details on version information and the VERSIONINFO structure.
|
||||
*/
|
||||
#define VERSION 1
|
||||
#define REVISION 1
|
||||
#define BUILD 0
|
||||
#define VERSIONSTR "1.2.0\0"
|
||||
#define VERSIONNAME "amxTime.dll\0"
|
||||
#define VERSIONDESCRIPTION "Pawn AMX: time routines\0"
|
||||
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
|
||||
#define VERSIONPRODUCTNAME "amxTime\0"
|
||||
#define VERSIONCOPYRIGHT "Copyright \251 2005-2006 ITB CompuPhase\0"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VERSION, REVISION, BUILD, 0
|
||||
PRODUCTVERSION VERSION, REVISION, BUILD, 0
|
||||
FILEFLAGSMASK 0x0000003FL
|
||||
FILEFLAGS 0
|
||||
#if defined(WIN32)
|
||||
FILEOS VOS__WINDOWS32
|
||||
#else
|
||||
FILEOS VOS__WINDOWS16
|
||||
#endif
|
||||
FILETYPE VFT_DLL
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", VERSIONCOMPANYNAME
|
||||
VALUE "FileDescription", VERSIONDESCRIPTION
|
||||
VALUE "FileVersion", VERSIONSTR
|
||||
VALUE "InternalName", VERSIONNAME
|
||||
VALUE "LegalCopyright", VERSIONCOPYRIGHT
|
||||
VALUE "OriginalFilename", VERSIONNAME
|
||||
VALUE "ProductName", VERSIONPRODUCTNAME
|
||||
VALUE "ProductVersion", VERSIONSTR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
79
SOURCE/amx/dllmain.c
Normal file
79
SOURCE/amx/dllmain.c
Normal file
@ -0,0 +1,79 @@
|
||||
/* DLL support functions for dynamically loadable extension libraries.
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2004-2005
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: dllmain.c 3363 2005-07-23 09:03:29Z thiadmer $
|
||||
*/
|
||||
|
||||
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
|
||||
# if !defined UNICODE /* for Windows */
|
||||
# define UNICODE
|
||||
# endif
|
||||
# if !defined _UNICODE /* for C library */
|
||||
# define _UNICODE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <windows.h>
|
||||
|
||||
#if !defined UNUSED_PARAM
|
||||
#define UNUSED_PARAM(p) ((void)(p))
|
||||
#endif
|
||||
|
||||
HINSTANCE hinstDLL;
|
||||
|
||||
/* Especially Watcom C/C++ does not like DLLs that do not have a LibMain()
|
||||
* set. Apparently, the start address is not set well, and some required
|
||||
* initializations are not done.
|
||||
*/
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID lpRes)
|
||||
{
|
||||
UNUSED_PARAM(lpRes);
|
||||
switch (dwReason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
hinstDLL=hinst;
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
} /* switch */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int FAR PASCAL LibMain(HINSTANCE hinst, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine)
|
||||
{
|
||||
UNUSED_PARAM(wDataSeg);
|
||||
UNUSED_PARAM(wHeapSize);
|
||||
UNUSED_PARAM(lpszCmdLine);
|
||||
hinstDLL=hinst;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FAR PASCAL _export WEP(int param)
|
||||
{
|
||||
UNUSED_PARAM(param);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* __WIN32__ */
|
||||
|
71
SOURCE/amx/examples/logfile.cpp
Normal file
71
SOURCE/amx/examples/logfile.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include <stdio.h>
|
||||
#include <malloc>
|
||||
#include <map>
|
||||
#include "amx.h"
|
||||
|
||||
class LogFile;
|
||||
static std::map<AMX*, LogFile*> lookup;
|
||||
|
||||
class LogFile {
|
||||
public:
|
||||
LogFile()
|
||||
{
|
||||
f = tmpfile();
|
||||
}
|
||||
|
||||
~LogFile()
|
||||
{
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
private:
|
||||
write(AMX* amx, cell params[])
|
||||
{
|
||||
int r = 0;
|
||||
char *pstr;
|
||||
|
||||
amx_StrParam(amx, params[1], pstr);
|
||||
if (pstr != NULL)
|
||||
r = fprintf(f, "%s", pstr);
|
||||
return r;
|
||||
}
|
||||
|
||||
FILE *f;
|
||||
|
||||
public:
|
||||
static cell n_write(AMX* amx, cell params[])
|
||||
{
|
||||
std::map<AMX*, LogFile*>::iterator p = lookup.find(amx);
|
||||
if (p != lookup.end())
|
||||
return p->second->write(amx, params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
extern "C"
|
||||
int amx_LogFileInit(AMX* amx)
|
||||
{
|
||||
LogFile* lf = new LogFile;
|
||||
if (lf) {
|
||||
lookup.insert(std::make_pair(amx, lf));
|
||||
|
||||
static AMX_NATIVE_INFO nativelist[] = {
|
||||
{ "write", LogFile::n_write },
|
||||
{ 0, 0 } /* terminator */
|
||||
};
|
||||
return amx_Register(amx, nativelist, -1);
|
||||
} /* if */
|
||||
return AMX_ERR_MEMORY;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
int amx_LogFileExit(AMX* amx)
|
||||
{
|
||||
std::map<AMX*, LogFile*>::iterator p = lookup.find(amx);
|
||||
if (p != lookup.end()) {
|
||||
delete p->second;
|
||||
lookup.erase(p);
|
||||
} /* if */
|
||||
return AMX_ERR_NONE;
|
||||
}
|
46
SOURCE/amx/examples/power.c
Normal file
46
SOURCE/amx/examples/power.c
Normal file
@ -0,0 +1,46 @@
|
||||
/* This file implements two the native functions: power(value,exponent)
|
||||
* and sqroot(value).
|
||||
*/
|
||||
#include "amx.h"
|
||||
|
||||
static cell n_power(AMX *amx, cell *params)
|
||||
{
|
||||
/* power(value, exponent);
|
||||
* params[1] = value
|
||||
* params[2] = exponent
|
||||
*/
|
||||
cell result = 1;
|
||||
while (params[2]-- > 0)
|
||||
result *= params[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static cell n_sqroot(AMX *amx, cell *params)
|
||||
{
|
||||
/* sqroot(value);
|
||||
* params[1] = value
|
||||
* This routine uses a simple successice approximation algorithm.
|
||||
*/
|
||||
cell div = params[1];
|
||||
cell result = 1;
|
||||
while (div > result) { /* end when div == result, or just below */
|
||||
div = (div + result) / 2; /* take mean value as new divisor */
|
||||
result = params[1] / div;
|
||||
} /* while */
|
||||
return div;
|
||||
}
|
||||
|
||||
int amx_PowerInit(AMX *amx)
|
||||
{
|
||||
static AMX_NATIVE_INFO power_Natives[] = {
|
||||
{ "power", n_power },
|
||||
{ "sqroot", n_sqroot },
|
||||
{ 0, 0 } /* terminator */
|
||||
};
|
||||
return amx_Register(amx, power_Natives, -1);
|
||||
}
|
||||
|
||||
int amx_PowerCleanup(AMX *amx)
|
||||
{
|
||||
return AMX_ERR_NONE;
|
||||
}
|
744
SOURCE/amx/fixed.c
Normal file
744
SOURCE/amx/fixed.c
Normal file
@ -0,0 +1,744 @@
|
||||
/* Fixed-point arithmetic for the Pawn Abstract Machine
|
||||
*
|
||||
* Fixed point numbers compromise range versus number of decimals. This
|
||||
* library decimal fixed point numbers with an configurable number of
|
||||
* decimals. The current setting is 3 decimals.
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 1998-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: fixed.c 3662 2006-11-07 08:44:33Z thiadmer $
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h> /* for NULL */
|
||||
#include "amx.h"
|
||||
|
||||
/*
|
||||
#if defined __BORLANDC__
|
||||
#pragma resource "amxFixed.res"
|
||||
#endif
|
||||
*/
|
||||
|
||||
#if !defined isdigit
|
||||
# define isdigit(c) ((unsigned)((c)-'0')<10u)
|
||||
#endif
|
||||
#define MULTIPLIER 1000L /* 10^decimals */
|
||||
|
||||
|
||||
static cell AMX_NATIVE_CALL n_fixed(AMX *amx,const cell *params)
|
||||
{
|
||||
(void)amx;
|
||||
return params[1] * MULTIPLIER;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL n_strfixed(AMX *amx,const cell *params)
|
||||
{
|
||||
char str[50],*ptr;
|
||||
cell *cstr,intpart,decimals;
|
||||
long multiplier,divisor;
|
||||
int len,sign=1;
|
||||
|
||||
amx_GetAddr(amx,params[1],&cstr);
|
||||
amx_StrLen(cstr,&len);
|
||||
if (len>=50) {
|
||||
amx_RaiseError(amx,AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
amx_GetString(str,cstr,0,UNLIMITED);
|
||||
ptr=str;
|
||||
intpart=0;
|
||||
decimals=0;
|
||||
multiplier=MULTIPLIER;
|
||||
divisor=1;
|
||||
while (*ptr!='\0' && *ptr<=' ')
|
||||
ptr++; /* skip whitespace */
|
||||
if (*ptr=='-') { /* handle sign */
|
||||
sign=-1;
|
||||
ptr++;
|
||||
} else if (*ptr=='+') {
|
||||
ptr++;
|
||||
} /* if */
|
||||
while (isdigit(*ptr)) {
|
||||
intpart=intpart*10 + (*ptr-'0');
|
||||
ptr++;
|
||||
} /* while */
|
||||
if (*ptr=='.') {
|
||||
ptr++;
|
||||
len=0;
|
||||
while (isdigit(*ptr) && len<8) {
|
||||
decimals=decimals*10 + (*ptr-'0');
|
||||
if (multiplier>1)
|
||||
multiplier/=10;
|
||||
else
|
||||
divisor*=10;
|
||||
ptr++;
|
||||
len++;
|
||||
} /* while */
|
||||
} /* if */
|
||||
return ((intpart*MULTIPLIER) + (decimals*multiplier+(divisor/2))/divisor) * sign;
|
||||
}
|
||||
|
||||
/* Some C/C++ compilers have problems with long lists of definitions, so
|
||||
* I create another macro to fix this.
|
||||
*/
|
||||
#if PAWN_CELL_SIZE!=32
|
||||
/* the assembler and compiler-supported optimizations are only implemented
|
||||
* for 32-bit cells
|
||||
*/
|
||||
#define USE_ANSI_C 1
|
||||
|
||||
#elif defined __WATCOMC__ && defined __386__ /* Watcom C/C++ */
|
||||
/* ANSI 64-bit division routine not needed for Watcom C/C++ because
|
||||
* it uses inline assembler.
|
||||
*/
|
||||
#define USE_ANSI_C 0
|
||||
|
||||
#elif defined _MSC_VER && _MSC_VER>=9 && defined _WIN32 /* Microsoft C/C++ */
|
||||
/* ANSI 64-bit division routine not needed for Microsoft Visual C/C++
|
||||
* because it supports 64-bit integers
|
||||
*/
|
||||
#define USE_ANSI_C 0
|
||||
|
||||
#elif defined __BORLANDC__ && __BORLANDC__ >= 0x500 && defined __32BIT__ /* Borland C++ v.5 */
|
||||
/* ANSI 64-bit division routine not needed for Borland C++ because it
|
||||
* supports 64-bit integers
|
||||
*/
|
||||
#define USE_ANSI_C 0
|
||||
|
||||
#elif defined __GNUC__ /* GNU GCC */
|
||||
/* ANSI 64-bit division routine not needed for GNU GCC because it
|
||||
* supports 64-bit integers
|
||||
*/
|
||||
#define USE_ANSI_C 0
|
||||
|
||||
#else
|
||||
|
||||
#define USE_ANSI_C 1
|
||||
|
||||
#endif
|
||||
|
||||
#if USE_ANSI_C
|
||||
#define WORDSHIFT (PAWN_CELL_SIZE/2)
|
||||
|
||||
#if PAWN_CELL_SIZE==32
|
||||
typedef unsigned short word_t;
|
||||
#define LOWORD(v) (word_t)((v) & 0xffffu)
|
||||
#define HIWORD(v) (word_t)(((v) >> 16) & 0xffffu)
|
||||
#elif PAWN_CELL_SIZE==64
|
||||
typedef uint32_t word_t;
|
||||
#define LOWORD(v) (word_t)((v) & 0xffffffffu)
|
||||
#define HIWORD(v) (word_t)(((v) >> 32) & 0xffffffffu)
|
||||
#else
|
||||
#error Unsupported cell size
|
||||
#endif
|
||||
|
||||
static ucell div64_32(ucell t[2], ucell divisor)
|
||||
{
|
||||
/* This function was adapted from source code that appeared in
|
||||
* Dr. Dobb's Journal, August 1992, page 117.
|
||||
*/
|
||||
ucell u, v;
|
||||
word_t rHigh, rLow, dHigh, dLow;
|
||||
|
||||
assert(divisor!=0);
|
||||
/* if the divisor is smaller than t[1], the result will not fit in a cell */
|
||||
assert(divisor>=t[1]);
|
||||
|
||||
dHigh=HIWORD(divisor);
|
||||
dLow=LOWORD(divisor);
|
||||
|
||||
/* Underestimate high half of quotient and subtract product
|
||||
* of estimate and divisor from dividend.
|
||||
*/
|
||||
rHigh = (word_t)(t[1] / (dHigh + 1));
|
||||
u = (ucell)rHigh * (ucell)dLow;
|
||||
v = (ucell)rHigh * (ucell)dHigh;
|
||||
if ((t[0] -= (u << WORDSHIFT)) > ((ucell)-1L - (u << WORDSHIFT)))
|
||||
t[1]--;
|
||||
t[1] -= HIWORD(u);
|
||||
t[1] -= v;
|
||||
|
||||
/* Correct estimate. */
|
||||
while ((t[1] > (ucell)dHigh) || ((t[1] == (ucell)dHigh) && (t[0] >= ((ucell)dLow << WORDSHIFT)))) {
|
||||
if ((t[0] -= ((ucell)dLow << WORDSHIFT)) > (ucell)-1L - ((ucell)dLow << WORDSHIFT))
|
||||
t[1]--;
|
||||
t[1] -= dHigh;
|
||||
rHigh++;
|
||||
} /* while */
|
||||
/* Underestimate low half of quotient and subtract product of
|
||||
* estimate and divisor from what remains of dividend.
|
||||
*/
|
||||
rLow = (word_t) ((ucell)((t[1] << WORDSHIFT) + HIWORD(t[0])) / (dHigh + 1));
|
||||
u = (ucell)rLow * (ucell)dLow;
|
||||
v = (ucell)rLow * (ucell)dHigh;
|
||||
if ((t[0] -= u) > ((ucell)-1L - u))
|
||||
t[1]--;
|
||||
if ((t[0] -= (v << WORDSHIFT)) > ((ucell)-1L - (v << WORDSHIFT)))
|
||||
t[1]--;
|
||||
t[1] -= HIWORD(v);
|
||||
|
||||
/* Correct estimate. */
|
||||
while ((t[1] > 0) || ((t[1] == 0) && t[0] >= divisor)) {
|
||||
if ((t[0] -= divisor) > ((ucell)-1L - divisor))
|
||||
t[1]--;
|
||||
rLow++;
|
||||
} /* while */
|
||||
|
||||
return ((ucell)rHigh << WORDSHIFT) + rLow;
|
||||
}
|
||||
#endif
|
||||
|
||||
static cell AMX_NATIVE_CALL n_fmul(AMX *amx,const cell *params)
|
||||
{
|
||||
#if !USE_ANSI_C
|
||||
#if defined __WATCOMC__ && defined __386__
|
||||
|
||||
cell __fmul(void);
|
||||
cell a=params[1];
|
||||
cell b=params[2];
|
||||
#if MULTIPLIER != 1000
|
||||
#error Assembler chunks must be modified for a different base
|
||||
#endif
|
||||
#pragma aux __fmul = \
|
||||
"mov eax, [a]" \
|
||||
"mov ebx, 1000" \
|
||||
"imul [b]" \
|
||||
"add eax, 500" \
|
||||
"adc edx, 0" \
|
||||
"idiv ebx" \
|
||||
"mov [a], eax" \
|
||||
modify [eax ebx edx];
|
||||
__fmul();
|
||||
(void)amx;
|
||||
return a;
|
||||
|
||||
#elif _MSC_VER>=9 && defined _WIN32
|
||||
|
||||
__int64 a=(__int64)params[1] * (__int64)params[2];
|
||||
a=(a+MULTIPLIER/2) / MULTIPLIER;
|
||||
(void)amx;
|
||||
return (cell)a;
|
||||
|
||||
#elif defined __BORLANDC__ && __BORLANDC__ >= 0x500 && (defined __32BIT__ || defined __WIN32__)
|
||||
|
||||
__int64 a=(__int64)params[1] * (__int64)params[2];
|
||||
a=(a+MULTIPLIER/2) / MULTIPLIER;
|
||||
(void)amx;
|
||||
return (cell)a;
|
||||
|
||||
#elif defined __GNUC__
|
||||
|
||||
long long a=(long long)params[1] * (long long)params[2];
|
||||
a=(a+MULTIPLIER/2) / MULTIPLIER;
|
||||
(void)amx;
|
||||
return (cell)a;
|
||||
|
||||
#else
|
||||
#error Unsupported compiler configuration, but USE_ANSI_C is false
|
||||
#endif
|
||||
|
||||
#else // USE_ANSI_C
|
||||
|
||||
/* (Xs * Ys) == (X*Y)ss, where "s" stands for scaled.
|
||||
* The desired result is (X*Y)s, so we must unscale once.
|
||||
* but we cannot do this before multiplication, because of loss
|
||||
* of precision, and we cannot do it after the multiplication
|
||||
* because of the possible overflow.
|
||||
* The technique used here is to cut the multiplicands into
|
||||
* components and to multiply these components separately:
|
||||
*
|
||||
* Assume Xs == (A << 16) + B and Ys == (C << 16) + D, where A, B,
|
||||
* C and D are 16 bit numbers.
|
||||
*
|
||||
* A B
|
||||
* C D
|
||||
* --- *
|
||||
* D*B + (D*A << 16) + (C*B << 16) + (C*A << (16+16))
|
||||
*
|
||||
* Thus we have built a 64-bit number, which can now be scaled back
|
||||
* to 32-bit by dividing by the scale factor.
|
||||
*/
|
||||
#define ADD_WRAP(var,carry,expr) (((var)+=(expr)), ((carry)+=((var)<(expr)) ? 1 : 0))
|
||||
ucell a,b,c,d;
|
||||
ucell v[2];
|
||||
cell sign=1;
|
||||
|
||||
(void)amx;
|
||||
assert(MULTIPLIER<=(1L<<WORDSHIFT));
|
||||
|
||||
/* make both operands positive values, but keep the sign of the result */
|
||||
if (params[1]<0) {
|
||||
((cell*)params)[1]=-params[1];
|
||||
sign=-sign; /* negate result */
|
||||
} /* if */
|
||||
if (params[2]<0) {
|
||||
((cell*)params)[2]=-params[2];
|
||||
sign=-sign; /* negate result */
|
||||
} /* if */
|
||||
|
||||
a = HIWORD(params[1]);
|
||||
b = LOWORD(params[1]);
|
||||
c = HIWORD(params[2]);
|
||||
d = LOWORD(params[2]);
|
||||
|
||||
/* store the intermediate into a 64-bit/128-bit number */
|
||||
v[1]=c*a;
|
||||
v[0]=d*b;
|
||||
ADD_WRAP(v[0],v[1],d*a << WORDSHIFT);
|
||||
ADD_WRAP(v[0],v[1],c*b << WORDSHIFT);
|
||||
|
||||
/* add half of the divisor, to round the data */
|
||||
ADD_WRAP(v[0],v[1],MULTIPLIER/2);
|
||||
|
||||
/* if the divisor is smaller than v[1], the result will not fit in a cell */
|
||||
if (MULTIPLIER<v[1]) {
|
||||
amx_RaiseError(amx,AMX_ERR_DOMAIN);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
return (cell)div64_32(v,MULTIPLIER) * sign;
|
||||
#endif
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL n_fdiv(AMX *amx,const cell *params)
|
||||
{
|
||||
#if !USE_ANSI_C
|
||||
#if defined __WATCOMC__ && defined __386__
|
||||
|
||||
cell __fdiv(void);
|
||||
cell a=params[1];
|
||||
cell b=params[2];
|
||||
#if MULTIPLIER != 1000
|
||||
#error Assembler chunks must be modified for a different base
|
||||
#endif
|
||||
|
||||
if (b==0) {
|
||||
amx_RaiseError(amx,AMX_ERR_DIVIDE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
#pragma aux __fdiv = \
|
||||
"mov eax, [a]" \
|
||||
"mov ecx, [b]" \
|
||||
"cdq" \
|
||||
"mov ebx, 1000" \
|
||||
"imul ebx" \
|
||||
"mov ebx, ecx" \
|
||||
"shr ecx, 1" \
|
||||
"add eax, ecx" \
|
||||
"adc edx, 0" \
|
||||
"idiv ebx" \
|
||||
"mov [a], eax" \
|
||||
modify [eax ebx ecx edx];
|
||||
__fdiv();
|
||||
return a;
|
||||
|
||||
#elif _MSC_VER>=9 && defined _WIN32
|
||||
|
||||
__int64 a;
|
||||
cell divisor=params[2];
|
||||
if (divisor==0) {
|
||||
amx_RaiseError(amx,AMX_ERR_DIVIDE);
|
||||
return 0;
|
||||
} /* if */
|
||||
a=((__int64)params[1] * (__int64)MULTIPLIER + (__int64)(divisor/2)) / (__int64)divisor;
|
||||
return (cell)a;
|
||||
|
||||
#elif defined __BORLANDC__ && __BORLANDC__ >= 0x500 && (defined __32BIT__ || defined __WIN32__)
|
||||
|
||||
__int64 a;
|
||||
cell divisor=params[2];
|
||||
if (divisor==0) {
|
||||
amx_RaiseError(amx,AMX_ERR_DIVIDE);
|
||||
return 0;
|
||||
} /* if */
|
||||
a=((__int64)params[1] * (__int64)MULTIPLIER + (__int64)(divisor/2)) / (__int64)divisor;
|
||||
return (cell)a;
|
||||
|
||||
#elif defined __GNUC__
|
||||
|
||||
long long a;
|
||||
cell divisor=params[2];
|
||||
if (divisor==0) {
|
||||
amx_RaiseError(amx,AMX_ERR_DIVIDE);
|
||||
return 0;
|
||||
} /* if */
|
||||
a=((long long)params[1] * (long long)MULTIPLIER + (long long)(divisor/2)) / (long long)divisor;
|
||||
return (cell)a;
|
||||
|
||||
#else
|
||||
#error Unsupported compiler configuration, but USE_ANSI_C is false
|
||||
#endif
|
||||
|
||||
#else // USE_ANSI_C
|
||||
|
||||
/* The dividend must be scaled prior to division. The dividend
|
||||
* is a 32-bit number, however, so when shifted, it will become
|
||||
* a value that no longer fits in a 32-bit variable. This routine
|
||||
* does the division by using only 16-bit and 32-bit values, but
|
||||
* with considerable effort.
|
||||
* If your compiler supports 64-bit integers, modify this routine
|
||||
* to use them. If your processor can do a simple 64-bit by 32-bit
|
||||
* division in assembler, write assembler chunks.
|
||||
* In other words: the straight C routine that follows is correct
|
||||
* and portable, but use it only as a last resort.
|
||||
*
|
||||
* This function was adapted from source code that appeared in
|
||||
* Dr. Dobb's Journal, August 1992, page 117.
|
||||
*/
|
||||
|
||||
cell dividend=params[1];
|
||||
cell divisor=params[2];
|
||||
cell sign=1;
|
||||
ucell b[2];
|
||||
|
||||
if (divisor==0) {
|
||||
amx_RaiseError(amx,AMX_ERR_NATIVE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
/* make both operands positive values, but keep the sign of the result */
|
||||
if (dividend<0) {
|
||||
dividend=-dividend;
|
||||
sign=-sign; /* negate result */
|
||||
} /* if */
|
||||
if (divisor<0) {
|
||||
divisor=-divisor;
|
||||
sign=-sign; /* negate result */
|
||||
} /* if */
|
||||
|
||||
/* pre-scale the dividend into a 64-bit/128-bit number */
|
||||
b[0]=dividend*MULTIPLIER;
|
||||
b[1]=(HIWORD(dividend)*MULTIPLIER) >> WORDSHIFT;
|
||||
|
||||
/* add half of the divisor, to round the data */
|
||||
b[0]+=(ucell)divisor/2;
|
||||
if (b[0]<(ucell)divisor/2)
|
||||
b[1]+=1; /* wrap-around ocurred */
|
||||
|
||||
/* if the divisor is smaller than b[1], the result will not fit in a cell */
|
||||
if ((ucell)divisor<b[1]) {
|
||||
amx_RaiseError(amx,AMX_ERR_DOMAIN);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
return (cell)div64_32(b,(ucell)divisor) * sign;
|
||||
#endif
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL n_fmuldiv(AMX *amx,const cell *params)
|
||||
{
|
||||
#if !USE_ANSI_C
|
||||
#if defined __WATCOMC__ && defined __386__
|
||||
|
||||
cell __fmuldiv(void);
|
||||
cell a=params[1];
|
||||
cell b=params[2];
|
||||
cell c=params[3];
|
||||
|
||||
if (c==0) {
|
||||
amx_RaiseError(amx,AMX_ERR_DIVIDE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
#pragma aux __fmuldiv = \
|
||||
"mov eax, [a]" \
|
||||
"mov ecx, [c]" \
|
||||
"imul [b]" \
|
||||
"mov ebx, ecx" \
|
||||
"shr ecx, 1" \
|
||||
"add eax, ecx" \
|
||||
"adc edx, 0" \
|
||||
"idiv ebx" \
|
||||
"mov [a], eax" \
|
||||
modify [eax ebx ecx edx];
|
||||
__fmuldiv();
|
||||
return a;
|
||||
|
||||
#elif _MSC_VER>=9 && defined _WIN32
|
||||
|
||||
__int64 a;
|
||||
cell divisor=params[3];
|
||||
if (divisor==0) {
|
||||
amx_RaiseError(amx,AMX_ERR_DIVIDE);
|
||||
return 0;
|
||||
} /* if */
|
||||
a=((__int64)params[1] * (__int64)params[2] + (__int64)(divisor/2)) / (__int64)divisor;
|
||||
return (cell)a;
|
||||
|
||||
#elif defined __BORLANDC__ && __BORLANDC__ >= 0x500 && (defined __32BIT__ || defined __WIN32__)
|
||||
|
||||
__int64 a;
|
||||
cell divisor=params[3];
|
||||
if (divisor==0) {
|
||||
amx_RaiseError(amx,AMX_ERR_DIVIDE);
|
||||
return 0;
|
||||
} /* if */
|
||||
a=((__int64)params[1] * (__int64)params[2] + (__int64)(divisor/2)) / (__int64)divisor;
|
||||
return (cell)a;
|
||||
|
||||
#elif defined __GNUC__
|
||||
|
||||
long long a;
|
||||
cell divisor=params[3];
|
||||
if (divisor==0) {
|
||||
amx_RaiseError(amx,AMX_ERR_DIVIDE);
|
||||
return 0;
|
||||
} /* if */
|
||||
a=((long long)params[1] * (long long)params[2] + (long long)(divisor/2)) / (long long)divisor;
|
||||
return (cell)a;
|
||||
|
||||
#else
|
||||
#error Unsupported compiler configuration, but USE_ANSI_C is false
|
||||
#endif
|
||||
|
||||
#else // USE_ANSI_C
|
||||
|
||||
ucell a,b,c,d;
|
||||
ucell v[2];
|
||||
cell sign=1;
|
||||
cell divisor=params[3];
|
||||
|
||||
assert(MULTIPLIER<=(1L<<16));
|
||||
|
||||
if (divisor==0) {
|
||||
amx_RaiseError(amx,AMX_ERR_DIVIDE);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
/* make all three operands positive values, but keep the sign of the result */
|
||||
if (params[1]<0) {
|
||||
((cell*)params)[1]=-params[1];
|
||||
sign=-sign; /* negate result */
|
||||
} /* if */
|
||||
if (params[2]<0) {
|
||||
((cell*)params)[2]=-params[2];
|
||||
sign=-sign; /* negate result */
|
||||
} /* if */
|
||||
if (divisor<0) {
|
||||
divisor=-divisor;
|
||||
sign=-sign; /* negate result */
|
||||
} /* if */
|
||||
|
||||
a = HIWORD(params[1]);
|
||||
b = LOWORD(params[1]);
|
||||
c = HIWORD(params[2]);
|
||||
d = LOWORD(params[2]);
|
||||
|
||||
/* store the intermediate into a 64-bit/128-bit number */
|
||||
v[1]=c*a;
|
||||
v[0]=d*b;
|
||||
ADD_WRAP(v[0],v[1],d*a << WORDSHIFT);
|
||||
ADD_WRAP(v[0],v[1],c*b << WORDSHIFT);
|
||||
|
||||
/* add half of the divisor, to round the data */
|
||||
ADD_WRAP(v[0],v[1],(ucell)divisor/2);
|
||||
|
||||
/* if the divisor is smaller than v[1], the result will not fit in a cell */
|
||||
if ((ucell)divisor<v[1]) {
|
||||
amx_RaiseError(amx,AMX_ERR_DOMAIN);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
return (cell)div64_32(v,(ucell)divisor) * sign;
|
||||
#endif
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL n_ffract(AMX *amx,const cell *params)
|
||||
{
|
||||
(void)amx;
|
||||
return params[1] % MULTIPLIER;
|
||||
}
|
||||
|
||||
static cell AMX_NATIVE_CALL n_fround(AMX *amx,const cell *params)
|
||||
{
|
||||
cell value;
|
||||
|
||||
(void)amx;
|
||||
switch (params[2]) {
|
||||
case 1: /* round downwards (truncate) */
|
||||
value=params[1] / MULTIPLIER;
|
||||
if (params[1]<0 && (params[1] % MULTIPLIER)!=0)
|
||||
value--;
|
||||
break;
|
||||
case 2: /* round upwards */
|
||||
value=params[1] / MULTIPLIER;
|
||||
if (params[1]>=0 && (params[1] % MULTIPLIER)!=0)
|
||||
value++;
|
||||
break;
|
||||
case 3: /* truncate: round down when > 0, round up when < 0 */
|
||||
value=params[1] / MULTIPLIER;
|
||||
break;
|
||||
case 4: /* round to even number when fractional part is exactly 0.5 */
|
||||
value=(params[1] + MULTIPLIER/2) / MULTIPLIER;
|
||||
if ((params[1] % MULTIPLIER)==MULTIPLIER/2 && (value & 1)==1)
|
||||
value--;
|
||||
break;
|
||||
default: /* standard (fractional part of 0.5 is rounded up */
|
||||
value=(params[1] + MULTIPLIER/2) / MULTIPLIER;
|
||||
} /* switch */
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Fixed:fsqroot(Fixed:value) */
|
||||
static cell AMX_NATIVE_CALL n_fsqroot(AMX *amx,const cell *params)
|
||||
{
|
||||
cell value=params[1];
|
||||
cell low=0;
|
||||
cell high=value;
|
||||
cell mid[3]={8,0,0};
|
||||
|
||||
if (value<0) {
|
||||
amx_RaiseError(amx, AMX_ERR_DOMAIN);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
while (high-low > 1) {
|
||||
mid[1]=mid[2]=(low+high)/2;
|
||||
if (n_fmul(amx,mid) < value)
|
||||
low=mid[1];
|
||||
else
|
||||
high=mid[1];
|
||||
} /* while */
|
||||
|
||||
/* check whether low or high mark comes closest */
|
||||
if (low!=high) {
|
||||
cell deltalow, deltahigh;
|
||||
mid[1]=mid[2]=low;
|
||||
deltalow=value-n_fmul(amx,mid);
|
||||
assert(deltalow>=0);
|
||||
mid[1]=mid[2]=high;
|
||||
deltahigh=n_fmul(amx,mid)-value;
|
||||
assert(deltahigh>=0);
|
||||
if (deltahigh<=deltalow)
|
||||
low=high; /* return "high" mark (comes closer to the answer) */
|
||||
} /* if */
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
/* Fixed: fpower(Fixed:value, exponent)
|
||||
* note: x^n = exp(n*ln(x)), see http://yacas.sourceforge.net/Algochapter5.html
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_fpower(AMX *amx,const cell *params)
|
||||
{
|
||||
#define LIMIT32 146542L /* top value to calculate with extra digit, when a cell is 32-bit */
|
||||
cell result[3] = {8,0,0};
|
||||
int power=(int)params[2];
|
||||
int iter=1;
|
||||
int reciprocal=0;
|
||||
int isscaled=0;
|
||||
|
||||
if (power<0) {
|
||||
reciprocal=1;
|
||||
power=-power;
|
||||
} /* if */
|
||||
if (power==0)
|
||||
return MULTIPLIER;
|
||||
|
||||
/* quick squaring, to nearest power of 2 */
|
||||
result[1]=params[1];
|
||||
/* first try to do this with an extra digit of precision */
|
||||
if (result[1]<LIMIT32) {
|
||||
assert(sizeof(cell)>=4);
|
||||
result[1]*=10; /* scale to have an extra digit */
|
||||
isscaled=1;
|
||||
while (2*iter<=power && result[1]<LIMIT32*10) {
|
||||
iter*=2;
|
||||
result[2]=result[1];
|
||||
result[1]=(n_fmul(amx,result)+5)/10;
|
||||
} /* while */
|
||||
} /* if */
|
||||
assert(2*iter>power || result[1]>=LIMIT32*10);
|
||||
if (result[1]>=LIMIT32*10) {
|
||||
result[1]=(result[1]+5)/10; /* undo scaling */
|
||||
isscaled=0;
|
||||
} /* if */
|
||||
while (2*iter<=power) {
|
||||
iter*=2;
|
||||
result[2]=result[1];
|
||||
result[1]=n_fmul(amx,result);
|
||||
} /* while */
|
||||
|
||||
/* multilply with the remainder */
|
||||
if (iter<power && (isscaled || result[1]<LIMIT32)) {
|
||||
if (!isscaled) {
|
||||
result[1]*=10; /* scale to have an extra digit */
|
||||
isscaled=1;
|
||||
} /* if */
|
||||
while (iter<power && result[1]<LIMIT32*10) {
|
||||
iter++;
|
||||
result[2]=params[1];
|
||||
result[1]=n_fmul(amx,result);
|
||||
} /* while */
|
||||
} /* if */
|
||||
if (isscaled) {
|
||||
result[1]=(result[1]+5)/10; /* undo scaling */
|
||||
/* isscaled=0; */
|
||||
} /* if */
|
||||
while (iter<power) {
|
||||
iter++;
|
||||
result[2]=params[1];
|
||||
result[1]=n_fmul(amx,result);
|
||||
} /* while */
|
||||
|
||||
if (reciprocal) {
|
||||
result[2]=result[1];
|
||||
result[1]=MULTIPLIER;
|
||||
result[1]=n_fdiv(amx,result); /* result[1] = 1 / result[1] */
|
||||
} /* if */
|
||||
|
||||
return result[1];
|
||||
}
|
||||
|
||||
/* Fixed: fabs(Fixed:value)
|
||||
*/
|
||||
static cell AMX_NATIVE_CALL n_fabs(AMX *amx,const cell *params)
|
||||
{
|
||||
cell result=params[1];
|
||||
(void)amx;
|
||||
return (result>=0) ? result : -result;
|
||||
}
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
const AMX_NATIVE_INFO fixed_Natives[] = {
|
||||
{ "fixed", n_fixed },
|
||||
{ "strfixed", n_strfixed },
|
||||
{ "fmul", n_fmul },
|
||||
{ "fdiv", n_fdiv },
|
||||
{ "ffract", n_ffract },
|
||||
{ "fround", n_fround },
|
||||
{ "fmuldiv", n_fmuldiv },
|
||||
{ "fsqroot", n_fsqroot },
|
||||
{ "fpower", n_fpower },
|
||||
{ "fabs", n_fabs },
|
||||
{ NULL, NULL } /* terminator */
|
||||
};
|
||||
|
||||
int AMXEXPORT amx_FixedInit(AMX *amx)
|
||||
{
|
||||
return amx_Register(amx,fixed_Natives,-1);
|
||||
}
|
||||
|
||||
int AMXEXPORT amx_FixedCleanup(AMX *amx)
|
||||
{
|
||||
(void)amx;
|
||||
return AMX_ERR_NONE;
|
||||
}
|
362
SOURCE/amx/float.c
Normal file
362
SOURCE/amx/float.c
Normal file
@ -0,0 +1,362 @@
|
||||
/* Float arithmetic for the Pawn Abstract Machine
|
||||
*
|
||||
* Copyright (c) Artran, Inc. 1999
|
||||
* Written by Greg Garner (gmg@artran.com)
|
||||
* This file may be freely used. No warranties of any kind.
|
||||
*
|
||||
* CHANGES -
|
||||
* 2002-08-27: Basic conversion of source from C++ to C by Adam D. Moss
|
||||
* <adam@gimp.org> <aspirin@icculus.org>
|
||||
* 2003-08-29: Removal of the dynamic memory allocation and replacing two
|
||||
* type conversion functions by macros, by Thiadmer Riemersma
|
||||
* 2003-09-22: Moved the type conversion macros to AMX.H, and simplifications
|
||||
* of some routines, by Thiadmer Riemersma
|
||||
* 2003-11-24: A few more native functions (geometry), plus minor modifications,
|
||||
* mostly to be compatible with dynamically loadable extension
|
||||
* modules, by Thiadmer Riemersma
|
||||
* 2004-01-09: Adaptions for 64-bit cells (using "double precision"), by
|
||||
* Thiadmer Riemersma
|
||||
*/
|
||||
#include <stdlib.h> /* for atof() */
|
||||
#include <stdio.h> /* for NULL */
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include "amx.h"
|
||||
|
||||
/*
|
||||
#if defined __BORLANDC__
|
||||
#pragma resource "amxFloat.res"
|
||||
#endif
|
||||
*/
|
||||
|
||||
#if PAWN_CELL_SIZE==32
|
||||
#define REAL float
|
||||
#elif PAWN_CELL_SIZE==64
|
||||
#define REAL double
|
||||
#else
|
||||
#error Unsupported cell size
|
||||
#endif
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_float(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = long value to convert to a float
|
||||
*/
|
||||
REAL fValue;
|
||||
|
||||
(void)amx;
|
||||
/* Convert to a float. Calls the compilers long to float conversion. */
|
||||
fValue = (REAL) params[1];
|
||||
|
||||
/* Return the cell. */
|
||||
return amx_ftoc(fValue);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_strfloat(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = virtual string address to convert to a float
|
||||
*/
|
||||
char szSource[60];
|
||||
cell *pString;
|
||||
REAL fNum;
|
||||
int nLen;
|
||||
|
||||
(void)amx;
|
||||
/* They should have sent us 1 cell. */
|
||||
assert(params[0]/sizeof(cell)==1);
|
||||
|
||||
/* Get the real address of the string. */
|
||||
amx_GetAddr(amx,params[1],&pString);
|
||||
|
||||
/* Find out how long the string is in characters. */
|
||||
amx_StrLen(pString, &nLen);
|
||||
if (nLen == 0 || nLen >= sizeof szSource)
|
||||
return 0;
|
||||
|
||||
/* Now convert the Pawn string into a C type null terminated string */
|
||||
amx_GetString(szSource, pString, 0, sizeof szSource);
|
||||
|
||||
/* Now convert this to a float. */
|
||||
fNum = (REAL)atof(szSource);
|
||||
|
||||
return amx_ftoc(fNum);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_floatmul(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float operand 1
|
||||
* params[2] = float operand 2
|
||||
*/
|
||||
REAL fRes = amx_ctof(params[1]) * amx_ctof(params[2]);
|
||||
(void)amx;
|
||||
return amx_ftoc(fRes);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_floatdiv(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float dividend (top)
|
||||
* params[2] = float divisor (bottom)
|
||||
*/
|
||||
REAL fRes = amx_ctof(params[1]) / amx_ctof(params[2]);
|
||||
(void)amx;
|
||||
return amx_ftoc(fRes);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_floatadd(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float operand 1
|
||||
* params[2] = float operand 2
|
||||
*/
|
||||
REAL fRes = amx_ctof(params[1]) + amx_ctof(params[2]);
|
||||
(void)amx;
|
||||
return amx_ftoc(fRes);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_floatsub(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float operand 1
|
||||
* params[2] = float operand 2
|
||||
*/
|
||||
REAL fRes = amx_ctof(params[1]) - amx_ctof(params[2]);
|
||||
(void)amx;
|
||||
return amx_ftoc(fRes);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/* Return fractional part of float */
|
||||
static cell AMX_NATIVE_CALL n_floatfract(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float operand
|
||||
*/
|
||||
REAL fA = amx_ctof(params[1]);
|
||||
fA = fA - (REAL)(floor((double)fA));
|
||||
(void)amx;
|
||||
return amx_ftoc(fA);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/* Return integer part of float, rounded */
|
||||
static cell AMX_NATIVE_CALL n_floatround(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float operand
|
||||
* params[2] = Type of rounding (long)
|
||||
*/
|
||||
REAL fA = amx_ctof(params[1]);
|
||||
|
||||
(void)amx;
|
||||
switch (params[2])
|
||||
{
|
||||
case 1: /* round downwards (truncate) */
|
||||
fA = (REAL)(floor((double)fA));
|
||||
break;
|
||||
case 2: /* round upwards */
|
||||
fA = (REAL)(ceil((double)fA));
|
||||
break;
|
||||
case 3: /* round towards zero */
|
||||
if ( fA>=0.0 )
|
||||
fA = (REAL)(floor((double)fA));
|
||||
else
|
||||
fA = (REAL)(ceil((double)fA));
|
||||
break;
|
||||
default: /* standard, round to nearest */
|
||||
fA = (REAL)(floor((double)fA+.5));
|
||||
break;
|
||||
}
|
||||
|
||||
return (long)fA;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_floatcmp(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float operand 1
|
||||
* params[2] = float operand 2
|
||||
*/
|
||||
REAL fA, fB;
|
||||
|
||||
(void)amx;
|
||||
fA = amx_ctof(params[1]);
|
||||
fB = amx_ctof(params[2]);
|
||||
if (fA == fB)
|
||||
return 0;
|
||||
else if (fA>fB)
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_floatsqroot(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float operand
|
||||
*/
|
||||
REAL fA = amx_ctof(params[1]);
|
||||
fA = (REAL)sqrt(fA);
|
||||
if (fA < 0)
|
||||
return amx_RaiseError(amx, AMX_ERR_DOMAIN);
|
||||
return amx_ftoc(fA);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_floatpower(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float operand 1 (base)
|
||||
* params[2] = float operand 2 (exponent)
|
||||
*/
|
||||
REAL fA = amx_ctof(params[1]);
|
||||
REAL fB = amx_ctof(params[2]);
|
||||
fA = (REAL)pow(fA, fB);
|
||||
(void)amx;
|
||||
return amx_ftoc(fA);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_floatlog(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float operand 1 (value)
|
||||
* params[2] = float operand 2 (base)
|
||||
*/
|
||||
REAL fValue = amx_ctof(params[1]);
|
||||
REAL fBase = amx_ctof(params[2]);
|
||||
(void)amx;
|
||||
if (fValue <= 0.0 || fBase <= 0)
|
||||
return amx_RaiseError(amx, AMX_ERR_DOMAIN);
|
||||
if (fBase == 10.0) // ??? epsilon
|
||||
fValue = (REAL)log10(fValue);
|
||||
else
|
||||
fValue = (REAL)(log(fValue) / log(fBase));
|
||||
return amx_ftoc(fValue);
|
||||
}
|
||||
|
||||
static REAL ToRadians(REAL angle, int radix)
|
||||
{
|
||||
switch (radix)
|
||||
{
|
||||
case 1: /* degrees, sexagesimal system (technically: degrees/minutes/seconds) */
|
||||
return (REAL)(angle * PI / 180.0);
|
||||
case 2: /* grades, centesimal system */
|
||||
return (REAL)(angle * PI / 200.0);
|
||||
default: /* assume already radian */
|
||||
return angle;
|
||||
} /* switch */
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_floatsin(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float operand 1 (angle)
|
||||
* params[2] = float operand 2 (radix)
|
||||
*/
|
||||
REAL fA = amx_ctof(params[1]);
|
||||
fA = ToRadians(fA, params[2]);
|
||||
fA = sin(fA);
|
||||
(void)amx;
|
||||
return amx_ftoc(fA);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_floatcos(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float operand 1 (angle)
|
||||
* params[2] = float operand 2 (radix)
|
||||
*/
|
||||
REAL fA = amx_ctof(params[1]);
|
||||
fA = ToRadians(fA, params[2]);
|
||||
fA = cos(fA);
|
||||
(void)amx;
|
||||
return amx_ftoc(fA);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_floattan(AMX *amx,const cell *params)
|
||||
{
|
||||
/*
|
||||
* params[0] = number of bytes
|
||||
* params[1] = float operand 1 (angle)
|
||||
* params[2] = float operand 2 (radix)
|
||||
*/
|
||||
REAL fA = amx_ctof(params[1]);
|
||||
fA = ToRadians(fA, params[2]);
|
||||
fA = tan(fA);
|
||||
(void)amx;
|
||||
return amx_ftoc(fA);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
static cell AMX_NATIVE_CALL n_floatabs(AMX *amx,const cell *params)
|
||||
{
|
||||
REAL fA = amx_ctof(params[1]);
|
||||
fA = (fA >= 0) ? fA : -fA;
|
||||
(void)amx;
|
||||
return amx_ftoc(fA);
|
||||
}
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
const AMX_NATIVE_INFO float_Natives[] = {
|
||||
{ "float", n_float },
|
||||
{ "strfloat", n_strfloat },
|
||||
{ "floatmul", n_floatmul },
|
||||
{ "floatdiv", n_floatdiv },
|
||||
{ "floatadd", n_floatadd },
|
||||
{ "floatsub", n_floatsub },
|
||||
{ "floatfract", n_floatfract },
|
||||
{ "floatround", n_floatround },
|
||||
{ "floatcmp", n_floatcmp },
|
||||
{ "floatsqroot", n_floatsqroot},
|
||||
{ "floatpower", n_floatpower },
|
||||
{ "floatlog", n_floatlog },
|
||||
{ "floatsin", n_floatsin },
|
||||
{ "floatcos", n_floatcos },
|
||||
{ "floattan", n_floattan },
|
||||
{ "floatabs", n_floatabs },
|
||||
{ NULL, NULL } /* terminator */
|
||||
};
|
||||
|
||||
int AMXEXPORT amx_FloatInit(AMX *amx)
|
||||
{
|
||||
return amx_Register(amx,float_Natives,-1);
|
||||
}
|
||||
|
||||
int AMXEXPORT amx_FloatCleanup(AMX *amx)
|
||||
{
|
||||
(void)amx;
|
||||
return AMX_ERR_NONE;
|
||||
}
|
906
SOURCE/amx/fpattern.c
Normal file
906
SOURCE/amx/fpattern.c
Normal file
@ -0,0 +1,906 @@
|
||||
/*
|
||||
from http://home.flash.net/~dtribble/text/fpattern.htm
|
||||
2000/12/12
|
||||
by Perry
|
||||
License statement is in comments below
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* fpattern.c
|
||||
* Functions for matching filename patterns to filenames.
|
||||
*
|
||||
* Usage
|
||||
* (See "fpattern.h".)
|
||||
*
|
||||
* Notes
|
||||
* These pattern matching capabilities are modeled after those found in
|
||||
* the UNIX command shells.
|
||||
*
|
||||
* `DELIM' must be defined to 1 if pathname separators are to be handled
|
||||
* explicitly.
|
||||
*
|
||||
* History
|
||||
* 1.00 1997-01-03 David Tribble.
|
||||
* First cut.
|
||||
* 1.01 1997-01-03 David Tribble.
|
||||
* Added SUB pattern character.
|
||||
* Added fpattern_matchn().
|
||||
* 1.02 1997-01-12 David Tribble.
|
||||
* Fixed missing lowercase matching cases.
|
||||
* 1.03 1997-01-13 David Tribble.
|
||||
* Pathname separator code is now controlled by DELIM macro.
|
||||
* 1.04 1997-01-14 David Tribble.
|
||||
* Added QUOTE macro.
|
||||
* 1.05 1997-01-15 David Tribble.
|
||||
* Handles special case of empty pattern and empty filename.
|
||||
* 1.06 1997-01-26 David Tribble.
|
||||
* Changed range negation character from '^' to '!', ala Unix.
|
||||
* 1.07 1997-08-02 David Tribble.
|
||||
* Uses the 'FPAT_XXX' constants.
|
||||
* 1.08 1998-06-28 David Tribble.
|
||||
* Minor fixed for MS-VC++ (5.0).
|
||||
*
|
||||
* Limitations
|
||||
* This code is copyrighted by the author, but permission is hereby
|
||||
* granted for its unlimited use provided that the original copyright
|
||||
* and authorship notices are retained intact.
|
||||
*
|
||||
* Other queries can be sent to:
|
||||
* dtribble@technologist.com
|
||||
* david.tribble@beasys.com
|
||||
* dtribble@flash.net
|
||||
*
|
||||
* Copyright 1997-1998 by David R. Tribble, all rights reserved.
|
||||
* $Id: fpattern.c 3612 2006-07-22 09:59:46Z thiadmer $
|
||||
*/
|
||||
|
||||
|
||||
/* Identification */
|
||||
#if 0
|
||||
static const char id[] =
|
||||
"@(#)lib/fpattern.c 1.08";
|
||||
|
||||
static const char copyright[] =
|
||||
"Copyright 1997-1998 David R. Tribble\n";
|
||||
#endif
|
||||
|
||||
|
||||
/* System includes */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if TEST
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if defined _WIN32 || defined __WIN32__ || defined WIN32
|
||||
#include <stdlib.h>
|
||||
#define sleep(q) Sleep(q*1000)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(unix) || defined(_unix) || defined(__unix) || \
|
||||
defined(__unix__) || ( defined(__MACH__) && defined(__APPLE_CC__) )
|
||||
#define UNIX 1
|
||||
#define DOS 0
|
||||
#elif defined(__MSDOS__) || defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
#define UNIX 0
|
||||
#define DOS 1
|
||||
#else
|
||||
#error Cannot ascertain O/S from predefined macros
|
||||
#endif
|
||||
|
||||
|
||||
/* Local includes */
|
||||
|
||||
#include "fpattern.h"
|
||||
|
||||
|
||||
/* Local constants */
|
||||
|
||||
#ifndef NULL
|
||||
# define NULL ((void *) 0)
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
# define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
# define TRUE 1
|
||||
#endif
|
||||
|
||||
#if TEST
|
||||
# define SUB '~'
|
||||
#else
|
||||
# define SUB FPAT_CLOSP
|
||||
#endif
|
||||
|
||||
#ifndef DELIM
|
||||
# define DELIM 0
|
||||
#endif
|
||||
|
||||
#ifndef SUBCLOS
|
||||
# define SUBCLOS 0
|
||||
#endif
|
||||
|
||||
#define DEL FPAT_DEL
|
||||
|
||||
#if UNIX
|
||||
#define DEL2 FPAT_DEL
|
||||
#else /*DOS*/
|
||||
#define DEL2 FPAT_DEL2
|
||||
#endif
|
||||
|
||||
#if UNIX
|
||||
#define QUOTE FPAT_QUOTE
|
||||
#else /*DOS*/
|
||||
#define QUOTE FPAT_QUOTE2
|
||||
#endif
|
||||
|
||||
|
||||
/* Local function macros */
|
||||
|
||||
/* Warning, while this code was originally filename search code
|
||||
* which was case insensitive on DOS and case sensitive on UNIX
|
||||
* it's being used for name searching and should behave the same everywhere
|
||||
*/
|
||||
static int lowercase(int c, int keepcase)
|
||||
{
|
||||
if (keepcase)
|
||||
return c;
|
||||
return tolower(c);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* fpattern_isvalid()
|
||||
* Checks that filename pattern 'pat' is a well-formed pattern.
|
||||
*
|
||||
* Returns
|
||||
* 1 (true) if 'pat' is a valid filename pattern, otherwise 0 (false).
|
||||
*
|
||||
* Caveats
|
||||
* If 'pat' is null, 0 (false) is returned.
|
||||
*
|
||||
* If 'pat' is empty (""), 1 (true) is returned, and it is considered a
|
||||
* valid (but degenerate) pattern (the only filename it matches is the
|
||||
* empty ("") string).
|
||||
*/
|
||||
|
||||
int fpattern_isvalid(const char *pat)
|
||||
{
|
||||
int len;
|
||||
char close;
|
||||
|
||||
/* Check args */
|
||||
if (pat == NULL)
|
||||
return (FALSE);
|
||||
|
||||
/* Verify that the pattern is valid */
|
||||
for (len = 0; pat[len] != '\0'; len++)
|
||||
{
|
||||
switch (pat[len])
|
||||
{
|
||||
case FPAT_SET_L:
|
||||
case FPAT_MSET_L:
|
||||
/* Char set */
|
||||
close = (char)((pat[len] == FPAT_SET_L) ? FPAT_SET_R : FPAT_MSET_R);
|
||||
len++;
|
||||
if (pat[len] == FPAT_SET_NOT)
|
||||
len++; /* Set negation */
|
||||
|
||||
while (pat[len] != close)
|
||||
{
|
||||
if (pat[len] == QUOTE)
|
||||
len++; /* Quoted char */
|
||||
if (pat[len] == '\0')
|
||||
return (FALSE); /* Missing closing bracket */
|
||||
len++;
|
||||
|
||||
if (pat[len] == FPAT_SET_THRU)
|
||||
{
|
||||
/* Char range */
|
||||
len++;
|
||||
if (pat[len] == QUOTE)
|
||||
len++; /* Quoted char */
|
||||
if (pat[len] == '\0')
|
||||
return (FALSE); /* Missing closing bracket */
|
||||
len++;
|
||||
}
|
||||
|
||||
if (pat[len] == '\0')
|
||||
return (FALSE); /* Missing closing bracket */
|
||||
}
|
||||
break;
|
||||
|
||||
case QUOTE:
|
||||
/* Quoted char */
|
||||
len++;
|
||||
if (pat[len] == '\0')
|
||||
return (FALSE); /* Missing quoted char */
|
||||
break;
|
||||
|
||||
case FPAT_NOT:
|
||||
/* Negated pattern */
|
||||
len++;
|
||||
if (pat[len] == '\0')
|
||||
return (FALSE); /* Missing subpattern */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Valid character */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* fpattern_submatch()
|
||||
* Attempts to match subpattern 'pat' to subfilename 'fname'.
|
||||
*
|
||||
* Returns
|
||||
* 1 (true) if the subfilename matches, otherwise 0 (false).
|
||||
*
|
||||
* Caveats
|
||||
* This does not assume that 'pat' is well-formed.
|
||||
*
|
||||
* If 'pat' is empty (""), the only filename it matches is the empty ("")
|
||||
* string.
|
||||
*
|
||||
* Some non-empty patterns (e.g., "") will match an empty filename ("").
|
||||
*/
|
||||
|
||||
static int fpattern_submatch(const char *pat, const char *fname, int flength, int keepcase)
|
||||
{
|
||||
int fch;
|
||||
int pch;
|
||||
int i;
|
||||
int yes, match;
|
||||
int lo, hi;
|
||||
|
||||
/* Attempt to match subpattern against subfilename */
|
||||
while (*pat != '\0')
|
||||
{
|
||||
fch = *fname;
|
||||
pch = *pat;
|
||||
pat++;
|
||||
|
||||
switch (pch)
|
||||
{
|
||||
case FPAT_ANY:
|
||||
/* Match a single char */
|
||||
#if DELIM
|
||||
if (fch == DEL || fch == DEL2 || fch == '\0')
|
||||
return (FALSE);
|
||||
#else
|
||||
if (flength == 0)
|
||||
return (FALSE);
|
||||
#endif
|
||||
fname++;
|
||||
flength--;
|
||||
break;
|
||||
|
||||
case FPAT_CLOS:
|
||||
/* Match zero or more chars */
|
||||
#if DELIM
|
||||
i = 0;
|
||||
while (fname[i] != '\0' &&
|
||||
fname[i] != DEL && fname[i] != DEL2)
|
||||
i++;
|
||||
#else
|
||||
i = flength;
|
||||
#endif
|
||||
while (i >= 0)
|
||||
{
|
||||
if (fpattern_submatch(pat, fname+i, flength-i, keepcase))
|
||||
return (TRUE);
|
||||
i--;
|
||||
}
|
||||
return (FALSE);
|
||||
|
||||
#if SUBCLOS
|
||||
case SUB:
|
||||
/* Match zero or more chars */
|
||||
i = 0;
|
||||
while (i < flength &&
|
||||
#if DELIM
|
||||
fname[i] != DEL && fname[i] != DEL2 &&
|
||||
#endif
|
||||
fname[i] != '.')
|
||||
i++;
|
||||
while (i >= 0)
|
||||
{
|
||||
if (fpattern_submatch(pat, fname+i, flength-i, keepcase))
|
||||
return (TRUE);
|
||||
i--;
|
||||
}
|
||||
return (FALSE);
|
||||
#endif
|
||||
|
||||
case QUOTE:
|
||||
/* Match a quoted char */
|
||||
pch = *pat;
|
||||
if (lowercase(fch, keepcase) != lowercase(pch, keepcase) || pch == '\0')
|
||||
return (FALSE);
|
||||
fname++;
|
||||
flength--;
|
||||
pat++;
|
||||
break;
|
||||
|
||||
case FPAT_SET_L:
|
||||
/* Match char set/range */
|
||||
yes = TRUE;
|
||||
if (*pat == FPAT_SET_NOT)
|
||||
{
|
||||
pat++;
|
||||
yes = FALSE; /* Set negation */
|
||||
}
|
||||
|
||||
/* Look for [s], [-], [abc], [a-c] */
|
||||
match = !yes;
|
||||
while (*pat != FPAT_SET_R && *pat != '\0')
|
||||
{
|
||||
if (*pat == QUOTE)
|
||||
pat++; /* Quoted char */
|
||||
|
||||
if (*pat == '\0')
|
||||
break;
|
||||
lo = *pat++;
|
||||
hi = lo;
|
||||
|
||||
if (*pat == FPAT_SET_THRU)
|
||||
{
|
||||
/* Range */
|
||||
pat++;
|
||||
|
||||
if (*pat == QUOTE)
|
||||
pat++; /* Quoted char */
|
||||
|
||||
if (*pat == '\0')
|
||||
break;
|
||||
hi = *pat++;
|
||||
}
|
||||
|
||||
if (*pat == '\0')
|
||||
break;
|
||||
|
||||
/* Compare character to set range */
|
||||
if (lowercase(fch, keepcase) >= lowercase(lo, keepcase) &&
|
||||
lowercase(fch, keepcase) <= lowercase(hi, keepcase))
|
||||
match = yes;
|
||||
}
|
||||
|
||||
if (!match)
|
||||
return (FALSE);
|
||||
|
||||
if (*pat == '\0')
|
||||
return (FALSE); /* Missing closing bracket */
|
||||
|
||||
fname++;
|
||||
flength--;
|
||||
pat++;
|
||||
break;
|
||||
|
||||
case FPAT_MSET_L:
|
||||
/* Match zero or more characters in a char set/range */
|
||||
yes = TRUE;
|
||||
if (*pat == FPAT_SET_NOT)
|
||||
{
|
||||
pat++;
|
||||
yes = FALSE; /* Set negation */
|
||||
}
|
||||
|
||||
do {
|
||||
const char *org_pat = pat;
|
||||
/* Look for [s], [-], [abc], [a-c] */
|
||||
match = !yes;
|
||||
while (*pat != FPAT_MSET_R && *pat != '\0')
|
||||
{
|
||||
if (*pat == QUOTE)
|
||||
pat++; /* Quoted char */
|
||||
|
||||
if (*pat == '\0')
|
||||
break;
|
||||
lo = *pat++;
|
||||
hi = lo;
|
||||
|
||||
if (*pat == FPAT_SET_THRU)
|
||||
{
|
||||
/* Range */
|
||||
pat++;
|
||||
|
||||
if (*pat == QUOTE)
|
||||
pat++; /* Quoted char */
|
||||
|
||||
if (*pat == '\0')
|
||||
break;
|
||||
hi = *pat++;
|
||||
}
|
||||
|
||||
if (*pat == '\0')
|
||||
break;
|
||||
|
||||
/* Compare character to set range */
|
||||
if (lowercase(fch, keepcase) >= lowercase(lo, keepcase) &&
|
||||
lowercase(fch, keepcase) <= lowercase(hi, keepcase)) {
|
||||
match = yes;
|
||||
while (*pat != FPAT_MSET_R && *pat != '\0')
|
||||
pat++;
|
||||
break;
|
||||
} /* if */
|
||||
}
|
||||
|
||||
if (*pat == '\0')
|
||||
return (FALSE); /* Missing closing bracket */
|
||||
|
||||
if (match) {
|
||||
fname++;
|
||||
flength--;
|
||||
fch = *fname;
|
||||
if (flength > 0)
|
||||
pat = org_pat;
|
||||
}
|
||||
|
||||
} while (match && flength > 0);
|
||||
|
||||
pat++;
|
||||
break;
|
||||
|
||||
case FPAT_NOT:
|
||||
/* Match only if rest of pattern does not match */
|
||||
if (*pat == '\0')
|
||||
return (FALSE); /* Missing subpattern */
|
||||
i = fpattern_submatch(pat, fname, flength, keepcase);
|
||||
return !i;
|
||||
|
||||
#if DELIM
|
||||
case DEL:
|
||||
#if DEL2 != DEL
|
||||
case DEL2:
|
||||
#endif
|
||||
/* Match path delimiter char */
|
||||
if (fch != DEL && fch != DEL2)
|
||||
return (FALSE);
|
||||
fname++;
|
||||
flength--;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
/* Match a (non-null) char exactly */
|
||||
if (lowercase(fch, keepcase) != lowercase(pch, keepcase))
|
||||
return (FALSE);
|
||||
fname++;
|
||||
flength--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for complete match */
|
||||
if (flength != 0)
|
||||
return (FALSE);
|
||||
|
||||
/* Successful match */
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* fpattern_match()
|
||||
* Attempts to match pattern 'pat' to filename 'fname'. The comparison is case
|
||||
* sensitive if 'keepcase' is true, and case insensitive otherwise. The 'flength'
|
||||
* parameter allows to check partial strings, or to check strings with embedded
|
||||
* zero bytes. When 'flength' is -1, it is set to the string length.
|
||||
*
|
||||
* Returns
|
||||
* 1 (true) if the filename matches, otherwise 0 (false).
|
||||
*
|
||||
* Caveats
|
||||
* If 'fname' is null, zero (false) is returned.
|
||||
*
|
||||
* If 'pat' is null, zero (false) is returned.
|
||||
*
|
||||
* If 'pat' is empty (""), the only filename it matches is the empty
|
||||
* string ("").
|
||||
*
|
||||
* If 'fname' is empty, the only pattern that will match it is the empty
|
||||
* string ("").
|
||||
*
|
||||
* If 'pat' is not a well-formed pattern, zero (false) is returned.
|
||||
*
|
||||
* Upper and lower case letters are treated the same; alphabetic
|
||||
* characters are converted to lower case before matching occurs.
|
||||
* Conversion to lower case is dependent upon the current locale setting.
|
||||
*/
|
||||
|
||||
int fpattern_match(const char *pat, const char *fname, int flength, int keepcase)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Check args */
|
||||
if (fname == NULL)
|
||||
return (FALSE);
|
||||
|
||||
if (pat == NULL)
|
||||
return (FALSE);
|
||||
|
||||
/* Verify that the pattern is valid, and get its length */
|
||||
if (!fpattern_isvalid(pat))
|
||||
return (FALSE);
|
||||
|
||||
/* Attempt to match pattern against filename */
|
||||
if (flength < 0)
|
||||
flength = strlen(fname);
|
||||
if (flength == 0)
|
||||
return (pat[0] == '\0'); /* Special case */
|
||||
rc = fpattern_submatch(pat, fname, flength, keepcase);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* fpattern_matchn()
|
||||
* Attempts to match pattern 'pat' to filename 'fname'.
|
||||
* This operates like fpattern_match() except that it does not verify that
|
||||
* pattern 'pat' is well-formed, assuming that it has been checked by a
|
||||
* prior call to fpattern_isvalid().
|
||||
*
|
||||
* Returns
|
||||
* 1 (true) if the filename matches, otherwise 0 (false).
|
||||
*
|
||||
* Caveats
|
||||
* If 'fname' is null, zero (false) is returned.
|
||||
*
|
||||
* If 'pat' is null, zero (false) is returned.
|
||||
*
|
||||
* If 'pat' is empty (""), the only filename it matches is the empty ("")
|
||||
* string.
|
||||
*
|
||||
* If 'pat' is not a well-formed pattern, unpredictable results may occur.
|
||||
*
|
||||
* Upper and lower case letters are treated the same; alphabetic
|
||||
* characters are converted to lower case before matching occurs.
|
||||
* Conversion to lower case is dependent upon the current locale setting.
|
||||
*
|
||||
* See also
|
||||
* fpattern_match().
|
||||
*/
|
||||
|
||||
int fpattern_matchn(const char *pat, const char *fname, int flength, int keepcase)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Check args */
|
||||
if (fname == NULL)
|
||||
return (FALSE);
|
||||
|
||||
if (pat == NULL)
|
||||
return (FALSE);
|
||||
|
||||
/* Assume that pattern is well-formed */
|
||||
|
||||
/* Attempt to match pattern against filename */
|
||||
if (flength < 0)
|
||||
flength = strlen(fname);
|
||||
rc = fpattern_submatch(pat, fname, flength, keepcase);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/* returns the largest packet that matches the pattern */
|
||||
int fpattern_matchcount(const char *pat, const char *fname, int flength, int keepcase)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (fname == NULL)
|
||||
return (FALSE);
|
||||
|
||||
if (pat == NULL)
|
||||
return (FALSE);
|
||||
|
||||
/* Assume that pattern is well-formed */
|
||||
|
||||
/* Attempt to match pattern against filename */
|
||||
if (flength < 0)
|
||||
flength = strlen(fname);
|
||||
|
||||
for (len = flength; len >= 0; len--)
|
||||
if (fpattern_submatch(pat, fname, flength, keepcase))
|
||||
break;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#if TEST
|
||||
|
||||
|
||||
/* Local variables */
|
||||
|
||||
static int count = 0;
|
||||
static int fails = 0;
|
||||
static int stop_on_fail = FALSE;
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* test()
|
||||
*/
|
||||
|
||||
static void test(int expect, const char *fname, const char *pat)
|
||||
{
|
||||
int failed;
|
||||
int result;
|
||||
char fbuf[80+1];
|
||||
char pbuf[80+1];
|
||||
|
||||
count++;
|
||||
printf("%3d. ", count);
|
||||
|
||||
if (fname == NULL)
|
||||
{
|
||||
printf("<null>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(fbuf, fname);
|
||||
printf("\"%s\"\n", fbuf);
|
||||
}
|
||||
|
||||
if (pat == NULL)
|
||||
{
|
||||
printf(" <null>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(pbuf, pat);
|
||||
printf(" \"%s\"\n", pbuf);
|
||||
}
|
||||
|
||||
result = fpattern_match(pat == NULL ? NULL : pbuf,
|
||||
fname == NULL ? NULL : fbuf,
|
||||
-1, FALSE);
|
||||
|
||||
failed = (result != expect);
|
||||
printf(" -> %c, expected %c: %s\n",
|
||||
"FT"[!!result], "FT"[!!expect], failed ? "FAIL ***" : "pass");
|
||||
|
||||
if (failed)
|
||||
{
|
||||
fails++;
|
||||
|
||||
if (stop_on_fail)
|
||||
exit(1);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* main()
|
||||
* Test driver.
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
(void) argc; /* Shut up lint */
|
||||
(void) argv; /* Shut up lint */
|
||||
|
||||
#if DEBUG
|
||||
dbg_f = stdout;
|
||||
#endif
|
||||
|
||||
printf("==========================================\n");
|
||||
|
||||
setlocale(LC_CTYPE, "");
|
||||
|
||||
#if UNIX
|
||||
printf("[O/S is UNIX]\n");
|
||||
#elif DOS
|
||||
printf("[O/S is DOS]\n");
|
||||
#else
|
||||
printf("[O/S is unknown]\n");
|
||||
#endif
|
||||
|
||||
#if 1 /* Set to nonzero to stop on first failure */
|
||||
stop_on_fail = TRUE;
|
||||
#endif
|
||||
|
||||
test(0, NULL, NULL);
|
||||
test(0, NULL, "");
|
||||
test(0, NULL, "abc");
|
||||
test(0, "", NULL);
|
||||
test(0, "abc", NULL);
|
||||
|
||||
test(1, "abc", "abc");
|
||||
test(0, "ab", "abc");
|
||||
test(0, "abcd", "abc");
|
||||
test(0, "Foo.txt", "Foo.x");
|
||||
test(1, "Foo.txt", "Foo.txt");
|
||||
test(1, "Foo.txt", "foo.txt");
|
||||
test(1, "FOO.txt", "foo.TXT");
|
||||
|
||||
test(1, "a", "?");
|
||||
test(1, "foo.txt", "f??.txt");
|
||||
test(1, "foo.txt", "???????");
|
||||
test(0, "foo.txt", "??????");
|
||||
test(0, "foo.txt", "????????");
|
||||
|
||||
test(1, "a", "`a");
|
||||
test(1, "AB", "a`b");
|
||||
test(0, "aa", "a`b");
|
||||
test(1, "a`x", "a``x");
|
||||
test(1, "a`x", "`a```x");
|
||||
test(1, "a*x", "a`*x");
|
||||
|
||||
#if DELIM
|
||||
test(0, "", "/");
|
||||
test(0, "", "\\");
|
||||
test(1, "/", "/");
|
||||
test(1, "/", "\\");
|
||||
test(1, "\\", "/");
|
||||
test(1, "\\", "\\");
|
||||
|
||||
test(1, "a/b", "a/b");
|
||||
test(1, "a/b", "a\\b");
|
||||
|
||||
test(1, "/", "*/*");
|
||||
test(1, "foo/a.c", "f*/*.?");
|
||||
test(1, "foo/a.c", "*/*");
|
||||
test(0, "foo/a.c", "/*/*");
|
||||
test(0, "foo/a.c", "*/*/");
|
||||
|
||||
test(1, "/", "~/~");
|
||||
test(1, "foo/a.c", "f~/~.?");
|
||||
test(0, "foo/a.c", "~/~");
|
||||
test(1, "foo/abc", "~/~");
|
||||
test(0, "foo/a.c", "/~/~");
|
||||
test(0, "foo/a.c", "~/~/");
|
||||
#endif
|
||||
|
||||
test(0, "", "*");
|
||||
test(1, "a", "*");
|
||||
test(1, "ab", "*");
|
||||
test(1, "abc", "**");
|
||||
test(1, "ab.c", "*.?");
|
||||
test(1, "ab.c", "*.*");
|
||||
test(1, "ab.c", "*?");
|
||||
test(1, "ab.c", "?*");
|
||||
test(1, "ab.c", "?*?");
|
||||
test(1, "ab.c", "?*?*");
|
||||
test(1, "ac", "a*c");
|
||||
test(1, "axc", "a*c");
|
||||
test(1, "ax-yyy.c", "a*c");
|
||||
test(1, "ax-yyy.c", "a*x-yyy.c");
|
||||
test(1, "axx/yyy.c", "a*x/*c");
|
||||
|
||||
#if SUBCLOS
|
||||
test(0, "", "~");
|
||||
test(1, "a", "~");
|
||||
test(1, "ab", "~");
|
||||
test(1, "abc", "~~");
|
||||
test(1, "ab.c", "~.?");
|
||||
test(1, "ab.c", "~.~");
|
||||
test(0, "ab.c", "~?");
|
||||
test(0, "ab.c", "?~");
|
||||
test(0, "ab.c", "?~?");
|
||||
test(1, "ab.c", "?~.?");
|
||||
test(1, "ab.c", "?~?~");
|
||||
test(1, "ac", "a~c");
|
||||
test(1, "axc", "a~c");
|
||||
test(0, "ax-yyy.c", "a~c");
|
||||
test(1, "ax-yyyvc", "a~c");
|
||||
test(1, "ax-yyy.c", "a~x-yyy.c");
|
||||
test(0, "axx/yyy.c", "a~x/~c");
|
||||
test(1, "axx/yyyvc", "a~x/~c");
|
||||
#endif
|
||||
|
||||
test(0, "a", "!");
|
||||
test(0, "a", "!a");
|
||||
test(1, "a", "!b");
|
||||
test(1, "abc", "!abb");
|
||||
test(0, "a", "!*");
|
||||
test(1, "abc", "!*.?");
|
||||
test(1, "abc", "!*.*");
|
||||
test(0, "", "!*"); /*!*/
|
||||
test(0, "", "!*?"); /*!*/
|
||||
test(0, "a", "!*?");
|
||||
test(0, "a", "a!*");
|
||||
test(1, "a", "a!?");
|
||||
test(1, "a", "a!*?");
|
||||
test(1, "ab", "*!?");
|
||||
test(1, "abc", "*!?");
|
||||
test(0, "ab", "?!?");
|
||||
test(1, "abc", "?!?");
|
||||
test(0, "a-b", "!a[-]b");
|
||||
test(0, "a-b", "!a[x-]b");
|
||||
test(0, "a=b", "!a[x-]b");
|
||||
test(0, "a-b", "!a[x`-]b");
|
||||
test(1, "a=b", "!a[x`-]b");
|
||||
test(0, "a-b", "!a[x---]b");
|
||||
test(1, "a=b", "!a[x---]b");
|
||||
|
||||
test(1, "abc", "a[b]c");
|
||||
test(1, "aBc", "a[b]c");
|
||||
test(1, "abc", "a[bB]c");
|
||||
test(1, "abc", "a[bcz]c");
|
||||
test(1, "azc", "a[bcz]c");
|
||||
test(0, "ab", "a[b]c");
|
||||
test(0, "ac", "a[b]c");
|
||||
test(0, "axc", "a[b]c");
|
||||
|
||||
test(0, "abc", "a[!b]c");
|
||||
test(0, "abc", "a[!bcz]c");
|
||||
test(0, "azc", "a[!bcz]c");
|
||||
test(0, "ab", "a[!b]c");
|
||||
test(0, "ac", "a[!b]c");
|
||||
test(1, "axc", "a[!b]c");
|
||||
test(1, "axc", "a[!bcz]c");
|
||||
|
||||
test(1, "a1z", "a[0-9]z");
|
||||
test(0, "a1", "a[0-9]z");
|
||||
test(0, "az", "a[0-9]z");
|
||||
test(0, "axz", "a[0-9]z");
|
||||
test(1, "a2z", "a[-0-9]z");
|
||||
test(1, "a-z", "a[-0-9]z");
|
||||
test(1, "a-b", "a[-]b");
|
||||
test(0, "a-b", "a[x-]b");
|
||||
test(0, "a=b", "a[x-]b");
|
||||
test(1, "a-b", "a[x`-]b");
|
||||
test(0, "a=b", "a[x`-]b");
|
||||
test(1, "a-b", "a[x---]b");
|
||||
test(0, "a=b", "a[x---]b");
|
||||
|
||||
test(0, "a0z", "a[!0-9]z");
|
||||
test(1, "aoz", "a[!0-9]z");
|
||||
test(0, "a1", "a[!0-9]z");
|
||||
test(0, "az", "a[!0-9]z");
|
||||
test(0, "a9Z", "a[!0-9]z");
|
||||
test(1, "acz", "a[!-0-9]z");
|
||||
test(0, "a7z", "a[!-0-9]z");
|
||||
test(0, "a-z", "a[!-0-9]z");
|
||||
test(0, "a-b", "a[!-]b");
|
||||
test(0, "a-b", "a[!x-]b");
|
||||
test(0, "a=b", "a[!x-]b");
|
||||
test(0, "a-b", "a[!x`-]b");
|
||||
test(1, "a=b", "a[!x`-]b");
|
||||
test(0, "a-b", "a[!x---]b");
|
||||
test(1, "a=b", "a[!x---]b");
|
||||
|
||||
test(1, "a!z", "a[`!0-9]z");
|
||||
test(1, "a3Z", "a[`!0-9]z");
|
||||
test(0, "A3Z", "a[`!0`-9]z");
|
||||
test(1, "a9z", "a[`!0`-9]z");
|
||||
test(1, "a-z", "a[`!0`-9]z");
|
||||
|
||||
test(1, "ac", "a{b}c");
|
||||
test(1, "abc", "a{b}c");
|
||||
test(1, "abbc", "a{b}c");
|
||||
test(1, "aBbBc", "a{b}c");
|
||||
test(1, "abc", "a{bB}c");
|
||||
test(1, "abc", "a{bpz}c");
|
||||
test(1, "azc", "a{bcz}");
|
||||
test(0, "ab", "a{b}c");
|
||||
test(0, "axc", "a{b}c");
|
||||
|
||||
printf("%d tests, %d failures\n", count, fails);
|
||||
return (fails == 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
|
||||
#endif /* TEST */
|
||||
|
||||
/* End fpattern.c */
|
||||
|
||||
|
187
SOURCE/amx/fpattern.h
Normal file
187
SOURCE/amx/fpattern.h
Normal file
@ -0,0 +1,187 @@
|
||||
/******************************************************************************
|
||||
* fpattern.h
|
||||
* Functions for matching filename patterns to filenames.
|
||||
*
|
||||
* Usage
|
||||
* Filename patterns are composed of regular (printable) characters which
|
||||
* may comprise a filename as well as special pattern matching characters:
|
||||
*
|
||||
* . Matches a period (.).
|
||||
* Note that a period in a filename is not treated any
|
||||
* differently than any other character.
|
||||
*
|
||||
* ? Any.
|
||||
* Matches any single character except '/' or '\'.
|
||||
*
|
||||
* * Closure.
|
||||
* Matches zero or more occurences of any characters other
|
||||
* than '/' or '\'.
|
||||
* Leading '*' characters are allowed.
|
||||
*
|
||||
* SUB Substitute (^Z); optionally supported.
|
||||
* Similar to '*', this matches zero or more occurences of
|
||||
* any characters other than '/', '\', or '.'.
|
||||
* Leading '^Z' characters are allowed.
|
||||
*
|
||||
* [ab] Set.
|
||||
* Matches the single character 'a' or 'b'.
|
||||
* If the dash '-' character is to be included, it must
|
||||
* immediately follow the opening bracket '['.
|
||||
* If the closing bracket ']' character is to be included,
|
||||
* it must be preceded by a quote '`'.
|
||||
*
|
||||
* [a-z] Range.
|
||||
* Matches a single character in the range 'a' to 'z'.
|
||||
* Ranges and sets may be combined within the same set of
|
||||
* brackets.
|
||||
*
|
||||
* [!R] Exclusive range.
|
||||
* Matches a single character not in the range 'R'.
|
||||
* If range 'R' includes the dash '-' character, the dash
|
||||
* must immediately follow the caret '!'.
|
||||
*
|
||||
* ! Not.
|
||||
* Makes the following pattern (up to the next '/') match
|
||||
* any filename except those what it would normally match.
|
||||
*
|
||||
* / Path separator (UNIX and DOS).
|
||||
* Matches a '/' or '\' pathname (directory) separator.
|
||||
* Multiple separators are treated like a single
|
||||
* separator.
|
||||
* A leading separator indicates an absolute pathname.
|
||||
*
|
||||
* \ Path separator (DOS).
|
||||
* Same as the '/' character.
|
||||
* Note that this character must be escaped if used within
|
||||
* string constants ("\\").
|
||||
*
|
||||
* \ Quote (UNIX).
|
||||
* Makes the next character a regular (nonspecial)
|
||||
* character.
|
||||
* Note that to match the quote character itself, it must
|
||||
* be quoted.
|
||||
* Note that this character must be escaped if used within
|
||||
* string constants ("\\").
|
||||
*
|
||||
* ` Quote (DOS).
|
||||
* Makes the next character a regular (nonspecial)
|
||||
* character.
|
||||
* Note that to match the quote character itself, it must
|
||||
* be quoted.
|
||||
*
|
||||
* Upper and lower case alphabetic characters are considered identical,
|
||||
* i.e., 'a' and 'A' match each other.
|
||||
* (What constitutes a lowercase letter depends on the current locale
|
||||
* settings.)
|
||||
*
|
||||
* Spaces and control characters are treated as normal characters.
|
||||
*
|
||||
* Examples
|
||||
* The following patterns in the left column will match the filenames in
|
||||
* the middle column and will not match filenames in the right column:
|
||||
*
|
||||
* Pattern Will Match Will Not Match
|
||||
* ------- ---------- --------------
|
||||
* a a (only) (anything else)
|
||||
* a. a. (only) (anything else)
|
||||
* a?c abc, acc, arc, a.c a, ac, abbc
|
||||
* a*c ac, abc, abbc, acc, a.c a, ab, acb, bac
|
||||
* a* a, ab, abb, a., a.b b, ba
|
||||
* * a, ab, abb, a., .foo, a.foo (nothing)
|
||||
* *. a., ab., abb., a.foo. a, ab, a.foo, .foo
|
||||
* *.* a., a.b, ah.bc.foo a
|
||||
* ^Z a, ab, abb a., .foo, a.foo
|
||||
* ^Z. a., ab., abb. a, .foo, a.foo
|
||||
* ^Z.* a, a., .foo, a.foo ab, abb
|
||||
* *2.c 2.c, 12.c, foo2.c, foo.12.c 2x.c
|
||||
* a[b-z]c abc, acc, azc (only) (anything else)
|
||||
* [ab0-9]x ax, bx, 0x, 9x zx
|
||||
* a[-.]b a-b, a.b (only) (anything else)
|
||||
* a[!a-z]b a0b, a.b, a@b aab, azb, aa0b
|
||||
* a[!-b]x a0x, a+x, acx a-x, abx, axxx
|
||||
* a[-!b]x a-x, a!x, abx (only) (anything else)
|
||||
* a[`]]x a]x (only) (anything else)
|
||||
* a``x a`x (only) (anything else)
|
||||
* oh`! oh! (only) (anything else)
|
||||
* is`?it is?it (only) (anything else)
|
||||
* !a?c a, ac, ab, abb, acb, a.foo abc, a.c, azc
|
||||
*
|
||||
* History
|
||||
* 1.00 1997-01-03 David Tribble.
|
||||
* First cut.
|
||||
* 1.01 1997-01-03 David Tribble.
|
||||
* Added '^Z' pattern character.
|
||||
* Added fpattern_matchn().
|
||||
* 1.02 1997-01-26 David Tribble.
|
||||
* Changed range negation character from '^' to '!', ala Unix.
|
||||
* 1.03 1997-08-02 David Tribble.
|
||||
* Added 'FPAT_XXX' macro constants.
|
||||
*
|
||||
* Limitations
|
||||
* This code is copyrighted by the author, but permission is hereby
|
||||
* granted for its unlimited use provided that the original copyright
|
||||
* and authorship notices are retained intact.
|
||||
*
|
||||
* Other queries can be sent to:
|
||||
* dtribble@technologist.com
|
||||
* david.tribble@beasys.com
|
||||
* dtribble@flash.net
|
||||
*
|
||||
* Copyright ©1997 by David R. Tribble, all rights reserved.
|
||||
* $Id: fpattern.h 3612 2006-07-22 09:59:46Z thiadmer $
|
||||
*/
|
||||
|
||||
|
||||
#ifndef fpattern_h
|
||||
#define fpattern_h 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
/* Identification */
|
||||
|
||||
#if 0
|
||||
static const char fpattern_h_id[] = "@(#)lib/fpattern.h 1.03";
|
||||
#endif
|
||||
|
||||
|
||||
/* Manifest constants */
|
||||
|
||||
#define FPAT_QUOTE '\\' /* Quotes a special char */
|
||||
#define FPAT_QUOTE2 '`' /* Quotes a special char */
|
||||
#define FPAT_DEL '/' /* Path delimiter (used only when DELIM is true) */
|
||||
#define FPAT_DEL2 '\\' /* Path delimiter (used only when DELIM is true) */
|
||||
#define FPAT_DOT '.' /* Dot char */
|
||||
#define FPAT_NOT '!' /* Exclusion */
|
||||
#define FPAT_ANY '?' /* Any one char */
|
||||
#define FPAT_CLOS '*' /* Zero or more chars */
|
||||
#define FPAT_CLOSP '\x1A' /* Zero or more nondelimiters (used only when SUBCLOS is true) */
|
||||
#define FPAT_SET_L '[' /* Set/range open bracket */
|
||||
#define FPAT_SET_R ']' /* Set/range close bracket */
|
||||
#define FPAT_MSET_L '{' /* Multi-set/range open bracket */
|
||||
#define FPAT_MSET_R '}' /* Multi-set/range close bracket*/
|
||||
#define FPAT_SET_NOT '!' /* Set exclusion */
|
||||
#define FPAT_SET_THRU '-' /* Set range of chars */
|
||||
|
||||
|
||||
/* Model-dependent aliases */
|
||||
/* omitted */
|
||||
|
||||
|
||||
/* Public functions */
|
||||
|
||||
extern int fpattern_isvalid(const char *pat);
|
||||
extern int fpattern_match(const char *pat, const char *fname, int flength, int keepcase);
|
||||
extern int fpattern_matchn(const char *pat, const char *fname, int flength, int keepcase);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* fpattern_h */
|
||||
|
||||
/* End fpattern.h */
|
BIN
SOURCE/amx/obj/amxexecc.obj
Normal file
BIN
SOURCE/amx/obj/amxexecc.obj
Normal file
Binary file not shown.
BIN
SOURCE/amx/obj/amxexecs.obj
Normal file
BIN
SOURCE/amx/obj/amxexecs.obj
Normal file
Binary file not shown.
BIN
SOURCE/amx/obj/amxjitr.obj
Normal file
BIN
SOURCE/amx/obj/amxjitr.obj
Normal file
Binary file not shown.
BIN
SOURCE/amx/obj/amxjits.obj
Normal file
BIN
SOURCE/amx/obj/amxjits.obj
Normal file
Binary file not shown.
98
SOURCE/amx/osdefs.h
Normal file
98
SOURCE/amx/osdefs.h
Normal file
@ -0,0 +1,98 @@
|
||||
/* __MSDOS__ set when compiling for DOS (not Windows)
|
||||
* _Windows set when compiling for any version of Microsoft Windows
|
||||
* __WIN32__ set when compiling for Windows95 or WindowsNT (32 bit mode)
|
||||
* __32BIT__ set when compiling in 32-bit "flat" mode (DOS or Windows)
|
||||
*
|
||||
* Copyright 1998-2005, ITB CompuPhase, The Netherlands.
|
||||
* info@compuphase.com.
|
||||
*/
|
||||
|
||||
#ifndef _OSDEFS_H
|
||||
#define _OSDEFS_H
|
||||
|
||||
/* Every compiler uses different "default" macros to indicate the mode
|
||||
* it is in. Throughout the source, we use the Borland C++ macros, so
|
||||
* the macros of Watcom C/C++ and Microsoft Visual C/C++ are mapped to
|
||||
* those of Borland C++.
|
||||
*/
|
||||
#if defined(__WATCOMC__)
|
||||
# if defined(__WINDOWS__) || defined(__NT__)
|
||||
# define _Windows 1
|
||||
# endif
|
||||
# ifdef __386__
|
||||
# define __32BIT__ 1
|
||||
# endif
|
||||
# if defined(_Windows) && defined(__32BIT__)
|
||||
# define __WIN32__ 1
|
||||
# endif
|
||||
#elif defined(_MSC_VER)
|
||||
# if defined(_WINDOWS) || defined(_WIN32)
|
||||
# define _Windows 1
|
||||
# endif
|
||||
# ifdef _WIN32
|
||||
# define __WIN32__ 1
|
||||
# define __32BIT__ 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined __FreeBSD__
|
||||
#include <sys/endian.h>
|
||||
#elif defined LINUX
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
/* Linux NOW has these */
|
||||
#if !defined BIG_ENDIAN
|
||||
#define BIG_ENDIAN 4321
|
||||
#endif
|
||||
#if !defined LITTLE_ENDIAN
|
||||
#define LITTLE_ENDIAN 1234
|
||||
#endif
|
||||
|
||||
/* educated guess, BYTE_ORDER is undefined, i386 is common => little endian */
|
||||
#if !defined BYTE_ORDER
|
||||
#if defined UCLINUX
|
||||
#define BYTE_ORDER BIG_ENDIAN
|
||||
#else
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined __MSDOS__ || defined __WIN32__ || defined _Windows
|
||||
#define DIRSEP_CHAR '\\'
|
||||
#elif defined macintosh
|
||||
#define DIRSEP_CHAR ':'
|
||||
#else
|
||||
#define DIRSEP_CHAR '/' /* directory separator character */
|
||||
#endif
|
||||
|
||||
/* _MAX_PATH is sometimes called differently and it may be in limits.h or
|
||||
* stdlib.h instead of stdio.h.
|
||||
*/
|
||||
#if !defined _MAX_PATH
|
||||
/* not defined, perhaps stdio.h was not included */
|
||||
#if !defined PATH_MAX
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#if !defined _MAX_PATH && !defined PATH_MAX
|
||||
/* no _MAX_PATH and no MAX_PATH, perhaps it is in limits.h */
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#if !defined _MAX_PATH && !defined PATH_MAX
|
||||
/* no _MAX_PATH and no MAX_PATH, perhaps it is in stdlib.h */
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
/* if _MAX_PATH is undefined, try common alternative names */
|
||||
#if !defined _MAX_PATH
|
||||
#if defined MAX_PATH
|
||||
#define _MAX_PATH MAX_PATH
|
||||
#elif defined _POSIX_PATH_MAX
|
||||
#define _MAX_PATH _POSIX_PATH_MAX
|
||||
#else
|
||||
/* everything failed, actually we have a problem here... */
|
||||
#define _MAX_PATH 1024
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* _OSDEFS_H */
|
2865
SOURCE/amx/pawndbg.c
Normal file
2865
SOURCE/amx/pawndbg.c
Normal file
File diff suppressed because it is too large
Load Diff
397
SOURCE/amx/pawnrun.c
Normal file
397
SOURCE/amx/pawnrun.c
Normal file
@ -0,0 +1,397 @@
|
||||
/* Simple "run-time" for the Pawn Abstract Machine
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 1997-2006
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty.
|
||||
* In no event will the authors be held liable for any damages arising from
|
||||
* the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software in
|
||||
* a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*
|
||||
* Version: $Id: pawnrun.c 3615 2006-07-27 07:49:08Z thiadmer $
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h> /* for memset() (on some compilers) */
|
||||
#include "osdefs.h" /* for _MAX_PATH */
|
||||
#include "amx.h"
|
||||
|
||||
#include <time.h>
|
||||
#if !defined CLOCKS_PER_SEC /* some (older) compilers do not have it */
|
||||
#define CLOCKS_PER_SEC CLK_TCK
|
||||
#endif
|
||||
|
||||
#if !defined AMX_NODYNALOAD && (defined LINUX || defined __FreeBSD__ || defined __OpenBSD__)
|
||||
#include <binreloc.h> /* from BinReloc, see www.autopackage.org */
|
||||
#endif
|
||||
|
||||
#if defined AMXDBG
|
||||
#include "amxdbg.h"
|
||||
static char g_filename[_MAX_PATH];/* for loading the debug information */
|
||||
#endif
|
||||
|
||||
|
||||
/* These initialization functions are part of the "extension modules"
|
||||
* (libraries with native functions) that this run-time uses. More
|
||||
* extension modules may be dynamically linked (depending on whether
|
||||
* support for dynamic linking is enabled).
|
||||
*/
|
||||
extern int AMXEXPORT amx_ConsoleInit(AMX *amx);
|
||||
extern int AMXEXPORT amx_CoreInit(AMX *amx);
|
||||
|
||||
AMX *global_amx;
|
||||
int AMXAPI srun_Monitor(AMX *amx);
|
||||
|
||||
static int abortflagged = 0;
|
||||
void sigabort(int sig)
|
||||
{
|
||||
/* install the debug hook procedure if this was not done already */
|
||||
amx_SetDebugHook(global_amx, srun_Monitor);
|
||||
abortflagged=1;
|
||||
signal(sig,sigabort); /* re-install the signal handler */
|
||||
}
|
||||
|
||||
typedef struct tagSTACKINFO {
|
||||
long maxstack, maxheap;
|
||||
} STACKINFO;
|
||||
|
||||
|
||||
/* srun_Monitor()
|
||||
* A simple debug hook, that allows the user to break out of a program
|
||||
* and that monitors stack usage. Note that the stack usage can only be
|
||||
* properly monitored when the debug hook is installed from the start
|
||||
* of the script to the end.
|
||||
*/
|
||||
int AMXAPI srun_Monitor(AMX *amx)
|
||||
{
|
||||
int err;
|
||||
STACKINFO *stackinfo;
|
||||
|
||||
/* record the heap and stack usage */
|
||||
err = amx_GetUserData(amx, AMX_USERTAG('S','t','c','k'), (void**)&stackinfo);
|
||||
if (err == AMX_ERR_NONE) {
|
||||
if (amx->stp - amx->stk > stackinfo->maxstack)
|
||||
stackinfo->maxstack = amx->stp - amx->stk;
|
||||
if (amx->hea - amx->hlw > stackinfo->maxheap)
|
||||
stackinfo->maxstack = amx->stp - amx->stk;
|
||||
} /* if */
|
||||
|
||||
/* check whether an "abort" was requested */
|
||||
return abortflagged ? AMX_ERR_EXIT : AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
/* aux_LoadProgram()
|
||||
* Load a compiled Pawn script into memory and initialize the abstract machine.
|
||||
* This function is extracted out of AMXAUX.C.
|
||||
*/
|
||||
int AMXAPI aux_LoadProgram(AMX *amx, char *filename, void *memblock)
|
||||
{
|
||||
FILE *fp;
|
||||
AMX_HEADER hdr;
|
||||
int result, didalloc;
|
||||
|
||||
/* open the file, read and check the header */
|
||||
if ((fp = fopen(filename, "rb")) == NULL)
|
||||
return AMX_ERR_NOTFOUND;
|
||||
fread(&hdr, sizeof hdr, 1, fp);
|
||||
amx_Align16(&hdr.magic);
|
||||
amx_Align32((uint32_t *)&hdr.size);
|
||||
amx_Align32((uint32_t *)&hdr.stp);
|
||||
if (hdr.magic != AMX_MAGIC) {
|
||||
fclose(fp);
|
||||
return AMX_ERR_FORMAT;
|
||||
} /* if */
|
||||
|
||||
/* allocate the memblock if it is NULL */
|
||||
didalloc = 0;
|
||||
if (memblock == NULL) {
|
||||
if ((memblock = malloc(hdr.stp)) == NULL) {
|
||||
fclose(fp);
|
||||
return AMX_ERR_MEMORY;
|
||||
} /* if */
|
||||
didalloc = 1;
|
||||
/* after amx_Init(), amx->base points to the memory block */
|
||||
} /* if */
|
||||
|
||||
/* read in the file */
|
||||
rewind(fp);
|
||||
fread(memblock, 1, (size_t)hdr.size, fp);
|
||||
fclose(fp);
|
||||
|
||||
/* initialize the abstract machine */
|
||||
memset(amx, 0, sizeof *amx);
|
||||
result = amx_Init(amx, memblock);
|
||||
|
||||
/* free the memory block on error, if it was allocated here */
|
||||
if (result != AMX_ERR_NONE && didalloc) {
|
||||
free(memblock);
|
||||
amx->base = NULL; /* avoid a double free */
|
||||
} /* if */
|
||||
|
||||
/* save the filename, for optionally reading the debug information (we could
|
||||
* also have read it here immediately
|
||||
*/
|
||||
#if defined AMXDBG
|
||||
strcpy(g_filename, filename);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* aux_FreeProgram()
|
||||
* Clean up a program and free memory.
|
||||
* This function is extracted out of AMXAUX.C.
|
||||
*/
|
||||
int AMXAPI aux_FreeProgram(AMX *amx)
|
||||
{
|
||||
if (amx->base!=NULL) {
|
||||
amx_Cleanup(amx);
|
||||
free(amx->base);
|
||||
memset(amx,0,sizeof(AMX));
|
||||
} /* if */
|
||||
return AMX_ERR_NONE;
|
||||
}
|
||||
|
||||
/* aux_StrError()
|
||||
* Convert an error code to a "readable" string.
|
||||
* This function is extracted out of AMXAUX.C.
|
||||
*/
|
||||
char * AMXAPI aux_StrError(int errnum)
|
||||
{
|
||||
static char *messages[] = {
|
||||
/* AMX_ERR_NONE */ "(none)",
|
||||
/* AMX_ERR_EXIT */ "Forced exit",
|
||||
/* AMX_ERR_ASSERT */ "Assertion failed",
|
||||
/* AMX_ERR_STACKERR */ "Stack/heap collision (insufficient stack size)",
|
||||
/* AMX_ERR_BOUNDS */ "Array index out of bounds",
|
||||
/* AMX_ERR_MEMACCESS */ "Invalid memory access",
|
||||
/* AMX_ERR_INVINSTR */ "Invalid instruction",
|
||||
/* AMX_ERR_STACKLOW */ "Stack underflow",
|
||||
/* AMX_ERR_HEAPLOW */ "Heap underflow",
|
||||
/* AMX_ERR_CALLBACK */ "No (valid) native function callback",
|
||||
/* AMX_ERR_NATIVE */ "Native function failed",
|
||||
/* AMX_ERR_DIVIDE */ "Divide by zero",
|
||||
/* AMX_ERR_SLEEP */ "(sleep mode)",
|
||||
/* 13 */ "(reserved)",
|
||||
/* 14 */ "(reserved)",
|
||||
/* 15 */ "(reserved)",
|
||||
/* AMX_ERR_MEMORY */ "Out of memory",
|
||||
/* AMX_ERR_FORMAT */ "Invalid/unsupported P-code file format",
|
||||
/* AMX_ERR_VERSION */ "File is for a newer version of the AMX",
|
||||
/* AMX_ERR_NOTFOUND */ "File or function is not found",
|
||||
/* AMX_ERR_INDEX */ "Invalid index parameter (bad entry point)",
|
||||
/* AMX_ERR_DEBUG */ "Debugger cannot run",
|
||||
/* AMX_ERR_INIT */ "AMX not initialized (or doubly initialized)",
|
||||
/* AMX_ERR_USERDATA */ "Unable to set user data field (table full)",
|
||||
/* AMX_ERR_INIT_JIT */ "Cannot initialize the JIT",
|
||||
/* AMX_ERR_PARAMS */ "Parameter error",
|
||||
};
|
||||
if (errnum < 0 || errnum >= sizeof messages / sizeof messages[0])
|
||||
return "(unknown)";
|
||||
return messages[errnum];
|
||||
}
|
||||
|
||||
void ExitOnError(AMX *amx, int error)
|
||||
{
|
||||
if (error != AMX_ERR_NONE) {
|
||||
#if defined AMXDBG
|
||||
FILE *fp;
|
||||
AMX_DBG amxdbg;
|
||||
long line;
|
||||
const char *filename;
|
||||
#endif
|
||||
|
||||
printf("Run time error %d: \"%s\" on address %ld\n",
|
||||
error, aux_StrError(error), (long)amx->cip);
|
||||
|
||||
/* optionally use the debug library to find the line number (if debug info.
|
||||
* is available)
|
||||
*/
|
||||
#if defined AMXDBG
|
||||
/* load the debug info. */
|
||||
if ((fp=fopen(g_filename,"r")) != NULL && dbg_LoadInfo(&amxdbg,fp) == AMX_ERR_NONE) {
|
||||
dbg_LookupFile(&amxdbg, amx->cip, &filename);
|
||||
dbg_LookupLine(&amxdbg, amx->cip, &line);
|
||||
printf("File: %s, line: %ld\n", filename, line);
|
||||
dbg_FreeInfo(&amxdbg);
|
||||
fclose(fp);
|
||||
} /* if */
|
||||
#endif
|
||||
exit(1);
|
||||
} /* if */
|
||||
}
|
||||
|
||||
void PrintUsage(char *program)
|
||||
{
|
||||
printf("Usage: %s <filename> [options]\n\n"
|
||||
"Options:\n"
|
||||
"\t-stack\tto monitor stack usage\n"
|
||||
"\t...\tother options are passed to the script\n"
|
||||
, program);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
AMX amx;
|
||||
cell ret = 0;
|
||||
int err, i;
|
||||
clock_t start,end;
|
||||
STACKINFO stackinfo = { 0 };
|
||||
AMX_IDLE idlefunc;
|
||||
|
||||
if (argc < 2)
|
||||
PrintUsage(argv[0]); /* function "usage" aborts the program */
|
||||
|
||||
#if !defined AMX_NODYNALOAD && (defined LINUX || defined __FreeBSD__ || defined __OpenBSD__)
|
||||
/* see www.autopackage.org for the BinReloc module */
|
||||
if (br_init(NULL)) {
|
||||
char *libroot=br_find_exe_dir("");
|
||||
setenv("AMXLIB",libroot,0);
|
||||
free(libroot);
|
||||
} /* if */
|
||||
#endif
|
||||
|
||||
/* Load the program and initialize the abstract machine. */
|
||||
err = aux_LoadProgram(&amx, argv[1], NULL);
|
||||
if (err != AMX_ERR_NONE) {
|
||||
/* try adding an extension */
|
||||
char filename[_MAX_PATH];
|
||||
strcpy(filename, argv[1]);
|
||||
strcat(filename, ".amx");
|
||||
err = aux_LoadProgram(&amx, filename, NULL);
|
||||
if (err != AMX_ERR_NONE)
|
||||
PrintUsage(argv[0]);
|
||||
} /* if */
|
||||
|
||||
/* To install the debug hook "just-in-time", the signal function needs
|
||||
* a pointer to the abstract machine(s) to abort. There are various ways
|
||||
* to implement this; here I have done so with a simple global variable.
|
||||
*/
|
||||
global_amx = &amx;
|
||||
signal(SIGINT, sigabort);
|
||||
|
||||
/* Initialize two core extension modules (more extension modules may be
|
||||
* loaded & initialized automatically as DLLs or shared libraries.
|
||||
*/
|
||||
amx_ConsoleInit(&amx);
|
||||
err = amx_CoreInit(&amx);
|
||||
ExitOnError(&amx, err);
|
||||
|
||||
/* save the idle function, if set by any of the extension modules */
|
||||
if (amx_GetUserData(&amx, AMX_USERTAG('I','d','l','e'), (void**)&idlefunc) != AMX_ERR_NONE)
|
||||
idlefunc = NULL;
|
||||
|
||||
for (i = 2; i < argc; i++) {
|
||||
if (strcmp(argv[i],"-stack") == 0) {
|
||||
uint16_t flags;
|
||||
amx_Flags(&amx, &flags);
|
||||
if ((flags & AMX_FLAG_NOCHECKS) != 0)
|
||||
printf("This script was compiled with debug information removed.\n"
|
||||
"Stack monitoring is disfunctional\n\n");
|
||||
/* Set "user data" with which the debug monitor can monitor stack usage
|
||||
* per abstract machine (in this example, though, there is only one abstract
|
||||
* machine, so a global variable would have sufficed).
|
||||
*/
|
||||
memset(&stackinfo, 0, sizeof stackinfo);
|
||||
err = amx_SetUserData(&amx, AMX_USERTAG('S','t','c','k'), &stackinfo);
|
||||
ExitOnError(&amx, err);
|
||||
/* Install the debug hook, so that we can start monitoring the stack/heap
|
||||
* usage right from the beginning of the script.
|
||||
*/
|
||||
amx_SetDebugHook(&amx, srun_Monitor);
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
start=clock();
|
||||
|
||||
/* Run the compiled script and time it. The "sleep" instruction causes the
|
||||
* abstract machine to return in a "restartable" state (it restarts from
|
||||
* the point that it stopped. This allows for a kind of light-weight
|
||||
* cooperative multi-tasking. As native functions (or the debug hook) can
|
||||
* also force an abstract machine to "sleep", you can also use it to create
|
||||
* "latent functions": functions that allow the host application to continue
|
||||
* processing, and/or other abstract machines to run, while they wait for
|
||||
* some resource.
|
||||
*/
|
||||
err = amx_Exec(&amx, &ret, AMX_EXEC_MAIN);
|
||||
while (err == AMX_ERR_SLEEP) {
|
||||
if (idlefunc != NULL) {
|
||||
/* If the abstract machine was put to sleep, we can handle events during
|
||||
* that time. To save the "restart point", we must make a copy of the AMX
|
||||
* (keeping the stack, frame, instruction pointer and other vital
|
||||
* registers), but without cloning the entire abstract machine.
|
||||
* There should be some criterion on when the abstract machine must be
|
||||
* "woken up". In this example run-time, the parameter of the sleep
|
||||
* instruction is taken to be a delay in milliseconds. In your own host
|
||||
* application, you can choose to wait on a resource/semaphore or other.
|
||||
*/
|
||||
AMX nested_amx = amx;
|
||||
clock_t stamp = clock();
|
||||
while (((clock() - stamp)*1000)/CLOCKS_PER_SEC < amx.pri
|
||||
&& (err = idlefunc(&nested_amx,amx_Exec)) == AMX_ERR_NONE)
|
||||
/* nothing */;
|
||||
ExitOnError(&nested_amx, err);
|
||||
} /* if */
|
||||
err = amx_Exec(&amx, &ret, AMX_EXEC_CONT);
|
||||
} /* while */
|
||||
ExitOnError(&amx, err);
|
||||
|
||||
/* For event-driven programs, we also need to loop over the idle/monitor
|
||||
* function that some extension module installed (this could be the console
|
||||
* module, for example). We did this if the main program was put to "sleep",
|
||||
* but we do that here too.
|
||||
*/
|
||||
if (idlefunc != NULL) {
|
||||
while ((err = idlefunc(&amx,amx_Exec)) == AMX_ERR_NONE)
|
||||
/* nothing */;
|
||||
ExitOnError(&amx, err);
|
||||
} /* if */
|
||||
|
||||
end=clock();
|
||||
|
||||
/* Free the compiled script and resources. This also unloads and DLLs or
|
||||
* shared libraries that were registered automatically by amx_Init().
|
||||
*/
|
||||
aux_FreeProgram(&amx);
|
||||
|
||||
/* Print the return code of the compiled script (often not very useful),
|
||||
* its run time, and its stack usage.
|
||||
*/
|
||||
if (ret!=0)
|
||||
printf("\nReturn value: %ld\n", (long)ret);
|
||||
|
||||
printf("\nRun time: %.2f seconds\n",(double)(end-start)/CLOCKS_PER_SEC);
|
||||
if (stackinfo.maxstack != 0 || stackinfo.maxheap != 0) {
|
||||
printf("Stack usage: %ld cells (%ld bytes)\n",
|
||||
stackinfo.maxstack / sizeof(cell), stackinfo.maxstack);
|
||||
printf("Heap usage: %ld cells (%ld bytes)\n",
|
||||
stackinfo.maxheap / sizeof(cell), stackinfo.maxheap);
|
||||
} /* if */
|
||||
|
||||
#if defined AMX_TERMINAL
|
||||
/* This is likely a graphical terminal, which should not be closed
|
||||
* automatically
|
||||
*/
|
||||
{
|
||||
extern int amx_termctl(int,int);
|
||||
while (amx_termctl(4,0))
|
||||
/* nothing */;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
56
SOURCE/amx/pawnrun/prun1.c
Normal file
56
SOURCE/amx/pawnrun/prun1.c
Normal file
@ -0,0 +1,56 @@
|
||||
/* Command-line shell for the "Small" Abstract Machine.
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2001-2005
|
||||
*
|
||||
* This file may be freely used. No warranties of any kind.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for exit() */
|
||||
#include <signal.h>
|
||||
#include <string.h> /* for memset() (on some compilers) */
|
||||
#include "amx.h"
|
||||
#include "amxaux.c"
|
||||
|
||||
static void ErrorExit(AMX *amx, int errorcode)
|
||||
{
|
||||
printf("Run time error %d: \"%s\" on line %ld\n",
|
||||
errorcode, aux_StrError(errorcode),
|
||||
(amx != NULL) ? amx->curline : 0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void PrintUsage(char *program)
|
||||
{
|
||||
printf("Usage: %s <filename>\n<filename> is a compiled script.\n", program);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
extern AMX_NATIVE_INFO console_Natives[];
|
||||
extern AMX_NATIVE_INFO core_Natives[];
|
||||
|
||||
AMX amx;
|
||||
cell ret = 0;
|
||||
int err;
|
||||
|
||||
if (argc != 2)
|
||||
PrintUsage(argv[0]);
|
||||
|
||||
err = aux_LoadProgram(&amx, argv[1], NULL, NULL);
|
||||
if (err != AMX_ERR_NONE)
|
||||
ErrorExit(&amx, err);
|
||||
|
||||
amx_Register(&amx, console_Natives, -1);
|
||||
err = amx_Register(&amx, core_Natives, -1);
|
||||
if (err != AMX_ERR_NONE)
|
||||
ErrorExit(&amx, err);
|
||||
|
||||
err = amx_Exec(&amx, &ret, AMX_EXEC_MAIN, 0);
|
||||
if (err != AMX_ERR_NONE)
|
||||
ErrorExit(&amx, err);
|
||||
printf("%s returns %ld\n", argv[1], (long)ret);
|
||||
|
||||
aux_FreeProgram(&amx);
|
||||
return 0;
|
||||
}
|
82
SOURCE/amx/pawnrun/prun2.c
Normal file
82
SOURCE/amx/pawnrun/prun2.c
Normal file
@ -0,0 +1,82 @@
|
||||
/* Command-line shell for the "Small" Abstract Machine.
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 2001-2005
|
||||
*
|
||||
* This file may be freely used. No warranties of any kind.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h> /* for memset() (on some compilers) */
|
||||
#include "amx.h"
|
||||
#include "amxaux.c"
|
||||
|
||||
void core_Init(void); /* two functions from AMX_CORE.C */
|
||||
void core_Exit(void);
|
||||
|
||||
static int abortflagged = 0;
|
||||
void sigabort(int sig)
|
||||
{
|
||||
abortflagged=1;
|
||||
signal(sig,sigabort); /* re-install the signal handler */
|
||||
}
|
||||
|
||||
int AMXAPI srun_Monitor(AMX *amx)
|
||||
{
|
||||
switch (amx->dbgcode) {
|
||||
case DBG_INIT:
|
||||
return AMX_ERR_NONE;
|
||||
case DBG_LINE:
|
||||
/* check whether an "abort" was requested */
|
||||
return abortflagged ? AMX_ERR_EXIT : AMX_ERR_NONE;
|
||||
default:
|
||||
return AMX_ERR_DEBUG;
|
||||
} /* switch */
|
||||
}
|
||||
|
||||
|
||||
static void ErrorExit(AMX *amx, int errorcode)
|
||||
{
|
||||
printf("Run time error %d: \"%s\" on line %ld\n",
|
||||
errorcode, aux_StrError(errorcode),
|
||||
(amx != NULL) ? amx->curline : 0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void PrintUsage(char *program)
|
||||
{
|
||||
printf("Usage: %s <filename>\n<filename> is a compiled script.\n", program);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
extern AMX_NATIVE_INFO console_Natives[];
|
||||
extern AMX_NATIVE_INFO core_Natives[];
|
||||
|
||||
AMX amx;
|
||||
cell ret = 0;
|
||||
int err;
|
||||
|
||||
if (argc != 2)
|
||||
PrintUsage(argv[0]);
|
||||
|
||||
err = aux_LoadProgram(&amx, argv[1], NULL, srun_Monitor);
|
||||
if (err != AMX_ERR_NONE)
|
||||
ErrorExit(&amx, err);
|
||||
|
||||
amx_Register(&amx, console_Natives, -1);
|
||||
err = amx_Register(&amx, core_Natives, -1);
|
||||
if (err != AMX_ERR_NONE)
|
||||
ErrorExit(&amx, err);
|
||||
|
||||
signal(SIGINT, sigabort);
|
||||
|
||||
err = amx_Exec(&amx, &ret, AMX_EXEC_MAIN, 0);
|
||||
if (err != AMX_ERR_NONE)
|
||||
ErrorExit(&amx, err);
|
||||
printf("%s returns %ld\n", argv[1], (long)ret);
|
||||
|
||||
aux_FreeProgram(&amx);
|
||||
return 0;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user