Beispiel #1
0
static int parse_line(const char * line, char ** key, char ** value)
{
    const char * line_begin = line;

    while (*line != '\0' && (*line != ' ' && *line != '\t' && *line != '='))
        line ++;

    size_t key_len = line - line_begin;

    while (*line != '\0' && *line != '=')
        line ++;

    if (*line == '\0')
        return -1;

    assert(*line == '=');

    *key = mstrncpy(line_begin, key_len);

    line ++;
    while (*line != '\0' && (*line == ' ' || *line =='\t'))
        line ++;

    if (*line == '\0')
    {
        free(*key);
        return -1;
    }

    *value = mstrcpy(line);

    return 0;
}
Beispiel #2
0
static void copy_rule_result(mchar * dest, mchar * query_string, regmatch_t * pmatch, int idx)
{
	debug_printf("copy_rule_result: idx=%d\n", idx);
	if (idx > 0 && idx <= MAX_SUBMATCHES) {
		mstrncpy(dest, query_string + pmatch[idx].rm_so, pmatch[idx].rm_eo - pmatch[idx].rm_so + 1);
	}
}
Beispiel #3
0
static void copy_rule_result(mchar * dest, GMatchInfo * match_info, int idx)
{
	gchar *match = g_match_info_fetch(match_info, idx);
	if (!match)
		return;

	debug_printf("copy_rule_result: idx=%d\n", idx);
	if (idx > 0 && idx <= MAX_SUBMATCHES) {
		mstrncpy(dest, match, MAX_METADATA_LEN);
	}
}
Beispiel #4
0
/**
 * Parse the pattern part of a leaf.
 */
