diff --git a/src/mu-msg-fields.c b/src/mu-msg-fields.c index 332a3fa6..03e240c4 100644 --- a/src/mu-msg-fields.c +++ b/src/mu-msg-fields.c @@ -21,19 +21,19 @@ #include "mu-msg-fields.h" /* - * note: the differences for our purposes between a xapian field and a term: - * - there is only a single value for some item in per document (msg), ie. - * one value containing the list of To: addresses - * - there can be multiple terms, each containing e.g. one of the To: addresses - * - searching uses terms, but to display some field, it must be in the - * value (at least when using MuMsgIter) + * note: the differences for our purposes between a xapian field and a + * term: - there is only a single value for some item in per document + * (msg), ie. one value containing the list of To: addresses - there + * can be multiple terms, each containing e.g. one of the To: + * addresses - searching uses terms, but to display some field, it + * must be in the value (at least when using MuMsgIter) */ enum _FieldFlags { - FLAG_GMIME = 1 << 1, /* field retrieved through gmime */ - FLAG_XAPIAN_INDEX = 1 << 2, /* field is indexed in xapian */ - FLAG_XAPIAN_TERM = 1 << 3, /* field stored as term in xapian */ - FLAG_XAPIAN_VALUE = 1 << 4, /* field stored as value in xapian */ - FLAG_XAPIAN_CONTACT = 1 << 5 /* field contains an e-mail address */ + FLAG_GMIME = 1 << 0, /* field retrieved through gmime */ + FLAG_XAPIAN_INDEX = 1 << 1, /* field is indexed in xapian */ + FLAG_XAPIAN_TERM = 1 << 2, /* field stored as term in xapian */ + FLAG_XAPIAN_VALUE = 1 << 3, /* field stored as value in xapian */ + FLAG_XAPIAN_CONTACT = 1 << 4 /* field contains an e-mail address */ }; typedef enum _FieldFlags FieldFlags; @@ -44,10 +44,13 @@ struct _MuMsgField { MuMsgFieldId _id; /* the id of the field */ MuMsgFieldType _type; /* the type of the field */ const char *_name; /* the name of the field */ - const char *_shortcut; /* the shortcut for use in --fields and sorting */ - const char *_xprefix; /* the Xapian-prefix */ - FieldFlags _flags; /* the flags that tells us what to do */ + const char _shortcut; /* the shortcut for use in + * --fields and sorting */ + const char _xprefix; /* the Xapian-prefix */ + FieldFlags _flags; /* the flags that tells us + * what to do */ }; +typedef struct _MuMsgField MuMsgField; /* the name and shortcut fields must be lower case, or they might be * misinterpreted by the query-preprocesser which turns queries into @@ -56,247 +59,240 @@ static const MuMsgField FIELD_DATA[] = { { MU_MSG_FIELD_ID_BODY_TEXT, MU_MSG_FIELD_TYPE_STRING, - "body", "b", "B", + "body", 'b', 'B', FLAG_GMIME | FLAG_XAPIAN_INDEX }, { MU_MSG_FIELD_ID_BODY_HTML, MU_MSG_FIELD_TYPE_STRING, - "bodyhtml", "h", NULL, + "bodyhtml", 'h', 0, FLAG_GMIME }, { MU_MSG_FIELD_ID_CC, MU_MSG_FIELD_TYPE_STRING, - "cc", "c", "C", + "cc", 'c', 'C', FLAG_GMIME | FLAG_XAPIAN_CONTACT | FLAG_XAPIAN_VALUE }, { MU_MSG_FIELD_ID_DATE, MU_MSG_FIELD_TYPE_TIME_T, - "date", "d", "D", + "date", 'd', 'D', FLAG_GMIME | FLAG_XAPIAN_VALUE }, { MU_MSG_FIELD_ID_FLAGS, MU_MSG_FIELD_TYPE_INT, - "flags", "g", "G", /* flaGs */ + "flags", 'g', 'G', /* flaGs */ FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_VALUE }, { MU_MSG_FIELD_ID_FROM, MU_MSG_FIELD_TYPE_STRING, - "from", "f", "F", + "from", 'f', 'F', FLAG_GMIME | FLAG_XAPIAN_CONTACT | FLAG_XAPIAN_VALUE }, { MU_MSG_FIELD_ID_PATH, MU_MSG_FIELD_TYPE_STRING, - "path", "l", "L", /* 'l' for location */ + "path", 'l', 'L', /* 'l' for location */ FLAG_GMIME | FLAG_XAPIAN_VALUE }, { MU_MSG_FIELD_ID_MAILDIR, MU_MSG_FIELD_TYPE_STRING, - "maildir", "m", "M", + "maildir", 'm', 'M', FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_VALUE }, { MU_MSG_FIELD_ID_PRIO, MU_MSG_FIELD_TYPE_INT, - "prio", "p", "P", + "prio", 'p', 'P', FLAG_GMIME | FLAG_XAPIAN_VALUE }, { MU_MSG_FIELD_ID_SIZE, MU_MSG_FIELD_TYPE_BYTESIZE, - "size", "z", "Z", /* siZe */ + "size", 'z', 'Z', /* siZe */ FLAG_GMIME }, { MU_MSG_FIELD_ID_SUBJECT, MU_MSG_FIELD_TYPE_STRING, - "subject", "s", "S", + "subject", 's', 'S', FLAG_GMIME | FLAG_XAPIAN_INDEX | FLAG_XAPIAN_VALUE }, { MU_MSG_FIELD_ID_TO, MU_MSG_FIELD_TYPE_STRING, - "to", "t", "T", + "to", 't', 'T', FLAG_GMIME | FLAG_XAPIAN_CONTACT | FLAG_XAPIAN_VALUE }, { MU_MSG_FIELD_ID_MSGID, MU_MSG_FIELD_TYPE_STRING, - "msgid", "i", "I", /* 'i' for Id */ + "msgid", 'i', 'I', /* 'i' for Id */ FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_VALUE }, { MU_MSG_FIELD_ID_TIMESTAMP, MU_MSG_FIELD_TYPE_TIME_T, - "timestamp", "x", NULL, + "timestamp", 'x', 0, FLAG_GMIME } }; +/* the MsgField data in an array, indexed by the MsgFieldId; + * this allows for O(1) access + */ +static MuMsgField* _msg_field_data[MU_MSG_FIELD_ID_NUM]; +static const MuMsgField* mu_msg_field (MuMsgFieldId id) +{ + static gboolean _initialized = FALSE; + + /* initialize the array, but only once... */ + if (G_UNLIKELY(!_initialized)) { + int i; + for (i = 0; i != G_N_ELEMENTS(FIELD_DATA); ++i) + _msg_field_data[FIELD_DATA[i]._id] = + (MuMsgField*)&FIELD_DATA[i]; + _initialized = TRUE; + } + + return _msg_field_data[id]; +} + + void mu_msg_field_foreach (MuMsgFieldForEachFunc func, gconstpointer data) { int i; - for (i = 0; i != sizeof(FIELD_DATA)/sizeof(FIELD_DATA[0]); ++i) - func (&FIELD_DATA[i], data); -} - -typedef gboolean (*FieldMatchFunc) (const MuMsgField *field, - gconstpointer data); - -static const MuMsgField* -find_field (FieldMatchFunc matcher, gconstpointer data) -{ - int i; - for (i = 0; i != sizeof(FIELD_DATA)/sizeof(FIELD_DATA[0]); ++i) - if (matcher(&FIELD_DATA[i], data)) - return &FIELD_DATA[i]; - - return NULL; -} - -static gboolean -match_name (const MuMsgField *field, const gchar* name) -{ - return strcmp (field->_name, name) == 0; -} - -const MuMsgField* -mu_msg_field_from_name (const char* str) -{ - g_return_val_if_fail (str, NULL); - return find_field ((FieldMatchFunc)match_name, str); -} - -static gboolean -match_shortcut (const MuMsgField *field, char kar) -{ - return field->_shortcut[0] == kar; -} - -const MuMsgField* -mu_msg_field_from_shortcut (char kar) -{ - return find_field ((FieldMatchFunc)match_shortcut, - GUINT_TO_POINTER((guint)kar)); -} - -static gboolean -match_id (const MuMsgField *field, MuMsgFieldId id) -{ - return field->_id == id; -} - -const MuMsgField* -mu_msg_field_from_id (MuMsgFieldId id) -{ - return find_field ((FieldMatchFunc)match_id, - GUINT_TO_POINTER(id)); + for (i = 0; i != MU_MSG_FIELD_ID_NUM; ++i) + func (i, data); } -gboolean -mu_msg_field_gmime (const MuMsgField *field) +MuMsgFieldId +mu_msg_field_id_from_name (const char* str, gboolean err) { - g_return_val_if_fail (field, FALSE); - return field->_flags & FLAG_GMIME; -} + int i; - -gboolean -mu_msg_field_xapian_index (const MuMsgField *field) -{ - g_return_val_if_fail (field, FALSE); - return field->_flags & FLAG_XAPIAN_INDEX; -} - -gboolean -mu_msg_field_xapian_value (const MuMsgField *field) -{ - g_return_val_if_fail (field, FALSE); - return field->_flags & FLAG_XAPIAN_VALUE; -} - -gboolean -mu_msg_field_xapian_term (const MuMsgField *field) -{ - g_return_val_if_fail (field, FALSE); - return field->_flags & FLAG_XAPIAN_TERM; -} - -gboolean -mu_msg_field_xapian_contact (const MuMsgField *field) -{ - g_return_val_if_fail (field, FALSE); - return field->_flags & FLAG_XAPIAN_CONTACT; -} - - -gboolean -mu_msg_field_is_numeric (const MuMsgField *field) -{ - MuMsgFieldType type; + g_return_val_if_fail (str, MU_MSG_FIELD_ID_NONE); - g_return_val_if_fail (field, FALSE); + for (i = 0; i != G_N_ELEMENTS(FIELD_DATA); ++i) + if (strcmp(str, FIELD_DATA[i]._name) == 0) + return FIELD_DATA[i]._id; + + if (err) + g_return_val_if_reached (MU_MSG_FIELD_ID_NONE); + + return MU_MSG_FIELD_ID_NONE; +} + + +MuMsgFieldId +mu_msg_field_id_from_shortcut (char kar, gboolean err) +{ + int i; + for (i = 0; i != G_N_ELEMENTS(FIELD_DATA); ++i) + if (kar == FIELD_DATA[i]._shortcut) + return FIELD_DATA[i]._id; + + if (err) + g_return_val_if_reached (MU_MSG_FIELD_ID_NONE); + + return MU_MSG_FIELD_ID_NONE; +} + + +gboolean +mu_msg_field_gmime (MuMsgFieldId id) +{ + + g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE); + return mu_msg_field(id)->_flags & FLAG_GMIME; +} + + +gboolean +mu_msg_field_xapian_index (MuMsgFieldId id) +{ + g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE); + return mu_msg_field(id)->_flags & FLAG_XAPIAN_INDEX; +} + +gboolean +mu_msg_field_xapian_value (MuMsgFieldId id) +{ + g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE); + return mu_msg_field(id)->_flags & FLAG_XAPIAN_VALUE; +} + +gboolean +mu_msg_field_xapian_term (MuMsgFieldId id) +{ + g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE); + return mu_msg_field(id)->_flags & FLAG_XAPIAN_TERM; +} + +gboolean +mu_msg_field_xapian_contact (MuMsgFieldId id) +{ + g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE); + return mu_msg_field(id)->_flags & FLAG_XAPIAN_CONTACT; +} + + +gboolean +mu_msg_field_is_numeric (MuMsgFieldId mfid) +{ + g_return_val_if_fail (mu_msg_field_id_is_valid(mfid),FALSE); - type = mu_msg_field_type (field); - - return type == MU_MSG_FIELD_TYPE_BYTESIZE || - type == MU_MSG_FIELD_TYPE_TIME_T || - type == MU_MSG_FIELD_TYPE_INT; + return mfid == MU_MSG_FIELD_TYPE_BYTESIZE || + mfid == MU_MSG_FIELD_TYPE_TIME_T || + mfid == MU_MSG_FIELD_TYPE_INT; } const char* -mu_msg_field_name (const MuMsgField *field) +mu_msg_field_name (MuMsgFieldId id) { - g_return_val_if_fail (field, NULL); - return field->_name; + g_return_val_if_fail (mu_msg_field_id_is_valid(id),NULL); + return mu_msg_field(id)->_name; } -const char* -mu_msg_field_shortcut (const MuMsgField *field) -{ - g_return_val_if_fail (field, NULL); - return field->_shortcut; +char +mu_msg_field_shortcut (MuMsgFieldId id) +{ + g_return_val_if_fail (mu_msg_field_id_is_valid(id),0); + return mu_msg_field(id)->_shortcut; } -MuMsgFieldId -mu_msg_field_id (const MuMsgField *field) -{ - g_return_val_if_fail (field, MU_MSG_FIELD_ID_NONE); - return field->_id; -} -const char* -mu_msg_field_xapian_prefix (const MuMsgField *field) +char +mu_msg_field_xapian_prefix (MuMsgFieldId id) { - g_return_val_if_fail (field, NULL); - return field->_xprefix; + g_return_val_if_fail (mu_msg_field_id_is_valid(id),0); + return mu_msg_field(id)->_xprefix; } MuMsgFieldType -mu_msg_field_type (const MuMsgField *field) +mu_msg_field_type (MuMsgFieldId id) { - g_return_val_if_fail (field, MU_MSG_FIELD_TYPE_NONE); - return field->_type; + g_return_val_if_fail (mu_msg_field_id_is_valid(id), + MU_MSG_FIELD_TYPE_NONE); + return mu_msg_field(id)->_type; } diff --git a/src/mu-msg-fields.h b/src/mu-msg-fields.h index 08109ee5..34663822 100644 --- a/src/mu-msg-fields.h +++ b/src/mu-msg-fields.h @@ -27,7 +27,7 @@ G_BEGIN_DECLS /* don't change the order, add new types at the end, as these numbers * are used in the database */ enum _MuMsgFieldId { - MU_MSG_FIELD_ID_BODY_TEXT, + MU_MSG_FIELD_ID_BODY_TEXT = 0, MU_MSG_FIELD_ID_BODY_HTML, MU_MSG_FIELD_ID_CC, MU_MSG_FIELD_ID_DATE, @@ -42,13 +42,16 @@ enum _MuMsgFieldId { MU_MSG_FIELD_ID_MSGID, MU_MSG_FIELD_ID_TIMESTAMP, - MU_MSG_FIELD_ID_NUM, + MU_MSG_FIELD_ID_NUM }; -typedef enum _MuMsgFieldId MuMsgFieldId; -static const guint MU_MSG_FIELD_ID_NONE = MU_MSG_FIELD_ID_NUM + 1; -struct _MuMsgField; -typedef struct _MuMsgField MuMsgField; +static const guint MU_MSG_FIELD_ID_NONE = (guint)-1; +typedef guint MuMsgFieldId; + +#define mu_msg_field_id_is_valid(MFID) \ + ((MFID) < MU_MSG_FIELD_ID_NUM) + + /* don't change the order, add new types at the end (before _NUM)*/ enum _MuMsgFieldType { @@ -61,9 +64,11 @@ enum _MuMsgFieldType { MU_MSG_FIELD_TYPE_NUM }; typedef enum _MuMsgFieldType MuMsgFieldType; -static const guint MU_MSG_FIELD_TYPE_NONE = MU_MSG_FIELD_TYPE_NUM + 1; +static const guint MU_MSG_FIELD_TYPE_NONE = (guint)-1; -typedef void (*MuMsgFieldForEachFunc) (const MuMsgField *field, + + +typedef void (*MuMsgFieldForEachFunc) (MuMsgFieldId id, gconstpointer data); /** @@ -79,43 +84,32 @@ void mu_msg_field_foreach (MuMsgFieldForEachFunc func, gconstpointer data); * get the name of the field -- this a name that can be use in queries, * ie. 'subject:foo', with 'subject' being the name * - * @param field a MuMsgField - * + * @param id a MuMsgFieldId + * * @return the name of the field as a constant string, or * NULL if the field is unknown */ -const char* mu_msg_field_name (const MuMsgField *field) G_GNUC_CONST; +const char* mu_msg_field_name (MuMsgFieldId id) G_GNUC_PURE; /** * get the shortcut of the field -- this a shortcut that can be use in * queries, ie. 's:foo', with 's' meaning 'subject' being the name * - * @param field a MuMsgField + * @param id a MuMsgFieldId * - * @return the shortcut of the field as a constant string, or - * NULL if the field is unknown + * @return the shortcut character, or 0 if the field is unknown */ -const char* mu_msg_field_shortcut (const MuMsgField *field) G_GNUC_CONST; +char mu_msg_field_shortcut (MuMsgFieldId id) G_GNUC_PURE; /** * get the xapian prefix of the field -- that is, the prefix used in * the Xapian database to identify the field * - * @param field a MuMsgField + * @param id a MuMsgFieldId * - * @return the xapian prefix of the field as a constant string, or - * NULL if the field is unknown + * @return the xapian prefix char or 0 if the field is unknown */ -const char* mu_msg_field_xapian_prefix (const MuMsgField *field) G_GNUC_PURE; - -/** - * get the numerical ID of the field - * - * @param field a MuMsgField - * - * @return an id, or MU_MSG_FIELD_TYPE_NONE if the field is not known - */ -MuMsgFieldId mu_msg_field_id (const MuMsgField *field) G_GNUC_CONST; +char mu_msg_field_xapian_prefix (MuMsgFieldId id) G_GNUC_PURE; /** @@ -126,18 +120,17 @@ MuMsgFieldId mu_msg_field_id (const MuMsgField *field) G_GNUC_CONST; * @return the type of the field (a #MuMsgFieldType), or * MU_MSG_FIELD_TYPE_NONE if it is not found */ -MuMsgFieldType mu_msg_field_type (const MuMsgField *field) G_GNUC_CONST; +MuMsgFieldType mu_msg_field_type (MuMsgFieldId id) G_GNUC_PURE; /** * is the field numeric (has type MU_MSG_FIELD_TYPE_(BYTESIZE|TIME_T|INT))? * - * @param field a MuMsgField + * @param id a MuMsgFieldId * * @return TRUE if the field is numeric, FALSE otherwise */ -gboolean mu_msg_field_is_numeric (const MuMsgField *field) G_GNUC_CONST; - +gboolean mu_msg_field_is_numeric (MuMsgFieldId id) G_GNUC_PURE; /** @@ -145,20 +138,20 @@ gboolean mu_msg_field_is_numeric (const MuMsgField *field) G_GNUC_CONST * indexed in the in the Xapian database, so we can use the all the * phrasing, stemming etc. magic * - * @param field a MuMsgField + * @param id a MuMsgFieldId * * @return TRUE if the field is Xapian-enabled, FALSE otherwise */ -gboolean mu_msg_field_xapian_index (const MuMsgField *field) G_GNUC_PURE; +gboolean mu_msg_field_xapian_index (MuMsgFieldId id) G_GNUC_PURE; /** * should this field be stored as a xapian term? * - * @param field a MuMsgField + * @param id a MuMsgFieldId * * @return TRUE if the field is Xapian-enabled, FALSE otherwise */ -gboolean mu_msg_field_xapian_term (const MuMsgField *field) G_GNUC_PURE; +gboolean mu_msg_field_xapian_term (MuMsgFieldId id) G_GNUC_PURE; /** * should this field be stored as a xapian value? @@ -167,57 +160,55 @@ gboolean mu_msg_field_xapian_term (const MuMsgField *field) G_GNUC_PURE; * * @return TRUE if the field is Xapian-enabled, FALSE otherwise */ -gboolean mu_msg_field_xapian_value (const MuMsgField *field) G_GNUC_PURE; +gboolean mu_msg_field_xapian_value (MuMsgFieldId id) G_GNUC_PURE; /** * should this field be stored as contact information? This means that * e-mail address will be stored as terms, and names will be indexed * - * @param field a MuMsgField + * @param id a MuMsgFieldId * * @return TRUE if the field should be stored as contact information, * FALSE otherwise */ -gboolean mu_msg_field_xapian_contact (const MuMsgField *field) G_GNUC_PURE; +gboolean mu_msg_field_xapian_contact (MuMsgFieldId id) G_GNUC_PURE; /** * is the field gmime-enabled? That is, can be field be retrieved * using GMime? * - * @param field a MuMsgField + * @param id a MuMsgFieldId * * @return TRUE if the field is Gmime-enabled, FALSE otherwise */ -gboolean mu_msg_field_gmime (const MuMsgField *field) G_GNUC_PURE; +gboolean mu_msg_field_gmime (MuMsgFieldId id) G_GNUC_PURE; /** * get the corresponding MuMsgField for a name (as in mu_msg_field_name) * * @param str a name + * @param err, if TRUE, when the shortcut is not found, will issue a + * g_critical warning * * @return a MuMsgField, or NULL if it could not be found */ -const MuMsgField* mu_msg_field_from_name (const char* str) G_GNUC_PURE; +MuMsgFieldId mu_msg_field_id_from_name (const char* str, + gboolean err) G_GNUC_PURE; /** * get the corresponding MuMsgField for a shortcut (as in mu_msg_field_shortcut) * * @param kar a shortcut character + * @param err, if TRUE, when the shortcut is not found, will issue a + * g_critical warning * * @return a MuMsgField, or NULL if it could not be found */ -const MuMsgField* mu_msg_field_from_shortcut (char kar) G_GNUC_CONST; +MuMsgFieldId mu_msg_field_id_from_shortcut (char kar, + gboolean err) G_GNUC_PURE; -/** - * get the corresponding MuMsgField for an id (as in mu_msg_field_id) - * - * @param id an id - * - * @return a MuMsgField, or NULL if it could not be found - */ -const MuMsgField* mu_msg_field_from_id (MuMsgFieldId id) G_GNUC_CONST; G_END_DECLS