version 1.13, 2014/04/25 13:38:21 |
version 1.14, 2015/11/05 22:08:44 |
|
|
* |
* |
* For more information, see the README file. |
* For more information, see the README file. |
*/ |
*/ |
|
/* |
|
* Modified for use with illumos. |
|
* Copyright 2014 Garrett D'Amore <garrett@damore.org> |
|
*/ |
|
|
|
|
/* |
/* |
* Prompting and other messages. |
* Prompting and other messages. |
* There are three flavors of prompts, SHORT, MEDIUM and LONG, |
* There are three flavors of prompts, SHORT, MEDIUM and LONG, |
* selected by the -m/-M options. |
* selected by the -m/-M options. |
* There is also the "equals message", printed by the = command. |
* There is also the "equals message", printed by the = command. |
* A prompt is a message composed of various pieces, such as the |
* A prompt is a message composed of various pieces, such as the |
* name of the file being viewed, the percentage into the file, etc. |
* name of the file being viewed, the percentage into the file, etc. |
*/ |
*/ |
|
|
|
|
extern int jump_sline; |
extern int jump_sline; |
extern int less_is_more; |
extern int less_is_more; |
extern IFILE curr_ifile; |
extern IFILE curr_ifile; |
#if EDITOR |
|
extern char *editor; |
extern char *editor; |
extern char *editproto; |
extern char *editproto; |
#endif |
|
|
|
/* |
/* |
* Prototypes for the three flavors of prompts. |
* Prototypes for the three flavors of prompts. |
* These strings are expanded by pr_expand(). |
* These strings are expanded by pr_expand(). |
*/ |
*/ |
static constant char s_proto[] = |
static const char s_proto[] = |
"?n?f%f .?m(%T %i of %m) ..?e(END) ?x- Next\\: %x..%t"; |
"?n?f%f .?m(%T %i of %m) ..?e(END) ?x- Next\\: %x..%t"; |
static constant char m_proto[] = |
static const char m_proto[] = |
"?f%f .?m(%T %i of %m) .?e(END) ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t"; |
"?n?f%f .?m(%T %i of %m) ..?e(END) " |
static constant char M_proto[] = |
"?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t"; |
"?f%f .?n?m(%T %i of %m) ..?ltlines %lt-%lb?L/%L. :byte %bB?s/%s. .?e(END) ?x- Next\\: %x.:?pB%pB\\%..%t"; |
static const char M_proto[] = |
static constant char e_proto[] = |
"?f%f .?n?m(%T %i of %m) ..?" |
"?f%f .?m(%T %i of %m) .?ltlines %lt-%lb?L/%L. .byte %bB?s/%s. ?e(END) :?pB%pB\\%..%t"; |
"ltlines %lt-%lb?L/%L. :byte %bB?s/%s. .?e(END)" |
static constant char h_proto[] = |
" ?x- Next\\: %x.:?pB%pB\\%..%t"; |
"HELP -- ?eEND -- Press g to see it again:Press RETURN for more., or q when done"; |
static const char e_proto[] = |
static constant char w_proto[] = |
"?f%f .?m(%T %i of %m) .?ltlines " |
"Waiting for data"; |
"%lt-%lb?L/%L. .byte %bB?s/%s. ?e(END) :?pB%pB\\%..%t"; |
|
static const char h_proto[] = |
|
"HELP -- ?eEND -- Press g to see it again:" |
|
"Press RETURN for more., or q when done"; |
|
static const char w_proto[] = |
|
"Waiting for data"; |
|
static const char more_proto[] = |
|
"%f (?eEND ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t)"; |
|
static const char more_M_proto[] = |
|
"%f (?eEND ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t)" |
|
"[Press space to continue, q to quit, h for help]"; |
|
|
public char *prproto[3]; |
char *prproto[3]; |
public char constant *eqproto = e_proto; |
char const *eqproto = e_proto; |
public char constant *hproto = h_proto; |
char const *hproto = h_proto; |
public char constant *wproto = w_proto; |
char const *wproto = w_proto; |
|
|
static char message[PROMPT_SIZE]; |
static char message[PROMPT_SIZE]; |
static char *mp; |
static char *mp; |
|
|
/* |
/* |
* Initialize the prompt prototype strings. |
* Initialize the prompt prototype strings. |
*/ |
*/ |
public void |
void |
init_prompt() |
init_prompt(void) |
{ |
{ |
prproto[0] = save(s_proto); |
prproto[0] = save(s_proto); |
prproto[1] = save(m_proto); |
prproto[1] = save(less_is_more ? more_proto : m_proto); |
prproto[2] = save(M_proto); |
prproto[2] = save(less_is_more ? more_M_proto : M_proto); |
eqproto = save(e_proto); |
eqproto = save(e_proto); |
hproto = save(h_proto); |
hproto = save(h_proto); |
wproto = save(w_proto); |
wproto = save(w_proto); |
|
|
/* |
/* |
* Append a string to the end of the message. |
* Append a string to the end of the message. |
*/ |
*/ |
static void |
static void |
ap_str(s) |
ap_str(char *s) |
char *s; |
|
{ |
{ |
int len; |
int len; |
|
|
len = strlen(s); |
len = strlen(s); |
if (mp + len >= message + PROMPT_SIZE) |
if (mp + len >= message + PROMPT_SIZE) |
len = message + PROMPT_SIZE - mp - 1; |
len = message + PROMPT_SIZE - mp - 1; |
strncpy(mp, s, len); |
(void) strncpy(mp, s, len); |
mp += len; |
mp += len; |
*mp = '\0'; |
*mp = '\0'; |
} |
} |
|
|
/* |
/* |
* Append a character to the end of the message. |
* Append a character to the end of the message. |
*/ |
*/ |
static void |
static void |
ap_char(c) |
ap_char(char c) |
char c; |
|
{ |
{ |
char buf[2]; |
char buf[2]; |
|
|
|
|
} |
} |
|
|
/* |
/* |
* Append a POSITION (as a decimal integer) to the end of the message. |
* Append a off_t (as a decimal integer) to the end of the message. |
*/ |
*/ |
static void |
static void |
ap_pos(pos) |
ap_pos(off_t pos) |
POSITION pos; |
|
{ |
{ |
char buf[INT_STRLEN_BOUND(pos) + 2]; |
char buf[INT_STRLEN_BOUND(pos) + 2]; |
|
|
postoa(pos, buf, sizeof(buf)); |
postoa(pos, buf, sizeof buf); |
ap_str(buf); |
ap_str(buf); |
} |
} |
|
|
/* |
/* |
* Append a line number to the end of the message. |
* Append a line number to the end of the message. |
*/ |
*/ |
static void |
static void |
ap_linenum(linenum) |
ap_linenum(LINENUM linenum) |
LINENUM linenum; |
|
{ |
{ |
char buf[INT_STRLEN_BOUND(linenum) + 2]; |
char buf[INT_STRLEN_BOUND(linenum) + 2]; |
|
|
linenumtoa(linenum, buf, sizeof(buf)); |
linenumtoa(linenum, buf, sizeof buf); |
ap_str(buf); |
ap_str(buf); |
} |
} |
|
|
/* |
/* |
* Append an integer to the end of the message. |
* Append an integer to the end of the message. |
*/ |
*/ |
static void |
static void |
ap_int(num) |
ap_int(int num) |
int num; |
|
{ |
{ |
char buf[INT_STRLEN_BOUND(num) + 2]; |
char buf[INT_STRLEN_BOUND(num) + 2]; |
|
|
inttoa(num, buf, sizeof(buf)); |
inttoa(num, buf, sizeof buf); |
ap_str(buf); |
ap_str(buf); |
} |
} |
|
|
/* |
/* |
* Append a question mark to the end of the message. |
* Append a question mark to the end of the message. |
*/ |
*/ |
static void |
static void |
ap_quest() |
ap_quest(void) |
{ |
{ |
ap_str("?"); |
ap_str("?"); |
} |
} |
|
|
/* |
/* |
* Return the "current" byte offset in the file. |
* Return the "current" byte offset in the file. |
*/ |
*/ |
static POSITION |
static off_t |
curr_byte(where) |
curr_byte(int where) |
int where; |
|
{ |
{ |
POSITION pos; |
off_t pos; |
|
|
pos = position(where); |
pos = position(where); |
while (pos == NULL_POSITION && where >= 0 && where < sc_height-1) |
while (pos == -1 && where >= 0 && where < sc_height-1) |
pos = position(++where); |
pos = position(++where); |
if (pos == NULL_POSITION) |
if (pos == -1) |
pos = ch_length(); |
pos = ch_length(); |
return (pos); |
return (pos); |
} |
} |
|
|
/* |
/* |
* Return the value of a prototype conditional. |
* Return the value of a prototype conditional. |
* A prototype string may include conditionals which consist of a |
* A prototype string may include conditionals which consist of a |
* question mark followed by a single letter. |
* question mark followed by a single letter. |
* Here we decode that letter and return the appropriate boolean value. |
* Here we decode that letter and return the appropriate boolean value. |
*/ |
*/ |
static int |
static int |
cond(c, where) |
cond(char c, int where) |
char c; |
|
int where; |
|
{ |
{ |
POSITION len; |
off_t len; |
|
|
switch (c) |
switch (c) { |
{ |
|
case 'a': /* Anything in the message yet? */ |
case 'a': /* Anything in the message yet? */ |
return (mp > message); |
return (mp > message); |
case 'b': /* Current byte offset known? */ |
case 'b': /* Current byte offset known? */ |
return (curr_byte(where) != NULL_POSITION); |
return (curr_byte(where) != -1); |
case 'c': |
case 'c': |
return (hshift != 0); |
return (hshift != 0); |
case 'e': /* At end of file? */ |
case 'e': /* At end of file? */ |
|
|
return (linenums); |
return (linenums); |
case 'L': /* Final line number known? */ |
case 'L': /* Final line number known? */ |
case 'D': /* Final page number known? */ |
case 'D': /* Final page number known? */ |
return (linenums && ch_length() != NULL_POSITION); |
return (linenums && ch_length() != -1); |
case 'm': /* More than one file? */ |
case 'm': /* More than one file? */ |
#if TAGS |
|
return (ntags() ? (ntags() > 1) : (nifile() > 1)); |
return (ntags() ? (ntags() > 1) : (nifile() > 1)); |
#else |
|
return (nifile() > 1); |
|
#endif |
|
case 'n': /* First prompt in a new file? */ |
case 'n': /* First prompt in a new file? */ |
#if TAGS |
|
return (ntags() ? 1 : new_file); |
return (ntags() ? 1 : new_file); |
#else |
|
return (new_file); |
|
#endif |
|
case 'p': /* Percent into file (bytes) known? */ |
case 'p': /* Percent into file (bytes) known? */ |
return (curr_byte(where) != NULL_POSITION && |
return (curr_byte(where) != -1 && ch_length() > 0); |
ch_length() > 0); |
|
case 'P': /* Percent into file (lines) known? */ |
case 'P': /* Percent into file (lines) known? */ |
return (currline(where) != 0 && |
return (currline(where) != 0 && |
(len = ch_length()) > 0 && |
(len = ch_length()) > 0 && find_linenum(len) != 0); |
find_linenum(len) != 0); |
|
case 's': /* Size of file known? */ |
case 's': /* Size of file known? */ |
case 'B': |
case 'B': |
return (ch_length() != NULL_POSITION); |
return (ch_length() != -1); |
case 'x': /* Is there a "next" file? */ |
case 'x': /* Is there a "next" file? */ |
#if TAGS |
|
if (ntags()) |
if (ntags()) |
return (0); |
return (0); |
#endif |
|
return (next_ifile(curr_ifile) != NULL_IFILE); |
return (next_ifile(curr_ifile) != NULL_IFILE); |
} |
} |
return (0); |
return (0); |
|
|
* Here we decode that letter and take the appropriate action, |
* Here we decode that letter and take the appropriate action, |
* usually by appending something to the message being built. |
* usually by appending something to the message being built. |
*/ |
*/ |
static void |
static void |
protochar(c, where, iseditproto) |
protochar(int c, int where) |
int c; |
|
int where; |
|
int iseditproto; |
|
{ |
{ |
POSITION pos; |
off_t pos; |
POSITION len; |
off_t len; |
int n; |
int n; |
LINENUM linenum; |
LINENUM linenum; |
LINENUM last_linenum; |
LINENUM last_linenum; |
IFILE h; |
IFILE h; |
|
|
#undef PAGE_NUM |
#undef PAGE_NUM |
#define PAGE_NUM(linenum) ((((linenum) - 1) / (sc_height - 1)) + 1) |
#define PAGE_NUM(linenum) ((((linenum) - 1) / (sc_height - 1)) + 1) |
|
|
switch (c) |
switch (c) { |
{ |
|
case 'b': /* Current byte offset */ |
case 'b': /* Current byte offset */ |
pos = curr_byte(where); |
pos = curr_byte(where); |
if (pos != NULL_POSITION) |
if (pos != -1) |
ap_pos(pos); |
ap_pos(pos); |
else |
else |
ap_quest(); |
ap_quest(); |
|
|
case 'D': /* Final page number */ |
case 'D': /* Final page number */ |
/* Find the page number of the last byte in the file (len-1). */ |
/* Find the page number of the last byte in the file (len-1). */ |
len = ch_length(); |
len = ch_length(); |
if (len == NULL_POSITION) |
if (len == -1) { |
ap_quest(); |
ap_quest(); |
else if (len == 0) |
} else if (len == 0) { |
/* An empty file has no pages. */ |
/* An empty file has no pages. */ |
ap_linenum(0); |
ap_linenum(0); |
else |
} else { |
{ |
|
linenum = find_linenum(len - 1); |
linenum = find_linenum(len - 1); |
if (linenum <= 0) |
if (linenum <= 0) |
ap_quest(); |
ap_quest(); |
else |
else |
ap_linenum(PAGE_NUM(linenum)); |
ap_linenum(PAGE_NUM(linenum)); |
} |
} |
break; |
break; |
#if EDITOR |
|
case 'E': /* Editor name */ |
case 'E': /* Editor name */ |
ap_str(editor); |
ap_str(editor); |
break; |
break; |
#endif |
|
case 'f': /* File name */ |
case 'f': /* File name */ |
ap_str(get_filename(curr_ifile)); |
ap_str(get_filename(curr_ifile)); |
break; |
break; |
|
|
ap_str(last_component(get_filename(curr_ifile))); |
ap_str(last_component(get_filename(curr_ifile))); |
break; |
break; |
case 'i': /* Index into list of files */ |
case 'i': /* Index into list of files */ |
#if TAGS |
|
if (ntags()) |
if (ntags()) |
ap_int(curr_tag()); |
ap_int(curr_tag()); |
else |
else |
#endif |
|
ap_int(get_index(curr_ifile)); |
ap_int(get_index(curr_ifile)); |
break; |
break; |
case 'l': /* Current line number */ |
case 'l': /* Current line number */ |
|
|
break; |
break; |
case 'L': /* Final line number */ |
case 'L': /* Final line number */ |
len = ch_length(); |
len = ch_length(); |
if (len == NULL_POSITION || len == ch_zero() || |
if (len == -1 || len == ch_zero() || |
(linenum = find_linenum(len)) <= 0) |
(linenum = find_linenum(len)) <= 0) |
ap_quest(); |
ap_quest(); |
else |
else |
ap_linenum(linenum-1); |
ap_linenum(linenum-1); |
break; |
break; |
case 'm': /* Number of files */ |
case 'm': /* Number of files */ |
#if TAGS |
|
n = ntags(); |
n = ntags(); |
if (n) |
if (n) |
ap_int(n); |
ap_int(n); |
else |
else |
#endif |
|
ap_int(nifile()); |
ap_int(nifile()); |
break; |
break; |
case 'p': /* Percent into file (bytes) */ |
case 'p': /* Percent into file (bytes) */ |
pos = curr_byte(where); |
pos = curr_byte(where); |
len = ch_length(); |
len = ch_length(); |
if (pos != NULL_POSITION && len > 0) |
if (pos != -1 && len > 0) |
ap_int(percentage(pos,len)); |
ap_int(percentage(pos, len)); |
else |
else |
ap_quest(); |
ap_quest(); |
break; |
break; |
case 'P': /* Percent into file (lines) */ |
case 'P': /* Percent into file (lines) */ |
linenum = currline(where); |
linenum = currline(where); |
if (linenum == 0 || |
if (linenum == 0 || |
(len = ch_length()) == NULL_POSITION || len == ch_zero() || |
(len = ch_length()) == -1 || len == ch_zero() || |
(last_linenum = find_linenum(len)) <= 0) |
(last_linenum = find_linenum(len)) <= 0) |
ap_quest(); |
ap_quest(); |
else |
else |
|
|
case 's': /* Size of file */ |
case 's': /* Size of file */ |
case 'B': |
case 'B': |
len = ch_length(); |
len = ch_length(); |
if (len != NULL_POSITION) |
if (len != -1) |
ap_pos(len); |
ap_pos(len); |
else |
else |
ap_quest(); |
ap_quest(); |
|
|
*mp = '\0'; |
*mp = '\0'; |
break; |
break; |
case 'T': /* Type of list */ |
case 'T': /* Type of list */ |
#if TAGS |
|
if (ntags()) |
if (ntags()) |
ap_str("tag"); |
ap_str("tag"); |
else |
else |
#endif |
|
ap_str("file"); |
ap_str("file"); |
break; |
break; |
case 'x': /* Name of next file */ |
case 'x': /* Name of next file */ |
|
|
|
|
/* |
/* |
* Skip a false conditional. |
* Skip a false conditional. |
* When a false condition is found (either a false IF or the ELSE part |
* When a false condition is found (either a false IF or the ELSE part |
* of a true IF), this routine scans the prototype string to decide |
* of a true IF), this routine scans the prototype string to decide |
* where to resume parsing the string. |
* where to resume parsing the string. |
* We must keep track of nested IFs and skip them properly. |
* We must keep track of nested IFs and skip them properly. |
*/ |
*/ |
static constant char * |
static const char * |
skipcond(p) |
skipcond(const char *p) |
register constant char *p; |
|
{ |
{ |
register int iflevel; |
int iflevel; |
|
|
/* |
/* |
* We came in here after processing a ? or :, |
* We came in here after processing a ? or :, |
|
|
*/ |
*/ |
iflevel = 1; |
iflevel = 1; |
|
|
for (;;) switch (*++p) |
for (;;) { |
{ |
switch (*++p) { |
case '?': |
case '?': |
/* |
/* |
* Start of a nested IF. |
* Start of a nested IF. |
*/ |
*/ |
iflevel++; |
iflevel++; |
break; |
break; |
case ':': |
case ':': |
/* |
/* |
* Else. |
* Else. |
* If this matches the IF we came in here with, |
* If this matches the IF we came in here with, |
* then we're done. |
* then we're done. |
*/ |
*/ |
if (iflevel == 1) |
if (iflevel == 1) |
return (p); |
return (p); |
break; |
break; |
case '.': |
case '.': |
/* |
/* |
* Endif. |
* Endif. |
* If this matches the IF we came in here with, |
* If this matches the IF we came in here with, |
* then we're done. |
* then we're done. |
*/ |
*/ |
if (--iflevel == 0) |
if (--iflevel == 0) |
return (p); |
return (p); |
break; |
break; |
case '\\': |
case '\\': |
/* |
/* |
* Backslash escapes the next character. |
* Backslash escapes the next character. |
*/ |
*/ |
++p; |
++p; |
break; |
break; |
case '\0': |
case '\0': |
/* |
/* |
* Whoops. Hit end of string. |
* Whoops. Hit end of string. |
* This is a malformed conditional, but just treat it |
* This is a malformed conditional, but just treat it |
* as if all active conditionals ends here. |
* as if all active conditionals ends here. |
*/ |
*/ |
return (p-1); |
return (p-1); |
|
} |
} |
} |
/*NOTREACHED*/ |
/*NOTREACHED*/ |
} |
} |
|
|
/* |
/* |
* Decode a char that represents a position on the screen. |
* Decode a char that represents a position on the screen. |
*/ |
*/ |
static constant char * |
static const char * |
wherechar(p, wp) |
wherechar(const char *p, int *wp) |
char constant *p; |
|
int *wp; |
|
{ |
{ |
switch (*p) |
switch (*p) { |
{ |
|
case 'b': case 'd': case 'l': case 'p': case 'P': |
case 'b': case 'd': case 'l': case 'p': case 'P': |
switch (*++p) |
switch (*++p) { |
{ |
|
case 't': *wp = TOP; break; |
case 't': *wp = TOP; break; |
case 'm': *wp = MIDDLE; break; |
case 'm': *wp = MIDDLE; break; |
case 'b': *wp = BOTTOM; break; |
case 'b': *wp = BOTTOM; break; |
|
|
/* |
/* |
* Construct a message based on a prototype string. |
* Construct a message based on a prototype string. |
*/ |
*/ |
public char * |
char * |
pr_expand(proto, maxwidth) |
pr_expand(const char *proto, int maxwidth) |
constant char *proto; |
|
int maxwidth; |
|
{ |
{ |
register constant char *p; |
const char *p; |
register int c; |
int c; |
int where; |
int where; |
|
|
mp = message; |
mp = message; |
|
|
if (*proto == '\0') |
if (*proto == '\0') |
return (""); |
return (""); |
|
|
for (p = proto; *p != '\0'; p++) |
for (p = proto; *p != '\0'; p++) { |
{ |
switch (*p) { |
switch (*p) |
|
{ |
|
default: /* Just put the character in the message */ |
default: /* Just put the character in the message */ |
ap_char(*p); |
ap_char(*p); |
break; |
break; |
|
|
ap_char(*p); |
ap_char(*p); |
break; |
break; |
case '?': /* Conditional (IF) */ |
case '?': /* Conditional (IF) */ |
if ((c = *++p) == '\0') |
if ((c = *++p) == '\0') { |
--p; |
--p; |
else |
} else { |
{ |
|
where = 0; |
where = 0; |
p = wherechar(p, &where); |
p = wherechar(p, &where); |
if (!cond(c, where)) |
if (!cond(c, where)) |
|
|
case '.': /* ENDIF */ |
case '.': /* ENDIF */ |
break; |
break; |
case '%': /* Percent escape */ |
case '%': /* Percent escape */ |
if ((c = *++p) == '\0') |
if ((c = *++p) == '\0') { |
--p; |
--p; |
else |
} else { |
{ |
|
where = 0; |
where = 0; |
p = wherechar(p, &where); |
p = wherechar(p, &where); |
protochar(c, where, |
protochar(c, where); |
#if EDITOR |
|
(proto == editproto)); |
|
#else |
|
0); |
|
#endif |
|
|
|
} |
} |
break; |
break; |
} |
} |
|
|
|
|
if (mp == message) |
if (mp == message) |
return (""); |
return (""); |
if (maxwidth > 0 && mp >= message + maxwidth) |
if (maxwidth > 0 && mp >= message + maxwidth) { |
{ |
|
/* |
/* |
* Message is too long. |
* Message is too long. |
* Return just the final portion of it. |
* Return just the final portion of it. |
|
|
/* |
/* |
* Return a message suitable for printing by the "=" command. |
* Return a message suitable for printing by the "=" command. |
*/ |
*/ |
public char * |
char * |
eq_message() |
eq_message(void) |
{ |
{ |
return (pr_expand(eqproto, 0)); |
return (pr_expand(eqproto, 0)); |
} |
} |
|
|
* If we can't come up with an appropriate prompt, return NULL |
* If we can't come up with an appropriate prompt, return NULL |
* and the caller will prompt with a colon. |
* and the caller will prompt with a colon. |
*/ |
*/ |
public char * |
char * |
pr_string() |
prompt_string(void) |
{ |
{ |
char *prompt; |
char *prompt; |
int type; |
int type; |
|
|
type = (!less_is_more) ? pr_type : pr_type ? 0 : 1; |
type = pr_type; |
prompt = pr_expand((ch_getflags() & CH_HELPFILE) ? |
prompt = pr_expand((ch_getflags() & CH_HELPFILE) ? |
hproto : prproto[type], |
hproto : prproto[type], sc_width-so_s_width-so_e_width-2); |
sc_width-so_s_width-so_e_width-2); |
|
new_file = 0; |
new_file = 0; |
return (prompt); |
return (prompt); |
} |
} |
|
|
/* |
/* |
* Return a message suitable for printing while waiting in the F command. |
* Return a message suitable for printing while waiting in the F command. |
*/ |
*/ |
public char * |
char * |
wait_message() |
wait_message(void) |
{ |
{ |
return (pr_expand(wproto, sc_width-so_s_width-so_e_width-2)); |
return (pr_expand(wproto, sc_width-so_s_width-so_e_width-2)); |
} |
} |