#include <bits/stdc++.h>
struct matrix_operation {
  int type;
  int param1;
  int param2;
  int param3;
};
void shift_row_right(int arr[][100], int row, int m) {
  int temp = arr[row][m - 1];
  for (int j = m - 1; j >= 0; j--) {
    arr[row][j] = arr[row][j - 1];
  }
  arr[row][0] = temp;
}
void shift_column_down(int arr[][100], int column, int n) {
  int temp = arr[n - 1][column];
  for (int i = n - 1; i >= 0; i--) {
    arr[i][column] = arr[i - 1][column];
  }
  arr[0][column] = temp;
}
void print_matrix(int arr[][100], int n, int m) {
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
      std::cout << arr[i][j] << " ";
    }
    std::cout << std::endl;
  }
}
int main() {
  int arr[100][100];
  memset(&arr[0][0], 0, 100 * 100 * sizeof(int));
  int n, m, q;
  std::cin >> n >> m >> q;
  std::vector<matrix_operation> operations;
  operations.reserve(q);
  while (q--) {
    int optype, row, column, value;
    std::cin >> optype;
    switch (optype) {
      case 1: {
        std::cin >> row;
        operations.push_back({optype, (row - 1), 0, 0});
        break;
      }
      case 2: {
        std::cin >> column;
        operations.push_back({optype, (column - 1), 0, 0});
        break;
      }
      case 3: {
        std::cin >> row >> column >> value;
        operations.push_back({optype, row - 1, column - 1, value});
      }
    }
  }
  auto size = operations.size();
  for (int i = size - 1; i >= 0; --i) {
    matrix_operation &operation = operations[i];
    switch (operation.type) {
      case 1:
        shift_row_right(arr, operation.param1, m);
        break;
      case 2:
        shift_column_down(arr, operation.param1, n);
        break;
      case 3:
        arr[operation.param1][operation.param2] = operation.param3;
        break;
    }
  }
  print_matrix(arr, n, m);
  return 0;
}
