-
Notifications
You must be signed in to change notification settings - Fork 621
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A new substitution special string %(sh {shell-command}) that substitutes external command's output #1231
base: master
Are you sure you want to change the base?
A new substitution special string %(sh {shell-command}) that substitutes external command's output #1231
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -300,7 +300,7 @@ format_expand_arg(struct format_context *format, const char *name, const char *e | |
const char *value; | ||
const char *msgstart = name + STRING_SIZE("%(prompt"); | ||
const int msglen = end - msgstart - 1; | ||
|
||
char *tmp; | ||
if (end && msglen > 0 && string_format(msgbuf, "%.*s", msglen, msgstart)) { | ||
const char *msg = msgbuf; | ||
|
||
|
@@ -310,11 +310,39 @@ format_expand_arg(struct format_context *format, const char *name, const char *e | |
prompt = msg; | ||
} | ||
|
||
value = read_prompt(prompt); | ||
tmp=argv_format_arg(&argv_env, prompt); | ||
value = read_prompt(tmp); | ||
free(tmp); | ||
if (value == NULL) | ||
return false; | ||
return string_format_from(format->buf, &format->bufpos, "%s", value); | ||
} | ||
if (!prefixcmp(name, "%(sh")) { | ||
char cbuf[SIZEOF_STR]; | ||
const char *c=""; | ||
char value[SIZEOF_STR]={0}; | ||
const char *cstart = name + STRING_SIZE("%(sh"); | ||
const int clen = end - cstart - 1; | ||
int size; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this means we support recursive substitutions, like in
I think that's a bad idea because it means that inside the %(sh) expression, we need to take care of escaping both shell and Tigs %-substitutions. We should design something that's hard to misuse. |
||
char *tmp; | ||
FILE *cp; | ||
if (end && clen > 0 && string_format(cbuf, "%.*s", clen, cstart)) { | ||
c=cbuf; | ||
while (isspace(*c)) | ||
c++; | ||
} | ||
if (!*c||strlen(c)==8) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what if this fixed-size-buffer overflows? |
||
return false; | ||
tmp=argv_format_arg(&argv_env, c); | ||
cp=popen(tmp,"r"); | ||
free(tmp); | ||
size=fread(value,1,SIZEOF_STR-1,cp); | ||
if (value[0]==0 || size==0) | ||
return false; | ||
if (value[size-1]=='\n') | ||
value[size-1]='\0'; | ||
return string_format_from(format->buf, &format->bufpos, "%s", value); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the entire output becomes one string argument. An Maybe instead of
we should write
where the % is the magic key for "run this shell command and run the output as tig command" Something like this seems like a reasonably general approach but I'm sure there are many things I didn't consider. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean that it's not possible to embed |
||
} | ||
|
||
for (i = 0; i < format->vars_size; i++) { | ||
if (string_enum_compare(name, vars[i].name, vars[i].namelen)) | ||
|
@@ -329,6 +357,64 @@ format_expand_arg(struct format_context *format, const char *name, const char *e | |
return false; | ||
} | ||
|
||
static const char* | ||
get_closing_brace(const char *input) | ||
{ | ||
const char *s=input,*cur, *tmp; | ||
int idx,level=0,pair_idx; | ||
int level_to_pos[3000]={[0 ... 2998]=-1, -2}; | ||
int pos_to_level[256]={[0 ... 254]=-1, -2}; | ||
int pair_map[3000]={[0 ... 2998]=-1, -2}; | ||
int final_pairs[3000]={[0 ... 2998]=-1, -2}; | ||
int first=-1; | ||
while ( (cur = strstr(s,"(")), (tmp = strstr(s,")")), (cur&&cur<tmp?cur:(cur=tmp))) { | ||
s=cur+1; | ||
idx=cur-input; | ||
if ( *cur == '(' ) { | ||
pos_to_level[idx]=++level; | ||
level_to_pos[level]=idx; | ||
} else if ( *cur == ')' ) { | ||
if ( level > 0 ) { | ||
pair_idx=level_to_pos[level]; | ||
pos_to_level[idx]=level --; | ||
if (input[pair_idx]=='(' && input[idx]==')' || | ||
input[pair_idx]==')' && input[idx]=='(' ) { | ||
final_pairs[idx]=pair_idx; | ||
final_pairs[pair_idx]=idx; | ||
} | ||
} else { | ||
pos_to_level[idx]=-1; | ||
} | ||
} | ||
} | ||
|
||
for (idx=0;pos_to_level[idx]!=-2; idx++) { | ||
bool ok=false; | ||
if (pos_to_level[idx]==-1) | ||
continue; | ||
for (int j=0; final_pairs[j]!=-2;j++) { | ||
if (final_pairs[j]==-1) | ||
continue; | ||
if (final_pairs[j]==idx) { | ||
if (idx==0) | ||
first=j; | ||
ok=true; | ||
break; | ||
} | ||
} | ||
if (!ok) | ||
return NULL; | ||
} | ||
|
||
if (pos_to_level[0] < 0) | ||
return NULL; | ||
if (first<0) | ||
return NULL; | ||
|
||
return input+first; | ||
} | ||
|
||
|
||
static bool | ||
format_append_arg(struct format_context *format, const char ***dst_argv, const char *arg) | ||
{ | ||
|
@@ -339,7 +425,7 @@ format_append_arg(struct format_context *format, const char ***dst_argv, const c | |
const char *var = strstr(arg, "%("); | ||
const char *esc = strstr(arg, "%%"); | ||
bool is_escaped = esc && (esc < var || !var); | ||
const char *closing = var && !is_escaped ? strchr(var, ')') : NULL; | ||
const char *closing = var && !is_escaped ? get_closing_brace(var+1) : NULL; | ||
const char *next = is_escaped ? esc + 2 : closing ? closing + 1 : NULL; | ||
int len = var && !is_escaped ? var - arg : esc ? esc - arg + 1 : strlen(arg); | ||
|
||
|
@@ -349,7 +435,7 @@ format_append_arg(struct format_context *format, const char ***dst_argv, const c | |
if (len && !string_format_from(format->buf, &format->bufpos, "%.*s", len, arg)) | ||
return false; | ||
|
||
if (var && !is_escaped && !format_expand_arg(format, var, next)) | ||
if (var && !is_escaped && !format_expand_arg(format, var, next)) | ||
return false; | ||
|
||
arg = next; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we put spaces around binary operators