Opener Herschelle Gibbs top-scored with a battling 92 to steer South Africa into a strong position against Sri Lanka on the third day of the second Test in Colombo on Sunday.
South Africa, who scored 361 in the first innings and bowled Sri Lanka out for 321, batted through a closely-fought third day to close on 257 for seven.
Gibbs, under pressure after three cheap dismissals in the series, batted positively in the morning and then grafted hard during the afternoon as Sri Lanka bowled tightly to defensive fields.
The 32-year-old right-hander stroked 11 boundaries and one six during a 190-ball innings before missing out of what could have been his first Test hundred for 19 months and the 15th of his career.
Nevertheless, it was a timely return to form for a batsman who had passed 20 only once in his previous 11 innings.
The Sri Lankans were kept in the game by prolific off spinner Muttiah Muralitharan who snared three wickets in the final session to finish with four for 86, one short of a record-equalling fourth consecutive 10-wicket match haul.
South Africa had dominated the morning, adding 100 runs from 29 overs.
The only casualty of the session was makeshift opener Andrew Hall, who was caught behind for 32 off Farveez Maharoof.
Hall and Gibbs shared an opening stand of 76, allowing South Africa to tighten their grip on the game after their bowlers stole the initiative on day two.
The tension mounted in the afternoon as Sri Lanka applied pressure with two run outs, the first a controversial decision by television umpire Tyrone Wijewardene who ruled Jacques Rudolph out for 15.
Rudolph was slow to leave the field, convinced Chamara Kapugedera's hand had brushed the boundary rope before he threw down the stumps with a direct hit.
Kapugedera was then responsible for running out Hashim Amla (8), who was sent back too late by Gibbs, with an accurate throw from short fine leg.
Gibbs fell on the stroke of tea after top-edging a sweep off Muttiah Muralitharan, lifting the morale of a previously frustrated Sri Lankan team.
After tea the flow of runs reduced to a trickle as Maharoof found some reverse swing with the old ball and Muralitharan plugged away accurately.
However, Ashwell Prince (17) and AB de Villiers (33) chiselled out 41 crucial runs for the fifth wicket.
The game turned again in the final hour as Muralitharan struck twice in an over, snapping up a return catch off Prince and then the fortuitous scalp of de Villiers, who edged onto his helmet to be caught at short leg.
Shaun Pollock (14) perished shortly afterwards after picking out Upul Tharanga at square leg with a pull stroke.
Sri Lanka won the first Test in the two-match series by an innings and 153 runs.
South Africa 1st innings: 361 (A de Villiers 95, A Prince 86, S Pollock 57*; M Muralitharan 5-128)
Sri Lanka 1st innings: 321 (C Vaas 64, C Kapugedera 63, F Maharoof 56; D Steyn 5-82, M Ntini 4-84)
South Africa 2nd innings (Overnight: 6-0)
H Gibbs c Jayasuriya b Muralitharan 92
A Hall c P Jayawardene b Maharoof 32
J Rudolph run out 15
H Amla run out 8
A Prince c & b Muralitharan 17
A de Villiers c Dilshan b Muralitharan 33
M Boucher not out 28
S Pollock c Tharanga b Muralitharan 14
N Boje not out 5
Extras (b-9 lb-3 nb-1) 13
Total (for 7 wickets, 92 overs) 257
Fall of wickets: 1-76, 2-119, 3-131, 4-161, 5-206, 6-207, 7-235.
To bat: M Ntini, D Steyn
Bowling: C Vaas 16-4-41-0, L Malinga 12-1-55-0 (nb-1), F Maharoof 17-3-34-1, M Muralitharan 39-10-86-4, S Jayasuriya 8-0-29-0.