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 (the License). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/CDDL.txt 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/CDDL.txt. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets [] replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "@(#)scprt.c 1.2 08/05/20 SMI" 28 29 /* 30 * scprt 31 * 32 * This private command is used to print the localized help text 33 * in scinstall, clsetup, and scsetup. It prints the text in a line 34 * which has a maximum length limit, and wrap it into the next line 35 * if it is longer than the limit. A word is a chunk of chars that 36 * is separated by spaces. 37 * 38 * For single char text, it wraps the whole word into the next 39 * line when it is beyond the maximum length, unless the length of 40 * the word itself is longer than the maximum length in which case 41 * it is not wrapped and add "-" at the end of the line. 42 * 43 * For wide char text, it wraps it to next line when it is beyond 44 * the limit, and don't add "-". If the text is mixed with single 45 * chars, it adds "-" if the char at the position of the limit is 46 * single char. 47 */ 48 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <unistd.h> 52 #include <strings.h> 53 #include <string.h> 54 #include <wchar.h> 55 #include <locale.h> 56 57 #include <sys/types.h> 58 59 static const char *progname; 60 61 static void usage(FILE *out); 62 63 /* 64 * usage 65 * 66 * Print a simple usage message to stderr. 67 */ 68 static void 69 usage(FILE *out) 70 { 71 (void) fprintf(out, "%s: %s <leading_spaces> <line_length> <text>\n", 72 gettext("Usage"), 73 progname); 74 75 (void) putc('\n', out); 76 } 77 78 /* 79 * main 80 */ 81 int 82 main(int argc, char **argv) 83 { 84 int lead_length; 85 int line_length; 86 int i; 87 uint_t word_len, thisline_len; 88 uint_t tmp_len; 89 int cut_len; 90 wchar_t *wthis_line = NULL; 91 wchar_t *wthis_word; 92 wchar_t *word_p, *wline_ptr; 93 boolean_t start_line = B_TRUE; 94 boolean_t the_end = B_FALSE; 95 boolean_t the_start = B_TRUE; 96 boolean_t has_widechar = B_FALSE; 97 uint_t *display_len = NULL; 98 int w_index = 0; 99 100 /* Set the program name */ 101 if ((progname = strrchr(argv[0], '/')) == NULL) { 102 progname = argv[0]; 103 } else { 104 ++progname; 105 } 106 107 /* I18N housekeeping */ 108 (void) setlocale(LC_ALL, ""); 109 (void) bindtextdomain(TEXT_DOMAIN, MESSAGE_DIR); 110 (void) textdomain(TEXT_DOMAIN); 111 112 /* Check for parameters */ 113 if (argc != 4) { 114 usage(stderr); 115 exit(1); 116 } 117 if (((lead_length = atoi(argv[1])) == 0) || 118 ((line_length = atoi(argv[2])) == 0)) { 119 usage(stderr); 120 exit(1); 121 } 122 123 /* Go through the text */ 124 thisline_len = 0; 125 126 /* Convert the multibyte string to wide char form */ 127 tmp_len = strlen(argv[3]) + 1; 128 wthis_line = (wchar_t *)malloc(tmp_len * sizeof (wchar_t)); 129 if (!wthis_line) { 130 exit(1); 131 } 132 if (mbstowcs(wthis_line, argv[3], tmp_len) == (size_t)-1) { 133 exit(1); 134 } 135 136 /* Keep the pointer */ 137 wline_ptr = wthis_line; 138 139 /* Allocate memory to save display length of each char */ 140 display_len = (uint_t *)malloc(tmp_len * sizeof (int)); 141 if (!display_len) { 142 exit(1); 143 } 144 145 /* this_line = argv[3]; */ 146 while (*wthis_line) { 147 /* Get the word */ 148 wthis_word = wthis_line; 149 word_p = wthis_word; 150 word_len = 0; 151 i = 0; 152 has_widechar = B_FALSE; 153 w_index = 0; 154 while (*wthis_line && *wthis_line != ' ' && 155 *wthis_line != '\t') { 156 tmp_len = (uint_t)wcwidth(*wthis_line++); 157 word_len += tmp_len; 158 display_len[i++] = tmp_len; 159 160 /* Wide char? */ 161 if (!has_widechar && (tmp_len > 1)) { 162 has_widechar = B_TRUE; 163 } 164 } 165 166 if (!*wthis_line) { 167 the_end = B_TRUE; 168 } else { 169 *wthis_line = '\0'; 170 wthis_line++; 171 } 172 173 /* Process this word */ 174 while (word_len) { 175 /* Caculate the length */ 176 if (start_line) { 177 thisline_len = 0; 178 tmp_len = word_len; 179 if (!the_start) { 180 (void) printf("\n"); 181 } 182 183 /* Print the leading spaces */ 184 for (i = 0; i < lead_length; i++) { 185 (void) putchar(' '); 186 } 187 } else { 188 tmp_len = thisline_len + word_len + 1; 189 (void) putchar(' '); 190 } 191 192 /* Check the length */ 193 if ((int)tmp_len <= line_length) { 194 /* Print the word */ 195 while (*wthis_word) { 196 (void) putwchar(*wthis_word++); 197 } 198 199 if (start_line) { 200 start_line = B_FALSE; 201 } 202 203 thisline_len = tmp_len; 204 if (tmp_len == (uint_t)line_length) { 205 start_line = B_TRUE; 206 } 207 208 /* 209 * Word is printed so its not the very 210 * beginning 211 */ 212 if (the_start) { 213 the_start = B_FALSE; 214 } 215 break; 216 } 217 218 /* 219 * Process long word. For long single char word or 220 * single chars mixed with wide chars, we need to 221 * add "-" following the single char at the end of 222 * the line, so "line_length - 1". We don't add "-" 223 * if it is wide char at the end of the line. 224 */ 225 if (start_line) { 226 cut_len = line_length; 227 } else { 228 cut_len = (int)((uint_t)line_length - 229 thisline_len) - 1; 230 } 231 if (cut_len < 0) { 232 /* Right on the edge, start a new line */ 233 start_line = B_TRUE; 234 continue; 235 } 236 237 /* Check if it is long word */ 238 if (!has_widechar) { 239 /* 240 * Continue to display if the word length 241 * is longer than the line limit; But if not 242 * we start a new line. 243 */ 244 if (word_len <= (uint_t)line_length) { 245 start_line = B_TRUE; 246 continue; 247 } 248 } 249 250 /* Print the word */ 251 tmp_len = 0; 252 for (i = 0; i < cut_len; i++) { 253 /* Check if the display width is too long. */ 254 tmp_len += display_len[w_index++]; 255 if ((int)tmp_len < cut_len) { 256 (void) putwchar(wthis_word[i]); 257 continue; 258 } 259 260 /* Too long. Wrap to the next line. */ 261 if (display_len[w_index] == 1) { 262 if (word_len > (uint_t)line_length) { 263 (void) putchar('-'); 264 } 265 w_index--; 266 cut_len = (int)(tmp_len - 267 display_len[w_index]); 268 } else if ((int)tmp_len == cut_len) { 269 (void) putwchar(wthis_word[i]); 270 } else { 271 w_index--; 272 cut_len = (int)(tmp_len - 273 display_len[w_index]); 274 } 275 start_line = B_TRUE; 276 break; 277 } 278 279 /* Reset the word */ 280 word_len -= (uint_t)cut_len; 281 wthis_word = word_p + w_index; 282 thisline_len += (uint_t)cut_len + 1; 283 284 /* Word is printed so it's not the very beginning */ 285 if (the_start) { 286 the_start = B_FALSE; 287 } 288 } 289 290 /* Done. */ 291 if (the_end) { 292 break; 293 } 294 } 295 296 (void) putchar('\n'); 297 298 /* Free memory */ 299 free(wline_ptr); 300 free(display_len); 301 302 return (0); 303 } /*lint !e818 */ 304