On 7/10/2020 8:02 AM, Ivan Dyukov wrote: > This commit add function which treat link status structure > and format it to text representation. > > Signed-off-by: Ivan Dyukov <i.dyu...@samsung.com>
<...> > +static int > +rte_eth_link_strf_parser(char *str, size_t len, const char *const fmt, > + const struct rte_eth_link *link) > +{ > + size_t offset = 0; > + const char *fmt_cur = fmt; > + char *str_cur = str; > + double gbits = (double)link->link_speed / 1000.; > + static const char autoneg_str[] = "Autoneg"; > + static const char fixed_str[] = "Fixed"; > + static const char fdx_str[] = "FDX"; > + static const char hdx_str[] = "HDX"; > + static const char unknown_str[] = "Unknown"; > + static const char up_str[] = "Up"; > + static const char down_str[] = "Down"; > + char gbits_str[20]; > + char mbits_str[20]; > + > + /* preformat complex formatting to easily concatinate it further */ > + snprintf(mbits_str, sizeof(mbits_str), "%u", link->link_speed); > + snprintf(gbits_str, sizeof(gbits_str), "%.1f", gbits); > + /* init str before formatting */ > + str[0] = 0; > + while (*fmt_cur) { > + /* check str bounds */ > + if (offset > (len - 1)) { > + str[len - 1] = '\0'; > + return -1; > + } > + if (*fmt_cur == '%') { > + /* set null terminator to current position, > + * it's required for strlcat > + */ > + *str_cur = '\0'; > + switch (*++fmt_cur) { > + /* Speed in Mbits/s */ > + case 'M': > + if (link->link_speed == > + ETH_SPEED_NUM_UNKNOWN) > + offset = strlcat(str, unknown_str, > + len); > + else > + offset = strlcat(str, mbits_str, len); > + break; > + /* Speed in Gbits/s */ > + case 'G': > + if (link->link_speed == > + ETH_SPEED_NUM_UNKNOWN) > + offset = strlcat(str, unknown_str, > + len); > + else > + offset = strlcat(str, gbits_str, len); > + break; > + /* Link status */ > + case 'S': > + offset = strlcat(str, link->link_status ? > + up_str : down_str, len); > + break; > + /* Link autoneg */ > + case 'A': > + offset = strlcat(str, link->link_autoneg ? > + autoneg_str : fixed_str, len); > + break; > + /* Link duplex */ > + case 'D': > + offset = strlcat(str, link->link_duplex ? > + fdx_str : hdx_str, len); > + break; > + /* ignore unknown specifier */ > + default: > + *str_cur = '%'; > + offset++; > + fmt_cur--; > + break; What do you think ignoring the unknown specifiers and keep continue processing the string, instead of break? Just keep unknown specifier as it is in the output string. > + > + } > + if (offset > (len - 1)) > + return -1; For me "offset >= len" is simpler than "offset > (len - 1)", also it prevents any possible error when "len == 0" ('len' is unsigned) although I can see you have check for it. Anyway both deos same thing, up to you. > + > + str_cur = str + offset; > + } else { > + *str_cur++ = *fmt_cur; > + offset++; Why keeping both offset and the pointer ('str_cur'), just offset should be enough "str[offset++] = *fmt_cur;", I think this simplifies a little bit. > + } > + fmt_cur++; > + } > + *str_cur = '\0'; > + return offset; > +} > + > +int > +rte_eth_link_printf(const char *const fmt, > + const struct rte_eth_link *link) > +{ > + char text[200]; > + int ret; > + > + ret = rte_eth_link_strf(text, 200, fmt, link); > + if (ret > 0) > + printf("%s", text); > + return ret; > +} > + > +int > +rte_eth_link_strf(char *str, size_t len, const char *const fmt, > + const struct rte_eth_link *link) > +{ > + size_t offset = 0; > + double gbits = (double)link->link_speed / 1000.; > + char speed_gbits_str[20]; > + char speed_mbits_str[20]; > + /* TBD: make it international? */ > + static const char link_down_str[] = "Link down\n"; > + static const char link_up_str[] = "Link up at "; > + static const char unknown_speed_str[] = "Unknown speed "; > + static const char mbits_str[] = "Mbit/s"; > + static const char gbits_str[] = "Gbit/s"; > + static const char fdx_str[] = "FDX "; > + static const char hdx_str[] = "HDX "; > + /* autoneg is latest param in default string, so add '\n' */ > + static const char autoneg_str[] = "Autoneg\n"; > + static const char fixed_str[] = "Fixed\n"; Please put an empty line after variables. <...> > +/** > + * Format link status to textual representation. This function threats all > + * special values like ETH_SPEED_NUM_UNKNOWN, ETH_LINK_DOWN etc. and convert > + * them to textual representation. > + * > + * @param str > + * A pointer to a string to be filled with textual representation of > + * device status. > + * @param len > + * Length of available memory at 'str' string. > + * @param fmt > + * Format string which allow to format link status. If NULL is provided > + * , default formatting will be applied. > + * Following specifiers are available: > + * - '%M' link speed in Mbits/s > + * - '%G' link speed in Gbits/s > + * - '%S' link status. e.g. Up or Down > + * - '%A' link autonegotiation state > + * - '%D' link duplex state > + * @param link It should be 'eth_link' otherwise doxygen is complaining. > + * Link status provided by rte_eth_link_get function > + * @return > + * - Number of bytes written to str array. In case of error, -1 is > returned. > + * > + */ > +__rte_experimental > +int rte_eth_link_strf(char *str, size_t len, const char *const fmt, > + const struct rte_eth_link *eth_link); > + For the API name, I guess 'strf' is for 'stringify' but what do you think about 'rte_eth_link_to_str()', I think more clear and simpler.