⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclscan.c

📁 tcl是工具命令语言
💻 C
📖 第 1 页 / 共 2 页
字号:
    if (totalVars > 0) {	objs = (Tcl_Obj **) ckalloc(sizeof(Tcl_Obj*) * totalVars);	for (i = 0; i < totalVars; i++) {	    objs[i] = NULL;	}    }    string = Tcl_GetStringFromObj(objv[1], NULL);    baseString = string;    /*     * Iterate over the format string filling in the result objects until     * we reach the end of input, the end of the format string, or there     * is a mismatch.     */    objIndex = 0;    nconversions = 0;    while (*format != '\0') {	format += Tcl_UtfToUniChar(format, &ch);	flags = 0;	/*	 * If we see whitespace in the format, skip whitespace in the string.	 */	if (Tcl_UniCharIsSpace(ch)) {	    offset = Tcl_UtfToUniChar(string, &sch);	    while (Tcl_UniCharIsSpace(sch)) {		if (*string == '\0') {		    goto done;		}		string += offset;		offset = Tcl_UtfToUniChar(string, &sch);	    }	    continue;	}	    	if (ch != '%') {	    literal:	    if (*string == '\0') {		underflow = 1;		goto done;	    }	    string += Tcl_UtfToUniChar(string, &sch);	    if (ch != sch) {		goto done;	    }	    continue;	}	format += Tcl_UtfToUniChar(format, &ch);	if (ch == '%') {	    goto literal;	}	/*	 * Check for assignment suppression ('*') or an XPG3-style	 * assignment ('%n$').	 */	if (ch == '*') {	    flags |= SCAN_SUPPRESS;	    format += Tcl_UtfToUniChar(format, &ch);	} else if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */	    value = strtoul(format-1, &end, 10); /* INTL: "C" locale. */	    if (*end == '$') {		format = end+1;		format += Tcl_UtfToUniChar(format, &ch);		objIndex = (int) value - 1;	    }	}	/*	 * Parse any width specifier.	 */	if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */	    width = strtoul(format-1, &format, 10); /* INTL: "C" locale. */	    format += Tcl_UtfToUniChar(format, &ch);	} else {	    width = 0;	}	/*	 * Handle any size specifier.	 */	switch (ch) {	case 'l':	case 'L':#ifndef TCL_WIDE_INT_IS_LONG	    flags |= SCAN_LONGER;#endif	    /*	     * Fall through so we skip to the next character.	     */	case 'h':	    format += Tcl_UtfToUniChar(format, &ch);	}	/*	 * Handle the various field types.	 */	switch (ch) {	    case 'n':		if (!(flags & SCAN_SUPPRESS)) {		    objPtr = Tcl_NewIntObj(string - baseString);		    Tcl_IncrRefCount(objPtr);		    objs[objIndex++] = objPtr;		}		nconversions++;		continue;	    case 'd':		op = 'i';		base = 10;		fn = (long (*)())strtol;#ifndef TCL_WIDE_INT_IS_LONG		lfn = (Tcl_WideInt (*)())strtoll;#endif		break;	    case 'i':		op = 'i';		base = 0;		fn = (long (*)())strtol;#ifndef TCL_WIDE_INT_IS_LONG		lfn = (Tcl_WideInt (*)())strtoll;#endif		break;	    case 'o':		op = 'i';		base = 8;		fn = (long (*)())strtoul;#ifndef TCL_WIDE_INT_IS_LONG		lfn = (Tcl_WideInt (*)())strtoull;#endif		break;	    case 'x':		op = 'i';		base = 16;		fn = (long (*)())strtoul;#ifndef TCL_WIDE_INT_IS_LONG		lfn = (Tcl_WideInt (*)())strtoull;#endif		break;	    case 'u':		op = 'i';		base = 10;		flags |= SCAN_UNSIGNED;		fn = (long (*)())strtoul;#ifndef TCL_WIDE_INT_IS_LONG		lfn = (Tcl_WideInt (*)())strtoull;#endif		break;	    case 'f':	    case 'e':	    case 'g':		op = 'f';		break;	    case 's':		op = 's';		break;	    case 'c':		op = 'c';		flags |= SCAN_NOSKIP;		break;	    case '[':		op = '[';		flags |= SCAN_NOSKIP;		break;	}	/*	 * At this point, we will need additional characters from the	 * string to proceed.	 */	if (*string == '\0') {	    underflow = 1;	    goto done;	}		/*	 * Skip any leading whitespace at the beginning of a field unless	 * the format suppresses this behavior.	 */	if (!(flags & SCAN_NOSKIP)) {	    while (*string != '\0') {		offset = Tcl_UtfToUniChar(string, &sch);		if (!Tcl_UniCharIsSpace(sch)) {		    break;		}		string += offset;	    }	    if (*string == '\0') {		underflow = 1;		goto done;	    }	}	/*	 * Perform the requested scanning operation.	 */		switch (op) {	    case 's':		/*		 * Scan a string up to width characters or whitespace.		 */		if (width == 0) {		    width = (size_t) ~0;		}		end = string;		while (*end != '\0') {		    offset = Tcl_UtfToUniChar(end, &sch);		    if (Tcl_UniCharIsSpace(sch)) {			break;		    }		    end += offset;		    if (--width == 0) {			break;		    }		}		if (!(flags & SCAN_SUPPRESS)) {		    objPtr = Tcl_NewStringObj(string, end-string);		    Tcl_IncrRefCount(objPtr);		    objs[objIndex++] = objPtr;		}		string = end;		break;	    case '[': {		CharSet cset;		if (width == 0) {		    width = (size_t) ~0;		}		end = string;		format = BuildCharSet(&cset, format);		while (*end != '\0') {		    offset = Tcl_UtfToUniChar(end, &sch);		    if (!CharInSet(&cset, (int)sch)) {			break;		    }		    end += offset;		    if (--width == 0) {			break;		    }		}		ReleaseCharSet(&cset);		if (string == end) {		    /*		     * Nothing matched the range, stop processing		     */		    goto done;		}		if (!(flags & SCAN_SUPPRESS)) {		    objPtr = Tcl_NewStringObj(string, end-string);		    Tcl_IncrRefCount(objPtr);		    objs[objIndex++] = objPtr;		}		string = end;				break;	    }	    case 'c':		/*		 * Scan a single Unicode character.		 */		string += Tcl_UtfToUniChar(string, &sch);		if (!(flags & SCAN_SUPPRESS)) {		    objPtr = Tcl_NewIntObj((int)sch);		    Tcl_IncrRefCount(objPtr);		    objs[objIndex++] = objPtr;		}		break;	    case 'i':		/*		 * Scan an unsigned or signed integer.		 */		if ((width == 0) || (width > sizeof(buf) - 1)) {		    width = sizeof(buf) - 1;		}		flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO;		for (end = buf; width > 0; width--) {		    switch (*string) {			/*			 * The 0 digit has special meaning at the beginning of			 * a number.  If we are unsure of the base, it			 * indicates that we are in base 8 or base 16 (if it is			 * followed by an 'x').			 *			 * 8.1 - 8.3.4 incorrectly handled 0x... base-16			 * cases for %x by not reading the 0x as the			 * auto-prelude for base-16. [Bug #495213]			 */			case '0':			    if (base == 0) {				base = 8;				flags |= SCAN_XOK;			    }			    if (base == 16) {				flags |= SCAN_XOK;			    }			    if (flags & SCAN_NOZERO) {				flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS					| SCAN_NOZERO);			    } else {				flags &= ~(SCAN_SIGNOK | SCAN_XOK					| SCAN_NODIGITS);			    }			    goto addToInt;			case '1': case '2': case '3': case '4':			case '5': case '6': case '7':			    if (base == 0) {				base = 10;			    }			    flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);			    goto addToInt;			case '8': case '9':			    if (base == 0) {				base = 10;			    }			    if (base <= 8) {				break;			    }			    flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);			    goto addToInt;			case 'A': case 'B': case 'C':			case 'D': case 'E': case 'F': 			case 'a': case 'b': case 'c':			case 'd': case 'e': case 'f':			    if (base <= 10) {				break;			    }			    flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS);			    goto addToInt;			case '+': case '-':			    if (flags & SCAN_SIGNOK) {				flags &= ~SCAN_SIGNOK;				goto addToInt;			    }			    break;			case 'x': case 'X':			    if ((flags & SCAN_XOK) && (end == buf+1)) {				base = 16;				flags &= ~SCAN_XOK;				goto addToInt;			    }			    break;		    }		    /*		     * We got an illegal character so we are done accumulating.		     */		    break;		    addToInt:		    /*		     * Add the character to the temporary buffer.		     */		    *end++ = *string++;		    if (*string == '\0') {			break;		    }		}		/*		 * Check to see if we need to back up because we only got a		 * sign or a trailing x after a 0.		 */		if (flags & SCAN_NODIGITS) {		    if (*string == '\0') {			underflow = 1;		    }		    goto done;		} else if (end[-1] == 'x' || end[-1] == 'X') {		    end--;		    string--;		}		/*		 * Scan the value from the temporary buffer.  If we are		 * returning a large unsigned value, we have to convert it back		 * to a string since Tcl only supports signed values.		 */		if (!(flags & SCAN_SUPPRESS)) {		    *end = '\0';#ifndef TCL_WIDE_INT_IS_LONG		    if (flags & SCAN_LONGER) {			wideValue = (Tcl_WideInt) (*lfn)(buf, NULL, base);			if ((flags & SCAN_UNSIGNED) && (wideValue < 0)) {			    /* INTL: ISO digit */			    sprintf(buf, "%" TCL_LL_MODIFIER "u",				    (Tcl_WideUInt)wideValue);			    objPtr = Tcl_NewStringObj(buf, -1);			} else {			    objPtr = Tcl_NewWideIntObj(wideValue);			}		    } else {#endif /* !TCL_WIDE_INT_IS_LONG */			value = (long) (*fn)(buf, NULL, base);			if ((flags & SCAN_UNSIGNED) && (value < 0)) {			    sprintf(buf, "%lu", value); /* INTL: ISO digit */			    objPtr = Tcl_NewStringObj(buf, -1);			} else {			    if ((unsigned long) value > UINT_MAX) {				objPtr = Tcl_NewLongObj(value);			    } else {				objPtr = Tcl_NewIntObj(value);			    }			}#ifndef TCL_WIDE_INT_IS_LONG		    }#endif		    Tcl_IncrRefCount(objPtr);		    objs[objIndex++] = objPtr;		}		break;	    case 'f':		/*		 * Scan a floating point number		 */		if ((width == 0) || (width > sizeof(buf) - 1)) {		    width = sizeof(buf) - 1;		}		flags &= ~SCAN_LONGER;		flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_PTOK | SCAN_EXPOK;		for (end = buf; width > 0; width--) {		    switch (*string) {			case '0': case '1': case '2': case '3':			case '4': case '5': case '6': case '7':			case '8': case '9':			    flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS);			    goto addToFloat;			case '+': case '-':			    if (flags & SCAN_SIGNOK) {				flags &= ~SCAN_SIGNOK;				goto addToFloat;			    }			    break;			case '.':			    if (flags & SCAN_PTOK) {				flags &= ~(SCAN_SIGNOK | SCAN_PTOK);				goto addToFloat;			    }			    break;			case 'e': case 'E':			    /*			     * An exponent is not allowed until there has			     * been at least one digit.			     */			    if ((flags & (SCAN_NODIGITS | SCAN_EXPOK))				    == SCAN_EXPOK) {				flags = (flags & ~(SCAN_EXPOK|SCAN_PTOK))				    | SCAN_SIGNOK | SCAN_NODIGITS;				goto addToFloat;			    }			    break;		    }		    /*		     * We got an illegal character so we are done accumulating.		     */		    break;		    addToFloat:		    /*		     * Add the character to the temporary buffer.		     */		    *end++ = *string++;		    if (*string == '\0') {			break;		    }		}		/*		 * Check to see if we need to back up because we saw a		 * trailing 'e' or sign.		 */		if (flags & SCAN_NODIGITS) {		    if (flags & SCAN_EXPOK) {			/*			 * There were no digits at all so scanning has			 * failed and we are done.			 */			if (*string == '\0') {			    underflow = 1;			}			goto done;		    }		    /*		     * We got a bad exponent ('e' and maybe a sign).		     */		    end--;		    string--;		    if (*end != 'e' && *end != 'E') {			end--;			string--;		    }		}		/*		 * Scan the value from the temporary buffer.		 */		if (!(flags & SCAN_SUPPRESS)) {		    double dvalue;		    *end = '\0';		    dvalue = strtod(buf, NULL);		    objPtr = Tcl_NewDoubleObj(dvalue);		    Tcl_IncrRefCount(objPtr);		    objs[objIndex++] = objPtr;		}		break;	}	nconversions++;    }    done:    result = 0;    code = TCL_OK;    if (numVars) {	/*	 * In this case, variables were specified (classic scan)	 */	for (i = 0; i < totalVars; i++) {	    if (objs[i] != NULL) {		result++;		if (Tcl_ObjSetVar2(interp, objv[i+3], NULL,			objs[i], 0) == NULL) {		    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),			    "couldn't set variable \"",			    Tcl_GetString(objv[i+3]), "\"", (char *) NULL);		    code = TCL_ERROR;		}		Tcl_DecrRefCount(objs[i]);	    }	}    } else {	/*	 * Here no vars were specified, we want a list returned (inline scan)	 */	objPtr = Tcl_NewObj();	for (i = 0; i < totalVars; i++) {	    if (objs[i] != NULL) {		Tcl_ListObjAppendElement(NULL, objPtr, objs[i]);		Tcl_DecrRefCount(objs[i]);	    } else {		/*		 * More %-specifiers than matching chars, so we		 * just spit out empty strings for these		 */		Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewObj());	    }	}    }    if (objs != NULL) {	ckfree((char*) objs);    }    if (code == TCL_OK) {	if (underflow && (nconversions == 0)) {	    if (numVars) {		objPtr = Tcl_NewIntObj(-1);	    } else {		if (objPtr) {		    Tcl_SetListObj(objPtr, 0, NULL);		} else {		    objPtr = Tcl_NewObj();		}	    }	} else if (numVars) {	    objPtr = Tcl_NewIntObj(result);	}	Tcl_SetObjResult(interp, objPtr);    }    return code;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -