void op_fnzconvert3(mval *src, mval* ichset, mval* ochset, mval* dst) { UConverter *from, *to; int dstlen; MV_FORCE_STR(src); if (!gtm_utf8_mode) { /* Unicode not enabled, report error rather than silently ignoring the conversion */ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_INVFCN, 0, ERR_TEXT, 2, LEN_AND_LIT("Three-argument form of $ZCONVERT() is not allowed in the current $ZCHSET")); } MV_FORCE_STR(ichset); MV_FORCE_STR(ochset); /* The only supported names are: "UTF-8", "UTF-16", "UTF-16LE" and "UTF-16BE */ if (NULL == (from = get_chset_desc(&ichset->str))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADCHSET, 2, ichset->str.len, ichset->str.addr); if (NULL == (to = get_chset_desc(&ochset->str))) rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADCHSET, 2, ochset->str.len, ochset->str.addr); dstlen = gtm_conv(from, to, &src->str, NULL, NULL); assert(-1 != dstlen); MV_INIT_STRING(dst, dstlen, stringpool.free); stringpool.free += dst->str.len; }
int f_char(oprtype *a, opctype op) { boolean_t all_lits; unsigned char *base, *outptr, *tmpptr; int argc, ch, char_len, size; mval v; oprtype *argp, argv[CHARMAXARGS]; triple *curr, *last, *root; DCL_THREADGBL_ACCESS; SETUP_THREADGBL_ACCESS; /* If we are not in UTF8 mode, we need to reroute to the $ZCHAR function to handle things correctly */ if (!gtm_utf8_mode) return f_zchar(a, op); all_lits = TRUE; argp = &argv[0]; argc = 0; for (;;) { if (EXPR_FAIL == expr(argp, MUMPS_INT)) return FALSE; assert(TRIP_REF == argp->oprclass); if (OC_ILIT != argp->oprval.tref->opcode) all_lits = FALSE; argc++; argp++; if (TK_COMMA != TREF(window_token)) break; advancewindow(); if (CHARMAXARGS <= argc) { stx_error(ERR_FCHARMAXARGS); return FALSE; } } if (all_lits) { /* All literals, build the function inline */ size = argc * GTM_MB_LEN_MAX; ENSURE_STP_FREE_SPACE(size); base = stringpool.free; argp = &argv[0]; for (outptr = base, char_len = 0; argc > 0; --argc, argp++) { /* For each wide char value, convert to unicode chars in stringpool buffer */ ch = argp->oprval.tref->operand[0].oprval.ilit; if (0 <= ch) { /* As per the M standard, negative code points should map to no characters */ tmpptr = UTF8_WCTOMB(ch, outptr); assert(tmpptr - outptr <= 4); if (tmpptr != outptr) ++char_len; /* yet another valid character. update the character length */ else if (!badchar_inhibit) stx_error(ERR_INVDLRCVAL, 1, ch); outptr = tmpptr; } } stringpool.free = outptr; MV_INIT_STRING(&v, outptr - base, base); v.str.char_len = char_len; v.mvtype |= MV_UTF_LEN; CLEAR_MVAL_BITS(&v); s2n(&v); *a = put_lit(&v); return TRUE; } root = maketriple(op); root->operand[0] = put_ilit(argc + 1); last = root; argp = &argv[0]; for (; argc > 0 ;argc--, argp++) { curr = newtriple(OC_PARAMETER); curr->operand[0] = *argp; last->operand[1] = put_tref(curr); last = curr; } ins_triple(root); *a = put_tref(root); return TRUE; }
socket_struct *iosocket_create(char *sockaddr, uint4 bfsize, int file_des, boolean_t listen_specified) { socket_struct *socketptr; socket_struct *prev_socketptr; socket_struct *socklist_head; boolean_t passive = FALSE; unsigned short port; int ii, save_errno, tmplen, errlen, sockaddrlen; char temp_addr[SA_MAXLITLEN], protocolstr[6], *adptr; const char *errptr; struct addrinfo *ai_ptr; struct addrinfo hints, *addr_info_ptr = NULL; #ifndef VMS struct sockaddr_un *sa_un_ptr, sa_un_trans; mval localpath; mstr transpath; int trans_status; #endif enum socket_protocol protocol; int af; int sd; int errcode; char host_buffer[NI_MAXHOST]; char port_buffer[NI_MAXSERV]; int port_buffer_len; int colon_cnt, protooffset; char *last_2colon = NULL; int addrlen; GTM_SOCKLEN_TYPE tmp_addrlen; if (0 > file_des) { /* no socket descriptor yet */ memset(&hints, 0, SIZEOF(hints)); protooffset = colon_cnt = 0; sockaddrlen = STRLEN(sockaddr); for (ii = sockaddrlen - 1; 0 <= ii; ii--) { if (SEPARATOR == sockaddr[ii]) { colon_cnt++; if (1 == colon_cnt) protooffset = ii + 1; else { last_2colon = &sockaddr[ii]; break; } } } if (0 == colon_cnt) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC); return NULL; } tmplen = sockaddrlen - protooffset; if (SIZEOF(protocolstr) <= tmplen) { /* last piece just too big to be valid */ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PROTNOTSUP, 2, tmplen , &sockaddr[protooffset]); return NULL; } lower_to_upper((uchar_ptr_t)protocolstr, (uchar_ptr_t)&sockaddr[protooffset], tmplen); if (((SIZEOF("TCP") - 1) == tmplen) && (0 == MEMCMP_LIT(protocolstr, "TCP"))) protocol = socket_tcpip; # ifndef VMS else if (((SIZEOF("LOCAL") - 1) == tmplen) && (0 == MEMCMP_LIT(protocolstr, "LOCAL"))) protocol = socket_local; # endif else { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PROTNOTSUP, 2, tmplen , &sockaddr[protooffset]); return NULL; } if (socket_tcpip == protocol) { if (1 == colon_cnt) { /* for listening socket or broadcasting socket */ if (!listen_specified || (SSCANF(sockaddr, PORT_PROTO_FORMAT, &port, protocolstr) < 2)) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC); return NULL; } passive = TRUE; /* We always first try using IPv6 address, if supported */ af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET); if (-1 == (sd = socket(af, SOCK_STREAM, IPPROTO_TCP))) { /* Try creating IPv4 socket */ af = AF_INET; if (-1 == (sd = socket(af, SOCK_STREAM, IPPROTO_TCP))) { save_errno = errno; errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr); return NULL; } } SERVER_HINTS(hints, af); port_buffer_len = 0; I2A(port_buffer, port_buffer_len, port); port_buffer[port_buffer_len]='\0'; if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &addr_info_ptr))) { close(sd); RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); return NULL; } SOCKET_ALLOC(socketptr); socketptr->local.port = port; socketptr->temp_sd = sd; socketptr->sd = FD_INVALID; ai_ptr = &(socketptr->local.ai); memcpy(ai_ptr, addr_info_ptr, SIZEOF(struct addrinfo)); SOCKET_AI_TO_LOCAL_ADDR(socketptr, addr_info_ptr); ai_ptr->ai_addr = SOCKET_LOCAL_ADDR(socketptr); ai_ptr->ai_addrlen = addr_info_ptr->ai_addrlen; ai_ptr->ai_next = NULL; freeaddrinfo(addr_info_ptr); } else { /* connection socket */ assert(2 == colon_cnt); if (listen_specified || (SSCANF(last_2colon + 1, PORT_PROTO_FORMAT, &port, protocolstr) < 2)) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC); return NULL; } /* for connection socket */ SPRINTF(port_buffer, "%hu", port); addrlen = last_2colon - sockaddr; if ('[' == sockaddr[0]) { if (NULL == memchr(sockaddr, ']', addrlen)) { rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC); return NULL; } addrlen -= 2; memcpy(temp_addr, &sockaddr[1], addrlen); } else memcpy(temp_addr, sockaddr, addrlen); temp_addr[addrlen] = 0; CLIENT_HINTS(hints); if (0 != (errcode = getaddrinfo(temp_addr, port_buffer, &hints, &addr_info_ptr))) { RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode); return NULL; } /* we will test all address families in iosocket_connect() */ SOCKET_ALLOC(socketptr); socketptr->remote.ai_head = addr_info_ptr; socketptr->remote.port = port; socketptr->sd = socketptr->temp_sd = FD_INVALID; /* don't mess with 0 */ } # ifndef VMS } else if (socket_local == protocol) { /* should we get_full_path first */ /* check protooffset < sizeof sun_path */ /* protooffset is after colon */ SOCKET_ALLOC(socketptr); socketptr->protocol = socket_local; sa_un_ptr = malloc(SIZEOF(struct sockaddr_un)); sa_un_ptr->sun_family = AF_UNIX; MV_INIT_STRING(&localpath, protooffset - 1, sockaddr); trans_status = TRANS_LOG_NAME(&localpath.str, &transpath, sa_un_trans.sun_path, (int)SIZEOF(sa_un_trans.sun_path), dont_sendmsg_on_log2long); if (SS_LOG2LONG == trans_status) { /* if LOG2LONG, returned len not valid so report untranslated length */ SOCKET_FREE(socketptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG, 4, localpath.str.len, localpath.str.addr, localpath.str.len, SIZEOF(sa_un_trans.sun_path)); return NULL; } memcpy(sa_un_ptr->sun_path, transpath.addr, transpath.len); sa_un_ptr->sun_path[transpath.len] = '\0'; if (listen_specified) { passive = TRUE; socketptr->local.sa = (struct sockaddr *)sa_un_ptr; socketptr->local.ai.ai_family = AF_UNIX; socketptr->local.ai.ai_socktype = SOCK_STREAM; socketptr->local.ai.ai_addrlen = (size_t)((struct sockaddr_un *)0)->sun_path + protooffset; if (-1 == (sd = socket(AF_UNIX, SOCK_STREAM, 0))) { save_errno = errno; SOCKET_FREE(socketptr); errptr = (char *)STRERROR(save_errno); errlen = STRLEN(errptr); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr); return NULL; } socketptr->temp_sd = sd; socketptr->sd = FD_INVALID; } else { socketptr->remote.sa = (struct sockaddr *)sa_un_ptr; /* setup remote fields */ socketptr->remote.ai.ai_family = AF_UNIX; socketptr->remote.ai.ai_socktype = SOCK_STREAM; socketptr->remote.ai.ai_addrlen = (size_t)((struct sockaddr_un *)0)->sun_path + protooffset; socketptr->sd = socketptr->temp_sd = FD_INVALID; /* don't mess with 0 */ } # endif } else
/************************************************************************************************** * Routine to perform string-level case conversion to "upper", "lower" and "title" case. * Since ICU only supports API using UTF-16 representation, case conversion of UTF-8 strings involves * encoding conversion as described below: * 1. First, the UTF-8 source string is converted to UTF-16 representation (u_strFromUTF8()) * which is stored in a local buffer of size MAX_ZCONVBUFF. If this space is not sufficient, * we try to allocate it in heap. * 2. Since case conversion may expand the string, we compute the desired space required by * preflighting the ICU case conversion API and then allocate the space before performing * the real conversion. * 3. Translating the converted UTF-16 string back to UTF-8 is done in stringpool (with similar * preflighting to compute the required space. * NOTE: * Malloc is used only if the size exceeds 2K characters (a very unlikely situation esp. with * case conversion). * ***************************************************************************************************/ void op_fnzconvert2(mval *src, mval *kase, mval *dst) { int index; int32_t src_ustr_len, src_chlen, dst_chlen, ulen, dstlen = 0; UErrorCode status; char *dstbase; UChar src_ustr[MAX_ZCONVBUFF], dst_ustr[MAX_ZCONVBUFF], *src_ustr_ptr, *dst_ustr_ptr; intrpt_state_t prev_intrpt_state; DEFER_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC, prev_intrpt_state); MV_FORCE_STR(kase); if (-1 == (index = verify_case(&kase->str))) { ENABLE_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC, prev_intrpt_state); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADCASECODE, 2, kase->str.len, kase->str.addr); } MV_FORCE_STR(src); /* allocate stringpool */ if (!gtm_utf8_mode) { dstlen = src->str.len; ENSURE_STP_FREE_SPACE(dstlen); dstbase = (char *)stringpool.free; assert(NULL != casemaps[index].m); (*casemaps[index].m)((unsigned char *)dstbase, (unsigned char *)src->str.addr, dstlen); } else if (0 != src->str.len) { MV_FORCE_LEN_STRICT(src); if (2 * src->str.char_len <= MAX_ZCONVBUFF) { /* Check if the stack buffer is sufficient considering the worst case where all characters are surrogate pairs, each of which needs 2 UChars */ src_ustr_ptr = src_ustr; src_ustr_len = MAX_ZCONVBUFF; } else { /* To avoid preflight, allocate (2 * lenght of src->str.char_len). */ src_ustr_len = 2 * src->str.char_len; src_ustr_ptr = (UChar*)malloc(src_ustr_len * SIZEOF(UChar)); } /* Convert UTF-8 src to UTF-16 (UChar*) representation */ status = U_ZERO_ERROR; u_strFromUTF8(src_ustr_ptr, src_ustr_len, &src_chlen, src->str.addr, src->str.len, &status); if (U_FAILURE(status)) { RELEASE_IF_NOT_LOCAL(src_ustr_ptr, src_ustr); if (U_ILLEGAL_CHAR_FOUND == status || U_INVALID_CHAR_FOUND == status) utf8_len_strict((unsigned char *)src->str.addr, src->str.len); /* to report BADCHAR error */ ENABLE_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC, prev_intrpt_state); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ICUERROR, 1, status); /* ICU said bad, we say good or don't recognize error*/ } status = U_ZERO_ERROR; dst_ustr_ptr = dst_ustr; dst_chlen = (*casemaps[index].u)(dst_ustr_ptr, MAX_ZCONVBUFF, src_ustr_ptr, src_chlen, NULL, &status); if ( U_BUFFER_OVERFLOW_ERROR == status ) { status = U_ZERO_ERROR; dst_ustr_ptr = (UChar*)malloc(dst_chlen * SIZEOF(UChar)); /* Now, perform the real conversion with sufficient buffers */ dst_chlen = (*casemaps[index].u)(dst_ustr_ptr, dst_chlen, src_ustr_ptr, src_chlen, NULL, &status); } else if ( U_FILE_ACCESS_ERROR == status ) { RELEASE_IF_NOT_LOCAL(src_ustr_ptr, src_ustr); ENABLE_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC, prev_intrpt_state); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ICUERROR, 1, status); } RELEASE_IF_NOT_LOCAL(src_ustr_ptr, src_ustr); /* Fake the conversion from UTF-16 to UTF-8 to compute the required buffer size */ status = U_ZERO_ERROR; dstlen = 0; u_strToUTF8(NULL, 0, &dstlen, dst_ustr_ptr, dst_chlen, &status); assert(U_BUFFER_OVERFLOW_ERROR == status || U_SUCCESS(status)); if (MAX_STRLEN < dstlen) { RELEASE_IF_NOT_LOCAL(dst_ustr_ptr, dst_ustr); ENABLE_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC, prev_intrpt_state); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN); } ENSURE_STP_FREE_SPACE(dstlen); dstbase = (char *)stringpool.free; status = U_ZERO_ERROR; u_strToUTF8(dstbase, dstlen, &ulen, dst_ustr_ptr, dst_chlen, &status); if (U_FAILURE(status)) { RELEASE_IF_NOT_LOCAL(src_ustr_ptr, src_ustr); RELEASE_IF_NOT_LOCAL(dst_ustr_ptr, dst_ustr); ENABLE_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC, prev_intrpt_state); rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ICUERROR, 1, status); /* ICU said bad, but same call above just returned OK */ } assertpro(ulen == dstlen); RELEASE_IF_NOT_LOCAL(dst_ustr_ptr, dst_ustr); } MV_INIT_STRING(dst, dstlen, dstbase); stringpool.free += dstlen; ENABLE_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC, prev_intrpt_state); }
/* * ---------------------------------------------------------- * Set version of $extract * * Arguments: * src - source mval * expr - expression string mval to be inserted into source * schar - starting character index to be replaced * echar - ending character index to be replaced * dst - destination mval where the result is saved. * * Return: * none * ---------------------------------------------------------- */ void op_setextract(mval *src, mval *expr, int schar, int echar, mval *dst) { int srclen, padlen, pfxlen, sfxoff, sfxlen, dstlen, bytelen, skip, char_len; unsigned char *srcptr, *srcbase, *srctop, *straddr; error_def(ERR_MAXSTRLEN); padlen = pfxlen = sfxlen = 0; MV_FORCE_STR(expr); /* Expression to put into piece place */ if (MV_DEFINED(src)) { MV_FORCE_STR(src); /* Make sure is string prior to length check */ srclen = src->str.len; } else /* Source is not defined -- treat as a null string */ srclen = 0; schar = MAX(schar, 1); /* schar starts at 1 at a minimum */ /* There are four cases in the spec: 1) schar > echar or echar < 1 -- glvn and naked indicator are not changed. This is handled by generated code in m_set 2) echar >= schar-1 > $L(src) -- dst = src_$J("",schar-1-$L(src))_expr 3) schar-1 <= $L(src) < echar -- dst = $E(src,1,schar-1)_expr 4) All others -- dst = $E(src,1,schar-1)_expr_$E(src,echar+1,$L(src)) */ srcbase = (unsigned char *)src->str.addr; srctop = srcbase + srclen; for (srcptr = srcbase, skip = schar - 1; (skip > 0 && srcptr < srctop); --skip) { /* skip the first schar - 1 characters */ if (!UTF8_VALID(srcptr, srctop, bytelen) && !badchar_inhibit) utf8_badchar(0, srcptr, srctop, 0, NULL); srcptr += bytelen; } pfxlen = (int)(srcptr - srcbase); if (skip > 0) { /* Case #2: schar is past the string length. echar test handled in generated code. Should be padded with as many spaces as characters remained to be skipped */ padlen = skip; } for (skip = echar - schar + 1; (skip > 0 && srcptr < srctop); --skip) { /* skip up to the character position echar */ if (!UTF8_VALID(srcptr, srctop, bytelen) && !badchar_inhibit) utf8_badchar(0, srcptr, srctop, 0, NULL); srcptr += bytelen; } char_len = 0; if (skip <= 0) { /* Case #4: echar is within the string length, suffix to be added */ sfxoff = (int)(srcptr - srcbase); sfxlen = (int)(srctop - srcptr); if (!badchar_inhibit && sfxlen > 0) { /* validate the suffix, and we can compute char_len as well */ for (; (srcptr < srctop); ++char_len) { if (!UTF8_VALID(srcptr, srctop, bytelen)) utf8_badchar(0, srcptr, srctop, 0, NULL); srcptr += bytelen; } MV_FORCE_LEN(expr); char_len += schar - 1 + expr->str.char_len; } } /* Calculate total string len */ dstlen = pfxlen + padlen + expr->str.len + sfxlen; if (dstlen > MAX_STRLEN) rts_error(VARLSTCNT(1) ERR_MAXSTRLEN); ENSURE_STP_FREE_SPACE(dstlen); srcbase = (unsigned char *)src->str.addr; straddr = stringpool.free; if (0 < pfxlen) { /* copy prefix */ memcpy(straddr, srcbase, pfxlen); straddr += pfxlen; } if (0 < padlen) { /* insert padding */ memset(straddr, ' ', padlen); straddr += padlen; } if (0 < expr->str.len) { /* copy expression */ memcpy(straddr, expr->str.addr, expr->str.len); straddr += expr->str.len; } if (0 < sfxlen) { /* copy suffix */ memcpy(straddr, srcbase + sfxoff, sfxlen); straddr += sfxlen; } assert(straddr - stringpool.free == dstlen); MV_INIT_STRING(dst, straddr - stringpool.free, (char *)stringpool.free); if (0 < char_len) { dst->mvtype |= MV_UTF_LEN; dst->str.char_len = char_len; } stringpool.free = straddr; }