1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1998-2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include "check.h" 28 29 #ifndef DEBUG 30 #define MSG_DISORDER gettext("sort: disorder: ") 31 #define MSG_NONUNIQUE gettext("sort: non-unique: ") 32 #else /* DEBUG */ 33 #define MSG_DISORDER gettext("sort: disorder (%llu): ") 34 #define MSG_NONUNIQUE gettext("sort: non-unique (%llu): ") 35 #endif /* DEBUG */ 36 37 #define CHECK_FAILURE_DISORDER 0x1 38 #define CHECK_FAILURE_NONUNIQUE 0x2 39 #define CHECK_WIDE 0x4 40 41 static void 42 fail_check(line_rec_t *L, int flags, u_longlong_t lineno) 43 { 44 char *line; 45 ssize_t length; 46 47 if (flags & CHECK_WIDE) { 48 if ((length = (ssize_t)wcstombs(NULL, L->l_data.wp, 0)) < 0) 49 die(EMSG_ILLEGAL_CHAR); 50 51 /* 52 * +1 for null character 53 */ 54 line = alloca(length + 1); 55 (void) wcstombs(line, L->l_data.wp, L->l_data_length); 56 line[length] = '\0'; 57 } else { 58 line = L->l_data.sp; 59 length = L->l_data_length; 60 } 61 62 if (flags & CHECK_FAILURE_DISORDER) { 63 (void) fprintf(stderr, MSG_DISORDER, lineno); 64 (void) write(fileno(stderr), line, length); 65 (void) fprintf(stderr, "\n"); 66 return; 67 } 68 69 (void) fprintf(stderr, MSG_NONUNIQUE); 70 (void) write(fileno(stderr), line, length); 71 (void) fprintf(stderr, "\n"); 72 } 73 74 static void 75 swap_coll_bufs(line_rec_t *A, line_rec_t *B) 76 { 77 char *coll_buffer = B->l_collate.sp; 78 ssize_t coll_bufsize = B->l_collate_bufsize; 79 80 safe_free(B->l_raw_collate.sp); 81 copy_line_rec(A, B); 82 83 A->l_collate.sp = coll_buffer; 84 A->l_collate_bufsize = coll_bufsize; 85 A->l_raw_collate.sp = NULL; 86 } 87 88 /* 89 * check_if_sorted() interacts with a stream in a slightly different way than a 90 * simple sort or a merge operation: the check involves looking at two adjacent 91 * lines of the file and verifying that they are collated according to the key 92 * specifiers given. For files accessed via mmap(), this is simply done as the 93 * entirety of the file is present in the address space. For files accessed via 94 * stdio, regardless of locale, we must be able to guarantee that two lines are 95 * present in memory at once. The basic buffer code for stdio does not make 96 * such a guarantee, so we use stream_swap_buffer() to alternate between two 97 * input buffers. 98 */ 99 void 100 check_if_sorted(sort_t *S) 101 { 102 size_t input_mem; 103 int numerator, denominator; 104 105 char *data_buffer = NULL; 106 size_t data_bufsize = 0; 107 line_rec_t last_line; 108 u_longlong_t lineno = 0; 109 int r; 110 int swap_required; 111 flag_t coll_flags; 112 stream_t *cur_streamp = S->m_input_streams; 113 114 ssize_t (*conversion_fcn)(field_t *, line_rec_t *, flag_t, vchar_t) = 115 field_convert; 116 int (*collation_fcn)(line_rec_t *, line_rec_t *, ssize_t, flag_t) = 117 collated; 118 119 set_memory_ratio(S, &numerator, &denominator); 120 121 if (stream_open_for_read(S, cur_streamp) > 1) 122 die(EMSG_CHECK); 123 124 if (SOP_EOS(cur_streamp)) 125 exit(E_SUCCESS); 126 127 (void) memset(&last_line, 0, sizeof (line_rec_t)); 128 129 /* 130 * We need to swap data buffers for the stream with each fetch, except 131 * on STREAM_MMAP (which are implicitly STREAM_SUSTAIN). 132 */ 133 swap_required = !(cur_streamp->s_status & STREAM_MMAP); 134 if (swap_required) { 135 stream_set(cur_streamp, STREAM_INSTANT); 136 /* 137 * We use one half of the available memory for input, half for 138 * each buffer. (The other half is left unreserved, in case 139 * conversions to collatable form require it.) 140 */ 141 input_mem = numerator * S->m_memory_available / denominator / 4; 142 143 stream_set_size(cur_streamp, input_mem); 144 stream_swap_buffer(cur_streamp, &data_buffer, &data_bufsize); 145 stream_set_size(cur_streamp, input_mem); 146 147 if (cur_streamp->s_status & STREAM_WIDE) { 148 conversion_fcn = field_convert_wide; 149 collation_fcn = collated_wide; 150 } 151 } 152 153 if (SOP_PRIME(cur_streamp) > 1) 154 die(EMSG_CHECK); 155 156 if (S->m_field_options & FIELD_REVERSE_COMPARISONS) 157 coll_flags = COLL_REVERSE; 158 else 159 coll_flags = 0; 160 if (S->m_unique_lines) 161 coll_flags |= COLL_UNIQUE; 162 163 cur_streamp->s_current.l_collate_bufsize = INITIAL_COLLATION_SIZE 164 * cur_streamp->s_element_size; 165 cur_streamp->s_current.l_collate.sp = safe_realloc(NULL, 166 cur_streamp->s_current.l_collate_bufsize); 167 cur_streamp->s_current.l_raw_collate.sp = NULL; 168 169 last_line.l_collate_bufsize = INITIAL_COLLATION_SIZE * 170 cur_streamp->s_element_size; 171 last_line.l_collate.sp = safe_realloc(NULL, 172 last_line.l_collate_bufsize); 173 last_line.l_raw_collate.sp = NULL; 174 175 (void) conversion_fcn(S->m_fields_head, &cur_streamp->s_current, 176 FCV_REALLOC, S->m_field_separator); 177 178 swap_coll_bufs(&cur_streamp->s_current, &last_line); 179 if (swap_required) 180 stream_swap_buffer(cur_streamp, &data_buffer, &data_bufsize); 181 182 while (!SOP_EOS(cur_streamp)) { 183 (void) SOP_FETCH(cur_streamp); 184 lineno++; 185 186 (void) conversion_fcn(S->m_fields_head, &cur_streamp->s_current, 187 FCV_REALLOC, S->m_field_separator); 188 189 r = collation_fcn(&last_line, &cur_streamp->s_current, 0, 190 coll_flags); 191 192 if (r < 0 || (r == 0 && S->m_unique_lines == 0)) { 193 swap_coll_bufs(&cur_streamp->s_current, &last_line); 194 if (swap_required) 195 stream_swap_buffer(cur_streamp, &data_buffer, 196 &data_bufsize); 197 continue; 198 } 199 200 if (r > 0) { 201 #ifndef XPG4 202 fail_check(&cur_streamp->s_current, 203 CHECK_FAILURE_DISORDER | 204 (S->m_single_byte_locale ? 0 : CHECK_WIDE), 205 lineno); 206 #endif /* XPG4 */ 207 exit(E_FAILED_CHECK); 208 } 209 210 if (r == 0 && S->m_unique_lines != 0) { 211 #ifndef XPG4 212 fail_check(&cur_streamp->s_current, 213 CHECK_FAILURE_NONUNIQUE | 214 (S->m_single_byte_locale ? 0 : CHECK_WIDE), 215 lineno); 216 #endif /* XPG4 */ 217 exit(E_FAILED_CHECK); 218 } 219 } 220 221 exit(E_SUCCESS); 222 /*NOTREACHED*/ 223 } 224