NeoMutt  2025-12-11-911-gd8d604
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
source.c File Reference

Parse Source Commands. More...

#include "config.h"
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "source.h"
#include "parse/lib.h"
#include "module_data.h"
#include "muttlib.h"
#include <libintl.h>
+ Include dependency graph for source.c:

Go to the source code of this file.

Macros

#define MAX_ERRS   128
 

Functions

int source_rc (const char *rcfile_path, struct ParseContext *pc, struct ParseError *pe)
 Read an initialization file.
 
enum CommandResult parse_source (const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
 Parse the 'source' command - Implements Command::parse() -.
 
void source_stack_cleanup (void)
 Free memory from the stack used for the source command.
 
enum CommandResult parse_rc_line_cwd (const char *line, char *cwd, struct ParseContext *pc, struct ParseError *pe)
 Parse and run a muttrc line in a relative directory.
 
char * mutt_get_sourced_cwd (void)
 Get the current file path that is being parsed.
 

Detailed Description

Parse Source Commands.

Authors
  • Michael R. Elkins
  • g10 Code GmbH
  • Richard Russon
  • Aditya De Saha
  • Matthew Hughes
  • R Primus
  • Pietro Cerutti
  • Marco Sirabella
  • Dennis Schön

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file source.c.

Macro Definition Documentation

◆ MAX_ERRS

#define MAX_ERRS   128

Definition at line 55 of file source.c.

Function Documentation

◆ source_rc()

int source_rc ( const char * rcfile_path,
struct ParseContext * pc,
struct ParseError * pe )

Read an initialization file.

Parameters
rcfile_pathPath to initialization file
pcParse Context
peParse Errors
Return values
<0NeoMutt should pause to let the user know

Definition at line 64 of file source.c.

65{
66 if (!rcfile_path || !pc || !pe)
67 return -1;
68
70 struct Buffer *err = pe->message;
71
72 int lineno = 0, rc = 0, warnings = 0;
73 enum CommandResult line_rc;
74 struct Buffer *linebuf = NULL;
75 char *line = NULL;
76 char *currentline = NULL;
77 char rcfile[PATH_MAX + 1] = { 0 };
78 size_t linelen = 0;
79 pid_t pid;
80
81 mutt_str_copy(rcfile, rcfile_path, sizeof(rcfile));
82
83 size_t rcfilelen = mutt_str_len(rcfile);
84 if (rcfilelen == 0)
85 return -1;
86
87 bool ispipe = rcfile[rcfilelen - 1] == '|';
88
89 if (!ispipe)
90 {
91 struct ListNode *np = STAILQ_FIRST(&mod_data->muttrc_stack);
92 if (!mutt_path_to_absolute(rcfile, np ? NONULL(np->data) : ""))
93 {
94 mutt_error(_("Error: Can't build path of '%s'"), rcfile_path);
95 return -1;
96 }
97
98 STAILQ_FOREACH(np, &mod_data->muttrc_stack, entries)
99 {
100 if (mutt_str_equal(np->data, rcfile))
101 {
102 break;
103 }
104 }
105 if (np)
106 {
107 mutt_error(_("Error: Cyclic sourcing of configuration file '%s'"), rcfile);
108 return -1;
109 }
110
112 }
113
114 mutt_debug(LL_DEBUG2, "Reading configuration file '%s'\n", rcfile);
115
116 FILE *fp = mutt_open_read(rcfile, &pid);
117 if (!fp)
118 {
119 buf_printf(err, "%s: %s", rcfile, strerror(errno));
120 return -1;
121 }
122
123 linebuf = buf_pool_get();
124
125 const char *const c_config_charset = cs_subset_string(NeoMutt->sub, "config_charset");
126 const char *const c_charset = cc_charset();
127 while ((line = mutt_file_read_line(line, &linelen, fp, &lineno, MUTT_RL_CONT)) != NULL)
128 {
129 const bool conv = c_config_charset && c_charset;
130 if (conv)
131 {
132 currentline = mutt_str_dup(line);
133 if (!currentline)
134 continue;
135 mutt_ch_convert_string(&currentline, c_config_charset, c_charset, MUTT_ICONV_NONE);
136 }
137 else
138 {
139 currentline = line;
140 }
141
142 buf_strcpy(linebuf, currentline);
143
144 buf_reset(err);
145 line_rc = parse_rc_line(linebuf, pc, pe);
146 if (line_rc == MUTT_CMD_ERROR)
147 {
148 mutt_error("%s:%d: %s", rcfile, lineno, buf_string(err));
149 if (--rc < -MAX_ERRS)
150 {
151 if (conv)
152 FREE(&currentline);
153 break;
154 }
155 }
156 else if (line_rc == MUTT_CMD_WARNING)
157 {
158 /* Warning */
159 mutt_warning("%s:%d: %s", rcfile, lineno, buf_string(err));
160 warnings++;
161 }
162 else if (line_rc == MUTT_CMD_FINISH)
163 {
164 if (conv)
165 FREE(&currentline);
166 break; /* Found "finish" command */
167 }
168 else
169 {
170 if (rc < 0)
171 rc = -1;
172 }
173 if (conv)
174 FREE(&currentline);
175 }
176
177 FREE(&line);
178 mutt_file_fclose(&fp);
179 if (ispipe && (pid != -1))
180 {
181 int status = filter_wait(pid);
182 if (status != 0)
183 {
184 mutt_error(_("Command '%s' exited with status %d"), rcfile, status);
185 if (rc == 0)
186 rc = -1; // Set error code if not already set
187 }
188 }
189
190 if (rc)
191 {
192 /* the neomuttrc source keyword */
193 buf_reset(err);
194 buf_printf(err, (rc >= -MAX_ERRS) ? _("source: errors in %s") : _("source: reading aborted due to too many errors in %s"),
195 rcfile);
196 rc = -1;
197 }
198 else
199 {
200 /* Don't alias errors with warnings */
201 if (warnings > 0)
202 {
203 buf_printf(err, ngettext("source: %d warning in %s", "source: %d warnings in %s", warnings),
204 warnings, rcfile);
205 rc = -2;
206 }
207 }
208
209 if (!ispipe && !STAILQ_EMPTY(&mod_data->muttrc_stack))
210 {
211 struct ListNode *np = STAILQ_FIRST(&mod_data->muttrc_stack);
212 STAILQ_REMOVE_HEAD(&mod_data->muttrc_stack, entries);
213 FREE(&np->data);
214 FREE(&np);
215 }
216
217 buf_pool_release(&linebuf);
218 return rc;
219}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
CommandResult
Error codes for command_t parse functions.
Definition command.h:37
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition command.h:38
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition command.h:39
@ MUTT_CMD_FINISH
Finish: Stop processing this file.
Definition command.h:41
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
const char * cc_charset(void)
Get the cached value of $charset.
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition file.c:678
#define mutt_file_fclose(FP)
Definition file.h:144
@ MUTT_RL_CONT
-continuation
Definition file.h:44
#define mutt_warning(...)
Definition logging2.h:92
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition list.c:46
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
@ MODULE_ID_COMMANDS
ModuleCommands, NeoMutt Commands
Definition module_api.h:54
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition charset.c:817
#define MUTT_ICONV_NONE
No flags are set.
Definition charset.h:66
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:228
#define _(a)
Definition message.h:28
bool mutt_path_to_absolute(char *path, const char *reference)
Convert a relative path to its absolute form.
Definition path.c:333
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition string.c:586
#define PATH_MAX
Definition mutt.h:49
FILE * mutt_open_read(const char *path, pid_t *thepid)
Run a command to read from.
Definition muttlib.c:645
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:663
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define STAILQ_REMOVE_HEAD(head, field)
Definition queue.h:461
#define STAILQ_FIRST(head)
Definition queue.h:388
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define STAILQ_EMPTY(head)
Definition queue.h:382
enum CommandResult parse_rc_line(struct Buffer *line, struct ParseContext *pc, struct ParseError *pe)
Parse a line of user config.
Definition rc.c:45
#define MAX_ERRS
Definition source.c:55
#define NONULL(x)
Definition string2.h:44
String manipulation buffer.
Definition buffer.h:36
Commands private Module data.
Definition module_data.h:32
struct ListHead muttrc_stack
LIFO of sourced config files (avoid cycles)
Definition module_data.h:34
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
struct Buffer * message
Error message.
Definition perror.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ source_stack_cleanup()

void source_stack_cleanup ( void )

Free memory from the stack used for the source command.

Definition at line 272 of file source.c.

273{
275 if (mod_data)
276 mutt_list_free(&mod_data->muttrc_stack);
277}
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition list.c:123
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_rc_line_cwd()

enum CommandResult parse_rc_line_cwd ( const char * line,
char * cwd,
struct ParseContext * pc,
struct ParseError * pe )

Parse and run a muttrc line in a relative directory.

Parameters
lineLine to be parsed
cwdFile relative where to run the line
pcParse Context
peParse Errors
Return values
CommandResultResult e.g. MUTT_CMD_SUCCESS

Definition at line 287 of file source.c.

289{
290 if (!line || !cwd || !pc || !pe)
291 return MUTT_CMD_ERROR;
292
295
296 struct Buffer *buf = buf_pool_get();
297 buf_strcpy(buf, line);
298 enum CommandResult ret = parse_rc_line(buf, pc, pe);
299 buf_pool_release(&buf);
300
301 struct ListNode *np = STAILQ_FIRST(&mod_data->muttrc_stack);
302 STAILQ_REMOVE_HEAD(&mod_data->muttrc_stack, entries);
303 FREE(&np->data);
304 FREE(&np);
305
306 return ret;
307}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_get_sourced_cwd()

char * mutt_get_sourced_cwd ( void )

Get the current file path that is being parsed.

Return values
ptrFile path that is being parsed or cwd at runtime
Note
Caller is responsible for freeing returned string

Definition at line 315 of file source.c.

316{
318 struct ListNode *np = STAILQ_FIRST(&mod_data->muttrc_stack);
319 if (np && np->data)
320 return mutt_str_dup(np->data);
321
322 // stack is empty, return our own dummy file relative to cwd
323 struct Buffer *cwd = buf_pool_get();
324 mutt_path_getcwd(cwd);
325 buf_addstr(cwd, "/dummy.rc");
326 char *ret = buf_strdup(cwd);
327 buf_pool_release(&cwd);
328 return ret;
329}
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition path.c:476
+ Here is the call graph for this function:
+ Here is the caller graph for this function: