121970Sdist /* 221970Sdist * Copyright (c) 1980 Regents of the University of California. 333767Sbostic * Copyright (c) 1976 Board of Trustees of the University of Illinois. 433767Sbostic * All rights reserved. 533767Sbostic * 633767Sbostic * Redistribution and use in source and binary forms are permitted 733767Sbostic * provided that this notice is preserved and that due credit is given 833767Sbostic * to the University of California at Berkeley and the University of 933767Sbostic * Illinois at Urbana. The name of either University may not be used 1033767Sbostic * to endorse or promote products derived from this software without 1133767Sbostic * specific prior written permission. This software is provided 1233767Sbostic * ``as is'' without express or implied warranty. 1321970Sdist */ 148804Smckusick 1521970Sdist #ifndef lint 16*33768Sbostic static char sccsid[] = "@(#)lexi.c 5.7 (Berkeley) 03/22/88"; 1733767Sbostic #endif /* not lint */ 1821970Sdist 1933767Sbostic /* 2024455Smckusick * NAME: 2124455Smckusick * lexi 2224455Smckusick * 2324455Smckusick * FUNCTION: 2424455Smckusick * This is the token scanner for indent 2524455Smckusick * 2624455Smckusick * ALGORITHM: 2724455Smckusick * 1) Strip off intervening blanks and/or tabs. 2824455Smckusick * 2) If it is an alphanumeric token, move it to the token buffer "token". 2924455Smckusick * Check if it is a special reserved word that indent will want to 3024455Smckusick * know about. 3124455Smckusick * 3) Non-alphanumeric tokens are handled with a big switch statement. A 3224455Smckusick * flag is kept to remember if the last token was a "unary delimiter", 3324455Smckusick * which forces a following operator to be unary as opposed to binary. 3424455Smckusick * 3524455Smckusick * PARAMETERS: 3624455Smckusick * None 3724455Smckusick * 3824455Smckusick * RETURNS: 3924455Smckusick * An integer code indicating the type of token scanned. 4024455Smckusick * 4124455Smckusick * GLOBALS: 4224455Smckusick * buf_ptr = 4324455Smckusick * had_eof 4424455Smckusick * ps.last_u_d = Set to true iff this token is a "unary delimiter" 4524455Smckusick * 4624455Smckusick * CALLS: 4724455Smckusick * fill_buffer 4824455Smckusick * printf (lib) 4924455Smckusick * 5024455Smckusick * CALLED BY: 5124455Smckusick * main 5224455Smckusick * 5324455Smckusick * NOTES: 5424455Smckusick * Start of comment is passed back so that the comment can be scanned by 5524455Smckusick * pr_comment. 5624455Smckusick * 5724455Smckusick * Strings and character literals are returned just like identifiers. 5824455Smckusick * 5924455Smckusick * HISTORY: 6024455Smckusick * initial coding November 1976 D A Willcox of CAC 6124455Smckusick * 1/7/77 D A Willcox of CAC Fix to provide proper handling 6224455Smckusick * of "int a -1;" 6324455Smckusick * 6424455Smckusick */ 6524455Smckusick 668804Smckusick /* 6724455Smckusick * Here we have the token scanner for indent. It scans off one token and 6824455Smckusick * puts it in the global variable "token". It returns a code, indicating 6924455Smckusick * the type of token scanned. 7024455Smckusick */ 718804Smckusick 7233230Sbostic #include "indent_globs.h" 7333230Sbostic #include "indent_codes.h" 7424455Smckusick #include "ctype.h" 758804Smckusick 768804Smckusick #define alphanum 1 778804Smckusick #define opchar 3 788804Smckusick 798804Smckusick struct templ { 8024455Smckusick char *rwd; 8124455Smckusick int rwcode; 828804Smckusick }; 838804Smckusick 8424455Smckusick struct templ specials[100] = 858804Smckusick { 868804Smckusick "switch", 1, 878804Smckusick "case", 2, 8824455Smckusick "break", 0, 898804Smckusick "struct", 3, 9024455Smckusick "union", 3, 9124455Smckusick "enum", 3, 928804Smckusick "default", 2, 938804Smckusick "int", 4, 948804Smckusick "char", 4, 958804Smckusick "float", 4, 968804Smckusick "double", 4, 978804Smckusick "long", 4, 988804Smckusick "short", 4, 998804Smckusick "typdef", 4, 1008804Smckusick "unsigned", 4, 1018804Smckusick "register", 4, 1028804Smckusick "static", 4, 1038804Smckusick "global", 4, 1048804Smckusick "extern", 4, 10524455Smckusick "void", 4, 10624455Smckusick "goto", 0, 10724455Smckusick "return", 0, 1088804Smckusick "if", 5, 1098804Smckusick "while", 5, 1108804Smckusick "for", 5, 1118804Smckusick "else", 6, 1128804Smckusick "do", 6, 11324455Smckusick "sizeof", 7, 1148804Smckusick 0, 0 1158804Smckusick }; 1168804Smckusick 11724455Smckusick char chartype[128] = 11824455Smckusick { /* this is used to facilitate the decision 11924455Smckusick * of what type (alphanumeric, operator) 12024455Smckusick * each character is */ 1218804Smckusick 0, 0, 0, 0, 0, 0, 0, 0, 1228804Smckusick 0, 0, 0, 0, 0, 0, 0, 0, 1238804Smckusick 0, 0, 0, 0, 0, 0, 0, 0, 1248804Smckusick 0, 0, 0, 0, 0, 0, 0, 0, 125*33768Sbostic 0, 3, 0, 0, 1, 3, 3, 0, 1268804Smckusick 0, 0, 3, 3, 0, 3, 3, 3, 1278804Smckusick 1, 1, 1, 1, 1, 1, 1, 1, 1288804Smckusick 1, 1, 0, 0, 3, 3, 3, 3, 1298804Smckusick 0, 1, 1, 1, 1, 1, 1, 1, 1308804Smckusick 1, 1, 1, 1, 1, 1, 1, 1, 1318804Smckusick 1, 1, 1, 1, 1, 1, 1, 1, 1328804Smckusick 1, 1, 1, 0, 0, 0, 3, 1, 1338804Smckusick 0, 1, 1, 1, 1, 1, 1, 1, 1348804Smckusick 1, 1, 1, 1, 1, 1, 1, 1, 1358804Smckusick 1, 1, 1, 1, 1, 1, 1, 1, 1368804Smckusick 1, 1, 1, 0, 3, 0, 3, 0 1378804Smckusick }; 1388804Smckusick 1398804Smckusick 1408804Smckusick 1418804Smckusick 14224455Smckusick int 14324455Smckusick lexi() 14424455Smckusick { 14524455Smckusick register char *tok; /* local pointer to next char in token */ 14624455Smckusick int unary_delim; /* this is set to 1 if the current token 14724455Smckusick * 14824455Smckusick * forces a following operator to be unary */ 14924455Smckusick static int last_code; /* the last token type returned */ 15024455Smckusick static int l_struct; /* set to 1 if the last token was 'struct' */ 15124455Smckusick int code; /* internal code to be returned */ 15224455Smckusick char qchar; /* the delimiter character for a string */ 1538804Smckusick 15424455Smckusick tok = token; /* point to start of place to save token */ 1558804Smckusick unary_delim = false; 15624455Smckusick ps.col_1 = ps.last_nl; /* tell world that this token started in 15724455Smckusick * column 1 iff the last thing scanned was 15824455Smckusick * nl */ 15924455Smckusick ps.last_nl = false; 1608804Smckusick 16124455Smckusick while (*buf_ptr == ' ' || *buf_ptr == '\t') { /* get rid of blanks */ 16224455Smckusick ps.col_1 = false; /* leading blanks imply token is not in 16324455Smckusick * column 1 */ 1648804Smckusick if (++buf_ptr >= buf_end) 16524455Smckusick fill_buffer(); 1668804Smckusick } 1678804Smckusick 16824649Smckusick /* Scan an alphanumeric token. Note that we must also handle 16924649Smckusick * stuff like "1.0e+03" and "7e-6". */ 17024455Smckusick if (chartype[*buf_ptr & 0177] == alphanum) { /* we have a character 17124455Smckusick * or number */ 17224455Smckusick register char *j; /* used for searching thru list of 17324455Smckusick * reserved words */ 17424455Smckusick register struct templ *p; 17524649Smckusick register int c; 1768804Smckusick 17724649Smckusick do { /* copy it over */ 1788804Smckusick *tok++ = *buf_ptr++; 1798804Smckusick if (buf_ptr >= buf_end) 18024455Smckusick fill_buffer(); 18124649Smckusick } while (chartype[c = *buf_ptr & 0177] == alphanum || 18224649Smckusick isdigit(token[0]) && (c == '+' || c == '-') && 18324649Smckusick (tok[-1] == 'e' || tok[-1] == 'E')); 1848804Smckusick *tok++ = '\0'; 18524455Smckusick while (*buf_ptr == ' ' || *buf_ptr == '\t') { /* get rid of blanks */ 18624455Smckusick if (++buf_ptr >= buf_end) 18724455Smckusick fill_buffer(); 18824455Smckusick } 18924455Smckusick ps.its_a_keyword = false; 19024455Smckusick ps.sizeof_keyword = false; 19124455Smckusick if (l_struct) { /* if last token was 'struct', then this 19224455Smckusick * token should be treated as a 19324455Smckusick * declaration */ 1948804Smckusick l_struct = false; 1958804Smckusick last_code = ident; 19624455Smckusick ps.last_u_d = true; 1978804Smckusick return (decl); 1988804Smckusick } 19924455Smckusick ps.last_u_d = false; /* Operator after indentifier is binary */ 20024455Smckusick last_code = ident; /* Remember that this is the code we will 20124455Smckusick * return */ 2028804Smckusick 20324455Smckusick /* 20424455Smckusick * This loop will check if the token is a keyword. 20524455Smckusick */ 20624455Smckusick for (p = specials; (j = p->rwd) != 0; p++) { 20724455Smckusick tok = token; /* point at scanned token */ 20824455Smckusick if (*j++ != *tok++ || *j++ != *tok++) 20924455Smckusick continue; /* This test depends on the fact that 21024455Smckusick * identifiers are always at least 1 21124455Smckusick * character long (ie. the first two bytes 21224455Smckusick * of the identifier are always 21324455Smckusick * meaningful) */ 21424455Smckusick if (tok[-1] == 0) 21524455Smckusick break; /* If its a one-character identifier */ 21624455Smckusick while (*tok++ == *j) 21724455Smckusick if (*j++ == 0) 21824455Smckusick goto found_keyword; /* I wish that C had a multi-level 21924455Smckusick * break... */ 22024455Smckusick } 22124455Smckusick if (p->rwd) { /* we have a keyword */ 22224455Smckusick found_keyword: 22324455Smckusick ps.its_a_keyword = true; 22424455Smckusick ps.last_u_d = true; 22524455Smckusick switch (p->rwcode) { 22624455Smckusick case 1: /* it is a switch */ 22724455Smckusick return (swstmt); 22824455Smckusick case 2: /* a case or default */ 22924455Smckusick return (casestmt); 2308804Smckusick 23124455Smckusick case 3: /* a "struct" */ 23224455Smckusick if (ps.p_l_follow) 23324455Smckusick break; /* inside parens: cast */ 23424455Smckusick l_struct = true; 2358804Smckusick 23624455Smckusick /* 23724455Smckusick * Next time around, we will want to know that we have 23824455Smckusick * had a 'struct' 23924455Smckusick */ 24024455Smckusick case 4: /* one of the declaration keywords */ 24124455Smckusick if (ps.p_l_follow) { 24224455Smckusick ps.cast_mask |= 1 << ps.p_l_follow; 24324455Smckusick break; /* inside parens: cast */ 24424455Smckusick } 24524455Smckusick last_code = decl; 24624455Smckusick return (decl); 2478804Smckusick 24824455Smckusick case 5: /* if, while, for */ 24924455Smckusick return (sp_paren); 2508804Smckusick 25124455Smckusick case 6: /* do, else */ 25224455Smckusick return (sp_nparen); 2538804Smckusick 25424455Smckusick case 7: 25524455Smckusick ps.sizeof_keyword = true; 25624455Smckusick default: /* all others are treated like any other 25724455Smckusick * identifier */ 25824455Smckusick return (ident); 25924455Smckusick } /* end of switch */ 26024455Smckusick } /* end of if (found_it) */ 26124455Smckusick if (*buf_ptr == '(' && ps.tos <= 1 && ps.ind_level == 0 26224455Smckusick && (buf_ptr[1] != ')' || buf_ptr[2] != ';')) { 26324455Smckusick strncpy(ps.procname, token, sizeof ps.procname - 1); 26424455Smckusick ps.in_parameter_declaration = 1; 26524455Smckusick } 2668804Smckusick 26724455Smckusick /* 26824455Smckusick * The following hack attempts to guess whether or not the current 26924455Smckusick * token is in fact a declaration keyword -- one that has been 27024455Smckusick * typedefd 27124455Smckusick */ 27224455Smckusick if (((*buf_ptr == '*' && buf_ptr[1] != '=') || isalpha(*buf_ptr)) 27324455Smckusick && !ps.p_l_follow 27424455Smckusick && (ps.last_token == rparen || ps.last_token == semicolon || 27524455Smckusick ps.last_token == decl || 27624455Smckusick ps.last_token == lbrace || ps.last_token == rbrace)) { 27724455Smckusick ps.its_a_keyword = true; 27824455Smckusick ps.last_u_d = true; 27924455Smckusick last_code = decl; 28024455Smckusick return decl; 2818804Smckusick } 28224455Smckusick if (last_code == decl) /* if this is a declared variable, then 28324455Smckusick * following sign is unary */ 28424455Smckusick ps.last_u_d = true; /* will make "int a -1" work */ 2858804Smckusick last_code = ident; 28624455Smckusick return (ident); /* the ident is not in the list */ 28724455Smckusick } /* end of procesing for alpanum character */ 28824649Smckusick /* Scan a non-alphanumeric token */ 2898804Smckusick 29024455Smckusick *tok++ = *buf_ptr; /* if it is only a one-character token, it 29124455Smckusick * is moved here */ 2928804Smckusick *tok = '\0'; 2938804Smckusick if (++buf_ptr >= buf_end) 29424455Smckusick fill_buffer(); 2958804Smckusick 2968804Smckusick switch (*token) { 29724455Smckusick case '\n': 29824455Smckusick unary_delim = ps.last_u_d; 29924455Smckusick ps.last_nl = true; /* remember that we just had a newline */ 3008804Smckusick code = (had_eof ? 0 : newline); 30124455Smckusick 30224455Smckusick /* 30324455Smckusick * if data has been exausted, the newline is a dummy, and we 30424455Smckusick * should return code to stop 30524455Smckusick */ 3068804Smckusick break; 3078804Smckusick 30824455Smckusick case '\'': /* start of quoted character */ 30924455Smckusick case '"': /* start of string */ 31024455Smckusick qchar = *token; 31124455Smckusick if (troff) { 31224455Smckusick tok[-1] = '`'; 31324455Smckusick if (qchar == '"') 31424455Smckusick *tok++ = '`'; 31524455Smckusick *tok++ = BACKSLASH; 31624455Smckusick *tok++ = 'f'; 31724455Smckusick *tok++ = 'L'; 31824455Smckusick } 31924455Smckusick do { /* copy the string */ 32024455Smckusick while (1) { /* move one character or [/<char>]<char> */ 3218804Smckusick if (*buf_ptr == '\n') { 32224455Smckusick printf("%d: Unterminated literal\n", line_no); 3238804Smckusick goto stop_lit; 3248804Smckusick } 3258804Smckusick *tok = *buf_ptr++; 3268804Smckusick if (buf_ptr >= buf_end) 32724455Smckusick fill_buffer(); 3288804Smckusick if (had_eof || ((tok - token) > (bufsize - 2))) { 32924455Smckusick printf("Unterminated literal\n"); 3308804Smckusick ++tok; 3318804Smckusick goto stop_lit; 33224455Smckusick /* get outof literal copying loop */ 3338804Smckusick } 33424455Smckusick if (*tok == BACKSLASH) { /* if escape, copy extra 33524455Smckusick * char */ 33624455Smckusick if (*buf_ptr == '\n') /* check for escaped 33724455Smckusick * newline */ 3388804Smckusick ++line_no; 33924455Smckusick if (troff) { 34024455Smckusick *++tok = BACKSLASH; 34124455Smckusick if (*buf_ptr == BACKSLASH) 34224455Smckusick *++tok = BACKSLASH; 34324455Smckusick } 34424455Smckusick *++tok = *buf_ptr++; 34524455Smckusick ++tok; /* we must increment this again because we 34624455Smckusick * copied two chars */ 3478804Smckusick if (buf_ptr >= buf_end) 34824455Smckusick fill_buffer(); 3498804Smckusick } 3508804Smckusick else 35124455Smckusick break; /* we copied one character */ 35224455Smckusick } /* end of while (1) */ 3538804Smckusick } while (*tok++ != qchar); 35424455Smckusick if (troff) { 35524455Smckusick tok[-1] = BACKSLASH; 35624455Smckusick *tok++ = 'f'; 35724455Smckusick *tok++ = 'R'; 35824455Smckusick *tok++ = '\''; 35924455Smckusick if (qchar == '"') 36024455Smckusick *tok++ = '\''; 36124455Smckusick } 36224455Smckusick stop_lit: 3638804Smckusick code = ident; 3648804Smckusick break; 3658804Smckusick 36624455Smckusick case ('('): 36724455Smckusick case ('['): 3688804Smckusick unary_delim = true; 3698804Smckusick code = lparen; 3708804Smckusick break; 3718804Smckusick 37224455Smckusick case (')'): 37324455Smckusick case (']'): 3748804Smckusick code = rparen; 3758804Smckusick break; 3768804Smckusick 37724455Smckusick case '#': 37824455Smckusick unary_delim = ps.last_u_d; 3798804Smckusick code = preesc; 3808804Smckusick break; 3818804Smckusick 38224455Smckusick case '?': 3838804Smckusick unary_delim = true; 3848804Smckusick code = question; 3858804Smckusick break; 3868804Smckusick 38724455Smckusick case (':'): 3888804Smckusick code = colon; 3898804Smckusick unary_delim = true; 3908804Smckusick break; 3918804Smckusick 39224455Smckusick case (';'): 3938804Smckusick unary_delim = true; 3948804Smckusick code = semicolon; 3958804Smckusick break; 3968804Smckusick 39724455Smckusick case ('{'): 3988804Smckusick unary_delim = true; 39924455Smckusick 40024455Smckusick /* 40124455Smckusick * if (ps.in_or_st) ps.block_init = 1; 40224455Smckusick */ 40324455Smckusick code = ps.block_init ? lparen : lbrace; 4048804Smckusick break; 4058804Smckusick 40624455Smckusick case ('}'): 4078804Smckusick unary_delim = true; 40824455Smckusick code = ps.block_init ? rparen : rbrace; 4098804Smckusick break; 4108804Smckusick 41124455Smckusick case 014: /* a form feed */ 41224455Smckusick unary_delim = ps.last_u_d; 41324455Smckusick ps.last_nl = true; /* remember this so we can set 'ps.col_1' 41424455Smckusick * right */ 4158804Smckusick code = form_feed; 4168804Smckusick break; 4178804Smckusick 41824455Smckusick case (','): 4198804Smckusick unary_delim = true; 4208804Smckusick code = comma; 4218804Smckusick break; 4228804Smckusick 42324455Smckusick case '.': 4248804Smckusick unary_delim = false; 4258804Smckusick code = period; 4268804Smckusick break; 4278804Smckusick 42824455Smckusick case '-': 42924455Smckusick case '+': /* check for -, +, --, ++ */ 43024455Smckusick code = (ps.last_u_d ? unary_op : binary_op); 4318804Smckusick unary_delim = true; 4328804Smckusick 4338804Smckusick if (*buf_ptr == token[0]) { 43424455Smckusick /* check for doubled character */ 4358804Smckusick *tok++ = *buf_ptr++; 43624455Smckusick /* buffer overflow will be checked at end of loop */ 4378804Smckusick if (last_code == ident || last_code == rparen) { 43824455Smckusick code = (ps.last_u_d ? unary_op : postop); 43924455Smckusick /* check for following ++ or -- */ 4408804Smckusick unary_delim = false; 4418804Smckusick } 4428804Smckusick } 44324455Smckusick else if (*buf_ptr == '=') 44424455Smckusick /* check for operator += */ 44524455Smckusick *tok++ = *buf_ptr++; 44624677Smckusick else if (token[0] == '-' && *buf_ptr == '>') { 44724455Smckusick /* check for operator -> */ 44824455Smckusick *tok++ = *buf_ptr++; 44924677Smckusick if (!pointer_as_binop) { 45024677Smckusick code = unary_op; 45124677Smckusick unary_delim = false; 45224677Smckusick ps.want_blank = false; 45324677Smckusick } 45424455Smckusick } 45524455Smckusick /* buffer overflow will be checked at end of switch */ 4568804Smckusick 4578804Smckusick break; 4588804Smckusick 45924455Smckusick case '=': 46024455Smckusick if (ps.in_or_st) 46124455Smckusick ps.block_init = 1; 46224455Smckusick if (chartype[*buf_ptr] == opchar) { /* we have two char 46324455Smckusick * assignment */ 46424455Smckusick tok[-1] = *buf_ptr++; 46524455Smckusick if ((tok[-1] == '<' || tok[-1] == '>') && tok[-1] == *buf_ptr) 46624455Smckusick *tok++ = *buf_ptr++; 46724455Smckusick *tok++ = '='; /* Flip =+ to += */ 46824455Smckusick *tok = 0; 4698804Smckusick } 4708804Smckusick code = binary_op; 4718804Smckusick unary_delim = true; 47224455Smckusick break; 47324455Smckusick /* can drop thru!!! */ 4748804Smckusick 47524455Smckusick case '>': 47624455Smckusick case '<': 47724455Smckusick case '!': /* ops like <, <<, <=, !=, etc */ 4788804Smckusick if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') { 4798804Smckusick *tok++ = *buf_ptr; 4808804Smckusick if (++buf_ptr >= buf_end) 48124455Smckusick fill_buffer(); 4828804Smckusick } 4838804Smckusick if (*buf_ptr == '=') 48424455Smckusick *tok++ = *buf_ptr++; 48524455Smckusick code = (ps.last_u_d ? unary_op : binary_op); 4868804Smckusick unary_delim = true; 4878804Smckusick break; 4888804Smckusick 48924455Smckusick default: 4908804Smckusick if (token[0] == '/' && *buf_ptr == '*') { 49124455Smckusick /* it is start of comment */ 4928804Smckusick *tok++ = '*'; 4938804Smckusick 4948804Smckusick if (++buf_ptr >= buf_end) 49524455Smckusick fill_buffer(); 4968804Smckusick 4978804Smckusick code = comment; 49824455Smckusick unary_delim = ps.last_u_d; 4998804Smckusick break; 5008804Smckusick } 50124455Smckusick while (*(tok - 1) == *buf_ptr || *buf_ptr == '=') { 50224455Smckusick /* handle ||, &&, etc, and also things as in int *****i */ 5038804Smckusick *tok++ = *buf_ptr; 5048804Smckusick if (++buf_ptr >= buf_end) 50524455Smckusick fill_buffer(); 5068804Smckusick } 50724455Smckusick code = (ps.last_u_d ? unary_op : binary_op); 5088804Smckusick unary_delim = true; 5098804Smckusick 5108804Smckusick 51124455Smckusick } /* end of switch */ 5128804Smckusick if (code != newline) { 5138804Smckusick l_struct = false; 5148804Smckusick last_code = code; 5158804Smckusick } 51624455Smckusick if (buf_ptr >= buf_end) /* check for input buffer empty */ 51724455Smckusick fill_buffer(); 51824455Smckusick ps.last_u_d = unary_delim; 51924455Smckusick *tok = '\0'; /* null terminate the token */ 5208804Smckusick return (code); 5218804Smckusick }; 52224455Smckusick 52324455Smckusick /* Add the given keyword to the keyword table, using val as the keyword type 52424455Smckusick */ 52524455Smckusick addkey (key, val) 52624455Smckusick char *key; 52724455Smckusick { 52824455Smckusick register struct templ *p = specials; 52924455Smckusick while (p->rwd) 53024455Smckusick if (p->rwd[0] == key[0] && strcmp(p->rwd, key) == 0) 53124455Smckusick return; 53224455Smckusick else 53324455Smckusick p++; 53424455Smckusick if (p >= specials + sizeof specials / sizeof specials[0]) 53524455Smckusick return; /* For now, table overflows are silently 53624455Smckusick ignored */ 53724455Smckusick p->rwd = key; 53824455Smckusick p->rwcode = val; 53924455Smckusick p[1].rwd = 0; 54024455Smckusick p[1].rwcode = 0; 54124455Smckusick return; 54224455Smckusick } 543