Skip to content

Commit 28d7adb

Browse files
committed
github # 321: __FB_ARG_EXTRACT__ incorrectly recognizes commas nested in other forms with variadic macros
- previously __FB_ARG_EXTRACT__ used hlp-str.bas:hSplitStr() which incorrectly splits the string on commas nested in parens (), comments /' '/, and strings "," - internally use new hlp-str.bas:hStr2Args() procedure that recognizes commas used in nested forms - tests added
1 parent 2c5b644 commit 28d7adb

File tree

5 files changed

+284
-22
lines changed

5 files changed

+284
-22
lines changed

changelog.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ Version 1.08.1
22

33
[changed]
44
- github #314: fbc: pass '-T scriptfile' option to linker LD and add 'INSERT AFTER .data;' to fbextra.x linker script to quiet warning on LD version 2.36 and higher
5-
- gas64 : .a64 replaced by .asm to be coherent with documentation
5+
- gas64: .a64 replaced by .asm to be coherent with documentation
66

77
[added]
88

99
[fixed]
1010
- github #315: set parameters when calling SCREENCONTROL (was broken in fbc 1.08.0 due to new LONG/LONGINT SCREENCONTROL API's)
1111
- github #318: duplicate definition for deleting destructor; the deleting destructor was being emitted even though the class was declarations only on the fbc side
12-
- guthub #320: oGLfbGFX: scaling set by SCREENCONTROL not used when initializing opengl unix driver
12+
- github #320: oGLfbGFX: scaling set by SCREENCONTROL not used when initializing opengl unix driver
13+
- github #321: __FB_ARG_EXTRACT__ incorrectly recognizes commas nested in other forms with variadic macros - internally use new hlp-str.bas:hStr2Args() procedure
1314

1415

1516
Version 1.08.0

src/compiler/hlp-str.bas

Lines changed: 179 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,18 +1304,18 @@ end sub
13041304
'':::::
13051305
function hStr2Tok(byval txt as const zstring ptr, res() as string) as integer
13061306

1307-
var t = 0
1308-
var lc = 32UL
1309-
var s = cast(const ubyte ptr, txt)
1310-
do while( *s <> 0 )
1311-
var c = cast(uinteger, *s)
1307+
dim as integer t = 0
1308+
dim as uinteger lc = CHAR_SPACE
1309+
dim as const ubyte ptr s = cast(const ubyte ptr, txt)
1310+
do while( *s <> CHAR_NULL )
1311+
dim as uinteger c = cast(uinteger, *s)
13121312

1313-
if( c = 7 ) then
1314-
c = 32
1313+
if( c = CHAR_BELL ) then
1314+
c = CHAR_SPACE
13151315
end if
13161316

1317-
if( c = 32 ) then
1318-
if( lc <> 32 ) then
1317+
if( c = CHAR_SPACE ) then
1318+
if( lc <> CHAR_SPACE ) then
13191319
t += 1
13201320
end if
13211321
end if
@@ -1324,7 +1324,7 @@ function hStr2Tok(byval txt as const zstring ptr, res() as string) as integer
13241324
s += 1
13251325
loop
13261326

1327-
if( lc <> 32 ) then
1327+
if( lc <> CHAR_SPACE ) then
13281328
t += 1
13291329
end if
13301330

@@ -1335,17 +1335,17 @@ function hStr2Tok(byval txt as const zstring ptr, res() as string) as integer
13351335
redim res(0 to t-1)
13361336

13371337
t = 0
1338-
lc = 32
1338+
lc = CHAR_SPACE
13391339
s = cast(const ubyte ptr, txt)
1340-
do while( *s <> 0 )
1340+
do while( *s <> CHAR_NULL )
13411341
var c = cast(uinteger, *s)
13421342

1343-
if( c = 7 ) then
1344-
c = 32
1343+
if( c = CHAR_BELL ) then
1344+
c = CHAR_SPACE
13451345
end if
13461346

1347-
if( c = 32 ) then
1348-
if( lc <> 32 ) then
1347+
if( c = CHAR_SPACE ) then
1348+
if( lc <> CHAR_SPACE ) then
13491349
t += 1
13501350
end if
13511351
else
@@ -1356,6 +1356,167 @@ function hStr2Tok(byval txt as const zstring ptr, res() as string) as integer
13561356
s += 1
13571357
loop
13581358

1359-
function = iif(lc <> 32, t + 1, t)
1359+
function = iif(lc <> CHAR_SPACE, t + 1, t)
13601360

