📄 ckclib.c
字号:
strcpy(q,s); /* (no need for ckstrncpy() here) */ }#ifdef DEBUG else { /* This would be a really bad error */ char tmp[24]; /* So get a good record of it. */ if (x > 23) { ckstrncpy(tmp,s,20); strcpy(tmp+20,"..."); tmp[23] = NUL; } else { ckstrncpy(tmp,s,24); } debug(F110,"MAKESTR MALLOC FAILURE ",s,0); }#endif /* DEBUG */ } else q = NULL; /* Length of string is zero */ if (*p) { /* Now free the original storage. */#ifdef BETATEST memset(*p,0xFF,sizeof(**p)); /* (not portable) */#endif /* BETATEST */ free(*p); }#ifdef COMMENT *q = NULL; /* Set up return pointer */ if (q) *p = q;#else *p = q; /* This is exactly the same */#endif /* COMMENT */}/* X M A K E S T R -- Non-destructive makestr() if s is NULL. */VOID#ifdef CK_ANSICxmakestr(char **p, const char *s)#elsexmakestr(p,s) char **p, *s;#endif/* xmakestr */ { if (s) makestr(p,s);}/* C K M E M C P Y -- Portable (but slow) memcpy() *//* Copies n bytes from s to p, allowing for overlap. *//* For use when real memcpy() not available. */VOIDckmemcpy(p,s,n) char *p, *s; int n; { char * q = NULL; register int i; int x; if (!s || !p || n <= 0 || p == s) /* Verify args */ return; x = p - s; /* Check for overlap */ if (x < 0) x = 0 - x; if (x < n) { /* They overlap */ q = p; if (!(p = (char *)malloc(n))) /* So use a temporary buffer */ return; } for (i = 0; i < n; i++) /* Copy n bytes */ p[i] = s[i]; if (q) { /* If we used a temporary buffer */ for (i = 0; i < n; i++) /* copy from it to destination */ q[i] = p[i]; if (p) free(p); /* and free the temporary buffer */ }}/* C K S T R C M P -- String comparison with case-matters selection *//* Call with pointers to the two strings, s1 and s2, a length, n, and c == 0 for caseless comparison, nonzero for case matters. Call with n == -1 to compare without a length limit. Compares up to n characters of the two strings and returns: 1 if s1 > s2 0 if s1 = s2 -1 if s1 < s2*/intckstrcmp(s1,s2,n,c) char *s1, *s2; int n, c; { CHAR t1, t2; if (n == 0) return(0); if (!s1) s1 = ""; /* Watch out for null pointers. */ if (!s2) s2 = ""; if (!*s1) return(*s2 ? -1 : 0); if (!*s2) return(1); while (n--) { t1 = (CHAR) *s1++; /* Get next character from each. */ t2 = (CHAR) *s2++; if (!t1) return(t2 ? -1 : 0); if (!t2) return(1); if (!c) { /* If case doesn't matter */ if (isupper(t1)) t1 = tolower(t1); /* Convert case. */ if (isupper(t2)) t2 = tolower(t2); } if (t1 < t2) return(-1); /* s1 < s2 */ if (t1 > t2) return(1); /* s1 > s2 */ } return(0); /* They're equal */}/* C K S T R P R E -- Caseless string prefix comparison *//* Returns position of the first char in the 2 strings that doesn't match */intckstrpre(s1,s2) char *s1, *s2; { CHAR t1, t2; int n = 0; if (!s1) s1 = ""; if (!s2) s2 = ""; while (1) { t1 = (CHAR) *s1++; t2 = (CHAR) *s2++; if (!t1 || !t2) return(n); if (isupper(t1)) t1 = tolower(t1); if (isupper(t2)) t2 = tolower(t2); if (t1 != t2) return(n); n++; }}#define GLOBBING/* C K M A T C H -- Match a string against a pattern *//* Call with a pattern containing * and/or ? metacharacters. icase is 1 if case-sensitive, 0 otherwise. opts is a bitmask: Bit 0: 1 to match strings starting with '.', else 0. Bit 1: 1 = file globbing (dirseps are fences, etc), 0 = ordinary string. Bit 2 (and beyond): Undefined. Works only with NUL-terminated strings. Pattern may contain any number of ? and/or *. If CKREGEX is defined, also [abc], [a-z], and/or {string,string,...}. Returns: 0 if string does not match pattern, 1 if it does. To be done: Find a way to identify the piece of the string that matched the pattern, as in Snobol "LINE (PAT . RESULT)". Some prelinary attempts are commented out (see "mstart"); these fail because they always indicate the entire string. The piece we want (I think) is the the part that matches the first non-* segment of the pattern through the final non-* part. If this can be done, we can streamline INPUT and friends considerably, and also add regexp support to functions like \findex(\fpattern(a*b),\%s). INPUT accomplishes this now by repeated calls to ckmatch, which is overkill.*/#ifdef COMMENTchar * ckmstring = NULL;#endif /* COMMENT */intckmatch(pattern, string, icase, opts) char *pattern,*string; int icase, opts; { int q = 0, i = 0, k = -1, x, flag = 0; CHAR cp; /* Current character from pattern */ CHAR cs; /* Current character from string */ char * psave = NULL; int dot, globbing;#ifdef COMMENT char * mstart = NULL; /* Pointer to beginning of match */#endif /* COMMENT */ dot = opts & 1; globbing = opts & 2;#ifdef COMMENT makestr(&ckmstring,NULL);#endif /* COMMENT */ if (!pattern) pattern = ""; if (!*pattern) return(1); /* Null pattern always matches */ if (!string) string = ""; debug(F110,"ckmatch string",string,0); debug(F111,"ckmatch pattern",pattern,opts);#ifdef COMMENT mstart = string;#endif /* COMMENT */#ifdef UNIX if (!dot) { /* For UNIX file globbing */ if (*string == '.' && *pattern != '.' && !matchdot) { if (#ifdef CKREGEX *pattern != '{' && *pattern != '['#else 1#endif /* CKREGEX */ ) { debug(F110,"ckmatch skip",string,0); return(0); } } }#endif /* UNIX */ while (1) { k++; cp = *pattern; /* Character from pattern */ cs = *string; /* Character from string */ if (!cs) { /* End of string - done. */ x = (!cp || (cp == '*' && !*(pattern+1))) ? 1 : 0;#ifdef COMMENT if (x) makestr(&ckmstring,mstart);#endif /* COMMENT */ return(x); } if (!icase) { /* If ignoring case */ if (isupper(cp)) /* convert both to lowercase. */ cp = tolower(cp); if (isupper(cs)) cs = tolower(cs); } if (q) { /* This character was quoted */ q = 0; /* Turn off quote flag */ if (cs == cp) /* Compare directly */ pattern++, string++; /* no metacharacters */ continue; } if (cp == CMDQ && !q) { /* Quote in pattern */ q = 1; /* Set flag */ pattern++; /* Advance to next pattern character */ cp = *pattern; /* Case conversion... */ if (!icase) if (isupper(cp)) cp = tolower(cp); if (cp != cs) /* Literal char so compare now */ return(0); /* No match, done. */ string++, pattern++; /* They match so advance pointers */ continue; /* and continue. */ } if (cs && cp == '?') { /* '?' matches any char */ pattern++, string++; continue;#ifdef CKREGEX } else if (cp == '[') { /* Have bracket */ int q = 0; /* My own private q */ 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 */ for (flag = 0; !flag; pattern++) { /* Loop thru pattern */ c = (unsigned)*pattern; /* Current char */ if (q) { /* Quote within brackets */ q = 0; clist[c] = 1; continue; } if (!icase) /* Case conversion */ if (isupper(c)) c = tolower(c); switch (c) { /* Handle unquoted character */ case NUL: /* End of string */ return(0); /* No matching ']' so fail */ case CMDQ: /* Next char is quoted */ q = 1; /* Set flag */ continue; /* and continue. */ case '-': /* A range is specified */ c1 = (pattern > psave) ? (unsigned)*(pattern-1) : NUL; c2 = (unsigned)*(pattern+1); if (c2 == ']') c2 = NUL; if (c1 == NUL) c1 = c2; for (c = c1; c <= c2; c++) clist[c] = 1; continue; case ']': /* End of bracketed sequence */ flag = 1; /* Done with FOR loop */ break; /* Compare what we have */ default: /* Just a char */ clist[c] = 1; /* Record it */ continue; } } if (!clist[(unsigned)cs]) /* Match? */ return(0); /* Nope, done. */ string++; /* Yes, advance string pointer */ continue; /* and go on. */ } else if (cp == '{') { /* Braces with list of strings */ char * p, * s, * s2, * buf = NULL; int n, bc = 0; int len = 0; for (p = pattern++; *p; p++) { if (*p == '{') bc++; if (*p == '}') bc--; if (bc < 1) break; } if (bc != 0) { /* Braces don't match */ return(0); /* Fail */ } else { /* Braces do match */ int q = 0, done = 0; len = *p ? strlen(p+1) : 0; /* Length of rest of pattern */ n = p - pattern; /* Size of list in braces */ if (buf = (char *)malloc(n+1)) { /* Copy so we can poke it */ char * tp = NULL; int k; ckstrncpy(buf,pattern,n+1); n = 0; for (s = s2 = buf; 1; s++) { /* Loop through segments */ n++; if (q) { /* This char is quoted */ q = 0; if (!*s) done = 1; continue; } if (*s == CMDQ && !q) { /* Quote next char */ q = 1; continue; } if (!*s || *s == ',') { /* End of this segment */ if (!*s) /* If end of buffer */ done = 1; /* then end of last segment */ *s = NUL; /* Overwrite comma with NUL */ if (!*s2) { /* Empty segment, no advancement */ k = 0; } else if (tp = (char *)malloc(n+len+1)) { strcpy(tp,s2); /* Current segment */ strcat(tp,p+1); /* Add rest of pattern */ tp[n+len] = NUL; k = ckmatch(tp,string,icase,opts); free(tp); if (k > 0) { /* If it matched we're done */#ifdef COMMENT makestr(&ckmstring,mstart);#endif /* COMMENT */ return(1); } } else { /* Malloc failure, just compare */ k = !ckstrcmp(tp,string,n-1,icase); } if (k) { /* Successful comparison */ string += n-1; /* Advance pointers */ pattern = p+1; break; } if (done) /* If no more segments */ break; /* break out of segment loop. */ s2 = s+1; /* Otherwise, on to next segment */ n = 0; } } free(buf); } }#endif /* CKREGEX */ } else if (cp == '*') { /* Asterisk */ char * p, * s = NULL; int k, n, q = 0; while (*pattern == '*') /* Collapse successive asterisks */ pattern++; psave = pattern; /* First non-asterisk after asterisk */ for (n = 0, p = psave; *p; p++,n++) { /* Find next meta char */ if (!q) { if (*p == '?' || *p == '*' || *p == CMDQ#ifdef CKREGEX || *p == '[' || *p == '{'#endif /* CKREGEX */ ) break;#ifdef GLOBBING if (globbing#ifdef UNIXOROSK && *p == '/'#else#ifdef VMS && (*p == '.' || *p == ']' || *p == '<' || *p == '>' || *p == ':' || *p == ';')#else#ifdef datageneral && *p == ':'#else#ifdef STRATUS && *p == '>'#endif /* STRATUS */#endif /* datageneral */#endif /* VMS */#endif /* UNIXOROSK */ ) break;#endif /* GLOBBING */ } } if (n > 0) { /* Literal string to match */ s = (char *)malloc(n+1); if (s) { ckstrncpy(s,psave,n+1); /* Copy cuz no poking original */ debug(F111,"XXX",s,n+1); if (*p == '*') k = ckindex(s,string,0,0,icase); /* 1-based index() */ else k = ckindex(s,string,-1,1,icase); /* 1-based rindex() */ free(s); if (k < 1) return(0); string += k + n - 1; pattern += n; continue; } } else if (!*p) { /* Asterisk at end matches the rest */ if (!globbing) { /* (if not filename globbing) */#ifdef COMMENT makestr(&ckmstring,mstart);#endif /* COMMENT */ return(1); }#ifdef GLOBBING while (*string) { /* Globbing so don't cross fields */ if (globbing#ifdef UNIXOROSK && *string == '/'#else#ifdef VMS && (*string == '.' || *string == ']' || *string == '<' || *string == '>' || *string == ':' || *string == ';')#else#ifdef datageneral && *string == ':'#else#ifdef STRATUS && *string == '>'#endif /* STRATUS */#endif /* datageneral */#endif /* VMS */#endif /* UNIXOROSK */ ) return(0); string++; }#endif /* GLOBBING */#ifdef COMMENT makestr(&ckmstring,mstart);#endif /* COMMENT */ return(1); } else { /* A meta char follows asterisk */ while (*string && (k = ckmatch(p,string,icase,opts) < 1)) string++;#ifdef COMMENT if (*string) makestr(&ckmstring,mstart);#endif /* COMMENT */ return(*string ? 1 : 0); } } else if (cs == cp) { pattern++, string++; continue; } else return(0); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -