/* Messages with embedded format specifiers. */
[MSG_POS_INFO] = "line %ld, col %ld, t t y %d",
[MSG_CHAR_INFO] = "hex %02x, decimal %d",
[MSG_REPEAT_DESC] = "times %d .",
[MSG_REPEAT_DESC2] = "repeated %d .",
[MSG_WINDOW_LINE] = "window is line %d",
[MSG_WINDOW_BOUNDARY] = "%s at line %d, column %d",
[MSG_EDIT_PROMPT] = "edit %s, press space when done",
[MSG_NO_COMMAND] = "no commands for %c",
[MSG_KEYDESC] = "is %s",
/* Control keys. */ /* Most of these duplicate the entries in state names. */
[MSG_CTL_SHIFT] = "shift",
[MSG_CTL_ALTGR] = "altgr",
[MSG_CTL_CONTROL] = "control",
[MSG_CTL_ALT] = "alt",
[MSG_CTL_LSHIFT] = "l shift",
[MSG_CTL_SPEAKUP] = "speakup",
[MSG_CTL_LCONTROL] = "l control",
[MSG_CTL_RCONTROL] = "r control",
[MSG_CTL_CAPSSHIFT] = "caps shift",
/* * Function: next_specifier * Finds the start of the next format specifier in the argument string. * Return value: pointer to start of format * specifier, or NULL if no specifier exists.
*/ staticchar *next_specifier(char *input)
{ int found = 0; char *next_percent = input;
while (next_percent && !found) {
next_percent = strchr(next_percent, '%'); if (next_percent) { /* skip over doubled percent signs */ while (next_percent[0] == '%' &&
next_percent[1] == '%')
next_percent += 2; if (*next_percent == '%')
found = 1; elseif (*next_percent == '\0')
next_percent = NULL;
}
}
return next_percent;
}
/* Skip over 0 or more flags. */ staticchar *skip_flags(char *input)
{ while ((*input != '\0') && strchr(" 0+-#", *input))
input++; return input;
}
/* Skip over width.precision, if it exists. */ staticchar *skip_width(char *input)
{ while (isdigit(*input))
input++; if (*input == '.') {
input++; while (isdigit(*input))
input++;
} return input;
}
/* * Skip past the end of the conversion part. * Note that this code only accepts a handful of conversion specifiers: * c d s x and ld. Not accidental; these are exactly the ones used in * the default group of formatted messages.
*/ staticchar *skip_conversion(char *input)
{ if ((input[0] == 'l') && (input[1] == 'd'))
input += 2; elseif ((*input != '\0') && strchr("cdsx", *input))
input++; return input;
}
/* * Function: find_specifier_end * Return a pointer to the end of the format specifier.
*/ staticchar *find_specifier_end(char *input)
{
input++; /* Advance over %. */
input = skip_flags(input);
input = skip_width(input);
input = skip_conversion(input); return input;
}
/* * Function: compare_specifiers * Compare the format specifiers pointed to by *input1 and *input2. * Return true if they are the same, false otherwise. * Advance *input1 and *input2 so that they point to the character following * the end of the specifier.
*/ staticbool compare_specifiers(char **input1, char **input2)
{ bool same = false; char *end1 = find_specifier_end(*input1); char *end2 = find_specifier_end(*input2);
size_t length1 = end1 - *input1;
size_t length2 = end2 - *input2;
if ((length1 == length2) && !memcmp(*input1, *input2, length1))
same = true;
*input1 = end1;
*input2 = end2; return same;
}
/* * Function: fmt_validate * Check that two format strings contain the same number of format specifiers, * and that the order of specifiers is the same in both strings. * Return true if the condition holds, false if it doesn't.
*/ staticbool fmt_validate(char *template, char *user)
{ bool valid = true; bool still_comparing = true; char *template_ptr = template; char *user_ptr = user;
while (still_comparing && valid) {
template_ptr = next_specifier(template_ptr);
user_ptr = next_specifier(user_ptr); if (template_ptr && user_ptr) { /* Both have at least one more specifier. */
valid = compare_specifiers(&template_ptr, &user_ptr);
} else { /* No more format specifiers in one or both strings. */
still_comparing = false; /* See if one has more specifiers than the other. */ if (template_ptr || user_ptr)
valid = false;
}
} return valid;
}
/* * Function: msg_set * Description: Add a user-supplied message to the user_messages array. * The message text is copied to a memory area allocated with kmalloc. * If the function fails, then user_messages is untouched. * Arguments: * - index: a message number, as found in i18n.h. * - text: text of message. Not NUL-terminated. * - length: number of bytes in text. * Failure conditions: * -EINVAL - Invalid format specifiers in formatted message or illegal index. * -ENOMEM - Unable to allocate memory.
*/
ssize_t spk_msg_set(enum msg_index_t index, char *text, size_t length)
{ char *newstr = NULL; unsignedlong flags;
if ((index < MSG_FIRST_INDEX) || (index >= MSG_LAST_INDEX)) return -EINVAL;
newstr = kmemdup_nul(text, length, GFP_KERNEL); if (!newstr) return -ENOMEM;
/* * Find a message group, given its name. Return a pointer to the structure * if found, or NULL otherwise.
*/ struct msg_group_t *spk_find_msg_group(constchar *group_name)
{ struct msg_group_t *group = NULL; int i;
for (i = 0; i < num_groups; i++) { if (!strcmp(all_groups[i].name, group_name)) {
group = &all_groups[i]; break;
}
} return group;
}
for (i = group->start; i <= group->end; i++) { if (speakup_msgs[i] != speakup_default_msgs[i])
kfree(speakup_msgs[i]);
speakup_msgs[i] = speakup_default_msgs[i];
}
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
}
/* Called at initialization time, to establish default messages. */ void spk_initialize_msgs(void)
{
memcpy(speakup_msgs, speakup_default_msgs, sizeof(speakup_default_msgs));
}
/* Free user-supplied strings when module is unloaded: */ void spk_free_user_msgs(void)
{ enum msg_index_t index; unsignedlong flags;
spin_lock_irqsave(&speakup_info.spinlock, flags); for (index = MSG_FIRST_INDEX; index < MSG_LAST_INDEX; index++) { if (speakup_msgs[index] != speakup_default_msgs[index]) {
kfree(speakup_msgs[index]);
speakup_msgs[index] = speakup_default_msgs[index];
}
}
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.