Home | History | Annotate | Download | only in scprt
      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