Beispiel #1
0
// wp_next
struct
window_pane *wp_next(
	struct	window_pane *cur_wp, int dir,
	bool	(*filt)(struct window_pane *, struct window_pane *),
	int	(*sort)(const void *a, const void *b))
{
	struct	window_pane *wp;
	struct	window_pane *tar_wp;

	ARRAY_INIT(&panes);
	TAILQ_FOREACH(wp, &cur_wp->window->panes, entry)
		if (filt(cur_wp, wp))
			ARRAY_ADD(&panes, wp);

	// bypass filter
	if (ARRAY_LENGTH(&panes) == 0)
		TAILQ_FOREACH(wp, &cur_wp->window->panes, entry)
			switch(dir) {
				case WP_L:
					if (wp->xoff < cur_wp->xoff)
						ARRAY_ADD(&panes, wp);
					break;
				case WP_R:
					if (wp->xoff > cur_wp->xoff)
						ARRAY_ADD(&panes, wp);
					break;
				case WP_U:
					if (wp->yoff < cur_wp->yoff)
						ARRAY_ADD(&panes, wp);
					break;
				case WP_D:
					if (wp->yoff > cur_wp->yoff)
						ARRAY_ADD(&panes, wp);
					break;
			}

	if (ARRAY_LENGTH(&panes) > 0)
		qsort(ARRAY_DATA(&panes), ARRAY_LENGTH(&panes),
				sizeof(struct window_pane *), sort);

	if (ARRAY_LENGTH(&panes) > 0)
		tar_wp = ARRAY_FIRST(&panes);

	ARRAY_FREE(&panes);
	return tar_wp;
}
Beispiel #2
0
void printflike2
cfg_add_cause(struct causelist *causes, const char *fmt, ...)
{
	char	*cause;
	va_list	 ap;

	va_start(ap, fmt);
	xvasprintf(&cause, fmt, ap);
	va_end(ap);

	ARRAY_ADD(causes, cause);
}
Beispiel #3
0
void
keywords_load_from_char(char *kw)
{
	char *p, *last = NULL;

	keywords_clear();

	for ((p = strtok_r(kw, " ", &last)); p;
	    (p = strtok_r(NULL, " ", &last))) {
		ARRAY_ADD(&keywords, strdup(p));
	}
}
Beispiel #4
0
void
keywords_load_from_argv(char **av)
{
	char **kw = av;

	keywords_clear();

	while (*kw != NULL) {
		ARRAY_ADD(&keywords, strdup(*kw));
		kw++;
	}
}
Beispiel #5
0
void
cfg_add_cause(const char* fmt, ...)
{
	va_list	ap;
	char*	msg;

	va_start(ap, fmt);
	xvasprintf(&msg, fmt, ap);
	va_end (ap);

	ARRAY_ADD(&cfg_causes, msg);
}
Beispiel #6
0
/* Make an array of all the mboxes to visit. */
int
fetch_mbox_make(struct account *a)
{
	struct fetch_mbox_data	*data = a->data;
	struct fetch_mbox_mbox	*fmbox;
	char			*path;
	u_int			 i, j;
	glob_t			 g;

	ARRAY_INIT(&data->fmboxes);

	for (i = 0; i < ARRAY_LENGTH(data->mboxes); i++) {
		path = ARRAY_ITEM(data->mboxes, i);
		if (glob(path, GLOB_BRACE|GLOB_NOCHECK, NULL, &g) != 0) {
			log_warn("%s: glob(\"%s\")", a->name, path);
			goto error;
		}

		if (g.gl_pathc < 1)
			fatalx("glob returned garbage");
		for (j = 0; j < (u_int) g.gl_pathc; j++) {
			fmbox = xcalloc(1, sizeof *fmbox);
			fmbox->path = xstrdup(g.gl_pathv[j]);
			fmbox->fd = -1;
			fmbox->base = NULL;
			ARRAY_ADD(&data->fmboxes, fmbox);
		}

		globfree(&g);
	}

	return (0);

error:
	for (i = 0; i < ARRAY_LENGTH(&data->fmboxes); i++) {
		fmbox = ARRAY_ITEM(&data->fmboxes, i);

		xfree(fmbox->path);
		xfree(fmbox);
	}
	ARRAY_FREE(&data->fmboxes);

	return (-1);
}
Beispiel #7
0
void
window_more_vadd(struct window_pane *wp, const char *fmt, va_list ap)
{
	struct window_more_mode_data	*data = wp->modedata;
	struct screen			*s = &data->screen;
	struct screen_write_ctx	 	 ctx;
	char   				*msg;
	u_int				 size;

	xvasprintf(&msg, fmt, ap);
	ARRAY_ADD(&data->list, msg);

	screen_write_start(&ctx, wp, NULL);
	size = ARRAY_LENGTH(&data->list) - 1;
	if (size >= data->top && size <= data->top + screen_size_y(s) - 1) {
		window_more_write_line(wp, &ctx, size - data->top);
		if (size != data->top)
			window_more_write_line(wp, &ctx, 0);
	} else
		window_more_write_line(wp, &ctx, 0);
	screen_write_stop(&ctx);
}
Beispiel #8
0
/* Search state 2. */
int
imap_state_search2(struct account *a, struct fetch_ctx *fctx)
{
	struct fetch_imap_data	*data = a->data;
	char			*line, *ptr;
	u_int			 uid;

	if (imap_getln(a, fctx, IMAP_UNTAGGED, &line) != 0)
		return (FETCH_ERROR);
	if (line == NULL)
		return (FETCH_BLOCK);

	/* Skip the header. */
	if (strncasecmp(line, "* SEARCH", 8) != 0)
		return (imap_bad(a, line));
	line += 8;

	/* Read each UID and save it. */
	do {
		while (isspace((u_char) *line))
			line++;
		ptr = strchr(line, ' ');
		if (ptr == NULL)
			ptr = strchr(line, '\0');
		if (ptr == line)
			break;

		if (sscanf(line, "%u", &uid) != 1)
			return (imap_bad(a, line));
		ARRAY_ADD(&data->wanted, uid);
		log_debug3("%s: fetching UID: %u", a->name, uid);

		line = ptr;
	} while (*line == ' ');

	fctx->state = imap_state_search3;
	return (FETCH_AGAIN);
}
Beispiel #9
0
/*
 * Sometimes mail has wrapped header lines, this undoubtedly looks neat but
 * makes them a pain to match using regexps. We build a list of the newlines
 * in all the wrapped headers in m->wrapped, and can then quickly unwrap them
 * for regexp matching and wrap them again for delivery.
 */
