• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# encoding: utf-8
3# Copyright 2020 Huawei Technologies Co., Ltd
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16# ============================================================================
17import sys
18import math
19
20MIN_CHARS_PER_ROW = 20      # minimal number of chars on one line
21COLS_TO_ROWS_RATIO = 4      # ratio of # columns to # rows (unit is char)
22MAX_LABEL_LENGTH = 1000     # maximal number of chars of a label
23
24
25# for specified number of chars, calculate a suitable number for how many chars per row
26# Num Total Chars   : n
27# Num Chars Per Row : m
28# Num Rows          : k
29# (k - 1) * m < n <= k * m
30# suppose: m / k = u
31# ==> sqrt(u * n) <= m < u / 2 + sqrt(u * n + u * u / 4)
32#     m = max(20, m)
33# parameters:
34# @total_chars  number of total chars
35# @ratio        ratio of # columns to # rows (unit is char)
36def calc_num_chars_per_row(total_chars, ratio):
37    chars_per_row = math.ceil(math.sqrt(total_chars * ratio))
38    return max(MIN_CHARS_PER_ROW, chars_per_row)
39
40
41def process_label_text(text):
42    label_len = min(len(text), MAX_LABEL_LENGTH)
43    chars_per_row = calc_num_chars_per_row(label_len, COLS_TO_ROWS_RATIO)
44    if label_len <= MIN_CHARS_PER_ROW:
45        return text
46    beg_idx = 0
47    texts = []
48    while beg_idx < label_len:
49        end_idx = beg_idx + chars_per_row
50        if end_idx >= label_len:
51            texts.append(text[beg_idx:label_len])
52        else:
53            texts.append(text[beg_idx:end_idx])
54        beg_idx = end_idx
55    return "\\n".join(texts)
56
57
58# insert '\n' to labels which are too long
59def process_file(f):
60    line_text = f.readline()
61    beg_idx = -1    # label begin index, index of 'label="'
62    end_idx = -1    # label end index, index of '"'
63    label_text = ""
64    label_prefix = ""
65    label_postfix = ""
66    while line_text:
67        line_text = line_text.rstrip()
68
69        if beg_idx < 0:
70            beg_idx = line_text.find('label="')
71            if beg_idx >= 0:
72                end_idx = line_text.find('"', beg_idx + len('label="'))
73                if end_idx >= 0:    # the full label text is on one line
74                    label = line_text[beg_idx + len('label="'):end_idx]
75                    print('%slabel="%s"%s' % (line_text[0:beg_idx], process_label_text(label), line_text[end_idx + 1:]))
76                    beg_idx = -1    # reset to initial conditions
77                else:               # the label text is distributed on multiple lines
78                    label_prefix = line_text[0:beg_idx]
79                    label_text = line_text[beg_idx + len('label="'):]
80            else:
81                print(line_text)
82        else:
83            end_idx = line_text.find('"')
84            if end_idx >= 0:
85                label_text = label_text + line_text[0:end_idx]
86                label_postfix = line_text[end_idx + 1:]
87                print('%slabel="%s"%s' % (label_prefix, process_label_text(label_text), label_postfix))
88                beg_idx = -1  # reset to initial conditions
89            else:
90                label_text += line_text
91
92        # print(f'{len(line_text)} - {line_text}')
93        line_text = f.readline()
94
95
96if __name__ == "__main__":
97    if len(sys.argv) > 1 and sys.argv[1] == "--help":
98        print("Usage: %s < dotfile | dot -Tpng -o filename.png" % sys.argv[0])
99        sys.exit()
100
101    # read text from stdin
102    process_file(sys.stdin)
103