@@ -3586,6 +3586,8 @@ static Token *pp_strcat(Token *tline, const char *dname)
35863586 break ;
35873587 case TOKEN_STR :
35883588 unquote_token (t );
3589+ /* fall through */
3590+ case TOKEN_INTERNAL_STR :
35893591 len += t -> len ;
35903592 break ;
35913593 default :
@@ -3608,6 +3610,78 @@ static Token *pp_strcat(Token *tline, const char *dname)
36083610 return t ;
36093611}
36103612
3613+ /*
3614+ * Implement substring extraction as used by the %substr directive
3615+ * and function.
3616+ */
3617+ static Token * pp_substr (Token * tline , const char * dname )
3618+ {
3619+ int64_t start , count ;
3620+ const char * txt ;
3621+ size_t len ;
3622+ struct ppscan pps ;
3623+ Token * t ;
3624+ expr * evalresult ;
3625+ struct tokenval tokval ;
3626+
3627+ t = skip_white (tline );
3628+
3629+ if (!tok_is (t , TOKEN_STR )) {
3630+ nasm_nonfatal ("`%s' requires a string as parameter" , dname );
3631+ return NULL ;
3632+ }
3633+
3634+ pps .tptr = skip_white (t -> next );
3635+ if (tok_is (pps .tptr , TOKEN_COMMA ))
3636+ pps .tptr = skip_white (pps .tptr -> next );
3637+ if (!pps .tptr ) {
3638+ nasm_nonfatal ("`%s' requires a starting index" , dname );
3639+ return NULL ;
3640+ }
3641+
3642+ pps .ntokens = -1 ;
3643+ tokval .t_type = TOKEN_INVALID ;
3644+ evalresult = evaluate (ppscan , & pps , & tokval , NULL , true, NULL );
3645+ if (!evalresult ) {
3646+ return NULL ;
3647+ } else if (!is_simple (evalresult )) {
3648+ nasm_nonfatal ("non-constant value given to `%s'" , dname );
3649+ return NULL ;
3650+ }
3651+ start = evalresult -> value - 1 ;
3652+
3653+ pps .tptr = skip_white (pps .tptr );
3654+ if (!pps .tptr ) {
3655+ count = 1 ; /* Backwards compatibility: one character */
3656+ } else {
3657+ tokval .t_type = TOKEN_INVALID ;
3658+ evalresult = evaluate (ppscan , & pps , & tokval , NULL , true, NULL );
3659+ if (!evalresult ) {
3660+ return NULL ;
3661+ } else if (!is_simple (evalresult )) {
3662+ nasm_nonfatal ("non-constant value given to `%s'" , dname );
3663+ return NULL ;
3664+ }
3665+ count = evalresult -> value ;
3666+ }
3667+
3668+ unquote_token (t );
3669+ len = t -> len ;
3670+
3671+ /* make start and count being in range */
3672+ if (start < 0 )
3673+ start = 0 ;
3674+ if (count < 0 )
3675+ count = len + count + 1 - start ;
3676+ if (start + count > (int64_t )len )
3677+ count = len - start ;
3678+ if (!len || count < 0 || start >=(int64_t )len )
3679+ start = -1 , count = 0 ; /* empty string */
3680+
3681+ txt = (start < 0 ) ? "" : tok_text (t ) + start ;
3682+ return make_tok_qstr_len (NULL , txt , count );
3683+ }
3684+
36113685/**
36123686 * find and process preprocessor directive in passed line
36133687 * Find out if a line contains a preprocessor directive, and deal
@@ -4666,9 +4740,7 @@ static int do_directive(Token *tline, Token **output)
46664740 }
46674741
46684742 /*
4669- * Convert the string to a token stream. Note that smacros
4670- * are stored with the token stream reversed, so we have to
4671- * reverse the output of tokenize().
4743+ * Convert the string to a token stream.
46724744 */
46734745 macro_start = tokenize (unquote_token_cstr (t ));
46744746
@@ -4763,89 +4835,29 @@ static int do_directive(Token *tline, Token **output)
47634835 * zero, and a string token to use as an expansion. Create
47644836 * and store an SMacro.
47654837 */
4766- define_smacro (mname , casesense , macro_start , NULL );
4838+ if (macro_start )
4839+ define_smacro (mname , casesense , macro_start , NULL );
47674840 free_tlist (tline );
47684841 break ;
47694842
47704843 case PP_SUBSTR :
4771- {
4772- int64_t start , count ;
4773- const char * txt ;
4774- size_t len ;
4775-
47764844 if (!(mname = get_id (& tline , dname )))
47774845 goto done ;
47784846
47794847 last = tline ;
47804848 tline = expand_smacro (tline -> next );
47814849 last -> next = NULL ;
47824850
4783- t = skip_white (tline );
4784-
4785- /* t should now point to the string */
4786- if (!tok_is (t , TOKEN_STR )) {
4787- nasm_nonfatal ("`%s' requires string as second parameter" , dname );
4788- free_tlist (tline );
4789- goto done ;
4790- }
4791-
4792- pps .tptr = t -> next ;
4793- pps .ntokens = -1 ;
4794- tokval .t_type = TOKEN_INVALID ;
4795- evalresult = evaluate (ppscan , & pps , & tokval , NULL , true, NULL );
4796- if (!evalresult ) {
4797- free_tlist (tline );
4798- goto done ;
4799- } else if (!is_simple (evalresult )) {
4800- nasm_nonfatal ("non-constant value given to `%s'" , dname );
4801- free_tlist (tline );
4802- goto done ;
4803- }
4804- start = evalresult -> value - 1 ;
4805-
4806- pps .tptr = skip_white (pps .tptr );
4807- if (!pps .tptr ) {
4808- count = 1 ; /* Backwards compatibility: one character */
4809- } else {
4810- tokval .t_type = TOKEN_INVALID ;
4811- evalresult = evaluate (ppscan , & pps , & tokval , NULL , true, NULL );
4812- if (!evalresult ) {
4813- free_tlist (tline );
4814- goto done ;
4815- } else if (!is_simple (evalresult )) {
4816- nasm_nonfatal ("non-constant value given to `%s'" , dname );
4817- free_tlist (tline );
4818- goto done ;
4819- }
4820- count = evalresult -> value ;
4821- }
4822-
4823- unquote_token (t );
4824- len = t -> len ;
4825-
4826- /* make start and count being in range */
4827- if (start < 0 )
4828- start = 0 ;
4829- if (count < 0 )
4830- count = len + count + 1 - start ;
4831- if (start + count > (int64_t )len )
4832- count = len - start ;
4833- if (!len || count < 0 || start >=(int64_t )len )
4834- start = -1 , count = 0 ; /* empty string */
4835-
4836- txt = (start < 0 ) ? "" : tok_text (t ) + start ;
4837- len = count ;
4838- macro_start = make_tok_qstr_len (NULL , txt , len );
4839-
4851+ macro_start = pp_substr (tline , dname );
48404852 /*
48414853 * We now have a macro name, an implicit parameter count of
4842- * zero, and a numeric token to use as an expansion. Create
4854+ * zero, and a string token to use as an expansion. Create
48434855 * and store an SMacro.
48444856 */
4845- define_smacro (mname , casesense , macro_start , NULL );
4857+ if (macro_start )
4858+ define_smacro (mname , casesense , macro_start , NULL );
48464859 free_tlist (tline );
48474860 break ;
4848- }
48494861
48504862 case PP_ASSIGN :
48514863 if (!(mname = get_id (& tline , dname )))
@@ -6887,6 +6899,30 @@ stdmac_strcat(const SMacro *s, Token **params, int nparams)
68876899 return pp_strcat (expand_smacro_noreset (params [0 ]), s -> name );
68886900}
68896901
6902+ /* %substr() function */
6903+ static Token *
6904+ stdmac_substr (const SMacro * s , Token * * params , int nparams )
6905+ {
6906+ nasm_assert (nparams == 1 );
6907+ return pp_substr (expand_smacro_noreset (params [0 ]), s -> name );
6908+ }
6909+
6910+ /* %tok() function */
6911+ static Token *
6912+ stdmac_tok (const SMacro * s , Token * * params , int nparams )
6913+ {
6914+ Token * t = expand_smacro_noreset (params [0 ]);
6915+
6916+ (void )nparams ;
6917+
6918+ if (!tok_is (t , TOKEN_STR )) {
6919+ nasm_nonfatal ("`%s' requires string as parameter" , s -> name );
6920+ return NULL ;
6921+ }
6922+
6923+ return reverse_tokens (tokenize (unquote_token_cstr (t )));
6924+ }
6925+
68906926/* Add magic standard macros */
68916927struct magic_macros {
68926928 const char * name ;
@@ -6905,6 +6941,8 @@ static void pp_add_magic_stdmac(void)
69056941 { "%eval" , false, 1 , SPARM_EVAL |SPARM_VARADIC , stdmac_join },
69066942 { "%str" , false, 1 , SPARM_GREEDY |SPARM_STR , stdmac_join },
69076943 { "%strcat" , false, 1 , SPARM_GREEDY , stdmac_strcat },
6944+ { "%substr" , false, 1 , SPARM_GREEDY , stdmac_substr },
6945+ { "%tok" , false, 1 , 0 , stdmac_tok },
69086946 { NULL , false, 0 , 0 , NULL }
69096947 };
69106948 const struct magic_macros * m ;
0 commit comments