X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=ckclib.c;fp=ckclib.c;h=ac6f62df23e2dbbdf8c6fd9e32c08510ec8f44b9;hb=31e271107096d1ffa97b7d0c15222b8bd5e69f74;hp=36bf111acff4ec01472559f87fbb7bc1d6b2632f;hpb=8d5a97cca5dc3d41681e7a2dd709ac0ea93e73c5;p=ckermit.git diff --git a/ckclib.c b/ckclib.c index 36bf111..ac6f62d 100644 --- a/ckclib.c +++ b/ckclib.c @@ -1,4 +1,4 @@ -char * cklibv = "C-Kermit library, 8.0.033, 16 Mar 2003"; +char * cklibv = "C-Kermit library, 9.0.049, 30 Dec 2010"; #define CKCLIB_C @@ -8,7 +8,7 @@ char * cklibv = "C-Kermit library, 8.0.033, 16 Mar 2003"; Author: Frank da Cruz , Columbia University Academic Information Systems, New York City. - Copyright (C) 1999, 2004, + Copyright (C) 1999, 2010, Trustees of Columbia University in the City of New York. All rights reserved. See the C-Kermit COPYING.TXT file or the copyright text in the ckcmai.c module for disclaimer and permissions. @@ -33,6 +33,8 @@ char * cklibv = "C-Kermit library, 8.0.033, 16 Mar 2003"; ckuitoa() - Converts unsigned int to string. ckltoa() - Converts long to string. ckultoa() - Converts unsigned long to string. + ckfstoa() - Converts off_t-type integer (long or long long) to string. + ckatofs() - Converts a numeric string to an off_t-type integer. ckctoa() - Converts char to string. ckmakmsg() - Constructs a message from 4 source strings. ckmakxmsg() - Constructs a message from 12 source strings. @@ -59,6 +61,7 @@ char * cklibv = "C-Kermit library, 8.0.033, 16 Mar 2003"; ulongtohex() - Converts an unsigned long to a hex string. hextoulong() - Converts a hex string to an unsigned long. cksplit() - Splits a string into an array of words. + ispattern() - Tells if argument string is a pattern. Prototypes are in ckclib.h. @@ -188,7 +191,7 @@ ckstrncat(dest,src,len) char * dest, * src; int len; s1--; /* (back up over NUL) */ i = 0; - s2 = src; + s2 = (char *)src; while (*s2++) i++; /* i = strlen(src); */ if (i > (len-j)) @@ -200,7 +203,7 @@ ckstrncat(dest,src,len) char * dest, * src; int len; strncpy(&dest[j],src,i); #else j = i; /* This should be a bit faster... */ - s2 = src; /* depends on strcpy implementation; */ + s2 = (char *)src; /* depends on strcpy implementation; */ while ((*s1++ = *s2++) && j--) /* at least it shouldn't be slower. */ ; dest[len-1] = NUL; /* In case of early exit. */ @@ -277,6 +280,7 @@ ckmakxmsg(buf,len,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12) char *s; char *p, *a[12]; + if (!buf) return(n); /* No destination */ if (len < 1) return(n); /* No size */ @@ -496,7 +500,7 @@ ckultoa(unsigned long n) #else ckultoa(n) unsigned long n; #endif /* CK_ANSIC */ -/* ckltoa */ { +/* ckultoa */ { char buf[32]; /* Internal working buffer */ char * p, * s, * q; int k, x, len = 0; @@ -550,6 +554,84 @@ ckltox(n) long n; } +/* C K F S T O A -- File Size (or offset) to string */ + +/* This is just like ckltoa() except for the data type of the argument. */ +/* It's mainly for printing file sizes without having to know their data */ +/* type, so we don't have to hardware "%ld" or "%lld" into printf()s. */ +/* Works for 32 or 64 bits, according to CK_OFF_T definition. */ + +char * +#ifdef CK_ANSIC +ckfstoa(CK_OFF_T n) +#else +ckfstoa(n) CK_OFF_T n; +#endif /* CK_ANSIC */ +/* ckfstoa */ { + char buf[32]; /* Internal working buffer */ + char * p, * s, * q; + int k, x, len = 0, sign = 0; + + if (n < (CK_OFF_T)0) { /* Sign */ + n = (CK_OFF_T)0 - n; + sign = 1; + } + buf[31] = NUL; /* 2^63-1 is about 20 decimal digits */ + for (k = 30; k > 0; k--) { /* Convert number to string */ + x = n % (CK_OFF_T)10; + if (x < 0) { + /* x += 10; */ + ckstrncpy(&buf[23],"OVERFLOW",32); + sign = 0; + k = 23; + break; + } + buf[k] = x + '0'; + n = n / (CK_OFF_T)10; + if (!n) + break; + } + if (sign) buf[--k] = '-'; /* Add sign if necessary */ + len = 31 - k; + if (len + numbp > NUMBUF) + numbp = 0; + p = numbuf + numbp; + q = p; + s = buf + k; + while ((*p++ = *s++)) ; /* Copy */ + *p++ = NUL; + numbp += len+1; + return(q); /* Return pointer */ +} + +/* C K A T O F S -- String to File Size (or offset) */ + +/* This is the inverse of ckfstoa(), a replacement for atol() that works */ +/* for either 32-bit or 64-bit arguments, according to CK_OFF_T definition. */ +/* Like atol(), there is no error indication. */ + +CK_OFF_T +#ifdef CK_ANSIC +ckatofs(char * s) +#else +ckatofs(s) char * s; +#endif /* CK_ANSIC */ +/* ckatofs */ { + CK_OFF_T result = (CK_OFF_T)0; + int minus = 0; + while (*s && (*s == SP || *s == HT)) s++; + if (*s == '+') s++; + if (*s == '-') { + minus = 1; + s++; + } + while (isdigit(*s)) { + result = (result * (CK_OFF_T)10) + (CK_OFF_T)(*s - '0'); + s++; + } + return(minus ? -result : result); +} + /* C K I T O A -- Int to string -- FOR DISCIPLINED USE ONLY */ char * @@ -710,6 +792,7 @@ brstrip(p) char *p; { #else /* New version handles braces and doublequotes */ +/* WARNING: this function writes into its argument, it always has. */ char * brstrip(p) char *p; { @@ -1265,6 +1348,7 @@ ckstrpre(s1,s2) char *s1, *s2; { regular expression it matches any string of zero or more a's followed by one b. Regular expressions are especially useful in matching strings of (say) digits, or letters, e.g. "[0-9]*" matches any string of digits. + So far, Kermit doesn't do this. */ static char * mypat = NULL; /* For rewriting pattern */ static int matchpos = 0; @@ -1276,13 +1360,44 @@ static char * ostring = NULL; #define MATCHRETURN(x,y) { rc=y; where=x; goto xckmatch; } static char * lastpat = NULL; +static int xxflag = 0; /* Global bailout flag for ckmatch() */ + +int +ispattern(s) char * s; { + int quote = 0, sbflag = 0, sb = 0, cbflag = 0, cb = 0; + + char c = 0; + if (*s == '^') return(1); + while ((c = *s++)) { + if (quote) { + quote = 0; + continue; + } + if (c == '\\') { + quote = 1; + continue; + } + if (c == '*') return(1); + if (c == '?') return(1); + /* Unquoted brackets or braces must match */ + if (c == '[') { sbflag++; sb++; continue; } + if (c == ']') { sb--; continue; } + if (c == '{') { cbflag++; cb++; continue; } + if (c == '}') { cb--; continue; } + if (!*s && c == '$') return(1); + } + return(sbflag || cbflag); +} + int ckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; { int q = 0, i = 0, k = -1, x, flag = 0; int rc = 0; /* Return code */ + int havestar = 0; int where = -1; CHAR cp; /* Current character from pattern */ CHAR cs; /* Current character from string */ + char * patstart; /* Start of pattern */ int plen, dot, globbing, xstar = 0; int bronly = 0; /* Whole pattern is {a,b,c,...} */ @@ -1294,11 +1409,17 @@ ckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; { if (!string) string = ""; if (!pattern) pattern = ""; + if (!*pattern) { /* Empty pattern matches anything */ matchdepth++; /* (it wasn't incremented yet) */ MATCHRETURN(0,1); + } else if (!*string) { + MATCHRETURN(0,0); } + patstart = pattern; /* Remember beginning of pattern */ + if (matchdepth == 0) { /* Top-level call? */ + xxflag = 0; stringpos = 0; /* Reset indices etc. */ matchpos = 0; matchend = 0; @@ -1307,7 +1428,7 @@ ckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; { if (*pattern == '{') /* Entire pattern is {a,b.c} */ bronly = 1; /* Maybe */ dot = (opts & 1) || /* Match leading dot (if file) */ - (opts & 2 == 0) || /* always if not file */ + ((opts & 2) == 0) || /* always if not file */ (pattern[0] == '.'); /* or if pattern starts with '.' */ plen = strlen(pattern); /* Length of pattern */ @@ -1428,7 +1549,8 @@ ckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; { } debug(F110,"CKMATCH ? pat",pattern,0); debug(F110,"CKMATCH ? str",string,0); - pattern++, string++; + pattern++; + string++; stringpos++; continue; #ifdef CKREGEX @@ -1437,12 +1559,14 @@ ckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; { char * psave = NULL; /* and backup pointer */ CHAR clist[256]; /* Character list from brackets */ CHAR c, c1, c2; + for (i = 0; i < 256; i++) /* memset() etc not portable */ clist[i] = NUL; psave = ++pattern; /* Where pattern starts */ debug(F111,"CKMATCH [] ",pattern-1, matchpos); for (flag = 0; !flag; pattern++) { /* Loop thru pattern */ c = (CHAR)*pattern; /* Current char */ + debug(F000,">>> pattern char","",c); if (q) { /* Quote within brackets */ q = 0; clist[c] = 1; @@ -1488,8 +1612,30 @@ ckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; { continue; } } - if (!clist[(unsigned)cs]) { /* Match? */ - MATCHRETURN(5,0); /* Nope, done. */ + debug(F000,">>> cs","",cs); + debug(F101,">>> clist[cs]","",clist[cs]); + debug(F000,">>> string",string,*string); + + if (!clist[(unsigned)cs]) { /* No match? */ + if (!*string) { /* This clause 16 Jun 2005 */ + MATCHRETURN(5,0); /* Nope, done. */ + } +/* + We need to fail here if the [clist] is not allowed to float. + The [clist] is not allowed to float if it is not preceded + by an asterisk, right? 30 Dec 2005. +*/ + if (!havestar) { + MATCHRETURN(500,0); + } + string++; /* From here to end added 2005/6/15 */ + stringpos++; + pattern = lastpat; /* Back up pattern */ + k = ckmatch(pattern,string,icase,opts); + if (xxflag) MATCHRETURN(0,0); + if (!matchpos && k > 0) + matchpos = stringpos; + MATCHRETURN(5, (*string) ? matchpos : 0); } if (!matchpos) { matchpos = stringpos; @@ -1599,6 +1745,7 @@ ckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; { #endif /* DEBUG */ free(tp); tp = NULL; + if (xxflag) MATCHRETURN(0,0); if (k == 0) { matchpos = savpos; } @@ -1632,6 +1779,7 @@ ckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; { char * psave; char * p, * s = NULL; /* meaning match anything */ int k, n, q = 0; + havestar++; /* The rest can float */ while (*pattern == '*') /* Collapse successive asterisks */ pattern++; psave = pattern; /* First non-asterisk after asterisk */ @@ -1762,19 +1910,39 @@ ckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; { } else { /* A meta char follows asterisk */ if (!*string) MATCHRETURN(17, matchpos = 0); - while (*string && (k = ckmatch(p,string,icase,opts) < 1)) { +#ifdef COMMENT + /* This is more elegant but it doesn't work. */ + p--; + string++; + stringpos++; + k = ckmatch(p,string,icase,opts); +#else + while (*string && ((k = ckmatch(p,string,icase,opts)) < 1)) { + if (xxflag) MATCHRETURN(0,0); string++; stringpos++; } + if (!*string && k < 1) { +/* + Definitely no match so we set a global flag to inibit further backing up + and retrying by previous incarnations, since they don't see that the string + and/or pattern, which are on the stack, have been exhausted at this level. +*/ + xxflag++; + debug(F111,"CKMATCH DEFINITELY NO MATCH",p,k); + MATCHRETURN(91,0); + } +#endif /* COMMENT */ debug(F111,"CKMATCH * k",string, k); if (!matchpos && k > 0) { matchpos = stringpos; - debug(F111,"CKMATCH *",string, matchpos); + debug(F111,"CKMATCH * matchpos",string, matchpos); } MATCHRETURN(12, (*string) ? matchpos : 0); } } else if (cs == cp) { - pattern++, string++; + pattern++; + string++; stringpos++; if (!matchpos) { matchpos = stringpos; @@ -1788,20 +1956,21 @@ ckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; { xckmatch: { #ifdef DEBUG - char msgbuf[96]; + char msgbuf[256]; #endif /* DEBUG */ if (matchdepth > 0) matchdepth--; matchpos = rc; #ifdef DEBUG - ckmakxmsg(msgbuf,96, + ckmakxmsg(msgbuf,256, "CKMATCH RETURN[", ckitoa(where), "] matchpos=", ckitoa(matchpos), " matchdepth=", ckitoa(matchdepth), - " string=",NULL,NULL,NULL,NULL,NULL + " pat=",pattern, + " string=",string,NULL,NULL ); debug(F110,msgbuf,string,0); #endif /* DEBUG */ @@ -2016,8 +2185,19 @@ char * ckradix(s,in,out) char * s; int in, out; { char c, *r = rxresult; int d, minus = 0; +#ifdef COMMENT unsigned long zz = 0L; long z = 0L; +#else + /* + To get 64 bits on 32-bit hardware we use off_t, but there + is no unsigned version of off_t, so we lose the ability to + detect overflow. + */ + CK_OFF_T zz = (CK_OFF_T)0; + CK_OFF_T z = (CK_OFF_T)0; +#endif /* COMMENT */ + if (in < 2 || in > 36) /* Verify legal input radix */ return(NULL); if (out < 2 || out > 36) /* and output radix. */ @@ -2222,7 +2402,7 @@ b64tob8(s,n,out,len) char * s,* out; int n, len; { /* Decode */ /* C H K N U M -- See if argument string is an integer */ /* Returns 1 if OK, zero if not OK */ -/* If OK, string should be acceptable to atoi() */ +/* If OK, string should be acceptable to atoi() or atol() or ckatofs() */ /* Allows leading space, sign */ int @@ -2593,7 +2773,7 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { int gr_stk[NESTMAX]; /* Nesting bracket stack */ int gr_lvl = 0; /* Nesting level */ int wordnum = 0; /* Current word number */ - char c = 'A'; /* Current char (dummy start value) */ + CHAR c = 'A'; /* Current char (dummy start value) */ int class = 0; /* Current character class */ int state = ST_BW; /* Current FSA state */ int len = 0; /* Length of current word */ @@ -2601,7 +2781,16 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { int gquote = 0; /* Quoted group */ int cquote = 0; /* Quoted character */ int collapse = 1; /* Collapse adjacent separators */ + int all = 0; /* s3 == ALL */ + int csv = 0; /* s3 == CSV */ + int tsv = 0; /* s3 == TSV */ + int prevstate = -1; + unsigned int hex80 = 128; + unsigned int hexff = 255; + CHAR notsepbuf[256]; + + notsepbuf[0] = NUL; /* Keep set for "ALL" */ if (n4) collapse = 0; /* Don't collapse */ for (i = 0; i < NESTMAX; i++) /* Initialize nesting stack */ @@ -2619,16 +2808,24 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { if (splitting) { /* If splitting n = word count */ n = 0; /* Initialize it */ } else { /* Otherwise */ +#ifdef COMMENT if (n1 < 1) { /* If 0 (or less) */ ck_sval.a_size = 0; /* nothing to do. */ return(&ck_sval); } +#else + if (n1 == 0) { /* If 0 */ + ck_sval.a_size = 0; /* nothing to do. */ + return(&ck_sval); + } +#endif /* COMMENT */ n = n1; /* n = desired word number. */ } slen = 0; /* Get length of s1 */ debug(F111,"cksplit",s1,n); p = s1; + #ifdef COMMENT while (*p++) slen++; /* Make pokeable copy of s1 */ if (!splitbuf || slen > nsplitbuf) { /* Allocate buffer if needed */ @@ -2680,16 +2877,53 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { sep = s2; /* s2 = break set */ if (!sep) sep = ""; notsep = s3; /* s3 = include set */ - if (!notsep) notsep = ""; + if (!notsep) { + notsep = ""; + } else if ((all = !ckstrcmp(notsep,"ALL",3,1)) || + (csv = !ckstrcmp(notsep,"CSV",3,1)) || + (tsv = !ckstrcmp(notsep,"TSV",3,1))) { + int i, flag; CHAR c; + int n = 0; + char * ss; + if (!all && (csv || tsv)) { + all = 1; + collapse = 0; + } + if (csv || tsv) { + all = 1; + collapse = 0; + } + for (i = 1; i < 256; i++) { + flag = 0; + ss = sep; + while (c = *ss++ && !flag) { + if (c == i) flag++; + } + if (!flag) notsepbuf[n++] = c; + } + notsepbuf[n] = NUL; + notsep = (char *)notsepbuf; + debug(F110,"CKMATCH NOTSEPBUF ALL",notsep,0); + } + if (*s && csv) { /* For CSV skip leading whitespace */ + while (*s == SP || *s == HT) + s++; + c = *s; + } + if (n2 == 0 && csv) n2 = 1; /* CSV implies doublequote grouping */ if (n2 < 0) n2 = 63; /* n2 = grouping mask */ grouping = n2; p = ""; /* Pointer to current word */ while (c) { /* Loop through string */ c = *s; class = 0; - if (!cquote && c == CMDQ) { /* If CMDQ */ - cquote++; /* next one is quoted */ - goto nextc; /* go get it */ + if (!csv && !tsv) { /* fdc 2010-12-30 */ + /* In CSV and TSV splitting, backslash is not special */ + if (!cquote && c == CMDQ) { /* If CMDQ */ + cquote++; /* next one is quoted */ + goto nextc; /* go get it */ + } + } if (cquote && c == CMDQ) { /* Quoted CMDQ is special */ if (state != ST_BW) { /* because it can still separate */ @@ -2709,7 +2943,7 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { cquote = 0; x = 1; } else { /* Character is not quoted */ - if (c < SP) { /* Get its class */ + if (!all && c < SP) { /* Get its class */ x = 0; /* x == 0 means "is separator" */ } else if (*sep) { /* Break set given */ ss = sep; @@ -2718,7 +2952,8 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { } else { /* Default break set is */ x = ((c >= 'a' && c <= 'z') || /* all but alphanumerics */ (c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') + (c >= 'A' && c <= 'Z') || + ((unsigned int)c >= hex80 && (unsigned int)c <= hexff) ); } if (x == 0 && *notsep && c) { /* Include set if given */ @@ -2751,6 +2986,10 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { } } } + debug(F000,"cksplit char",s,c); + debug(F101,"cksplit state","",state); + debug(F101,"cksplit class","",class); + switch (state) { /* State switcher... */ case ST_BW: /* BETWEENWORDS */ if (class & CL_OPN) { /* Group opener */ @@ -2761,6 +3000,7 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { if (gr_lvl >= NESTMAX) goto xxsplit; gr_stk[gr_lvl] = gr_cls[ko]; + prevstate = state; state = ST_IG; /* Switch to INGROUP state */ } else if (class & CL_DAT) { /* Data character */ gr_lvl = 0; /* Clear group nesting stack */ @@ -2772,6 +3012,7 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { p--; gquote = 0; } + prevstate = state; state = ST_IW; /* Switch to INWORD state */ } else if (class & CL_QUO) { /* Group quote */ gquote = gr_lvl+1; /* Remember quoted level */ @@ -2784,18 +3025,40 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { case ST_IW: /* INWORD (but not in a group) */ if (class & CL_SEP) { /* Ends on any kind of separator */ *s = NUL; /* Terminate this word */ - wordnum++; /* Count it */ - if (splitting) { /* Dispose of it appropriately */ - if (wordnum > max) { /* Add to array if splitting */ - ck_sval.a_size = -2; + if (csv) { /* If comma-separated list */ + char * s2 = s; /* discard surrounding spaces */ + while (s2 > splitbuf) { /* first backwards... */ + s2--; + if (*s2 == SP || *s2 == HT) + *s2 = NUL; + else + break; + } + s2 = s+1; /* Then forwards... */ + while (*s2 && (*s2 == SP || *s2 == HT)) + *s2++; + s = s2-1; + } + if (!csv || prevstate != ST_IG) { + wordnum++; /* Count it */ + if (splitting || n < 0) { /* Dispose of it appropriately */ + if (wordnum > max) { /* Add to array if splitting */ + ck_sval.a_size = -2; + return(&ck_sval); + } + /* This inelegant bit corrects an edge condition */ + if (csv && !*p && (!c || !*(s+1))) { + wordnum--; + } else { + setword(wordnum,p,len); + } + } else if (wordnum == n) { /* Searching for word n */ + setword(1,p,len); + ck_sval.a_size = 1; return(&ck_sval); } - setword(wordnum,p,len); - } else if (wordnum == n) { /* Searching for word n */ - setword(1,p,len); - ck_sval.a_size = 1; - return(&ck_sval); } + prevstate = state; state = ST_BW; /* Switch to BETWEENWORDS state */ len = 0; } @@ -2803,6 +3066,14 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { case ST_IG: /* INGROUP */ if (class & CL_CLS) { /* Have group closer? */ + if (csv) { + if (*(s+1) == c) { + char *s2 = s; + while ((*s2 = *(s2+1))) s2++; + s++; + c = *s; + } + } if (c == gr_stk[gr_lvl]) { /* Does it match current opener? */ gr_lvl--; /* Yes, pop stack */ if (gr_lvl < 0) /* Don't pop it too much */ @@ -2812,10 +3083,9 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { s++; c = *s; *s = NUL; /* we have word. */ - wordnum++; /* Count and dispose of it. */ len--; - if (splitting) { + if (splitting || n < 0) { if (wordnum > max) { ck_sval.a_size = -2; return(&ck_sval); @@ -2826,6 +3096,7 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { ck_sval.a_size = 1; return(&ck_sval); } + prevstate = state; state = ST_BW; /* Switch to BETWEENWORDS state */ len = 0; } @@ -2846,26 +3117,44 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { } /* while (c) */ if (gr_lvl > 0) { /* In case of an unclosed group */ - if (splitting) { /* make it the last word. */ + if (splitting || n < 0) { /* make it the last word. */ if (++wordnum > max) { ck_sval.a_size = -2; return(&ck_sval); } setword(wordnum,p+1,len); - } else if (wordnum == n) { + } else if (wordnum == n) { /* Counting from left */ setword(1,p+1,len); ck_sval.a_size = 1; return(&ck_sval); - } + } else if (n < 0 && (wordnum + n > -1)) { /* Counting from right */ + char * s = wordarray[wordnum + n + 1]; + if (!s) s = ""; + setword(1,s,strlen(s)); + ck_sval.a_size = 1; + return(&ck_sval); + } } - if (!splitting) { /* Wanted word n but there was none? */ - setword(1,NULL,0); - ck_sval.a_size = 0; + if (!splitting) { /* Fword... */ + if (n < 0 && (wordnum + n > -1)) { /* Counting from right */ + char * s = wordarray[wordnum + n + 1]; + if (!s) s = ""; + setword(1,s,strlen(s)); + ck_sval.a_size = 1; + return(&ck_sval); + } + setword(1,NULL,0); /* From left... */ + ck_sval.a_size = 0; /* but there weren't n words */ return(&ck_sval); } else { /* Succeed otherwise */ ck_sval.a_size = wordnum; +/* + Always put a null element at the end of the array. It does no harm in + the normal case, and it's required if we're making an argv[] array to + pass to execvp(). This element is not included in the count. +*/ if (wordnum < MAXWORDS) - setword(wordnum+1,NULL,0); + setword(wordnum+1,NULL,0); } #ifdef DEBUG if (deblog) { @@ -2880,4 +3169,34 @@ cksplit(fc,n1,s1,s2,s3,n2,n3,n4) int fc,n1,n2,n3,n4; char *s1, *s2, *s3; { return(&ck_sval); } +/* + ckhexbytetoint() expects a string of two hex characters, + returns the int equivalent or -1 on error. +*/ +int +#ifdef CK_ANSIC +ckhexbytetoint( char * s ) +#else +ckhexbytetoint(s) char * s; +#endif /* CK_ANSIC */ +{ + int i, c[2]; + if (!s) return(-1); + if ((int)strlen(s) != 2) return(-1); + for (i = 0; i < 2; i++) { + c[i] = *s++; + if (!c[i]) return(-1); + if (islower(c[i])) c[i] = toupper(c[i]); + if (c[i] >= '0' && c[i] <= '9') { + c[i] -= 0x30; + } else if (c[i] >= 'A' && c[i] <= 'F') { + c[i] -= 0x37; + } else { + return(-1); + } + } + return(c[0] * 16 + c[1]); +} + + /* End of ckclib.c */