static int
c2_parse_pattern(session_t *ps, const char *pattern, int offset, c2_ptr_t *presult) {
  c2_l_t * const pleaf = presult->l;

  // Exists operator cannot have pattern
  if (!pleaf->op)
    return offset;

  C2H_SKIP_SPACES();

  char *endptr = NULL;
  // Check for boolean patterns
  if (!strcmp_wd("true", &pattern[offset])) {
    pleaf->ptntype = C2_L_PTINT;
    pleaf->ptnint = true;
    offset += strlen("true");
  }
  else if (!strcmp_wd("false", &pattern[offset])) {
    pleaf->ptntype = C2_L_PTINT;
    pleaf->ptnint = false;
    offset += strlen("false");
  }
  // Check for integer patterns
  else if (pleaf->ptnint = strtol(pattern + offset, &endptr, 0),
      pattern + offset != endptr) {
    pleaf->ptntype = C2_L_PTINT;
    offset = endptr - pattern;
    // Make sure we are stopping at the end of a word
    if (isalnum(pattern[offset]))
      c2_error("Trailing characters after a numeric pattern.");
  }
  // Check for string patterns
  else {
    bool raw = false;
    char delim = '\0';

    // String flags
    if ('r' == tolower(pattern[offset])) {
      raw = true;
      ++offset;
      C2H_SKIP_SPACES();
    }

    // Check for delimiters
    if ('\"' == pattern[offset] || '\'' == pattern[offset]) {
      pleaf->ptntype = C2_L_PTSTRING;
      delim = pattern[offset];
      ++offset;
    }

    if (C2_L_PTSTRING != pleaf->ptntype)
      c2_error("Invalid pattern type.");

    // Parse the string now
    // We can't determine the length of the pattern, so we use the length
    // to the end of the pattern string -- currently escape sequences
    // cannot be converted to a string longer than itself.
    char *tptnstr = malloc((strlen(pattern + offset) + 1) * sizeof(char));
    char *ptptnstr = tptnstr;
    pleaf->ptnstr = tptnstr;
    for (; pattern[offset] && delim != pattern[offset]; ++offset) {
      // Handle escape sequences if it's not a raw string
      if ('\\' == pattern[offset] && !raw) {
        switch(pattern[++offset]) {
          case '\\':  *(ptptnstr++) = '\\'; break;
          case '\'':  *(ptptnstr++) = '\''; break;
          case '\"':  *(ptptnstr++) = '\"'; break;
          case 'a':   *(ptptnstr++) = '\a'; break;
          case 'b':   *(ptptnstr++) = '\b'; break;
          case 'f':   *(ptptnstr++) = '\f'; break;
          case 'n':   *(ptptnstr++) = '\n'; break;
          case 'r':   *(ptptnstr++) = '\r'; break;
          case 't':   *(ptptnstr++) = '\t'; break;
          case 'v':   *(ptptnstr++) = '\v'; break;
          case 'o':
          case 'x':
                      {
                        char *tstr = mstrncpy(pattern + offset + 1, 2);
                        char *pstr = NULL;
                        long val = strtol(tstr, &pstr,
                            ('o' == pattern[offset] ? 8: 16));
                        free(tstr);
                        if (pstr != &tstr[2] || val <= 0)
                          c2_error("Invalid octal/hex escape sequence.");
                        assert(val < 256 && val >= 0);
                        *(ptptnstr++) = val;
                        offset += 2;
                        break;
                      }
          default:   c2_error("Invalid escape sequence.");
        }
      }
      else {
        *(ptptnstr++) = pattern[offset];
      }
    }
    if (!pattern[offset])
      c2_error("Premature end of pattern string.");
    ++offset;
    *ptptnstr = '\0';
    pleaf->ptnstr = mstrcpy(tptnstr);
    free(tptnstr);
  }

  C2H_SKIP_SPACES();

  if (!pleaf->ptntype)
    c2_error("Invalid pattern type.");

  // Check if the type is correct
  if (!(((C2_L_TSTRING == pleaf->type
            || C2_L_TATOM == pleaf->type)
          && C2_L_PTSTRING == pleaf->ptntype)
        || ((C2_L_TCARDINAL == pleaf->type
            || C2_L_TWINDOW == pleaf->type
            || C2_L_TDRAWABLE == pleaf->type)
          && C2_L_PTINT == pleaf->ptntype)))
    c2_error("Pattern type incompatible with target type.");

  if (C2_L_PTINT == pleaf->ptntype && pleaf->match)
    c2_error("Integer/boolean pattern cannot have operator qualifiers.");

  if (C2_L_PTINT == pleaf->ptntype && pleaf->match_ignorecase)
    c2_error("Integer/boolean pattern cannot have flags.");

  if (C2_L_PTSTRING == pleaf->ptntype
      && (C2_L_OGT == pleaf->op || C2_L_OGTEQ == pleaf->op
        || C2_L_OLT == pleaf->op || C2_L_OLTEQ == pleaf->op))
    c2_error("String pattern cannot have an arithmetic operator.");

  return offset;
}
Beispiel #5
0
/**
 * Parse the target part of a rule.
 */