u_int
fill_wrapped(struct mail *m)
{
	char		*ptr;
	size_t		 end, off;
	u_int		 n;

	if (!ARRAY_EMPTY(&m->wrapped))
		fatalx("already wrapped");

	ARRAY_INIT(&m->wrapped);
	m->wrapchar = '\0';

	end = m->body;
	ptr = m->data;

	n = 0;
	for (;;) {
		ptr = memchr(ptr, '\n', m->size - (ptr - m->data));
		if (ptr == NULL)
			break;
		ptr++;
		off = ptr - m->data;
		if (off >= end)
			break;

		/* Check if the line starts with whitespace. */
		if (!isblank((u_char) *ptr))
			continue;

		/* Save the position. */
		ARRAY_ADD(&m->wrapped, off - 1);
		n++;
	}

	return (n);
}
Beispiel #10
0
int
main(int argc, char **argv)
{
	struct passwd	*pw;
	struct keylist	*keylist;
	char		*s, *path, *label, *home, **var;
	int	 	 opt, flags, quiet, keys;

#if defined(DEBUG) && defined(__OpenBSD__)
	malloc_options = (char *) "AFGJPX";
#endif

	quiet = flags = 0;
	label = path = NULL;
	login_shell = (**argv == '-');
	while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUvV")) != -1) {
		switch (opt) {
		case '2':
			flags |= IDENTIFY_256COLOURS;
			flags &= ~IDENTIFY_88COLOURS;
			break;
		case '8':
			flags |= IDENTIFY_88COLOURS;
			flags &= ~IDENTIFY_256COLOURS;
			break;
		case 'c':
			if (shell_cmd != NULL)
				xfree(shell_cmd);
			shell_cmd = xstrdup(optarg);
			break;
		case 'V':
			printf("%s %s\n", __progname, VERSION);
			exit(0);
		case 'f':
			if (cfg_file != NULL)
				xfree(cfg_file);
			cfg_file = xstrdup(optarg);
			break;
		case 'l':
			login_shell = 1;
			break;
		case 'L':
			if (label != NULL)
				xfree(label);
			label = xstrdup(optarg);
			break;
		case 'q':
			quiet = 1;
			break;
		case 'S':
			if (path != NULL)
				xfree(path);
			path = xstrdup(optarg);
			break;
		case 'u':
			flags |= IDENTIFY_UTF8;
			break;
		case 'v':
			debug_level++;
			break;
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (shell_cmd != NULL && argc != 0)
		usage();

	log_open_tty(debug_level);

	if (!(flags & IDENTIFY_UTF8)) {
		/*
		 * If the user has set whichever of LC_ALL, LC_CTYPE or LANG
		 * exist (in that order) to contain UTF-8, it is a safe
		 * assumption that either they are using a UTF-8 terminal, or
		 * if not they know that output from UTF-8-capable programs may
		 * be wrong.
		 */
		if ((s = getenv("LC_ALL")) == NULL) {
			if ((s = getenv("LC_CTYPE")) == NULL)
				s = getenv("LANG");
		}
		if (s != NULL && (strcasestr(s, "UTF-8") != NULL ||
		    strcasestr(s, "UTF8") != NULL))
			flags |= IDENTIFY_UTF8;
	}

	environ_init(&global_environ);
	for (var = environ; *var != NULL; var++)
		environ_put(&global_environ, *var);

	options_init(&global_options, NULL);
	options_table_populate_tree(server_options_table, &global_options);
	options_set_number(&global_options, "quiet", quiet);

	options_init(&global_s_options, NULL);
	options_table_populate_tree(session_options_table, &global_s_options);
	options_set_string(&global_s_options, "default-shell", "%s", getshell());

	options_init(&global_w_options, NULL);
	options_table_populate_tree(window_options_table, &global_w_options);

	/* Set the prefix option (its a list, so not in the table). */
	keylist = xmalloc(sizeof *keylist);
	ARRAY_INIT(keylist);
	ARRAY_ADD(keylist, '\002');
	options_set_data(&global_s_options, "prefix", keylist, xfree);

	/* Enable UTF-8 if the first client is on UTF-8 terminal. */
	if (flags & IDENTIFY_UTF8) {
		options_set_number(&global_s_options, "status-utf8", 1);
		options_set_number(&global_s_options, "mouse-utf8", 1);
		options_set_number(&global_w_options, "utf8", 1);
	}

	/* Override keys to vi if VISUAL or EDITOR are set. */
	if ((s = getenv("VISUAL")) != NULL || (s = getenv("EDITOR")) != NULL) {
		if (strrchr(s, '/') != NULL)
			s = strrchr(s, '/') + 1;
		if (strstr(s, "vi") != NULL)
			keys = MODEKEY_VI;
		else
			keys = MODEKEY_EMACS;
		options_set_number(&global_s_options, "status-keys", keys);
		options_set_number(&global_w_options, "mode-keys", keys);
	}

	/* Locate the configuration file. */
	if (cfg_file == NULL) {
		home = getenv("HOME");
		if (home == NULL || *home == '\0') {
			pw = getpwuid(getuid());
			if (pw != NULL)
				home = pw->pw_dir;
		}
		xasprintf(&cfg_file, "%s/%s", home, DEFAULT_CFG);
		if (access(cfg_file, R_OK) != 0 && errno == ENOENT) {
			xfree(cfg_file);
			cfg_file = NULL;
		}
	}

	/*
	 * Figure out the socket path. If specified on the command-line with -S
	 * or -L, use it, otherwise try $TMUX or assume -L default.
	 */
	parseenvironment();
	if (path == NULL) {
		/* If no -L, use the environment. */
		if (label == NULL) {
			if (environ_path != NULL)
				path = xstrdup(environ_path);
			else
				label = xstrdup("default");
		}

		/* -L or default set. */
		if (label != NULL) {
			if ((path = makesocketpath(label)) == NULL) {
				log_warn("can't create socket");
				exit(1);
			}
		}
	}
	if (label != NULL)
		xfree(label);
	if (realpath(path, socket_path) == NULL)
		strlcpy(socket_path, path, sizeof socket_path);
	xfree(path);

#ifdef HAVE_SETPROCTITLE
	/* Set process title. */
	setproctitle("%s (%s)", __progname, socket_path);
#endif

	/* Pass control to the client. */
	ev_base = osdep_event_init();
	exit(client_main(argc, argv, flags));
}
Beispiel #11
0
static void
read_file (struct buffer *buffer)
{
  int fd;
  void *map = MAP_FAILED;

  struct line line_buffer;
  size_t line_length;

  const char *line_begin, *line_end, *end;

  char newline[8];
  size_t newline_length = 0;

  off_t size = 0;
  uint32_t digest = 0;

  if (-1 == (fd = open (buffer->path + 7, O_RDONLY)))
    {
      if (errno != ENOENT)
        {
          set_error (_("Failed to open '%s' for reading: %s"),
                     buffer->path, strerror (errno));

          goto failed;
        }

      buffer->charset = CHARSET_UTF8;
      buffer->line_ending = LINE_ENDING_LF;

      buffer->log = log_open (buffer->undo_path, buffer, 0);

      if (!buffer->log)
        goto failed;

      return;
    }

  if (-1 == (size = lseek (fd, 0, SEEK_END)))
    {
      static const size_t readbuf_size = 65536;
      char *readbuf;
      const char *begin, *end;
      int ret;

      struct line encoded_buffer;

      readbuf = malloc (readbuf_size);

      ARRAY_INIT (&encoded_buffer);

      while (0 < (ret = read (fd, readbuf, readbuf_size)))
        {
          digest = crc32 (digest, readbuf, ret);

          if (!buffer->charset)
            {
              charset_detect (&buffer->charset, &buffer->line_ending, readbuf, ret);

              newline_length = charset_encode_line_ending (newline, buffer->charset, buffer->line_ending);
            }

          begin = readbuf;
          end = readbuf + ret;

          while (begin != end)
            {
              line_end = memmem (begin, end - begin, newline, newline_length);

              if (!line_end)
                {
                  ARRAY_ADD_SEVERAL (&encoded_buffer, begin, end - begin);

                  break;
                }

              ARRAY_ADD_SEVERAL (&encoded_buffer, begin, line_end - begin);

              begin = line_end + newline_length;

              line_length = charset_decode (0, buffer->charset,
                                            &ARRAY_GET (&encoded_buffer, 0),
                                            ARRAY_COUNT (&encoded_buffer));

              ARRAY_INIT (&line_buffer);
              ARRAY_RESERVE (&line_buffer, line_length);

              charset_decode (&ARRAY_GET (&line_buffer, 0), buffer->charset,
                              &ARRAY_GET (&encoded_buffer, 0),
                              ARRAY_COUNT (&encoded_buffer));

              ARRAY_COUNT (&line_buffer) = line_length;

              pthread_mutex_lock (&buffer->lock);

              ARRAY_ADD (&buffer->lines, line_buffer);

              pthread_mutex_unlock (&buffer->lock);

              ARRAY_RESET (&encoded_buffer);
            }
        }
    }
  else if (size > 0)
    {
      if (MAP_FAILED == (map = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0)))
        {
          set_error (_("Failed to mmap '%s': %s"), buffer->path, strerror (errno));

          goto failed;
        }

      digest = crc32 (0, map, size);

      charset_detect (&buffer->charset, &buffer->line_ending, map, size);

      newline_length = charset_encode_line_ending (newline, buffer->charset, buffer->line_ending);

      end = (char *) map + size;

      for (line_begin = map; line_begin < end; line_begin = line_end + newline_length)
        {
          line_end = memmem (line_begin, end - line_begin,
                             newline, newline_length);

          if (!line_end)
            line_end = end;

          line_length = charset_decode (0, buffer->charset, line_begin,
                                        line_end - line_begin);

          ARRAY_INIT (&line_buffer);
          ARRAY_RESERVE (&line_buffer, line_length);

          charset_decode (&ARRAY_GET (&line_buffer, 0), buffer->charset,
                          line_begin, line_end - line_begin);

          ARRAY_COUNT (&line_buffer) = line_length;

          pthread_mutex_lock (&buffer->lock);

          ARRAY_ADD (&buffer->lines, line_buffer);

          pthread_mutex_unlock (&buffer->lock);

          /* XXX: Avoid issuing full repaints when nothing really happens onscreen */

          gui_repaint ();
        }
    }
  else
    {
      buffer->charset = CHARSET_UTF8;
      buffer->line_ending = LINE_ENDING_LF;
    }

  buffer->log = log_open (buffer->undo_path, buffer, digest);

failed:

  if (fd != -1)
    close (fd);

  if (map != MAP_FAILED)
    munmap (map, size);
}
Beispiel #12
0
/* Check mail against next rule or part of expression. */
int
mail_match(struct mail_ctx *mctx, struct msg *msg, struct msgbuf *msgbuf)
{
	struct account	*a = mctx->account;
	struct mail	*m = mctx->mail;
	struct expritem	*ei;
	struct replstrs	*users;
	int		 should_free, this = -1, error = MAIL_CONTINUE;
	char		 desc[DESCBUFSIZE];

	set_wrapped(m, ' ');

	/* If blocked, check for msgs from parent. */
	if (mctx->msgid != 0) {
		if (msg == NULL || msg->id != mctx->msgid)
			return (MAIL_BLOCKED);
		mctx->msgid = 0;

		if (msg->type != MSG_DONE)
			fatalx("unexpected message");
		if (msgbuf->buf != NULL && msgbuf->len != 0) {
			strb_destroy(&m->tags);
			m->tags = msgbuf->buf;
			reset_tags(&m->tags);
		}

		ei = mctx->expritem;
		switch (msg->data.error) {
		case MATCH_ERROR:
			return (MAIL_ERROR);
		case MATCH_TRUE:
			this = 1;
			break;
		case MATCH_FALSE:
			this = 0;
			break;
		default:
			fatalx("unexpected response");
		}
		apply_result(ei, &mctx->result, this);

		goto next_expritem;
	}

	/* Check for completion and end of ruleset. */
	if (mctx->done)
		return (MAIL_DONE);
	if (mctx->rule == NULL) {
		switch (conf.impl_act) {
		case DECISION_NONE:
			log_warnx("%s: reached end of ruleset. no "
			    "unmatched-mail option; keeping mail",  a->name);
			m->decision = DECISION_KEEP;
			break;
		case DECISION_KEEP:
			log_debug2("%s: reached end of ruleset. keeping mail",
			    a->name);
			m->decision = DECISION_KEEP;
			break;
		case DECISION_DROP:
			log_debug2("%s: reached end of ruleset. dropping mail",
			    a->name);
			m->decision = DECISION_DROP;
			break;
		}
		return (MAIL_DONE);
	}

	/* Expression not started. Start it. */
	if (mctx->expritem == NULL) {
		/* Start the expression. */
		mctx->result = 0;
		mctx->expritem = TAILQ_FIRST(mctx->rule->expr);
	}

	/* Check this expression item and adjust the result. */
	ei = mctx->expritem;

	/* Handle short-circuit evaluation. */
	switch (ei->op) {
	case OP_NONE:
		break;
	case OP_AND:
		/* And and the result is already false. */
		if (!mctx->result)
			goto next_expritem;
		break;
	case OP_OR:
		/* Or and the result is already true. */
		if (mctx->result)
			goto next_expritem;
		break;
	}

	switch (ei->match->match(mctx, ei)) {
	case MATCH_ERROR:
		return (MAIL_ERROR);
	case MATCH_PARENT:
		return (MAIL_BLOCKED);
	case MATCH_TRUE:
		this = 1;
		break;
	case MATCH_FALSE:
		this = 0;
		break;
	default:
		fatalx("unexpected op");
	}
	apply_result(ei, &mctx->result, this);

	ei->match->desc(ei, desc, sizeof desc);
	log_debug3("%s: tried %s, result now %d", a->name, desc, mctx->result);

next_expritem:
	/* Move to the next item. If there is one, then return. */
	mctx->expritem = TAILQ_NEXT(mctx->expritem, entry);
	if (mctx->expritem != NULL)
		return (MAIL_CONTINUE);

	log_debug3("%s: finished rule %u, result %d", a->name, mctx->rule->idx,
	    mctx->result);

	/* If the result was false, skip to find the next rule. */
	if (!mctx->result)
		goto next_rule;
	log_debug2("%s: matched to rule %u", a->name, mctx->rule->idx);

	/*
	 * If this rule is stop, mark the context so when we get back after
	 * delivery we know to stop.
	 */
	if (mctx->rule->stop)
		mctx->done = 1;

	/* Handle nested rules. */
	if (!TAILQ_EMPTY(&mctx->rule->rules)) {
		log_debug2("%s: entering nested rules", a->name);

		/*
		 * Stack the current rule (we are at the end of it so the
		 * the expritem must be NULL already).
		 */
		ARRAY_ADD(&mctx->stack, mctx->rule);

		/* Continue with the first rule of the nested list. */
		mctx->rule = TAILQ_FIRST(&mctx->rule->rules);
		return (MAIL_CONTINUE);
	}
	mctx->matched = 1;

	/* Handle lambda actions. */
	if (mctx->rule->lambda != NULL) {
		users = find_delivery_users(mctx, NULL, &should_free);

		chained = MAXACTIONCHAIN;
		if (fill_from_action(mctx,
		    mctx->rule, mctx->rule->lambda, users) != 0) {
			if (should_free)
				ARRAY_FREEALL(users);
			return (MAIL_ERROR);
		}

		if (should_free)
			ARRAY_FREEALL(users);
		error = MAIL_DELIVER;
	}

	/* Fill the delivery action queue. */
	if (!ARRAY_EMPTY(mctx->rule->actions)) {
		chained = MAXACTIONCHAIN;
		if (fill_from_strings(mctx,
		    mctx->rule, mctx->rule->actions) != 0)
			return (MAIL_ERROR);
		error = MAIL_DELIVER;
	}

next_rule:
	/* Move to the next rule. */
	mctx->ruleidx = mctx->rule->idx;	/* save last index */
	mctx->rule = TAILQ_NEXT(mctx->rule, entry);

	/* If no more rules, try to move up the stack. */
	while (mctx->rule == NULL) {
		if (ARRAY_EMPTY(&mctx->stack))
			break;
		log_debug2("%s: exiting nested rules", a->name);
		mctx->rule = ARRAY_LAST(&mctx->stack);
		mctx->rule = TAILQ_NEXT(mctx->rule, entry);
		ARRAY_TRUNC(&mctx->stack, 1);
	}

	return (error);
}
Beispiel #13
0
int
load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
{
	FILE		*f;
	u_int		 n, found;
	char		*buf, *copy, *line, *cause1, *msg;
	size_t		 len, oldlen;
	struct cmd_list	*cmdlist;

	log_debug("loading %s", path);
	if ((f = fopen(path, "rb")) == NULL) {
		xasprintf(cause, "%s: %s", path, strerror(errno));
		return (-1);
	}

	n = found = 0;
	line = NULL;
	while ((buf = fgetln(f, &len))) {
		/* Trim \n. */
		if (buf[len - 1] == '\n')
			len--;
		log_debug("%s: %.*s", path, (int)len, buf);

		/* Current line is the continuation of the previous one. */
		if (line != NULL) {
			oldlen = strlen(line);
			line = xrealloc(line, 1, oldlen + len + 1);
		} else {
			oldlen = 0;
			line = xmalloc(len + 1);
		}

		/* Append current line to the previous. */
		memcpy(line + oldlen, buf, len);
		line[oldlen + len] = '\0';
		n++;

		/* Continuation: get next line? */
		len = strlen(line);
		if (len > 0 && line[len - 1] == '\\') {
			line[len - 1] = '\0';

			/* Ignore escaped backslash at EOL. */
			if (len > 1 && line[len - 2] != '\\')
				continue;
		}
		copy = line;
		line = NULL;

		/* Skip empty lines. */
		buf = copy;
		while (isspace((u_char)*buf))
			buf++;
		if (*buf == '\0') {
			free(copy);
			continue;
		}

		/* Parse and run the command. */
		if (cmd_string_parse(buf, &cmdlist, path, n, &cause1) != 0) {
			free(copy);
			if (cause1 == NULL)
				continue;
			xasprintf(&msg, "%s:%u: %s", path, n, cause1);
			ARRAY_ADD(&cfg_causes, msg);
			free(cause1);
			continue;
		}
		free(copy);

		if (cmdlist == NULL)
			continue;
		cmdq_append(cmdq, cmdlist);
		cmd_list_free(cmdlist);
		found++;
	}
	if (line != NULL)
		free(line);
	fclose(f);

	return (found);
}