pebble/src/fw/popups/phone_formatting.c
2025-01-27 11:38:16 -08:00

106 lines
4.1 KiB
C

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "phone_formatting.h"
#include "applib/graphics/utf8.h"
#include "util/math.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>
// Turn every word after the first one into an initial.
// e.g. Katharine Claire Berry -> Katharine C. B.
void phone_format_caller_name(const char *full_name, char *destination, size_t length) {
char *space = strchr(full_name, ' ');
// If there are no spaces, just use the whole thing and bail.
if (!space) {
strncpy(destination, full_name, length);
destination[length - 1] = '\0';
return;
}
// Copy the first name to the destination, as long as it fits.
size_t pos = MIN((size_t)(space - full_name), length - 1);
strncpy(destination, full_name, pos);
// Then keep adding the character after the space until we run out of spaces.
do {
space++;
// Abort if it is impossible for us to fit a space, one-byte initial, period and null in the
// buffer (= four bytes)
// Also bail out if this space terminates the string; otherwise we append an unnecessary
// space to the destination.
if ((pos + 4 > length - 1) || (*space == '\0')) {
break;
}
// Skip ahead if this is a space. This avoids stray dots on double spaces.
if (*space == ' ') {
continue;
}
destination[pos++] = ' ';
size_t initial_size = utf8_copy_character((utf8_t *)&destination[pos], (utf8_t *)space,
length - pos - 2); // 2 = ".\0"
// If we couldn't fit anything, stop here.
if (initial_size == 0) {
pos--; // the space we previously added should be omitted from our string.
break;
}
pos += initial_size;
destination[pos++] = '.';
} while ((space = strchr(space, ' ')));
destination[pos] = '\0';
}
// based on https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers
void phone_format_phone_number(const char *phone_number, char *formatted_phone_number,
size_t length) {
const int phone_number_length = strlen(phone_number);
// Only modify if phone number includes area code and correctly formatted
const int long_distance_min_len = 12; // 650-777-1234, +49 30 90260
if (phone_number_length >= long_distance_min_len) {
int local_number_length = 0;
// Parse from the end of the string to identify the local portion of the phone number
// After local_number_min_len, a separator delimits the regional or international portion
const int local_number_min_len = 6;
for (local_number_length = local_number_min_len; local_number_length < phone_number_length;
local_number_length++) {
const char key = phone_number[phone_number_length - local_number_length - 1];
if (!isdigit(key)) {
break;
}
}
// Force the local part of the phone number to the second line using newline
const int region_min_len = 3;
if (local_number_length <= (phone_number_length - region_min_len)) {
int region_length = phone_number_length - local_number_length;
const char *local_number = &phone_number[region_length];
// Remove dash, dot or space from region line
if ((phone_number[region_length - 1] == '-') || (phone_number[region_length - 1] == '.') ||
(phone_number[region_length - 1] == ' ')) {
region_length--;
}
snprintf(formatted_phone_number, length, "%.*s\n%.*s",
region_length, phone_number, local_number_length, local_number);
return;
}
}
// copy original to the output buffer for non-covered cases
strncpy(formatted_phone_number, phone_number, length);
}