static int
c2_parse_target(session_t *ps, const char *pattern, int offset, c2_ptr_t *presult) {
  // Initialize leaf
  presult->isbranch = false;
  presult->l = malloc(sizeof(c2_l_t));
  if (!presult->l)
    c2_error("Failed to allocate memory for new leaf.");

  c2_l_t * const pleaf = presult->l;
  memcpy(pleaf, &leaf_def, sizeof(c2_l_t));

  // Parse negation marks
  while ('!' == pattern[offset]) {
    pleaf->neg = !pleaf->neg;
    ++offset;
    C2H_SKIP_SPACES();
  }

  // Copy target name out
  unsigned tgtlen = 0;
  for (; pattern[offset]
      && (isalnum(pattern[offset]) || '_' == pattern[offset]); ++offset) {
    ++tgtlen;
  }
  if (!tgtlen)
    c2_error("Empty target.");
  pleaf->tgt = mstrncpy(&pattern[offset - tgtlen], tgtlen);

  // Check for predefined targets
  for (unsigned i = 1; i < sizeof(C2_PREDEFS) / sizeof(C2_PREDEFS[0]); ++i) {
    if (!strcmp(C2_PREDEFS[i].name, pleaf->tgt)) {
      pleaf->predef = i;
      pleaf->type = C2_PREDEFS[i].type;
      pleaf->format = C2_PREDEFS[i].format;
      break;
    }
  }

  // Alias for predefined targets
  if (!pleaf->predef) {
#define TGTFILL(pdefid) \
  (pleaf->predef = pdefid, \
   pleaf->type = C2_PREDEFS[pdefid].type, \
   pleaf->format = C2_PREDEFS[pdefid].format)

  // if (!strcmp("WM_NAME", tgt) || !strcmp("_NET_WM_NAME", tgt))
  //   TGTFILL(C2_L_PNAME);
#undef TGTFILL

    // Alias for custom properties
#define TGTFILL(target, type, format) \
  (pleaf->target = mstrcpy(target), \
   pleaf->type = type, \
   pleaf->format = format)

    // if (!strcmp("SOME_ALIAS"))
    //   TGTFILL("ALIAS_TEXT", C2_L_TSTRING, 32);
#undef TGTFILL
  }

  C2H_SKIP_SPACES();

  // Parse target-on-frame flag
  if ('@' == pattern[offset]) {
    pleaf->tgt_onframe = true;
    ++offset;
    C2H_SKIP_SPACES();
  }

  // Parse index
  if ('[' == pattern[offset]) {
    offset++;

    C2H_SKIP_SPACES();

    int index = -1;
    char *endptr = NULL;

    index = strtol(pattern + offset, &endptr, 0);

    if (!endptr || pattern + offset == endptr)
      c2_error("No index number found after bracket.");

    if (index < 0)
      c2_error("Index number invalid.");

    if (pleaf->predef)
      c2_error("Predefined targets can't have index.");

    pleaf->index = index;
    offset = endptr - pattern;

    C2H_SKIP_SPACES();

    if (']' != pattern[offset])
      c2_error("Index end marker not found.");

    ++offset;

    C2H_SKIP_SPACES();
  }

  // Parse target type and format
  if (':' == pattern[offset]) {
    ++offset;
    C2H_SKIP_SPACES();

    // Look for format
    bool hasformat = false;
    int format = 0;
    {
      char *endptr = NULL;
      format =  strtol(pattern + offset, &endptr, 0);
      assert(endptr);
      if ((hasformat = (endptr && endptr != pattern + offset)))
        offset = endptr - pattern;
      C2H_SKIP_SPACES();
    }

    // Look for type
    enum c2_l_type type = C2_L_TUNDEFINED;
    {
      switch (pattern[offset]) {
        case 'w': type = C2_L_TWINDOW; break;
        case 'd': type = C2_L_TDRAWABLE; break;
        case 'c': type = C2_L_TCARDINAL; break;
        case 's': type = C2_L_TSTRING; break;
        case 'a': type = C2_L_TATOM; break;
        default:  c2_error("Invalid type character.");
      }

      if (type) {
        if (pleaf->predef) {
          printf_errf("(): Warning: Type specified for a default target will be ignored.");
        }
        else {
          if (pleaf->type && type != pleaf->type)
            printf_errf("(): Warning: Default type overridden on target.");
          pleaf->type = type;
        }
      }

      offset++;
      C2H_SKIP_SPACES();
    }

    // Default format
    if (!pleaf->format) {
      switch (pleaf->type) {
        case C2_L_TWINDOW:
        case C2_L_TDRAWABLE:
        case C2_L_TATOM:
          pleaf->format = 32;  break;
        case C2_L_TSTRING:
          pleaf->format = 8;   break;
        default:
          break;
      }
    }

    // Write format
    if (hasformat) {
      if (pleaf->predef)
        printf_errf("(): Warning: Format \"%d\" specified on a default target will be ignored.", format);
      else if (C2_L_TSTRING == pleaf->type)
        printf_errf("(): Warning: Format \"%d\" specified on a string target will be ignored.", format);
      else {
        if (pleaf->format && pleaf->format != format)
          printf_err("Warning: Default format %d overridden on target.",
              pleaf->format);
        pleaf->format = format;
      }
    }
  }

  if (!pleaf->type)
    c2_error("Target type cannot be determined.");

  // if (!pleaf->predef && !pleaf->format && C2_L_TSTRING != pleaf->type)
  //   c2_error("Target format cannot be determined.");

  if (pleaf->format && 8 != pleaf->format
        && 16 != pleaf->format && 32 != pleaf->format)
    c2_error("Invalid format.");

  return offset;
}
Beispiel #6
0
void parse_metadata(RIP_MANAGER_INFO * rmi, TRACK_INFO * ti)
{
	int i;
	int eflags;
	int rc;
	int matched;
	mchar query_string[MAX_TRACK_LEN];
	Parse_Rule *rulep;

	/* Has any m/.../s rule matched? */
	BOOL save_track_matched = FALSE;

	/* Has any m/.../x rule matched? */
	BOOL exclude_track_matched = FALSE;

	ti->artist[0] = 0;
	ti->title[0] = 0;
	ti->album[0] = 0;
	ti->composed_metadata[0] = 0;
	ti->save_track = TRUE;

	/* Loop through rules, if we find a matching rule, then use it */
	/* For now, only default rules supported with ascii 
	   regular expressions. */
	debug_printf("Converting query string to wide\n");
	gstring_from_string(rmi, query_string, MAX_TRACK_LEN, ti->raw_metadata, CODESET_METADATA);
	for (rulep = rmi->parse_rules; rulep->cmd; rulep++) {
#if !defined (USE_GLIB_REGEX)
		regmatch_t pmatch[MAX_SUBMATCHES + 1];
#endif
		eflags = 0;
		if (rulep->cmd == PARSERULE_CMD_MATCH) {
			debug_mprintf(m_("Testing match rule: ") m_S m_(" vs. ") m_S m_("\n"),
				      query_string, rulep->match);
			if (rulep->flags & PARSERULE_SKIP) {
#if defined (USE_GLIB_REGEX)
				rc = g_regex_match(rulep->reg, query_string, 0, NULL);
				matched = rc;
#else
				rc = mregexec(rulep->reg, query_string, 0, NULL, eflags);
				matched = !rc;
#endif
				if (!matched) {
					continue;
				}
				/* GCS FIX: We need to return to the 
				   caller that the metadata should be dropped. */
				debug_printf("Skip rule matched\n");
				ti->save_track = FALSE;
				ti->have_track_info = 0;
				return;
			} else if (rulep->flags & PARSERULE_SAVE) {
#if defined (USE_GLIB_REGEX)
				rc = g_regex_match(rulep->reg, query_string, 0, NULL);
				matched = rc;
#else
				rc = mregexec(rulep->reg, query_string, 0, NULL, eflags);
				matched = !rc;
#endif
				if (!matched) {
					if (!save_track_matched)
						ti->save_track = FALSE;
					continue;
				}
				if (!exclude_track_matched) {
					ti->save_track = TRUE;
					save_track_matched = TRUE;
				}
			} else if (rulep->flags & PARSERULE_EXCLUDE) {
#if defined (USE_GLIB_REGEX)
				rc = g_regex_match(rulep->reg, query_string, 0, NULL);
				matched = rc;
#else
				rc = mregexec(rulep->reg, query_string, 0, NULL, eflags);
				matched = !rc;
#endif
				if (matched && !save_track_matched) {
					/* Rule matched => Exclude track */
					ti->save_track = FALSE;
					exclude_track_matched = TRUE;
				}
			} else {
#if defined (USE_GLIB_REGEX)
				GMatchInfo *match_info;
				gint nmatch;

				rc = g_regex_match(rulep->reg, query_string, 0, &match_info);
				if (rc == 0) {
					/* Didn't match rule. */
					continue;
				}
				nmatch = g_match_info_get_match_count(match_info);
				debug_printf("Got %d matches\n", nmatch);
				for (i = 0; i < nmatch; i++) {
					gchar *match = g_match_info_fetch(match_info, i);
					debug_printf("[%d] = %s\n", i, match);
					g_free(match);
				}
				copy_rule_result(ti->artist, match_info, rulep->artist_idx);
				copy_rule_result(ti->title, match_info, rulep->title_idx);
				copy_rule_result(ti->album, match_info, rulep->album_idx);
				copy_rule_result(ti->track_p, match_info, rulep->trackno_idx);
				copy_rule_result(ti->year, match_info, rulep->year_idx);
				g_match_info_free(match_info);
#else
				eflags = 0;
				rc = mregexec(rulep->reg, query_string, MAX_SUBMATCHES + 1, pmatch, eflags);
				if (rc != 0) {
					/* Didn't match rule. */
					continue;
				}

				for (i = 0; i < MAX_SUBMATCHES + 1; i++) {
					debug_printf("pmatch[%d]: (so,eo) = (%d,%d)\n", i,
						     pmatch[i].rm_so, pmatch[i].rm_eo);
				}
				copy_rule_result(ti->artist, query_string, pmatch, rulep->artist_idx);
				copy_rule_result(ti->title, query_string, pmatch, rulep->title_idx);
				copy_rule_result(ti->album, query_string, pmatch, rulep->album_idx);
				copy_rule_result(ti->track_p, query_string, pmatch, rulep->trackno_idx);
				copy_rule_result(ti->year, query_string, pmatch, rulep->year_idx);
#endif
				ti->have_track_info = 1;
				compose_metadata(rmi, ti);
				debug_mprintf(m_("Parsed track info.\n")
					      m_("ARTIST: ") m_S m_("\n")
					      m_("TITLE: ") m_S m_("\n")
					      m_("ALBUM: ") m_S m_("\n")
					      m_("TRACK: ") m_S m_("\n")
					      m_("YEAR: ") m_S m_("\n"),
					      ti->artist, ti->title, ti->album, ti->track_p, ti->year);
				return;
			}
		} else if (rulep->cmd == PARSERULE_CMD_SUBST) {
#if defined (USE_GLIB_REGEX)
			GMatchInfo *match_info;
			gint start_pos, end_pos;
			gchar *tmp, *subst_string;

			debug_mprintf(m_("Testing subst rule: ") m_S m_(" vs. ") m_S m_("\n"),
				      query_string, rulep->match);
			rc = g_regex_match(rulep->reg, query_string, 0, &match_info);
			if (rc == 0) {
				/* Didn't match rule. */
				continue;
			}
			rc = g_match_info_fetch_pos(match_info, 0, &start_pos, &end_pos);
			if (!rc) {
				debug_printf("g_match_info_fetch_pos returned 0\n");
				g_match_info_free(match_info);
				continue;
			}
			debug_printf("Matched at (%d,%d)\n", start_pos, end_pos);
			if (start_pos == -1) {
				g_match_info_free(match_info);
				continue;
			}
			tmp = g_strndup(query_string, start_pos);
			tmp[start_pos] = 0;
			subst_string = g_strconcat(tmp, rulep->subst, &tmp[end_pos], NULL);
			g_free(tmp);
			g_match_info_free(match_info);
			mstrncpy(query_string, subst_string, MAX_TRACK_LEN);
#else
			mchar subst_string[MAX_TRACK_LEN];
			int used, left;
			debug_mprintf(m_("Testing subst rule: ") m_S m_(" vs. ") m_S m_("\n"),
				      query_string, rulep->match);
			rc = mregexec(rulep->reg, query_string, 1, pmatch, eflags);
			if (rc != 0) {
				/* Didn't match rule. */
				continue;
			}
			/* Update the query string and continue. */
			debug_printf("Matched at (%d,%d)\n", pmatch[0].rm_so, pmatch[0].rm_eo);
			mstrncpy(subst_string, query_string, pmatch[0].rm_so + 1);
			debug_mprintf(m_("(1) subst_string = ") m_S m_("\n"), subst_string);
			used = pmatch[0].rm_so;
			left = MAX_TRACK_LEN - used;
			mstrncpy(subst_string + used, rulep->subst, left);
			debug_mprintf(m_("(2) subst_string = ") m_S m_("\n"), subst_string);
			used += mstrlen(rulep->subst);
			left = MAX_TRACK_LEN - used;
			mstrncpy(subst_string + used, query_string + pmatch[0].rm_eo, left);
			debug_mprintf(m_("(3) subst_string = ") m_S m_("\n"), subst_string);
			mstrncpy(query_string, subst_string, MAX_TRACK_LEN);
			debug_mprintf(m_("(4) query_string = ") m_S m_("\n"), query_string);
#endif
		}
	}
	debug_printf("Fell through while parsing data...\n");
	mstrncpy(ti->title, query_string, MAX_TRACK_LEN);
	ti->have_track_info = 1;
	compose_metadata(rmi, ti);
}