1*3e12c5d1SDavid du Colombier #include <u.h> 2*3e12c5d1SDavid du Colombier #include <libc.h> 3*3e12c5d1SDavid du Colombier #include <stdio.h> 4*3e12c5d1SDavid du Colombier #include "cpp.h" 5*3e12c5d1SDavid du Colombier 6*3e12c5d1SDavid du Colombier static char wbuf[2*OBS]; 7*3e12c5d1SDavid du Colombier static char *wbp = wbuf; 8*3e12c5d1SDavid du Colombier 9*3e12c5d1SDavid du Colombier /* 10*3e12c5d1SDavid du Colombier * 1 for tokens that don't need whitespace when they get inserted 11*3e12c5d1SDavid du Colombier * by macro expansion 12*3e12c5d1SDavid du Colombier */ 13*3e12c5d1SDavid du Colombier static const char wstab[] = { 14*3e12c5d1SDavid du Colombier 0, /* END */ 15*3e12c5d1SDavid du Colombier 0, /* UNCLASS */ 16*3e12c5d1SDavid du Colombier 0, /* NAME */ 17*3e12c5d1SDavid du Colombier 0, /* NUMBER */ 18*3e12c5d1SDavid du Colombier 0, /* STRING */ 19*3e12c5d1SDavid du Colombier 0, /* CCON */ 20*3e12c5d1SDavid du Colombier 1, /* NL */ 21*3e12c5d1SDavid du Colombier 0, /* WS */ 22*3e12c5d1SDavid du Colombier 0, /* DSHARP */ 23*3e12c5d1SDavid du Colombier 0, /* EQ */ 24*3e12c5d1SDavid du Colombier 0, /* NEQ */ 25*3e12c5d1SDavid du Colombier 0, /* LEQ */ 26*3e12c5d1SDavid du Colombier 0, /* GEQ */ 27*3e12c5d1SDavid du Colombier 0, /* LSH */ 28*3e12c5d1SDavid du Colombier 0, /* RSH */ 29*3e12c5d1SDavid du Colombier 0, /* LAND */ 30*3e12c5d1SDavid du Colombier 0, /* LOR */ 31*3e12c5d1SDavid du Colombier 0, /* PPLUS */ 32*3e12c5d1SDavid du Colombier 0, /* MMINUS */ 33*3e12c5d1SDavid du Colombier 0, /* ARROW */ 34*3e12c5d1SDavid du Colombier 1, /* SBRA */ 35*3e12c5d1SDavid du Colombier 1, /* SKET */ 36*3e12c5d1SDavid du Colombier 1, /* LP */ 37*3e12c5d1SDavid du Colombier 1, /* RP */ 38*3e12c5d1SDavid du Colombier 0, /* DOT */ 39*3e12c5d1SDavid du Colombier 0, /* AND */ 40*3e12c5d1SDavid du Colombier 0, /* STAR */ 41*3e12c5d1SDavid du Colombier 0, /* PLUS */ 42*3e12c5d1SDavid du Colombier 0, /* MINUS */ 43*3e12c5d1SDavid du Colombier 0, /* TILDE */ 44*3e12c5d1SDavid du Colombier 0, /* NOT */ 45*3e12c5d1SDavid du Colombier 0, /* SLASH */ 46*3e12c5d1SDavid du Colombier 0, /* PCT */ 47*3e12c5d1SDavid du Colombier 0, /* LT */ 48*3e12c5d1SDavid du Colombier 0, /* GT */ 49*3e12c5d1SDavid du Colombier 0, /* CIRC */ 50*3e12c5d1SDavid du Colombier 0, /* OR */ 51*3e12c5d1SDavid du Colombier 0, /* QUEST */ 52*3e12c5d1SDavid du Colombier 0, /* COLON */ 53*3e12c5d1SDavid du Colombier 0, /* ASGN */ 54*3e12c5d1SDavid du Colombier 1, /* COMMA */ 55*3e12c5d1SDavid du Colombier 0, /* SHARP */ 56*3e12c5d1SDavid du Colombier 1, /* SEMIC */ 57*3e12c5d1SDavid du Colombier 1, /* CBRA */ 58*3e12c5d1SDavid du Colombier 1, /* CKET */ 59*3e12c5d1SDavid du Colombier 0, /* ASPLUS */ 60*3e12c5d1SDavid du Colombier 0, /* ASMINUS */ 61*3e12c5d1SDavid du Colombier 0, /* ASSTAR */ 62*3e12c5d1SDavid du Colombier 0, /* ASSLASH */ 63*3e12c5d1SDavid du Colombier 0, /* ASPCT */ 64*3e12c5d1SDavid du Colombier 0, /* ASCIRC */ 65*3e12c5d1SDavid du Colombier 0, /* ASLSH */ 66*3e12c5d1SDavid du Colombier 0, /* ASRSH */ 67*3e12c5d1SDavid du Colombier 0, /* ASOR */ 68*3e12c5d1SDavid du Colombier 0, /* ASAND */ 69*3e12c5d1SDavid du Colombier 0, /* ELLIPS */ 70*3e12c5d1SDavid du Colombier 0, /* DSHARP1 */ 71*3e12c5d1SDavid du Colombier 0, /* NAME1 */ 72*3e12c5d1SDavid du Colombier 0, /* DEFINED */ 73*3e12c5d1SDavid du Colombier 0, /* UMINUS */ 74*3e12c5d1SDavid du Colombier }; 75*3e12c5d1SDavid du Colombier 76*3e12c5d1SDavid du Colombier void 77*3e12c5d1SDavid du Colombier maketokenrow(int size, Tokenrow *trp) 78*3e12c5d1SDavid du Colombier { 79*3e12c5d1SDavid du Colombier trp->max = size; 80*3e12c5d1SDavid du Colombier trp->bp = (Token *)domalloc(size*sizeof(Token)); 81*3e12c5d1SDavid du Colombier trp->tp = trp->bp; 82*3e12c5d1SDavid du Colombier trp->lp = trp->bp; 83*3e12c5d1SDavid du Colombier } 84*3e12c5d1SDavid du Colombier 85*3e12c5d1SDavid du Colombier Token * 86*3e12c5d1SDavid du Colombier growtokenrow(Tokenrow *trp) 87*3e12c5d1SDavid du Colombier { 88*3e12c5d1SDavid du Colombier int ncur = trp->tp - trp->bp; 89*3e12c5d1SDavid du Colombier int nlast = trp->lp - trp->bp; 90*3e12c5d1SDavid du Colombier 91*3e12c5d1SDavid du Colombier trp->max = 3*trp->max/2 + 1; 92*3e12c5d1SDavid du Colombier trp->bp = (Token *)realloc(trp->bp, trp->max*sizeof(Token)); 93*3e12c5d1SDavid du Colombier trp->lp = &trp->bp[nlast]; 94*3e12c5d1SDavid du Colombier trp->tp = &trp->bp[ncur]; 95*3e12c5d1SDavid du Colombier return trp->lp; 96*3e12c5d1SDavid du Colombier } 97*3e12c5d1SDavid du Colombier 98*3e12c5d1SDavid du Colombier /* 99*3e12c5d1SDavid du Colombier * Compare a row of tokens, ignoring the content of WS; return !=0 if different 100*3e12c5d1SDavid du Colombier */ 101*3e12c5d1SDavid du Colombier int 102*3e12c5d1SDavid du Colombier comparetokens(Tokenrow *tr1, Tokenrow *tr2) 103*3e12c5d1SDavid du Colombier { 104*3e12c5d1SDavid du Colombier Token *tp1, *tp2; 105*3e12c5d1SDavid du Colombier 106*3e12c5d1SDavid du Colombier tp1 = tr1->tp; 107*3e12c5d1SDavid du Colombier tp2 = tr2->tp; 108*3e12c5d1SDavid du Colombier if (tr1->lp-tp1 != tr2->lp-tp2) 109*3e12c5d1SDavid du Colombier return 1; 110*3e12c5d1SDavid du Colombier for (; tp1<tr1->lp ; tp1++, tp2++) { 111*3e12c5d1SDavid du Colombier if (tp1->type != tp2->type 112*3e12c5d1SDavid du Colombier || (tp1->wslen==0) != (tp2->wslen==0) 113*3e12c5d1SDavid du Colombier || tp1->len != tp2->len 114*3e12c5d1SDavid du Colombier || strncmp((char*)tp1->t, (char*)tp2->t, tp1->len)!=0) 115*3e12c5d1SDavid du Colombier return 1; 116*3e12c5d1SDavid du Colombier } 117*3e12c5d1SDavid du Colombier return 0; 118*3e12c5d1SDavid du Colombier } 119*3e12c5d1SDavid du Colombier 120*3e12c5d1SDavid du Colombier /* 121*3e12c5d1SDavid du Colombier * replace ntok tokens starting at dtr->tp with the contents of str. 122*3e12c5d1SDavid du Colombier * tp ends up pointing just beyond the replacement. 123*3e12c5d1SDavid du Colombier * Canonical whitespace is assured on each side. 124*3e12c5d1SDavid du Colombier */ 125*3e12c5d1SDavid du Colombier void 126*3e12c5d1SDavid du Colombier insertrow(Tokenrow *dtr, int ntok, Tokenrow *str) 127*3e12c5d1SDavid du Colombier { 128*3e12c5d1SDavid du Colombier int nrtok = rowlen(str); 129*3e12c5d1SDavid du Colombier 130*3e12c5d1SDavid du Colombier dtr->tp += ntok; 131*3e12c5d1SDavid du Colombier adjustrow(dtr, nrtok-ntok); 132*3e12c5d1SDavid du Colombier dtr->tp -= ntok; 133*3e12c5d1SDavid du Colombier movetokenrow(dtr, str); 134*3e12c5d1SDavid du Colombier makespace(dtr); 135*3e12c5d1SDavid du Colombier dtr->tp += nrtok; 136*3e12c5d1SDavid du Colombier makespace(dtr); 137*3e12c5d1SDavid du Colombier } 138*3e12c5d1SDavid du Colombier 139*3e12c5d1SDavid du Colombier /* 140*3e12c5d1SDavid du Colombier * make sure there is WS before trp->tp, if tokens might merge in the output 141*3e12c5d1SDavid du Colombier */ 142*3e12c5d1SDavid du Colombier void 143*3e12c5d1SDavid du Colombier makespace(Tokenrow *trp) 144*3e12c5d1SDavid du Colombier { 145*3e12c5d1SDavid du Colombier uchar *tt; 146*3e12c5d1SDavid du Colombier Token *tp = trp->tp; 147*3e12c5d1SDavid du Colombier 148*3e12c5d1SDavid du Colombier if (tp >= trp->lp) 149*3e12c5d1SDavid du Colombier return; 150*3e12c5d1SDavid du Colombier if (tp->wslen) { 151*3e12c5d1SDavid du Colombier if (tp->flag&XPWS 152*3e12c5d1SDavid du Colombier && (wstab[tp->type] || trp->tp>trp->bp && wstab[(tp-1)->type])) { 153*3e12c5d1SDavid du Colombier tp->wslen = 0; 154*3e12c5d1SDavid du Colombier return; 155*3e12c5d1SDavid du Colombier } 156*3e12c5d1SDavid du Colombier tp->t[-1] = ' '; 157*3e12c5d1SDavid du Colombier return; 158*3e12c5d1SDavid du Colombier } 159*3e12c5d1SDavid du Colombier if (wstab[tp->type] || trp->tp>trp->bp && wstab[(tp-1)->type]) 160*3e12c5d1SDavid du Colombier return; 161*3e12c5d1SDavid du Colombier tt = newstring(tp->t, tp->len, 1); 162*3e12c5d1SDavid du Colombier *tt++ = ' '; 163*3e12c5d1SDavid du Colombier tp->t = tt; 164*3e12c5d1SDavid du Colombier tp->wslen = 1; 165*3e12c5d1SDavid du Colombier tp->flag |= XPWS; 166*3e12c5d1SDavid du Colombier } 167*3e12c5d1SDavid du Colombier 168*3e12c5d1SDavid du Colombier /* 169*3e12c5d1SDavid du Colombier * Copy an entire tokenrow into another, at tp. 170*3e12c5d1SDavid du Colombier * It is assumed that there is enough space. 171*3e12c5d1SDavid du Colombier * Not strictly conforming. 172*3e12c5d1SDavid du Colombier */ 173*3e12c5d1SDavid du Colombier void 174*3e12c5d1SDavid du Colombier movetokenrow(Tokenrow *dtr, Tokenrow *str) 175*3e12c5d1SDavid du Colombier { 176*3e12c5d1SDavid du Colombier int nby; 177*3e12c5d1SDavid du Colombier 178*3e12c5d1SDavid du Colombier /* nby = sizeof(Token) * (str->lp - str->bp); */ 179*3e12c5d1SDavid du Colombier nby = (char *)str->lp - (char *)str->bp; 180*3e12c5d1SDavid du Colombier memmove(dtr->tp, str->bp, nby); 181*3e12c5d1SDavid du Colombier } 182*3e12c5d1SDavid du Colombier 183*3e12c5d1SDavid du Colombier /* 184*3e12c5d1SDavid du Colombier * Move the tokens in a row, starting at tr->tp, rightward by nt tokens; 185*3e12c5d1SDavid du Colombier * nt may be negative (left move). 186*3e12c5d1SDavid du Colombier * The row may need to be grown. 187*3e12c5d1SDavid du Colombier * Non-strictly conforming because of the (char *), but easily fixed 188*3e12c5d1SDavid du Colombier */ 189*3e12c5d1SDavid du Colombier void 190*3e12c5d1SDavid du Colombier adjustrow(Tokenrow *trp, int nt) 191*3e12c5d1SDavid du Colombier { 192*3e12c5d1SDavid du Colombier int nby, size; 193*3e12c5d1SDavid du Colombier 194*3e12c5d1SDavid du Colombier if (nt==0) 195*3e12c5d1SDavid du Colombier return; 196*3e12c5d1SDavid du Colombier size = (trp->lp - trp->bp) + nt; 197*3e12c5d1SDavid du Colombier while (size > trp->max) 198*3e12c5d1SDavid du Colombier growtokenrow(trp); 199*3e12c5d1SDavid du Colombier /* nby = sizeof(Token) * (trp->lp - trp->tp); */ 200*3e12c5d1SDavid du Colombier nby = (char *)trp->lp - (char *)trp->tp; 201*3e12c5d1SDavid du Colombier if (nby) 202*3e12c5d1SDavid du Colombier memmove(trp->tp+nt, trp->tp, nby); 203*3e12c5d1SDavid du Colombier trp->lp += nt; 204*3e12c5d1SDavid du Colombier } 205*3e12c5d1SDavid du Colombier 206*3e12c5d1SDavid du Colombier /* 207*3e12c5d1SDavid du Colombier * Copy a row of tokens into the destination holder, allocating 208*3e12c5d1SDavid du Colombier * the space for the contents. Return the destination. 209*3e12c5d1SDavid du Colombier */ 210*3e12c5d1SDavid du Colombier Tokenrow * 211*3e12c5d1SDavid du Colombier copytokenrow(Tokenrow *dtr, Tokenrow *str) 212*3e12c5d1SDavid du Colombier { 213*3e12c5d1SDavid du Colombier int len = rowlen(str); 214*3e12c5d1SDavid du Colombier 215*3e12c5d1SDavid du Colombier maketokenrow(len, dtr); 216*3e12c5d1SDavid du Colombier movetokenrow(dtr, str); 217*3e12c5d1SDavid du Colombier dtr->lp += len; 218*3e12c5d1SDavid du Colombier return dtr; 219*3e12c5d1SDavid du Colombier } 220*3e12c5d1SDavid du Colombier 221*3e12c5d1SDavid du Colombier /* 222*3e12c5d1SDavid du Colombier * Produce a copy of a row of tokens. Start at trp->tp. 223*3e12c5d1SDavid du Colombier * The value strings are copied as well. The first token 224*3e12c5d1SDavid du Colombier * has WS available. 225*3e12c5d1SDavid du Colombier */ 226*3e12c5d1SDavid du Colombier Tokenrow * 227*3e12c5d1SDavid du Colombier normtokenrow(Tokenrow *trp) 228*3e12c5d1SDavid du Colombier { 229*3e12c5d1SDavid du Colombier Token *tp; 230*3e12c5d1SDavid du Colombier Tokenrow *ntrp = new(Tokenrow); 231*3e12c5d1SDavid du Colombier int len; 232*3e12c5d1SDavid du Colombier 233*3e12c5d1SDavid du Colombier len = trp->lp - trp->tp; 234*3e12c5d1SDavid du Colombier if (len<=0) 235*3e12c5d1SDavid du Colombier len = 1; 236*3e12c5d1SDavid du Colombier maketokenrow(len, ntrp); 237*3e12c5d1SDavid du Colombier for (tp=trp->tp; tp < trp->lp; tp++) { 238*3e12c5d1SDavid du Colombier *ntrp->lp = *tp; 239*3e12c5d1SDavid du Colombier if (tp->len) { 240*3e12c5d1SDavid du Colombier ntrp->lp->t = newstring(tp->t, tp->len, 1); 241*3e12c5d1SDavid du Colombier *ntrp->lp->t++ = ' '; 242*3e12c5d1SDavid du Colombier if (tp->wslen) 243*3e12c5d1SDavid du Colombier ntrp->lp->wslen = 1; 244*3e12c5d1SDavid du Colombier } 245*3e12c5d1SDavid du Colombier ntrp->lp++; 246*3e12c5d1SDavid du Colombier } 247*3e12c5d1SDavid du Colombier if (ntrp->lp > ntrp->bp) 248*3e12c5d1SDavid du Colombier ntrp->bp->wslen = 0; 249*3e12c5d1SDavid du Colombier return ntrp; 250*3e12c5d1SDavid du Colombier } 251*3e12c5d1SDavid du Colombier 252*3e12c5d1SDavid du Colombier /* 253*3e12c5d1SDavid du Colombier * Debugging 254*3e12c5d1SDavid du Colombier */ 255*3e12c5d1SDavid du Colombier void 256*3e12c5d1SDavid du Colombier peektokens(Tokenrow *trp, char *str) 257*3e12c5d1SDavid du Colombier { 258*3e12c5d1SDavid du Colombier Token *tp; 259*3e12c5d1SDavid du Colombier int c; 260*3e12c5d1SDavid du Colombier 261*3e12c5d1SDavid du Colombier tp = trp->tp; 262*3e12c5d1SDavid du Colombier flushout(); 263*3e12c5d1SDavid du Colombier if (str) 264*3e12c5d1SDavid du Colombier fprintf(stderr, "%s ", str); 265*3e12c5d1SDavid du Colombier if (tp <trp->bp || tp>trp->lp) 266*3e12c5d1SDavid du Colombier fprintf(stderr, "(tp offset %d) ", tp-trp->bp); 267*3e12c5d1SDavid du Colombier for (tp=trp->bp; tp<trp->lp && tp<trp->bp+32; tp++) { 268*3e12c5d1SDavid du Colombier if (tp->type!=NL) { 269*3e12c5d1SDavid du Colombier c = tp->t[tp->len]; 270*3e12c5d1SDavid du Colombier tp->t[tp->len] = 0; 271*3e12c5d1SDavid du Colombier fprintf(stderr, "%s", tp->t, tp->len); 272*3e12c5d1SDavid du Colombier tp->t[tp->len] = c; 273*3e12c5d1SDavid du Colombier } 274*3e12c5d1SDavid du Colombier if (tp->type==NAME) { 275*3e12c5d1SDavid du Colombier fprintf(stderr, tp==trp->tp?"{*":"{"); 276*3e12c5d1SDavid du Colombier prhideset(tp->hideset); 277*3e12c5d1SDavid du Colombier fprintf(stderr, "} "); 278*3e12c5d1SDavid du Colombier } else 279*3e12c5d1SDavid du Colombier fprintf(stderr, tp==trp->tp?"{%x*} ":"{%x} ", tp->type); 280*3e12c5d1SDavid du Colombier } 281*3e12c5d1SDavid du Colombier fprintf(stderr, "\n"); 282*3e12c5d1SDavid du Colombier fflush(stderr); 283*3e12c5d1SDavid du Colombier } 284*3e12c5d1SDavid du Colombier 285*3e12c5d1SDavid du Colombier void 286*3e12c5d1SDavid du Colombier puttokens(Tokenrow *trp) 287*3e12c5d1SDavid du Colombier { 288*3e12c5d1SDavid du Colombier Token *tp; 289*3e12c5d1SDavid du Colombier int len; 290*3e12c5d1SDavid du Colombier uchar *p; 291*3e12c5d1SDavid du Colombier 292*3e12c5d1SDavid du Colombier if (verbose) 293*3e12c5d1SDavid du Colombier peektokens(trp, ""); 294*3e12c5d1SDavid du Colombier tp = trp->bp; 295*3e12c5d1SDavid du Colombier for (; tp<trp->lp; tp++) { 296*3e12c5d1SDavid du Colombier len = tp->len+tp->wslen; 297*3e12c5d1SDavid du Colombier p = tp->t-tp->wslen; 298*3e12c5d1SDavid du Colombier while (tp<trp->lp-1 && p+len == (tp+1)->t - (tp+1)->wslen) { 299*3e12c5d1SDavid du Colombier tp++; 300*3e12c5d1SDavid du Colombier len += tp->wslen+tp->len; 301*3e12c5d1SDavid du Colombier } 302*3e12c5d1SDavid du Colombier memcpy(wbp, p, len); 303*3e12c5d1SDavid du Colombier wbp += len; 304*3e12c5d1SDavid du Colombier if (wbp >= &wbuf[OBS]) { 305*3e12c5d1SDavid du Colombier write(1, wbuf, OBS); 306*3e12c5d1SDavid du Colombier if (wbp > &wbuf[OBS]) 307*3e12c5d1SDavid du Colombier memcpy(wbuf, wbuf+OBS, wbp - &wbuf[OBS]); 308*3e12c5d1SDavid du Colombier wbp -= OBS; 309*3e12c5d1SDavid du Colombier } 310*3e12c5d1SDavid du Colombier } 311*3e12c5d1SDavid du Colombier trp->tp = tp; 312*3e12c5d1SDavid du Colombier if (cursource->fd==0) 313*3e12c5d1SDavid du Colombier flushout(); 314*3e12c5d1SDavid du Colombier } 315*3e12c5d1SDavid du Colombier 316*3e12c5d1SDavid du Colombier void 317*3e12c5d1SDavid du Colombier flushout(void) 318*3e12c5d1SDavid du Colombier { 319*3e12c5d1SDavid du Colombier if (wbp>wbuf) { 320*3e12c5d1SDavid du Colombier write(1, wbuf, wbp-wbuf); 321*3e12c5d1SDavid du Colombier wbp = wbuf; 322*3e12c5d1SDavid du Colombier } 323*3e12c5d1SDavid du Colombier } 324*3e12c5d1SDavid du Colombier 325*3e12c5d1SDavid du Colombier /* 326*3e12c5d1SDavid du Colombier * turn a row into just a newline 327*3e12c5d1SDavid du Colombier */ 328*3e12c5d1SDavid du Colombier void 329*3e12c5d1SDavid du Colombier setempty(Tokenrow *trp) 330*3e12c5d1SDavid du Colombier { 331*3e12c5d1SDavid du Colombier trp->tp = trp->bp; 332*3e12c5d1SDavid du Colombier trp->lp = trp->bp+1; 333*3e12c5d1SDavid du Colombier *trp->bp = nltoken; 334*3e12c5d1SDavid du Colombier } 335*3e12c5d1SDavid du Colombier 336*3e12c5d1SDavid du Colombier /* 337*3e12c5d1SDavid du Colombier * generate a number 338*3e12c5d1SDavid du Colombier */ 339*3e12c5d1SDavid du Colombier char * 340*3e12c5d1SDavid du Colombier outnum(char *p, int n) 341*3e12c5d1SDavid du Colombier { 342*3e12c5d1SDavid du Colombier if (n>=10) 343*3e12c5d1SDavid du Colombier p = outnum(p, n/10); 344*3e12c5d1SDavid du Colombier *p++ = n%10 + '0'; 345*3e12c5d1SDavid du Colombier return p; 346*3e12c5d1SDavid du Colombier } 347*3e12c5d1SDavid du Colombier 348*3e12c5d1SDavid du Colombier /* 349*3e12c5d1SDavid du Colombier * allocate and initialize a new string from s, of length l, at offset o 350*3e12c5d1SDavid du Colombier * Null terminated. 351*3e12c5d1SDavid du Colombier */ 352*3e12c5d1SDavid du Colombier uchar * 353*3e12c5d1SDavid du Colombier newstring(uchar *s, int l, int o) 354*3e12c5d1SDavid du Colombier { 355*3e12c5d1SDavid du Colombier uchar *ns = (uchar *)domalloc(l+o+1); 356*3e12c5d1SDavid du Colombier 357*3e12c5d1SDavid du Colombier ns[l+o] = '\0'; 358*3e12c5d1SDavid du Colombier return (uchar*)strncpy((char*)ns+o, (char*)s, l) - o; 359*3e12c5d1SDavid du Colombier } 360