1361-
end function
1361+
end function
1362+
1363+
'':::::
1364+
function hStr2args( byval txt as const zstring ptr, res() as string ) as integer
1365+
1366+
'' !!! TODO !! add the wstring version
1367+
1368+
dim as integer t = 0
1369+
dim as const ubyte ptr s = cast(const ubyte ptr, txt)
1370+
dim as integer prntcnt = 0
1371+
dim as uinteger c = CHAR_NULL
1372+
dim as integer max_t = 10
1373+
1374+
#define PeekChar() cast( uinteger, s[0] )
1375+
#define SkipChar() s += 1
1376+
#define ReadChar(c) res(t-1) += chr(c) : s += 1
1377+
1378+
redim res( 0 to max_t-1 ) as string
1379+
1380+
do
1381+
c = PeekChar()
1382+
if (c = CHAR_TAB) or (c = CHAR_SPACE) then
1383+
SkipChar()
1384+
else
1385+
exit do
1386+
end if
1387+
loop
1388+
1389+
'' no arguments?
1390+
if( c = CHAR_NULL ) then
1391+
return 0
1392+
end if
1393+
1394+
'' ok, there's at least one argument
1395+
t += 1
1396+
1397+
'' scan for arguments
1398+
do
1399+
c = PeekChar()
1400+
select case c
1401+
case CHAR_NULL
1402+
exit do
1403+
1404+
case CHAR_LPRNT
1405+
prntcnt += 1
1406+
1407+
case CHAR_RPRNT
1408+
if( prntcnt > 0 ) then
1409+
prntcnt -= 1
1410+
end if
1411+
1412+
case CHAR_COMMA
1413+
if( prntcnt = 0 ) then
1414+
t += 1
1415+
if( t > max_t ) then
1416+
max_t += 10
1417+
redim preserve res( 0 to max_t - 1 )
1418+
end if
1419+
SkipChar()
1420+
continue do
1421+
end if
1422+
1423+
case CHAR_QUOTE, CHAR_EXCL, CHAR_DOLAR
1424+
dim as integer escaped = env.opt.escapestr
1425+
if( c <> CHAR_QUOTE ) then
1426+
escaped = ( c = CHAR_EXCL )
1427+
1428+
'' '!' | '$'
1429+
ReadChar(c)
1430+
c = PeekChar()
1431+
if( c <> CHAR_QUOTE ) then
1432+
continue do
1433+
end if
1434+
1435+
end if
1436+
1437+
'' '"'
1438+
ReadChar(c)
1439+
1440+
do
1441+
c = PeekChar()
1442+
if( c = CHAR_NULL ) then
1443+
exit do
1444+
end if
1445+
1446+
'' '"' | '\\' | any other string char
1447+
ReadChar(c)
1448+
if( c = CHAR_QUOTE ) then
1449+
1450+
c = PeekChar()
1451+
if( c <> CHAR_QUOTE ) then
1452+
exit do
1453+
end if
1454+
1455+
'' '"'
1456+
ReadChar(c)
1457+
1458+
elseif( c = CHAR_RSLASH ) then
1459+
1460+
c = PeekChar()
1461+
select case c
1462+
case CHAR_QUOTE, CHAR_RSLASH
1463+
'' '"' | '\\'
1464+
ReadChar(c)
1465+
end select
1466+
1467+
end if
1468+
loop
1469+
continue do
1470+
1471+
case CHAR_SLASH
1472+
1473+
'' '/'
1474+
ReadChar(c)
1475+
1476+
c = PeekChar()
1477+
if( c <> CHAR_APOST ) then
1478+
continue do
1479+
end if
1480+
1481+
'' '''
1482+
ReadChar(c)
1483+
1484+
do
1485+
c = PeekChar()
1486+
if( c = CHAR_NULL ) then
1487+
exit do
1488+
end if
1489+
1490+
'' ''' | any other comment char
1491+
ReadChar(c)
1492+
1493+
if( c = CHAR_APOST ) then
1494+
c = PeekChar()
1495+
if( c = CHAR_SLASH ) then
1496+
'' '/'
1497+
ReadChar(c)
1498+
exit do
1499+
end if
1500+
end if
1501+
1502+
loop
1503+
continue do
1504+
1505+
case CHAR_APOST
1506+
while( c <> CHAR_NULL )
1507+
'' ''' or any comment char to end of line
1508+
ReadChar(c)
1509+
c = PeekChar()
1510+
wend
1511+
exit do
1512+
1513+
end select
1514+
1515+
'' any other char not handled above
1516+
ReadChar(c)
1517+
1518+
loop
1519+
1520+
function = t
1521+
1522+
end function

src/compiler/hlp-str.bi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ declare sub hSplitStr(byref txt as string, byref del as string, res() as string)
136136

137137
declare function hStr2Tok(byval txt as const zstring ptr, res() as string) as integer
138138

139+
declare function hStr2Args(byval txt as const zstring ptr, res() as string) as integer
140+
139141
'':::::
140142
#define ZstrAllocate(chars) xallocate( chars + 1 )
141143

src/compiler/symb-define.bas

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,8 +453,10 @@ private function hDefArgExtract_cb( byval argtb as LEXPP_ARGTB ptr, byval errnum
453453
var argString = hMacro_getArgZ( argtb, 1 )
454454
dim varArgs() as string
455455

456-
hSplitStr(*argString, ",", varArgs())
457-
res = varArgs(index)
456+
if( hStr2Args( argString, varArgs() ) > 0 ) then
457+
res = varArgs(index)
458+
end if
459+
458460
ZStrFree(argString)
459461
end if
460462

tests/pp/macro-arg-extract.bas

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,101 @@ SUITE( fbc_tests.pp.macro_arg_extract )
7171
CU_ASSERT_EQUAL( FLOAT_VAL, __FB_ARG_EXTRACT__(2, WHOLE_LIST) )
7272
END_TEST
7373

74+
#macro nested1( n, arg0, arg1, arg3 )
75+
__FB_UNQUOTE__( "#define n1 " ) __FB_QUOTE__( arg1 )
76+
#endmacro
77+
78+
#macro nestedX( n, args... )
79+
__FB_UNQUOTE__( "#define nx " ) __FB_QUOTE__( __FB_ARG_EXTRACT__( n, args ) )
80+
#endmacro
81+
82+
#macro nestedreset
83+
__FB_UNQUOTE__( "#undef n1" )
84+
__FB_UNQUOTE__( "#undef nx" )
85+
#endmacro
86+
87+
TEST( nested_comma_direct )
88+
89+
scope
90+
dim a(0,0) as integer
91+
nested1( 1, 1, a(0,0), 3 )
92+
nestedX( 1, 1, a(0,0), 3 )
93+
CU_ASSERT_EQUAL( n1, nx )
94+
nestedreset
95+
end scope
96+
97+
nested1( 1, 1, /'2,3'/, 3 )
98+
nestedX( 1, 1, /'2,3'/, 3 )
99+
CU_ASSERT_EQUAL( n1, __FB_QUOTE__( ) )
100+
CU_ASSERT_EQUAL( n1, __FB_QUOTE__( ) )
101+
nestedreset
102+
103+
nested1( 1, 1, "2,3", 3 )
104+
nestedX( 1, 1, "2,3", 3 )
105+
CU_ASSERT_EQUAL( n1, __FB_QUOTE__( "2,3" ) )
106+
CU_ASSERT_EQUAL( nx, __FB_QUOTE__( "2,3" ) )
107+
nestedreset
108+
109+
nested1( 1, 1, "2,(3", 3 )
110+
nestedX( 1, 1, "2,(3", 3 )
111+
CU_ASSERT_EQUAL( n1, __FB_QUOTE__( "2,(3" ) )
112+
CU_ASSERT_EQUAL( nx, __FB_QUOTE__( "2,(3" ) )
113+
nestedreset
114+
115+
nested1( 1, 1, "2,""3", 3 )
116+
nestedX( 1, 1, "2,""3", 3 )
117+
CU_ASSERT_EQUAL( n1, __FB_QUOTE__( "2,""3" ) )
118+
CU_ASSERT_EQUAL( nx, __FB_QUOTE__( "2,""3" ) )
119+
nestedreset
120+
121+
nested1( 1, 1, $"2,3", 3 )
122+
nestedX( 1, 1, $"2,3", 3 )
123+
CU_ASSERT_EQUAL( n1, __FB_QUOTE__( $"2,3" ) )
124+
CU_ASSERT_EQUAL( nx, __FB_QUOTE__( $"2,3" ) )
125+
nestedreset
126+
127+
nested1( 1, 1, !"2,3", 3 )
128+
nestedX( 1, 1, !"2,3", 3 )
129+
CU_ASSERT_EQUAL( n1, __FB_QUOTE__( !"2,3" ) )
130+
CU_ASSERT_EQUAL( nx, __FB_QUOTE__( !"2,3" ) )
131+
nestedreset
132+
133+
nested1( 1, 1, !"\\\"""2,3", 3 )
134+
nestedX( 1, 1, !"\\\"""2,3", 3 )
135+
CU_ASSERT_EQUAL( n1, __FB_QUOTE__( !"\\\"""2,3" ) )
136+
CU_ASSERT_EQUAL( nx, __FB_QUOTE__( !"\\\"""2,3" ) )
137+
nestedreset
138+
139+
END_TEST
140+
141+
#macro nested_test( arg )
142+
nested1( 1, 1, arg, 3 )
143+
nestedX( 1, 1, arg, 3 )
144+
CU_ASSERT_EQUAL( n1, __FB_QUOTE__( arg ) )
145+
CU_ASSERT_EQUAL( nx, __FB_QUOTE__( arg ) )
146+
nestedreset
147+
148+
#endmacro
149+
150+
TEST( nested_comma_indirect )
151+
152+
nested_test( /' comment '/ )
153+
nested_test( () )
154+
nested_test( a(1,2) )
155+
nested_test( "2,3" )
156+
nested_test( "2,(3" )
157+
nested_test( "2,""3" )
158+
nested_test( "/' string '/" )
159+
nested_test( $"2,3" )
160+
nested_test( !"2,3" )
161+
nested_test( $"\\""""2,3" )
162+
nested_test( !"\\\"""2,3" )
163+
164+
END_TEST
165+
166+
TEST( string_args )
167+
168+
END_TEST
169+
74170
END_SUITE
75171

0 commit comments

Comments
 (0)